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