Differences
This shows you the differences between two versions of the page.
|
search [2012/04/02 09:47] 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 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; | ||