001 /**
002 * Copyright 2010 The Kuali Foundation Licensed under the
003 * Educational Community License, Version 2.0 (the "License"); you may
004 * not use this file except in compliance with the License. You may
005 * obtain a copy of the License at
006 *
007 * http://www.osedu.org/licenses/ECL-2.0
008 *
009 * Unless required by applicable law or agreed to in writing,
010 * software distributed under the License is distributed on an "AS IS"
011 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
012 * or implied. See the License for the specific language governing
013 * permissions and limitations under the License.
014 */
015
016 package org.kuali.student.common.ui.client.widgets.search;
017
018 import java.util.ArrayList;
019 import java.util.HashMap;
020 import java.util.LinkedHashMap;
021 import java.util.List;
022 import java.util.Map;
023
024 import org.kuali.student.common.ui.client.application.Application;
025 import org.kuali.student.common.ui.client.configurable.mvc.DefaultWidgetFactory;
026 import org.kuali.student.common.ui.client.mvc.Callback;
027 import org.kuali.student.common.ui.client.widgets.KSButton;
028 import org.kuali.student.common.ui.client.widgets.KSDropDown;
029 import org.kuali.student.common.ui.client.widgets.KSLabel;
030 import org.kuali.student.common.ui.client.widgets.KSButtonAbstract.ButtonStyle;
031 import org.kuali.student.common.ui.client.widgets.buttongroups.ButtonEnumerations;
032 import org.kuali.student.common.ui.client.widgets.buttongroups.ButtonEnumerations.ButtonEnum;
033 import org.kuali.student.common.ui.client.widgets.field.layout.button.ActionCancelGroup;
034 import org.kuali.student.common.ui.client.widgets.field.layout.button.ButtonGroup;
035 import org.kuali.student.common.ui.client.widgets.field.layout.element.FieldElement;
036 import org.kuali.student.common.ui.client.widgets.layout.HorizontalBlockFlowPanel;
037 import org.kuali.student.common.ui.client.widgets.layout.VerticalFlowPanel;
038 import org.kuali.student.common.ui.client.widgets.list.KSSelectItemWidgetAbstract;
039 import org.kuali.student.common.ui.client.widgets.list.ListItems;
040 import org.kuali.student.common.ui.client.widgets.list.SelectionChangeEvent;
041 import org.kuali.student.common.ui.client.widgets.list.SelectionChangeHandler;
042 import org.kuali.student.common.ui.client.widgets.searchtable.ResultRow;
043 import org.kuali.student.core.assembly.data.LookupMetadata;
044 import org.kuali.student.core.assembly.data.LookupParamMetadata;
045 import org.kuali.student.core.assembly.data.Metadata;
046 import org.kuali.student.core.assembly.data.LookupMetadata.Usage;
047 import org.kuali.student.core.assembly.data.Metadata.WriteAccess;
048 import org.kuali.student.core.search.dto.SearchParam;
049 import org.kuali.student.core.search.dto.SearchRequest;
050
051 import com.google.gwt.core.client.GWT;
052 import com.google.gwt.event.dom.client.ClickEvent;
053 import com.google.gwt.event.dom.client.ClickHandler;
054 import com.google.gwt.user.client.ui.Composite;
055 import com.google.gwt.user.client.ui.HTMLPanel;
056 import com.google.gwt.user.client.ui.HasText;
057 import com.google.gwt.user.client.ui.HasValue;
058 import com.google.gwt.user.client.ui.SimplePanel;
059 import com.google.gwt.user.client.ui.VerticalPanel;
060 import com.google.gwt.user.client.ui.Widget;
061
062 public class SearchPanel extends Composite{
063
064 //Layout configuration
065 private VerticalFlowPanel layout = new VerticalFlowPanel();
066 private SimplePanel searchSelectorPanel = new SimplePanel();
067 private VerticalFlowPanel resultsTablePanel = new VerticalFlowPanel();
068 private HorizontalBlockFlowPanel enteredCriteriaString = new HorizontalBlockFlowPanel();
069 private CollapsablePanel modifySearchPanel;
070 private String criteriaInstructions = getMessage("searchPanelEnterFields");
071 private KSLabel enteredCriteriaHeading = new KSLabel(getMessage("searchPanelCriteria"));
072 private SearchResultsTable table;
073 private boolean isMultiSelect = true;
074
075 public static enum SearchStyle{ADVANCED, CUSTOM};
076 private ActionCancelGroup actionCancelButtons;
077
078 private String actionLabel = getMessage("search"); //set default action label
079 private boolean resultsSelected = false;
080
081 //Search data
082 private List<LookupMetadata> lookups = new ArrayList<LookupMetadata>();
083 private boolean multiSelect = false;
084 private boolean resultsShown = false;
085 private SearchParametersWidget activeSearchParametersWidget = null;
086 // uses "name" of the lookup metadata to lookup the widget that layouts the search UI
087 private Map<String, SearchParametersWidget> searchParameterWidgetMap = new HashMap<String, SearchParametersWidget>();
088 private List<SearchField> searchFields = new ArrayList<SearchField>();
089 private List<Callback<LookupMetadata>> lookupChangedCallbacks = new ArrayList<Callback<LookupMetadata>>();
090 private String selectedLookupName;
091 private List<Callback<List<SelectedResults>>> selectedCompleteCallbacks = new ArrayList<Callback<List<SelectedResults>>>();
092 private List<Callback<Boolean>> actionCompletedCallbacks = new ArrayList<Callback<Boolean>>();
093
094
095 interface SearchParametersWidget {
096 public SearchRequest getSearchRequest();
097 public LookupMetadata getLookupMetadata();
098 public List<HasSearchParam> getSearchParams();
099 }
100
101 public SearchPanel(LookupMetadata meta){
102 lookups.add(meta);
103 // setupSearch();
104 this.initWidget(layout);
105 }
106
107 public SearchPanel(List<LookupMetadata> metas){
108 lookups = metas;
109 // setupSearch();
110 this.initWidget(layout);
111 }
112
113 @SuppressWarnings("unchecked")
114 public ButtonGroup getButtons(){
115 return actionCancelButtons;
116 }
117
118 public void setMutipleSelect(boolean isMultiSelect){
119 this.isMultiSelect = isMultiSelect;
120 }
121
122 public void setupButtons() {
123 if (actionCancelButtons != null) {
124 actionCancelButtons.setButtonText(ButtonEnumerations.SearchCancelEnum.SEARCH, getActionLabel());
125 actionCancelButtons.addCallback(new Callback<ButtonEnumerations.ButtonEnum>(){
126 @Override
127 public void exec(ButtonEnum result) {
128 if (result == ButtonEnumerations.SearchCancelEnum.SEARCH) {
129 table.getContentTable().removeContent();
130 getActionCompleteCallback().exec(true);
131 }
132 }
133 });
134 }
135 }
136
137 public void setupSearch() {
138
139 resultsTablePanel.clear();
140 layout.clear();
141 resultsShown = false;
142
143 //create search panel
144 Widget searchParamPanel;
145 if (lookups.size() == 1) {
146 searchParamPanel = createSearchParamPanel(lookups.get(0));
147 selectedLookupName = lookups.get(0).getName();
148 activeSearchParametersWidget = searchParameterWidgetMap.get(selectedLookupName);
149 } else {
150 LinkedHashMap<String, Widget> searches = new LinkedHashMap<String, Widget>();
151 LinkedHashMap<String, LookupMetadata> searchLookups = new LinkedHashMap<String, LookupMetadata>();
152 for(LookupMetadata lookup: lookups){
153 searches.put(lookup.getName(), createSearchParamPanel(lookup));
154 searchLookups.put(lookup.getName(), lookup);
155 }
156 selectedLookupName = lookups.get(0).getName();
157 // Sets the activeSearchParametersWidget to be the first search
158 activeSearchParametersWidget = searchParameterWidgetMap.get(selectedLookupName);
159 String actionLabel = (lookups.get(0) == null)? null : lookups.get(0)
160 .getWidgetOptionValue(LookupMetadata.WidgetOption.ADVANCED_LIGHTBOX_ACTION_LABEL);
161 setActionLabel(actionLabel);
162 searchParamPanel = new SwappablePanel(searches);
163 ((SwappablePanel)searchParamPanel).setSearchLookups(searchLookups);
164 ((SwappablePanel)searchParamPanel).addLookupChangedCallback(new Callback<LookupMetadata>() {
165 @Override
166 public void exec(LookupMetadata selectedLookup) {
167 activeSearchParametersWidget = searchParameterWidgetMap.get(selectedLookup.getName());
168 selectedLookupName = selectedLookup.getName();
169 if (lookupChangedCallbacks != null) {
170 for (Callback<LookupMetadata> callback : lookupChangedCallbacks) {
171 callback.exec(selectedLookup);
172 }
173 }
174 }
175 });
176 }
177 searchSelectorPanel.setWidget(searchParamPanel);
178 layout.add(searchSelectorPanel);
179
180 //create layout for results screen
181 enteredCriteriaHeading.addStyleName("ks-form-module-single-line-margin");
182 enteredCriteriaHeading.addStyleName("KS-Advanced-Search-Search-Criteria-Label");
183 resultsTablePanel.add(enteredCriteriaHeading);
184 resultsTablePanel.add(enteredCriteriaString);
185 resultsTablePanel.setVisible(false);
186 table = new SearchResultsTable();
187 table.setMutipleSelect(isMultiSelect);
188 table.addStyleName("KS-Advanced-Search-Results-Table");
189 resultsTablePanel.add(table);
190 layout.add(resultsTablePanel);
191
192 table.getMslabel().addClickHandler(new ClickHandler(){
193
194 @Override
195 public void onClick(ClickEvent event) {
196 if(modifySearchPanel.isOpen()){
197 modifySearchPanel.close();
198 }
199 else{
200 modifySearchPanel.open();
201 }
202
203 resultsTablePanel.setVisible(false);
204 resultsSelected = false;
205 actionCancelButtons.setButtonText(ButtonEnumerations.SearchCancelEnum.SEARCH, getActionLabel());
206 }
207 });
208
209 resultsSelected = false;
210 actionCancelButtons.setButtonText(ButtonEnumerations.SearchCancelEnum.SEARCH, getActionLabel());
211 }
212
213 private Widget createSearchParamPanel(LookupMetadata meta){
214 ParamListItems listItems = new ParamListItems(meta);
215 final AdvancedSearch advancedSearch = new AdvancedSearch(meta);
216 LinkPanel panel = new LinkPanel(SearchStyle.ADVANCED, advancedSearch);
217 searchParameterWidgetMap.put(meta.getName(), advancedSearch);
218
219 //check whether we need custom tab i.e. whether we have at least one parameter that should appear on custom tab
220 for(LookupParamMetadata metaParam: meta.getParams()){
221 if ((metaParam.getUsage() == Usage.CUSTOM) || (metaParam.getUsage() == Usage.ADVANCED_CUSTOM)) {
222 final CustomizedSearch customizedSearch = new CustomizedSearch(meta, listItems);
223 KSButton button = panel.addLinkToPanel(SearchStyle.ADVANCED, getMessage("searchPanelCustomizeSearch"), SearchStyle.CUSTOM);
224 button.addClickHandler(new ClickHandler(){
225
226 @Override
227 public void onClick(ClickEvent event) {
228 resultsTablePanel.setVisible(false);
229 activeSearchParametersWidget = customizedSearch;
230 }});
231 button.addStyleName("KS-Advanced-Search-Link");
232 button.getParent().addStyleName("clearfix");
233 panel.addPanel(SearchStyle.CUSTOM, customizedSearch);
234 button = panel.addLinkToPanel(SearchStyle.CUSTOM, getMessage("searchPanelReturnToAdvancedSearch"), SearchStyle.ADVANCED);
235 button.addClickHandler(new ClickHandler(){
236
237 @Override
238 public void onClick(ClickEvent event) {
239 resultsTablePanel.setVisible(false);
240 activeSearchParametersWidget = advancedSearch;
241 }});
242 button.addStyleName("KS-Advanced-Search-Link");
243 button.getParent().addStyleName("clearfix");
244 break;
245 }
246 }
247
248 return panel;
249 }
250
251 private class CustomizedSearch extends Composite implements SearchParametersWidget {
252
253 private List<CustomLine> lines = new ArrayList<CustomLine>();
254 private List<HasSearchParam> searchParams = new ArrayList<HasSearchParam>();
255 private VerticalPanel layout = new VerticalPanel();
256 private VerticalPanel linePanel = new VerticalPanel();
257 private LookupMetadata meta;
258
259 public CustomizedSearch(final LookupMetadata meta, final ParamListItems listItems){
260
261 KSLabel instrLabel = new KSLabel(criteriaInstructions);
262 layout.add(instrLabel);
263
264 layout.add(linePanel);
265 CustomLine line = new CustomLine(meta, listItems);
266 line.addStyleName("ks-form-module-single-line-margin");
267 linePanel.add(line);
268 lines.add(line);
269 searchParams.add(line);
270 this.meta = meta;
271
272 KSButton addCriteria = new KSButton(getMessage("searchPanelAddCriteria"), ButtonStyle.SECONDARY);
273 addCriteria.addClickHandler(new ClickHandler(){
274
275 @Override
276 public void onClick(ClickEvent event) {
277 CustomLine line = new CustomLine(meta, listItems);
278 line.addStyleName("ks-form-module-single-line-margin");
279 linePanel.add(line);
280 lines.add(line);
281 searchParams.add(line);
282 }
283 });
284
285 addCriteria.addStyleName("ks-form-module-single-line-margin");
286 layout.add(addCriteria);
287
288 this.initWidget(layout);
289 }
290
291 public LookupMetadata getLookupMetadata() {
292 return meta;
293 }
294
295 @Override
296 public SearchRequest getSearchRequest() {
297 //Create search request and then pass it to the table
298 //TODO pass search to the table
299 SearchRequest sr = new SearchRequest();
300 List<SearchParam> params = new ArrayList<SearchParam>();
301 for(CustomLine field: lines){
302 SearchParam param = field.getSearchParam();
303 //TODO is this check needed here? probably. assuming string here
304 if((param.getValue() != null)){
305 params.add(param);
306 }
307 }
308
309 //add search criteria widgets to the custom tab
310 for(LookupParamMetadata metaParam: meta.getParams()){
311
312 //select only parameters shown on custom search tab
313 if ((metaParam.getUsage() != Usage.CUSTOM) && (metaParam.getUsage() != Usage.ADVANCED_CUSTOM)) {
314 continue;
315 }
316
317 if(metaParam.getWriteAccess() == WriteAccess.NEVER){
318 SearchParam param = new SearchParam();
319 param.setKey(metaParam.getKey());
320 if(metaParam.getDefaultValueList()==null){
321 param.setValue(metaParam.getDefaultValueString());
322 }else{
323 param.setValue(metaParam.getDefaultValueList());
324 }
325 params.add(param);
326 }
327 else if(metaParam.getWriteAccess() == WriteAccess.WHEN_NULL){
328 if((metaParam.getDefaultValueString() != null && !metaParam.getDefaultValueString().isEmpty())||
329 (metaParam.getDefaultValueList() != null && !metaParam.getDefaultValueList().isEmpty())){
330 SearchParam param = new SearchParam();
331 param.setKey(metaParam.getKey());
332 if(metaParam.getDefaultValueList()==null){
333 param.setValue(metaParam.getDefaultValueString());
334 }else{
335 param.setValue(metaParam.getDefaultValueList());
336 }
337 params.add(param);
338 }
339 }
340 }
341
342 sr.setParams(params);
343 sr.setSearchKey(meta.getSearchTypeId());
344 return sr;
345 }
346
347 @Override
348 public List<HasSearchParam> getSearchParams() {
349 return searchParams;
350 }
351
352 }
353
354 private interface HasSearchParam{
355 public SearchParam getSearchParam();
356 public String getFieldName();
357 }
358
359 private static class CustomLine extends Composite implements HasSearchParam{
360 private KSDropDown paramSelector = new KSDropDown();
361 private SimplePanel widgetPanel = new SimplePanel();
362 private Widget widget = null;
363 private String key;
364 private HorizontalBlockFlowPanel layout = new HorizontalBlockFlowPanel();
365 private ParamListItems listItems;
366
367 public CustomLine(LookupMetadata meta, final ParamListItems listItems){
368
369 List<LookupParamMetadata> customParams = new ArrayList<LookupParamMetadata>();
370
371 for (LookupParamMetadata lookupParamMetadata : listItems.getParams()) {
372 if (lookupParamMetadata.getWriteAccess() != WriteAccess.NEVER){
373 if (lookupParamMetadata.getUsage() == Usage.CUSTOM || lookupParamMetadata.getUsage() == Usage.ADVANCED_CUSTOM ) {
374 customParams.add(lookupParamMetadata);
375 }
376 }
377 }
378
379 ParamListItems customParamList = new ParamListItems(customParams);
380
381 this.listItems = customParamList;
382 paramSelector.setBlankFirstItem(false);
383 paramSelector.setListItems(customParamList);
384
385 String id = meta.getParams().get(0).getKey();
386 paramSelector.selectItem(id);
387 widget = listItems.getWidget(id);
388 key = id;
389 widgetPanel.setWidget(widget);
390 paramSelector.addSelectionChangeHandler(new SelectionChangeHandler(){
391
392 @Override
393 public void onSelectionChange(SelectionChangeEvent event) {
394 String id = ((KSSelectItemWidgetAbstract)event.getWidget()).getSelectedItem();
395 widget = listItems.getWidget(id);
396 widgetPanel.setWidget(widget);
397 key = id;
398
399 }
400 });
401 layout.add(paramSelector);
402 layout.add(widgetPanel);
403 this.initWidget(layout);
404 }
405
406 public SearchParam getSearchParam(){
407 return SearchPanel.getSearchParam(widget, key);
408 }
409
410 public String getKey(){
411 return key;
412 }
413
414 public String getFieldName(){
415 String id = paramSelector.getSelectedItem();
416 return listItems.getItemText(id);
417 }
418 }
419
420 private class AdvancedSearch extends Composite implements SearchParametersWidget {
421 private LookupMetadata meta;
422 private List<HasSearchParam> searchParams = new ArrayList<HasSearchParam>();
423
424 public AdvancedSearch(final LookupMetadata meta){
425 VerticalPanel panel = new VerticalPanel();
426
427 KSLabel instrLabel = new KSLabel();
428 panel.add(instrLabel);
429 this.meta = meta;
430
431 //add widget for each search criteria to the advanced tab
432 boolean allFieldsRequired = true;
433 for(LookupParamMetadata param: meta.getParams()){
434
435 //select only parameters shown on advanced search tab
436 if ((param.getUsage() != Usage.ADVANCED) && (param.getUsage() != Usage.ADVANCED_CUSTOM)) {
437 continue;
438 }
439
440 if ((param.getWriteAccess() == WriteAccess.ALWAYS) || (param.getWriteAccess() == WriteAccess.REQUIRED)){
441 SearchField paramField = new SearchField(param);
442 searchFields.add(paramField);
443 panel.add(paramField);
444 searchParams.add(paramField);
445 }
446 else if (param.getWriteAccess() == WriteAccess.WHEN_NULL){
447 if(param.getDefaultValueString() == null && param.getDefaultValueList() == null){
448 SearchField paramField = new SearchField(param);
449 searchFields.add(paramField);
450 panel.add(paramField);
451 searchParams.add(paramField);
452 }
453 }
454
455 if (param.getWriteAccess() != Metadata.WriteAccess.REQUIRED) {
456 allFieldsRequired = false;
457 }
458 }
459
460 //do not show criteria instructions if we have only one criteria field or in case all fields are required
461 if ((searchFields.size() > 1) || (allFieldsRequired == false)) {
462 instrLabel.setText(criteriaInstructions);
463 }
464
465 this.initWidget(panel);
466 }
467
468 public LookupMetadata getLookupMetadata() {
469 return meta;
470 }
471
472 @Override
473 public SearchRequest getSearchRequest() {
474 SearchRequest sr = new SearchRequest();
475 List<SearchParam> params = new ArrayList<SearchParam>();
476 List<HasSearchParam> searchParams = getSearchParams();
477
478 //initialize search parameters if user entered values into search criteria fields in UI
479
480 for(HasSearchParam field: searchParams){
481 SearchParam param = field.getSearchParam();
482 //TODO is this null check needed here? probably. assuming string here
483 //TODO make check more robust here/inserting params more robust
484 //do not pass to the search parameters that are empty
485 //FIXME hack - comparison to 'optional' - replace with check against 'optional' field and update related lookup metadata
486 if ((param.getValue() != null) && ((param.getValue().toString().trim().isEmpty() == false) || (param.getKey().toLowerCase().indexOf("optional") == -1))) {
487 params.add(param);
488 }
489 }
490
491 //initialize search parameters that are hidden from the UI because they are set to default context specific values
492 for(LookupParamMetadata metaParam: meta.getParams()){
493 if(metaParam.getWriteAccess() == WriteAccess.NEVER){
494 if ((metaParam.getDefaultValueString() == null || metaParam.getDefaultValueString().isEmpty())&&
495 (metaParam.getDefaultValueList() == null || metaParam.getDefaultValueList().isEmpty())) {
496 //FIXME throw an exception?
497 GWT.log("Key = " + metaParam.getKey() + " has write access NEVER but has no default value!", null);
498 continue;
499 }
500 SearchParam param = new SearchParam();
501 param.setKey(metaParam.getKey());
502 if(metaParam.getDefaultValueList()==null){
503 param.setValue(metaParam.getDefaultValueString());
504 }else{
505 param.setValue(metaParam.getDefaultValueList());
506 }
507 params.add(param);
508 }
509 else if(metaParam.getWriteAccess() == WriteAccess.WHEN_NULL){
510 if((metaParam.getDefaultValueString() != null && !metaParam.getDefaultValueString().isEmpty())||
511 (metaParam.getDefaultValueList() != null && !metaParam.getDefaultValueList().isEmpty())){
512 SearchParam param = new SearchParam();
513 param.setKey(metaParam.getKey());
514 if(metaParam.getDefaultValueList()==null){
515 param.setValue(metaParam.getDefaultValueString());
516 }else{
517 param.setValue(metaParam.getDefaultValueList());
518 }
519 params.add(param);
520 }
521 }
522 }
523 sr.setParams(params);
524 if (meta.getResultSortKey() != null) {
525 sr.setSortColumn(meta.getResultSortKey());
526 }
527 sr.setSearchKey(meta.getSearchTypeId());
528 return sr;
529 }
530
531 @Override
532 public List<HasSearchParam> getSearchParams() {
533 return searchParams;
534 }
535 }
536
537 private static class SearchField extends Composite implements HasSearchParam{
538
539 private Widget widget = null;
540 private LookupParamMetadata meta = null;
541 private VerticalFlowPanel panel = new VerticalFlowPanel();
542 private String fieldName;
543
544 public SearchParam getSearchParam(){
545 return SearchPanel.getSearchParam(widget, meta.getKey());
546 }
547
548 public SearchField(LookupParamMetadata param){
549 meta = param;
550 //TODO use message call here
551 fieldName = param.getName();
552 widget = DefaultWidgetFactory.getInstance().getWidget(param);
553 if(param.getDefaultValueString() != null){
554 //TODO Add handling of default value lists here
555 if(widget instanceof HasText){
556 ((HasText) widget).setText(param.getDefaultValueString().toString());
557 }
558 else if(widget instanceof HasValue){
559 ((HasValue) widget).setValue(param.getDefaultValueString());
560 }
561 }
562
563 //FIXME: remove because required field '*' indication will be part of FieldElement class
564 if (param.getWriteAccess() == Metadata.WriteAccess.REQUIRED) {
565 fieldName += " *";
566 }
567
568 FieldElement fieldElement = new FieldElement(fieldName, widget);
569 fieldElement.getTitleWidget().addStyleName("KS-Picker-Criteria-Text");
570 panel.add(fieldElement);
571 panel.addStyleName("clear");
572
573 this.initWidget(panel);
574 }
575
576 public Widget getFieldPanel(){
577 return panel;
578 }
579
580 public String getFieldName() {
581 return fieldName;
582 }
583 }
584
585 private static SearchParam getSearchParam(final Widget widget, String key){
586 SearchParam param = new SearchParam();
587 param.setKey(key);
588 if(widget instanceof HasText){
589 param.setValue(((HasText) widget).getText());
590 }
591 else if(widget instanceof HasValue){
592 Object value = ((HasValue) widget).getValue();
593 if(value != null){
594 //TODO need to handle date and other types here, how they are converted for search, etc
595 if(value instanceof String){
596 param.setValue((String)value);
597 }
598 else{
599 param.setValue(value.toString());
600 GWT.log("Fields in search probably(?) shouldnt have values other than string", null);
601 }
602 }
603 }
604 else if (widget instanceof KSPicker){
605 param.setValue(((KSPicker)widget).getDisplayValue());
606 }
607 else {
608 param.setValue("");
609 }
610
611 return param;
612 }
613
614 private void showCriteriaChosen(List<HasSearchParam> fields){
615 enteredCriteriaString.clear();
616 boolean first = true;;
617 for(HasSearchParam field: fields){
618 String name = field.getFieldName();
619 //TODO Should be string only, needs type safety
620 String value = field.getSearchParam().getValue().toString();
621 if(!value.isEmpty()){
622 HTMLPanel label = new HTMLPanel(name + ": <b>" + value + "</b> ");
623 if (!first) {
624 label.addStyleName("KS-Advanced-Search-Search-Criteria-Text");
625 }
626 enteredCriteriaString.add(label);
627 first = false;
628 }
629 }
630 }
631
632 public List<String> getSelectedIds(){
633 List<String> ids = new ArrayList<String>();
634 if(table != null){
635 ids = table.getSelectedIds();
636 }
637 return ids;
638 }
639
640 public List<SelectedResults> getSelectedValues() {
641
642 List<SelectedResults> selectedValues = new ArrayList<SelectedResults>();
643 if (table != null) {
644 List<ResultRow> selectedRows = table.getSelectedRows();
645 for (ResultRow row : selectedRows) {
646 String displayKey = row.getValue(activeSearchParametersWidget.getLookupMetadata().getResultDisplayKey());
647 String returnKey = row.getValue(activeSearchParametersWidget.getLookupMetadata().getResultReturnKey());
648 selectedValues.add(new SelectedResults(displayKey, returnKey, row));
649 if (multiSelect == false) {
650 break;
651 }
652 }
653 }
654
655 return selectedValues;
656 }
657
658 public boolean isMultiSelect() {
659 return multiSelect;
660 }
661
662 public void setMultiSelect(boolean multiSelect) {
663 this.multiSelect = multiSelect;
664 }
665
666 private static class ParamListItems implements ListItems{
667
668 private List<LookupParamMetadata> params = new ArrayList<LookupParamMetadata>();
669
670 public ParamListItems(LookupMetadata meta){
671 params = meta.getParams();
672 }
673
674 public ParamListItems(List<LookupParamMetadata> params){
675 this.params = params;
676 }
677
678 @Override
679 public List<String> getAttrKeys() {
680 return new ArrayList<String>();
681 }
682
683 @Override
684 public String getItemAttribute(String id, String attrkey) {
685 return "";
686 }
687
688 @Override
689 public int getItemCount() {
690 return params.size();
691 }
692
693 @Override
694 public List<String> getItemIds() {
695 List<String> ids = new ArrayList<String>();
696 for(LookupParamMetadata param: params){
697 ids.add(param.getKey());
698 }
699 return ids;
700 }
701
702 @Override
703 public String getItemText(String id) {
704 String itemText = id;
705 for(LookupParamMetadata param: params){
706 if(param.getKey().equals(id)){
707 //TODO this should be a message key
708 itemText = param.getName();
709 break;
710 }
711 }
712 return itemText;
713 }
714
715 public Widget getWidget(String id){
716 Widget w = null;
717 for(LookupParamMetadata param: params){
718 if(param.getKey().equals(id)){
719 w = DefaultWidgetFactory.getInstance().getWidget(param);
720 break;
721 }
722 }
723 return w;
724 }
725
726 public List<LookupParamMetadata> getParams() {
727 return params;
728 }
729 }
730
731 private String getMessage(final String msgKey) {
732 return Application.getApplicationContext().getMessage(msgKey);
733 }
734
735 public void addLookupChangedCallback(Callback<LookupMetadata> callback) {
736 lookupChangedCallbacks.add(callback);
737 }
738
739 public Callback<Boolean> getActionCompleteCallback() {
740 return new Callback<Boolean>() {
741
742 @Override
743 public void exec(Boolean result) {
744
745 if (resultsSelected == true) {
746 List<SelectedResults> selectedItems = getSelectedValues();
747 for(Callback<List<SelectedResults>> callback: selectedCompleteCallbacks){
748 callback.exec(selectedItems);
749 }
750 return;
751 }
752
753 actionCancelButtons.setButtonText(ButtonEnumerations.SearchCancelEnum.SEARCH, getMessage("select"));
754 resultsSelected = true;
755
756 SearchRequest sr = getSearchRequest();
757 table.performSearch(sr, activeSearchParametersWidget.getLookupMetadata().getResults(), activeSearchParametersWidget.getLookupMetadata().getResultReturnKey());
758 resultsTablePanel.setVisible(true);
759 List<HasSearchParam> userCriteria = new ArrayList<HasSearchParam>();
760 List<HasSearchParam> searchParams = activeSearchParametersWidget.getSearchParams();
761
762 //initialize search parameters if user entered values into search criteria fields in UI
763 for(HasSearchParam field: searchParams){
764 SearchParam param = field.getSearchParam();
765 //TODO is this null check needed here? probably. assuming string here
766 //TODO make check more robust here/inserting params more robust
767 //do not pass to the search parameters that are empty
768 //FIXME hack - comparison to 'optional' - replace with check against 'optional' field and update related lookup metadata
769 if ((param.getValue() != null) && ((param.getValue().toString().trim().isEmpty() == false) || (param.getKey().toLowerCase().indexOf("optional") == -1))) {
770 userCriteria.add(field);
771 }
772 }
773 showCriteriaChosen(userCriteria);
774
775 if(!resultsShown){
776 searchSelectorPanel.removeFromParent();
777 modifySearchPanel = new CollapsablePanel(getMessage("searchPanelModifySearch"), searchSelectorPanel, false);
778 modifySearchPanel.getLabel().addClickHandler(new ClickHandler(){
779 @Override
780 public void onClick(ClickEvent event) {
781 resultsTablePanel.setVisible(false);
782 actionCancelButtons.setButtonText(ButtonEnumerations.SearchCancelEnum.SEARCH, getActionLabel());
783 resultsSelected = false;
784 }});
785 SearchPanel.this.layout.insert(modifySearchPanel, 0);
786
787 }
788 else{
789 modifySearchPanel.close();
790 }
791 resultsShown = true;
792
793 for(Callback<Boolean> callback: actionCompletedCallbacks){
794 callback.exec( Boolean.valueOf(true));
795 }
796 }
797 };
798 }
799
800 public SearchRequest getSearchRequest() {
801 if (activeSearchParametersWidget != null) {
802 return activeSearchParametersWidget.getSearchRequest();
803 }
804 return null;
805 }
806
807 public void setActionCancelButtonGroup(ActionCancelGroup actionCancelButtons) {
808 this.actionCancelButtons = actionCancelButtons;
809 }
810
811 public String getSelectedLookupName() {
812 return selectedLookupName;
813 }
814
815 public void setSelectedLookupName(String selectedLookupName) {
816 this.selectedLookupName = selectedLookupName;
817 }
818
819 public void addSelectionCompleteCallback(Callback<List<SelectedResults>> callback){
820 selectedCompleteCallbacks.add(callback);
821 }
822
823 public void addActionCompleteCallback(Callback<Boolean> callback){
824 actionCompletedCallbacks.add(callback);
825 }
826
827 public String getActionLabel() {
828 return actionLabel;
829 }
830
831 public void setActionLabel(String actionLabel) {
832 if ((actionLabel != null) && (actionLabel.trim().length() > 0)) {
833 this.actionLabel = actionLabel;
834 }
835 }
836
837
838 }