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