Differences
This shows you the differences between two versions of the page.
search [2012/04/02 11:10] srdjan.lukovic [Search Sample] |
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. Searching without any of the fields filled, will find all Persons from the database. Providing parameter values will filter result set. Selecting one or more Bank Advisers from the list will search only for Persons which have selected instances as their bank advisers. | + | |
- | In additional options you can choose columns to be displayed, page size and whether result count to be displayed or not (this can have impact on performance on large data sets). Clicking on any column header will sort results in ascending/descending order based on values in that column. Results can be exported as excel table. | + | **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 31: | Line 48: | ||
private static final SimpleQueryDefinition prototypeQuery; | private static final SimpleQueryDefinition prototypeQuery; | ||
- | @Parameter // @Parametar annotation means that QueryBuilder expects parameter value from element component named as annotated String | + | @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 column "Name" will be in result table | + | @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) // @OrderByAnother - "Person" column will be order by 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 72: | Line 89: | ||
)); | )); | ||
- | includeInResultOnce( // columns in result table, in this order | + | includeInResultOnce( // Columns in the result table, in this order |
PERSON, | PERSON, | ||
GENDER, | GENDER, | ||
Line 132: | 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 155: | 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 161: | 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 170: | 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 247: | 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 285: | 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; |