Differences
This shows you the differences between two versions of the page.
search [2012/04/02 09:48] srdjan.lukovic [GUI Code] |
search [2012/07/09 10:51] (current) srdjan.lukovic [GUI Code] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Search Sample ====== | + | ====== Search ====== |
- | This sample is basic example of querying database with some advanced features. | + | |
+ | **Search** is a [[SOLoist Sample Applications|SOLoist sample application]] that shows a prototypical search form for searching the object space according to the user's input criteria. | ||
+ | |||
+ | The filtering criteria are entered in the input controls in the top part of the form. The result set is returned and shown in the grid at the bottom. | ||
+ | |||
+ | Searching without any of the fields filled in will return all objects of the class //Person// from the object space. Entering parameter values will filter the result set. Selecting one or more //Bank Advisers// from the list will search only for the //Persons// that have the selected objects as their //Bank Advisers// (linked over the //myBankAdvisers// association end). | ||
+ | |||
+ | In the result table, additional options can be selected: | ||
+ | * the columns to be displayed or hidden | ||
+ | * the page size | ||
+ | * whether the size of the entire result set will be calculated and displayed or not (this may have a great performance impact for very large data sets and complex queries). | ||
+ | |||
+ | Clicking on any column header of the result table will sort the results in the ascending/descending order of the values in that column. | ||
+ | |||
+ | The results can be exported to an Excel table. | ||
+ | |||
+ | A double-click on a //Person// object icon shows the form with the details of that object. | ||
==== Live example ==== | ==== Live example ==== | ||
- | [[http://soloistdemo.org/SampleApplications/search.html]] | + | [[http://soloistdemo.org/SampleApplications/search.html]]\\ |
+ | [[http://soloistdemo.org/SampleApplications/oql?q=SELECT+p%2C+p.name%2C+p.gender%2C+p.age%2C+p.dateOfBirth%2C+p.height%2C+p.isMarried%2C+p.photo%2C+p.rootFolder%0D%0AFROM+Person+p&f=html | OQL Query: Persons]] | ||
+ | |{{screen:search.png?250}}| | ||
===== UML Model ===== | ===== UML Model ===== | ||
+ | {{bankadvisers.png}} | ||
{{search.png}} | {{search.png}} | ||
Line 29: | Line 48: | ||
private static final SimpleQueryDefinition prototypeQuery; | private static final SimpleQueryDefinition prototypeQuery; | ||
- | @Parameter @Result("Name") | + | @Parameter // @Parametar annotation means that QueryBuilder expects a parameter value from the element component named as the annotated string |
+ | @Result("Name") // @Result annotation means that the column "Name" will be in the result table | ||
public static final String NAME = "NAME"; | public static final String NAME = "NAME"; | ||
- | @Result("Person") @OrderByAnother(NAME) | + | @Result("Person") @OrderByAnother(NAME) // @OrderByAnother - objects of Person will be ordered by the name attribute |
public static final String PERSON = "PERSON"; | public static final String PERSON = "PERSON"; | ||
Line 69: | Line 89: | ||
)); | )); | ||
- | includeInResultOnce( | + | includeInResultOnce( // Columns in the result table, in this order |
PERSON, | PERSON, | ||
GENDER, | GENDER, | ||
Line 129: | Line 149: | ||
import rs.sol.soloist.server.guiconfiguration.components.GUISearchPanelComponent; | import rs.sol.soloist.server.guiconfiguration.components.GUISearchPanelComponent; | ||
import rs.sol.soloist.server.guiconfiguration.construction.GUIComponentBinding; | import rs.sol.soloist.server.guiconfiguration.construction.GUIComponentBinding; | ||
- | import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIElementComponent; | + | import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIEdit; |
- | import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIInputKind; | + | import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIInput; |
- | import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIListWidget; | + | |
- | import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIMultipleElementWidget; | + | |
- | import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUISlotEditorKind; | + | |
- | import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUISubnodesInput; | + | |
- | import rs.sol.soloist.server.guiconfiguration.layout.CellLayoutData; | + | |
import rs.sol.soloist.server.guiconfiguration.layout.FlowLayout; | import rs.sol.soloist.server.guiconfiguration.layout.FlowLayout; | ||
- | import rs.sol.soloist.server.guiconfiguration.layout.LayoutData; | + | import rs.sol.soloist.server.guiconfiguration.layout.TableLayoutData; |
+ | import rs.sol.soloist.server.guiconfiguration.nonvisualcompoments.GUIFindAllInstancesSAPComponent; | ||
import rs.sol.soloist.server.guiconfiguration.style.GUIBindingsFeature; | import rs.sol.soloist.server.guiconfiguration.style.GUIBindingsFeature; | ||
import rs.sol.soloist.server.guiconfiguration.style.GUIContext; | import rs.sol.soloist.server.guiconfiguration.style.GUIContext; | ||
Line 152: | Line 168: | ||
public void init() throws InitializerFailedException { | public void init() throws InitializerFailedException { | ||
GUIApplicationComponent application = new GUIApplicationComponent(); | GUIApplicationComponent application = new GUIApplicationComponent(); | ||
- | application.name.set(Text.fromString("SearchSample")); | + | application.setName("SearchSample"); |
SoloistServiceServlet.registerApplication(application); | SoloistServiceServlet.registerApplication(application); | ||
Line 158: | Line 174: | ||
GUILabelComponent title = GUILabelComponent.create(root, "Search"); | GUILabelComponent title = GUILabelComponent.create(root, "Search"); | ||
- | title.styleName.set(Text.fromString("titleStyle")); | + | title.setStyle("titleStyle"); |
GUIPanelComponent topPanel = GUIPanelComponent.createFlow(root); | GUIPanelComponent topPanel = GUIPanelComponent.createFlow(root); | ||
- | topPanel.styleName.set(Text.fromString("topPanel")); | + | topPanel.setStyle("topPanel"); |
GUIDeckComponent mainDeck = GUIDeckComponent.create(topPanel); | GUIDeckComponent mainDeck = GUIDeckComponent.create(topPanel); | ||
Line 167: | Line 183: | ||
GUIPanelComponent wrapPanel = GUIPanelComponent.createFlow(mainDeck); | GUIPanelComponent wrapPanel = GUIPanelComponent.createFlow(mainDeck); | ||
GUISearchPanelComponent searchForm = GUISearchPanelComponent.create(wrapPanel, new FlowLayout()); | GUISearchPanelComponent searchForm = GUISearchPanelComponent.create(wrapPanel, new FlowLayout()); | ||
- | //GUISearchPanelComponent binds element components implicitly between search form and query builder based on components' names | + | // GUISearchPanelComponent binds element components implicitly between the search form and the query builder based on the components' names |
- | searchForm.styleName.set(Text.fromString("form searchForm")); | + | searchForm.setStyle("form searchForm"); |
GUIPanelComponent table = GUIPanelComponent.createTable(searchForm); | GUIPanelComponent table = GUIPanelComponent.createTable(searchForm); | ||
- | table.styleName.set(Text.fromString("table")); | + | table.setStyle("table"); |
- | LayoutData.setSize(table, "100%", null); | + | table.setSize("100%", null); |
int row = 0; | int row = 0; | ||
- | GUIElementComponent.createInput(table, PersonQueryBuilder.NAME, Text.CLASSIFIER, row++, 1); // name needs to be provided, in this case PersonQueryBuilder.NAME constant | + | // name needs to be provided, in this case PersonQueryBuilder.NAME constant |
- | GUIElementComponent.createInput(table, PersonQueryBuilder.GENDER, Repository.getRepository().getEnumeration(Gender.FQ_TYPE_NAME), row++, 1); | + | GUIInput.createField(table, Text.CLASSIFIER, row++, 1).setName(PersonQueryBuilder.NAME); |
- | GUIElementComponent.createInput(table, PersonQueryBuilder.DATE_OF_BIRTH, Date.CLASSIFIER, row++, 1); | + | GUIInput.createField(table, Repository.getRepository().getEnumeration(Gender.FQ_TYPE_NAME), row++, 1).setName(PersonQueryBuilder.GENDER); |
- | GUIElementComponent.createInput(table, PersonQueryBuilder.IS_MARRIED, Boolean.CLASSIFIER, row++, 1); | + | GUIInput.createField(table, Date.CLASSIFIER, row++, 1).setName(PersonQueryBuilder.DATE_OF_BIRTH); |
- | GUIElementComponent.createInput(table, PersonQueryBuilder.OLDER_THAN, Integer.CLASSIFIER, row++, 1); | + | GUIInput.createField(table, Boolean.CLASSIFIER, row++, 1).setName(PersonQueryBuilder.IS_MARRIED); |
- | GUIElementComponent.createInput(table, PersonQueryBuilder.YOUNGER_THAN, Integer.CLASSIFIER, row++, 1); | + | GUIInput.createField(table, Integer.CLASSIFIER, row++, 1).setName(PersonQueryBuilder.OLDER_THAN); |
+ | GUIInput.createField(table, Integer.CLASSIFIER, row++, 1).setName(PersonQueryBuilder.YOUNGER_THAN); | ||
row = 0; | row = 0; | ||
- | GUILabelComponent.create(table, "Name", row++, 0).styleName.set(Text.fromString("formLabel")); | + | GUILabelComponent.create(table, "Name", row++, 0).setStyle("formLabel"); |
- | GUILabelComponent.create(table, "Gender", row++, 0).styleName.set(Text.fromString("formLabel")); | + | GUILabelComponent.create(table, "Gender", row++, 0).setStyle("formLabel"); |
- | GUILabelComponent.create(table, "Date of birth", row++, 0).styleName.set(Text.fromString("formLabel")); | + | GUILabelComponent.create(table, "Date of birth", row++, 0).setStyle("formLabel"); |
- | GUILabelComponent.create(table, "Is married?", row++, 0).styleName.set(Text.fromString("formLabel")); | + | GUILabelComponent.create(table, "Is married?", row++, 0).setStyle("formLabel"); |
- | GUILabelComponent.create(table, "Older than", row++, 0).styleName.set(Text.fromString("formLabel")); | + | GUILabelComponent.create(table, "Older than", row++, 0).setStyle("formLabel"); |
- | GUILabelComponent.create(table, "Younger than", row++, 0).styleName.set(Text.fromString("formLabel")); | + | GUILabelComponent.create(table, "Younger than", row++, 0).setStyle("formLabel"); |
GUILabelComponent.create(wrapPanel, "Search by Bank Advisers:"); | GUILabelComponent.create(wrapPanel, "Search by Bank Advisers:"); | ||
GUISearchPanelComponent searchList = GUISearchPanelComponent.create(wrapPanel, new FlowLayout()); | GUISearchPanelComponent searchList = GUISearchPanelComponent.create(wrapPanel, new FlowLayout()); | ||
- | GUIElementComponent bankAdvisors = GUIElementComponent.createInput(searchList, PersonQueryBuilder.BANK_ADVISOR, new GUIListWidget(), | + | GUIFindAllInstancesSAPComponent advisersSource = GUIFindAllInstancesSAPComponent.create(searchList, BankAdviser.CLASSIFIER); |
- | GUISubnodesInput.create(BankAdviser.CLASSIFIER), null); | + | GUIInput bankAdvisors = GUIInput.createList(searchList); |
- | GUIInputKind.get(bankAdvisors).upperBound.set(Integer.valueOf(-1)); | + | GUIComponentBinding.create(advisersSource.opValue(), bankAdvisors.ipCollection()); |
- | CellLayoutData.setSize(bankAdvisors, "250px", "154px"); | + | bankAdvisors.setName(PersonQueryBuilder.BANK_ADVISOR); |
- | bankAdvisors.styleName.set(Text.fromString("listWidget")); | + | bankAdvisors.setUpperBound(-1); |
+ | bankAdvisors.setSize("250px", "154px"); | ||
+ | bankAdvisors.setStyle("listWidget"); | ||
GUIButtonComponent btnAll = GUIButtonComponent.create(wrapPanel, "Select All"); | GUIButtonComponent btnAll = GUIButtonComponent.create(wrapPanel, "Select All"); | ||
GUIButtonComponent btnNone = GUIButtonComponent.create(wrapPanel, "Select None"); | GUIButtonComponent btnNone = GUIButtonComponent.create(wrapPanel, "Select None"); | ||
- | GUIComponentBinding.create(btnAll.click, GUIMultipleElementWidget.get(bankAdvisors).selectAll); | + | GUIComponentBinding.create(btnAll.opClick(), bankAdvisors.ipSelectAll()); |
- | GUIComponentBinding.create(btnNone.click, GUIMultipleElementWidget.get(bankAdvisors).unselectAll); | + | GUIComponentBinding.create(btnNone.opClick(), bankAdvisors.ipUnselectAll()); |
GUIPanelComponent buttonPanel = GUIPanelComponent.createFlow(wrapPanel); | GUIPanelComponent buttonPanel = GUIPanelComponent.createFlow(wrapPanel); | ||
- | buttonPanel.styleName.set(Text.fromString("searchButtons")); | + | buttonPanel.setStyle("searchButtons"); |
GUIButtonComponent searchButton = GUIButtonComponent.create(buttonPanel, "Search"); | GUIButtonComponent searchButton = GUIButtonComponent.create(buttonPanel, "Search"); | ||
- | searchButton.styleName.set(Text.fromString("submitButton")); | + | searchButton.setStyle("submitButton"); |
GUIButtonComponent resetButton = GUIButtonComponent.create(buttonPanel, "Reset"); | GUIButtonComponent resetButton = GUIButtonComponent.create(buttonPanel, "Reset"); | ||
- | resetButton.styleName.set(Text.fromString("submitButton")); | + | resetButton.setStyle("submitButton"); |
GUIPanelComponent searchTable = GUIPanelComponent.createFlow(wrapPanel); | GUIPanelComponent searchTable = GUIPanelComponent.createFlow(wrapPanel); | ||
- | searchTable.styleName.set(Text.fromString("searchPanel")); | + | searchTable.setStyle("searchPanel"); |
PersonSearch searchResult = new PersonSearch(); | PersonSearch searchResult = new PersonSearch(); | ||
- | searchResult.parent.set(searchTable); | + | searchTable.add(searchResult); |
- | searchResult.doInitialSearch.set(Boolean.FALSE); | + | searchResult.setDoInitialSearch(false); |
- | searchForm.dynamicBindingDest.set(searchResult); // binds all fields in search form with corresponding query builder | + | searchForm.addDynamicBindingDest(searchResult); // binds all fields in search form with corresponding query builder |
- | searchList.dynamicBindingDest.set(searchResult); | + | searchList.addDynamicBindingDest(searchResult); |
- | LayoutData.setSize(searchResult, "100%", null); | + | GUIComponentBinding.create(searchButton.opClick(), searchResult.ipSearch()); |
+ | GUIComponentBinding.create(resetButton.opClick(), searchForm.ipReset()); | ||
+ | GUIComponentBinding.create(resetButton.opClick(), searchResult.ipClearContents()); | ||
- | GUIComponentBinding.create(searchButton.click, searchResult.search); | + | GUIComponentBinding.create(searchButton.opClick(), searchResult.ipSearch()); |
- | GUIComponentBinding.create(resetButton.click, searchForm.reset); | + | GUIComponentBinding.create(resetButton.opClick(), searchForm.ipReset()); |
- | GUIComponentBinding.create(resetButton.click, searchResult.clearContents); | + | GUIComponentBinding.create(resetButton.opClick(), searchResult.ipClearContents()); |
- | GUIComponentBinding.create(wrapPanel.output, searchResult.search); | + | GUIComponentBinding.create(wrapPanel.opRelay2(), searchResult.ipSearch()); |
GUIPanelComponent personDetails = GUIPanelComponent.createTable(mainDeck); | GUIPanelComponent personDetails = GUIPanelComponent.createTable(mainDeck); | ||
- | personDetails.styleName.set(Text.fromString("searchDetails")); | + | personDetails.setStyle("searchDetails"); |
GUIPanelComponent detailsTable = GUIPanelComponent.createTable(personDetails); | GUIPanelComponent detailsTable = GUIPanelComponent.createTable(personDetails); | ||
- | application.context.set(createContextAndStyles(detailsTable)); | + | application.setContext(createContextAndStyles(detailsTable)); |
createDetails(detailsTable, wrapPanel); | createDetails(detailsTable, wrapPanel); | ||
Line 244: | Line 265: | ||
int row = 0; | int row = 0; | ||
GUILabelComponent.create(personDetails, "Name: ", row, 0); | GUILabelComponent.create(personDetails, "Name: ", row, 0); | ||
- | GUIElementComponent nameEditor = GUIElementComponent.createSlotEditor(personDetails, Person.PROPERTIES.name, row++, 1); | + | GUIEdit nameEditor = GUIEdit.createField(personDetails, Person.PROPERTIES.name, row++, 1); |
GUILabelComponent.create(personDetails, "Gender: ", row, 0); | GUILabelComponent.create(personDetails, "Gender: ", row, 0); | ||
- | GUIElementComponent genderEditor = GUIElementComponent.createSlotEditor(personDetails, Person.PROPERTIES.gender, row++, 1); | + | GUIEdit genderEditor = GUIEdit.createField(personDetails, Person.PROPERTIES.gender, row++, 1); |
GUILabelComponent.create(personDetails, "Age: ", row, 0); | GUILabelComponent.create(personDetails, "Age: ", row, 0); | ||
- | GUIElementComponent ageEditor = GUIElementComponent.createSlotEditor(personDetails, Person.PROPERTIES.age, row++, 1); | + | GUIEdit ageEditor = GUIEdit.createField(personDetails, Person.PROPERTIES.age, row++, 1); |
GUILabelComponent.create(personDetails, "Date of birth: ", row, 0); | GUILabelComponent.create(personDetails, "Date of birth: ", row, 0); | ||
- | GUIElementComponent dateOfBirthEditor = GUIElementComponent.createSlotEditor(personDetails, Person.PROPERTIES.dateOfBirth, row++, 1); | + | GUIEdit dateOfBirthEditor = GUIEdit.createField(personDetails, Person.PROPERTIES.dateOfBirth, row++, 1); |
GUILabelComponent.create(personDetails, "Height [m]: ", row, 0); | GUILabelComponent.create(personDetails, "Height [m]: ", row, 0); | ||
- | GUIElementComponent heightEditor = GUIElementComponent.createSlotEditor(personDetails, Person.PROPERTIES.height, row++, 1); | + | GUIEdit heightEditor = GUIEdit.createField(personDetails, Person.PROPERTIES.height, row++, 1); |
GUILabelComponent.create(personDetails, "Is married: ", row, 0); | GUILabelComponent.create(personDetails, "Is married: ", row, 0); | ||
- | GUIElementComponent isMarriedEditor = GUIElementComponent.createSlotEditor(personDetails, Person.PROPERTIES.isMarried, row++, 1); | + | GUIEdit isMarriedEditor = GUIEdit.createField(personDetails, Person.PROPERTIES.isMarried, row++, 1); |
- | GUIComponentBinding.create(personDetails.input, GUISlotEditorKind.get(nameEditor).element); | + | GUIComponentBinding.create(personDetails.opRelay1(), nameEditor.ipElement()); |
- | GUIComponentBinding.create(personDetails.input, GUISlotEditorKind.get(genderEditor).element); | + | GUIComponentBinding.create(personDetails.opRelay1(), genderEditor.ipElement()); |
- | GUIComponentBinding.create(personDetails.input, GUISlotEditorKind.get(ageEditor).element); | + | GUIComponentBinding.create(personDetails.opRelay1(), ageEditor.ipElement()); |
- | GUIComponentBinding.create(personDetails.input, GUISlotEditorKind.get(dateOfBirthEditor).element); | + | GUIComponentBinding.create(personDetails.opRelay1(), dateOfBirthEditor.ipElement()); |
- | GUIComponentBinding.create(personDetails.input, GUISlotEditorKind.get(heightEditor).element); | + | GUIComponentBinding.create(personDetails.opRelay1(), heightEditor.ipElement()); |
- | GUIComponentBinding.create(personDetails.input, GUISlotEditorKind.get(isMarriedEditor).element); | + | GUIComponentBinding.create(personDetails.opRelay1(), isMarriedEditor.ipElement()); |
- | GUIButtonComponent backButton = GUIButtonComponent.create(personDetails, "Back", row++, 0); | + | GUIButtonComponent backButton = GUIButtonComponent.create(personDetails, "Back"); |
- | GUIComponentBinding.create(backButton.click, backTo.show); | + | backButton.setLayoutData(TableLayoutData.create(row++, 0)); |
+ | GUIComponentBinding.create(backButton.opClick(), backTo.ipShow()); | ||
} | } | ||
private GUIContext createContextAndStyles(GUIPanelComponent personDetails) { | private GUIContext createContextAndStyles(GUIPanelComponent personDetails) { | ||
GUIContext context = new GUIContext(); | GUIContext context = new GUIContext(); | ||
- | context.supercontext.set(DefaultContextInit.getRoot()); | + | DefaultContextInit.getRoot().addContext(context); |
// how will Person objects look like in the GUI? | // how will Person objects look like in the GUI? | ||
Line 282: | Line 304: | ||
GUIBindingsFeature bf = GUIBindingsFeature.create(person); | GUIBindingsFeature bf = GUIBindingsFeature.create(person); | ||
- | GUIComponentBinding.create(bf.doubleClick, personDetails.input); // doubleClick signal carries Person object | + | // doubleClick signal carries a Person object |
- | // panel's input pin is unfortunately named, it is actually input/output pin, and can be used to send messages to panel's internal components (see createDetails() method) | + | GUIComponentBinding.create(bf.opDoubleClick(), personDetails.ipRelay1()); |
- | GUIComponentBinding.create(bf.doubleClick, personDetails.show); // double-clicking on person in result table will show person's details | + | // double-clicking on a person in the result table will show the person's details |
+ | GUIComponentBinding.create(bf.opDoubleClick(), personDetails.ipShow()); | ||
return context; | return context; |