Coverage Report - org.kuali.student.common.ui.client.widgets.search.KSPicker
 
Classes in this File Line Coverage Branch Coverage Complexity
KSPicker
0%
0/211
0%
0/130
2.985
KSPicker$1
0%
0/4
0%
0/2
2.985
KSPicker$2
0%
0/6
0%
0/2
2.985
KSPicker$3
0%
0/4
0%
0/2
2.985
KSPicker$4
0%
0/7
0%
0/6
2.985
KSPicker$5
0%
0/4
0%
0/2
2.985
KSPicker$6
0%
0/7
0%
0/2
2.985
KSPicker$7
0%
0/1
N/A
2.985
KSPicker$BasicWidget
0%
0/125
0%
0/78
2.985
KSPicker$BasicWidget$1
0%
0/9
0%
0/6
2.985
KSPicker$BasicWidget$2
0%
0/4
N/A
2.985
KSPicker$BasicWidget$3
0%
0/3
N/A
2.985
KSPicker$BasicWidget$4
0%
0/4
0%
0/2
2.985
KSPicker$BasicWidget$5
0%
0/3
N/A
2.985
KSPicker$BasicWidget$6
0%
0/5
0%
0/2
2.985
KSPicker$SelectionContainerWidget
0%
0/9
N/A
2.985
 
 1  
 /**
 2  
  * Copyright 2010 The Kuali Foundation Licensed under the
 3  
  * Educational Community License, Version 2.0 (the "License"); you may
 4  
  * not use this file except in compliance with the License. You may
 5  
  * obtain a copy of the License at
 6  
  *
 7  
  * http://www.osedu.org/licenses/ECL-2.0
 8  
  *
 9  
  * Unless required by applicable law or agreed to in writing,
 10  
  * software distributed under the License is distributed on an "AS IS"
 11  
  * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 12  
  * or implied. See the License for the specific language governing
 13  
  * permissions and limitations under the License.
 14  
  */
 15  
 
 16  
 package org.kuali.student.common.ui.client.widgets.search;
 17  
 
 18  
 import java.util.ArrayList;
 19  
 import java.util.HashSet;
 20  
 import java.util.Iterator;
 21  
 import java.util.List;
 22  
 import java.util.Map;
 23  
 
 24  
 import org.kuali.student.common.assembly.data.Data;
 25  
 import org.kuali.student.common.assembly.data.Data.DataValue;
 26  
 import org.kuali.student.common.assembly.data.Data.Property;
 27  
 import org.kuali.student.common.assembly.data.Data.StringValue;
 28  
 import org.kuali.student.common.assembly.data.Data.Value;
 29  
 import org.kuali.student.common.assembly.data.LookupMetadata;
 30  
 import org.kuali.student.common.assembly.data.LookupParamMetadata;
 31  
 import org.kuali.student.common.assembly.data.Metadata.WriteAccess;
 32  
 import org.kuali.student.common.assembly.data.QueryPath;
 33  
 import org.kuali.student.common.search.dto.SearchParam;
 34  
 import org.kuali.student.common.search.dto.SearchRequest;
 35  
 import org.kuali.student.common.search.dto.SearchResult;
 36  
 import org.kuali.student.common.ui.client.application.Application;
 37  
 import org.kuali.student.common.ui.client.application.KSAsyncCallback;
 38  
 import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
 39  
 import org.kuali.student.common.ui.client.configurable.mvc.WidgetConfigInfo;
 40  
 import org.kuali.student.common.ui.client.configurable.mvc.binding.SelectItemWidgetBinding;
 41  
 import org.kuali.student.common.ui.client.mvc.Callback;
 42  
 import org.kuali.student.common.ui.client.mvc.HasCrossConstraints;
 43  
 import org.kuali.student.common.ui.client.mvc.HasDataValue;
 44  
 import org.kuali.student.common.ui.client.mvc.HasFocusLostCallbacks;
 45  
 import org.kuali.student.common.ui.client.mvc.TranslatableValueWidget;
 46  
 import org.kuali.student.common.ui.client.service.CachingSearchService;
 47  
 import org.kuali.student.common.ui.client.widgets.HasInputWidget;
 48  
 import org.kuali.student.common.ui.client.widgets.KSDropDown;
 49  
 import org.kuali.student.common.ui.client.widgets.KSErrorDialog;
 50  
 import org.kuali.student.common.ui.client.widgets.KSLabel;
 51  
 import org.kuali.student.common.ui.client.widgets.KSTextBox;
 52  
 import org.kuali.student.common.ui.client.widgets.list.KSCheckBoxList;
 53  
 import org.kuali.student.common.ui.client.widgets.list.KSLabelList;
 54  
 import org.kuali.student.common.ui.client.widgets.list.KSRadioButtonList;
 55  
 import org.kuali.student.common.ui.client.widgets.list.KSSelectItemWidgetAbstract;
 56  
 import org.kuali.student.common.ui.client.widgets.list.ListItems;
 57  
 import org.kuali.student.common.ui.client.widgets.list.SearchResultListItems;
 58  
 import org.kuali.student.common.ui.client.widgets.list.SelectionChangeEvent;
 59  
 import org.kuali.student.common.ui.client.widgets.list.SelectionChangeHandler;
 60  
 import org.kuali.student.common.ui.client.widgets.suggestbox.IdableSuggestOracle.IdableSuggestion;
 61  
 import org.kuali.student.common.ui.client.widgets.suggestbox.KSSuggestBox;
 62  
 import org.kuali.student.common.ui.client.widgets.suggestbox.SearchSuggestOracle;
 63  
 
 64  
 import com.google.gwt.core.client.GWT;
 65  
 import com.google.gwt.dom.client.Element;
 66  
 import com.google.gwt.event.dom.client.BlurEvent;
 67  
 import com.google.gwt.event.dom.client.BlurHandler;
 68  
 import com.google.gwt.event.dom.client.ClickEvent;
 69  
 import com.google.gwt.event.dom.client.ClickHandler;
 70  
 import com.google.gwt.event.dom.client.KeyUpEvent;
 71  
 import com.google.gwt.event.dom.client.KeyUpHandler;
 72  
 import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
 73  
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
 74  
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
 75  
 import com.google.gwt.event.shared.HandlerRegistration;
 76  
 import com.google.gwt.user.client.DOM;
 77  
 import com.google.gwt.user.client.ui.Anchor;
 78  
 import com.google.gwt.user.client.ui.Composite;
 79  
 import com.google.gwt.user.client.ui.FlowPanel;
 80  
 import com.google.gwt.user.client.ui.HasText;
 81  
 import com.google.gwt.user.client.ui.SuggestBox;
 82  
 import com.google.gwt.user.client.ui.Widget;
 83  
 
 84  0
 public class KSPicker extends Composite implements HasFocusLostCallbacks, HasValueChangeHandlers<String>, HasDataValue, TranslatableValueWidget, HasInputWidget, HasCrossConstraints {
 85  
 
 86  0
     private FlowPanel layout = new FlowPanel();
 87  
     private BasicWidget basicWidget;
 88  0
     private Anchor advSearchLink = new Anchor(getMessage("advSearch"));
 89  0
     private AdvancedSearchWindow advSearchWindow = null;
 90  
     private SearchPanel searchPanel;
 91  
     public SearchPanel getSearchPanel() {
 92  0
                 return searchPanel;
 93  
         }
 94  
 
 95  
         private WidgetConfigInfo config;
 96  
     private Callback<List<SelectedResults>> advancedSearchCallback;
 97  0
         private List<Callback<SelectedResults>> basicSelectionCallbacks =
 98  
         new ArrayList<Callback<SelectedResults>>();
 99  0
     private List<Callback<String>> basicSelectionTextChangeCallbacks =
 100  
         new ArrayList<Callback<String>>();
 101  0
     private CachingSearchService cachingSearchService = CachingSearchService.getSearchService();
 102  
     
 103  
     private HashSet<String> crossConstraints;
 104  
 
 105  0
     private boolean deferSearch=false;
 106  
     
 107  0
     public KSPicker(WidgetConfigInfo config) {
 108  0
         this.config = config;
 109  0
                 init(config.lookupMeta, config.additionalLookups);
 110  0
         }
 111  
 
 112  0
     public KSPicker(LookupMetadata inLookupMetadata, List<LookupMetadata> additionalLookupMetadata){
 113  0
             init(inLookupMetadata, additionalLookupMetadata);
 114  0
     }
 115  
 
 116  
     @Override
 117  
     public Widget getInputWidget(){
 118  0
             if(basicWidget != null){
 119  0
                     return basicWidget.get();
 120  
             }
 121  0
             return null;
 122  
 
 123  
     }
 124  
 
 125  
     private void init(LookupMetadata inLookupMetadata, List<LookupMetadata> additionalLookupMetadata) {
 126  0
             this.initWidget(layout);
 127  0
         if (inLookupMetadata == null) {
 128  0
             KSErrorDialog.show(new Throwable(getMessage("invalidLookupConfig")));
 129  0
             return;
 130  
         }
 131  
 
 132  0
         if(config == null) {
 133  0
             config = new WidgetConfigInfo();
 134  
         }
 135  
 
 136  0
         setupBasicSearch(inLookupMetadata);
 137  0
         setupAdvancedSearch(additionalLookupMetadata);
 138  0
     }
 139  
 
 140  
     private static String getMessage(final String messageId) {
 141  0
         return Application.getApplicationContext().getMessage(messageId);
 142  
     }
 143  
 
 144  
     private void setupBasicSearch(LookupMetadata inLookupMetadata) {
 145  
 
 146  
             //setup initial search widget such as suggest box, drop down etc.
 147  0
             if (inLookupMetadata.getWidget() != null){
 148  0
                     switch (inLookupMetadata.getWidget()){
 149  
                             case SUGGEST_BOX:
 150  0
                                     setupSuggestBox(inLookupMetadata);
 151  0
                                     break;
 152  
                             case DROP_DOWN:
 153  
                             case CHECKBOX_LIST:
 154  0
                                     setupListWidget(inLookupMetadata);
 155  0
                                     break;
 156  
                             case RADIO:
 157  0
                                     setupListWidget(inLookupMetadata);
 158  0
                                     break;
 159  
                             case NO_WIDGET:
 160  0
                         if ((inLookupMetadata.getName() != null) && (inLookupMetadata.getName().trim().length() > 0)) {
 161  0
                             advSearchLink.setText(inLookupMetadata.getName().trim());
 162  
                         }
 163  0
                         basicWidget = new BasicWidget(new SelectionContainerWidget());
 164  0
                         break;
 165  
                             default:
 166  0
                                     setupDefaultWidget(inLookupMetadata);
 167  
                     }
 168  
             } else {
 169  0
                         setupDefaultWidget(inLookupMetadata);
 170  
             }
 171  0
     }
 172  
 
 173  
     private void setupDefaultWidget(LookupMetadata inLookupMetadata){
 174  0
         basicWidget = new BasicWidget(config != null && config.canEdit ? new KSTextBox() : new KSLabel());
 175  0
         GWT.log("KSTextBox for " + inLookupMetadata.getSearchTypeId(), null);
 176  0
         layout.add(basicWidget.get());
 177  0
     }
 178  
 
 179  
     private void setupSuggestBox(LookupMetadata inLookupMetadata){
 180  0
         if(config.canEdit) {
 181  0
                 final SearchSuggestOracle orgSearchOracle = new SearchSuggestOracle(inLookupMetadata);
 182  0
                 final KSSuggestBox suggestBox = new KSSuggestBox(orgSearchOracle, true);
 183  0
                 suggestBox.addKeyUpHandler(new KeyUpHandler() {
 184  
                     @Override
 185  
                     public void onKeyUp(KeyUpEvent event) {
 186  0
                         for(Callback<String> basicSelectionTextChangeCallback: basicSelectionTextChangeCallbacks){
 187  0
                             basicSelectionTextChangeCallback.exec("Text Changed");
 188  
                         }
 189  0
                     }
 190  
                 });
 191  0
                 suggestBox.addSelectionChangeHandler(new SelectionChangeHandler(){
 192  
 
 193  
                     @Override
 194  
                     public void onSelectionChange(SelectionChangeEvent event) {
 195  0
                         IdableSuggestion currentSuggestion = suggestBox.getSelectedSuggestion();
 196  0
                         SelectedResults selectedResults = new SelectedResults(
 197  
                                 currentSuggestion.getReplacementString(), currentSuggestion.getId());
 198  0
                         for(Callback<SelectedResults> basicSelectionCallback: basicSelectionCallbacks){
 199  0
                             basicSelectionCallback.exec(selectedResults);
 200  
                         }
 201  0
                     }
 202  
                 });
 203  0
                 basicWidget = new BasicWidget(suggestBox);
 204  0
                 ((KSSuggestBox) basicWidget.get()).setAutoSelectEnabled(false);
 205  0
                 orgSearchOracle.setTextWidget(((SuggestBox) basicWidget.get()).getTextBox());
 206  0
         } else {
 207  0
             basicWidget = new BasicWidget(new KSLabel());
 208  
         }
 209  0
         layout.add(basicWidget.get());
 210  0
     }
 211  
 
 212  
     private void setupListWidget(LookupMetadata inLookupMetadata){
 213  
 
 214  
         //FIXME should we search on values to populate drop down here or later when user will access the screen?
 215  0
         if(config.canEdit) {
 216  
 
 217  0
             KSSelectItemWidgetAbstract listItemWidget = null;
 218  0
             switch (inLookupMetadata.getWidget()){
 219  
                     case DROP_DOWN:
 220  0
                             listItemWidget = new KSDropDown();
 221  0
                             break;
 222  
                     case CHECKBOX_LIST:
 223  0
                             listItemWidget = new KSCheckBoxList();
 224  0
                             ((KSCheckBoxList)listItemWidget).setIgnoreMultipleAttributes(true);
 225  0
                             break;
 226  
                     case RADIO:
 227  0
                             listItemWidget = new KSRadioButtonList();
 228  
                             break;
 229  
             }
 230  0
             basicWidget = new BasicWidget(listItemWidget);
 231  0
             SearchRequest sr = initializeSearchRequest(inLookupMetadata);
 232  0
             if(!deferSearch) populateListWidget(sr);
 233  0
         } else {
 234  0
                 if (inLookupMetadata.getWidget() == LookupMetadata.Widget.DROP_DOWN || inLookupMetadata.getWidget() == LookupMetadata.Widget.RADIO){
 235  0
                 basicWidget = new BasicWidget(new KSLabel());
 236  
                 } else {
 237  
                         //FIXME: This method of creating read is very inefficient, need better solution
 238  0
                         basicWidget = new BasicWidget(new KSLabelList());
 239  0
                 SearchRequest sr = initializeSearchRequest(inLookupMetadata);
 240  0
                 if(!deferSearch) populateListWidget(sr);
 241  
                 }
 242  0
             layout.add(basicWidget.get());
 243  
         }
 244  0
     }
 245  
 
 246  
     private void setupAdvancedSearch(List<LookupMetadata> additionalLookupMetadata) {
 247  
 
 248  
         //setup advanced search widget such as advanced search box, browse hierarchy search box etc.
 249  0
         List<LookupMetadata> advancedLightboxLookupdata = getLookupMetadataBasedOnWidget(additionalLookupMetadata, LookupMetadata.Widget.ADVANCED_LIGHTBOX);
 250  0
         if ((advancedLightboxLookupdata != null) && config.canEdit) {
 251  
 
 252  
             //for multiple searches, show a drop down for user to select from
 253  0
             if (advancedLightboxLookupdata.size() == 1) {
 254  0
                 String actionLabel = advancedLightboxLookupdata.get(0).getWidgetOptionValue(LookupMetadata.WidgetOption.ADVANCED_LIGHTBOX_ACTION_LABEL);
 255  0
                 searchPanel = new SearchPanel(advancedLightboxLookupdata.get(0));
 256  0
                 searchPanel.setActionLabel(actionLabel);
 257  0
                 advSearchWindow = new AdvancedSearchWindow("Advanced Search: " + advancedLightboxLookupdata.get(0).getTitle(), searchPanel);
 258  0
             } else {
 259  0
                 searchPanel = new SearchPanel(advancedLightboxLookupdata);
 260  0
                 advSearchWindow = new AdvancedSearchWindow("Advanced Search: " + advancedLightboxLookupdata.get(0).getTitle(), searchPanel);
 261  0
                 searchPanel.addLookupChangedCallback(new Callback<LookupMetadata>() {
 262  
                     @Override
 263  
                     public void exec(LookupMetadata selectedLookup) {
 264  0
                         String actionLabel = (selectedLookup == null)? null : selectedLookup
 265  
                                 .getWidgetOptionValue(LookupMetadata.WidgetOption.ADVANCED_LIGHTBOX_ACTION_LABEL);
 266  0
                         searchPanel.setActionLabel(actionLabel);
 267  0
                     }
 268  
                 });
 269  0
                 LookupMetadata initialLookupMetaData = advancedLightboxLookupdata.get(0);
 270  0
                 String actionLabel = (initialLookupMetaData == null)? null : initialLookupMetaData
 271  
                         .getWidgetOptionValue(LookupMetadata.WidgetOption.ADVANCED_LIGHTBOX_ACTION_LABEL);
 272  0
                 searchPanel.setActionLabel(actionLabel);
 273  
             }
 274  0
             searchPanel.setMultiSelect(true);
 275  
 
 276  
             /*
 277  
             advSearchWindow.addActionCompleteCallback(new Callback<Boolean>() {
 278  
                 @Override
 279  
                 public void exec(Boolean result) {
 280  
                     searchPanel.getActionCompleteCallback().exec(true);
 281  
                 }
 282  
             }); */
 283  
 
 284  0
             String previewMode = additionalLookupMetadata.get(0).getWidgetOptionValue(LookupMetadata.WidgetOption.ADVANCED_LIGHTBOX_PREVIEW_MODE);
 285  0
             if (previewMode != null && previewMode.equals("true")) {
 286  0
                 searchPanel.setActionLabel("Preview");
 287  
             }
 288  
 
 289  0
             searchPanel.addSelectionCompleteCallback(new Callback<List<SelectedResults>>() {
 290  
                 public void exec(List<SelectedResults> results) {
 291  0
                         if (results != null && results.size() > 0) {
 292  0
                             if (advancedSearchCallback != null) {
 293  0
                                 advancedSearchCallback.exec(results);
 294  
                             }
 295  
                             else {
 296  0
                                 basicWidget.setResults(results);
 297  
                             }
 298  0
                         advSearchWindow.hide();
 299  
                         }
 300  0
                 }
 301  
             });
 302  
 
 303  0
             advSearchLink.addClickHandler(new ClickHandler(){
 304  
                 @Override
 305  
                 public void onClick(ClickEvent event) {
 306  0
                    if(advSearchWindow != null){
 307  0
                        advSearchWindow.show();
 308  
                    }
 309  0
                 }
 310  
             });
 311  0
             layout.add(advSearchLink);
 312  
         }
 313  0
     }
 314  
 
 315  
     private void populateListWidget(SearchRequest sr){
 316  
         
 317  0
         cachingSearchService.search(sr, new KSAsyncCallback<SearchResult>(){
 318  
 
 319  
             @Override
 320  
             public void onSuccess(SearchResult results) {
 321  0
                 if(results != null){
 322  0
                     ((KSSelectItemWidgetAbstract)basicWidget.get()).setListItems(new SearchResultListItems(results.getRows(), config.lookupMeta));
 323  
                 } else {
 324  0
                     ((KSSelectItemWidgetAbstract)basicWidget.get()).setListItems(new SearchResultListItems(null, config.lookupMeta));
 325  
                     //FIXME is this configuration error?
 326  
                 }
 327  
                 //((KSDropDown)basicWidget.get()).processOutstandingCallback();  //due to possible race condition
 328  0
                 ((KSSelectItemWidgetAbstract)basicWidget.get()).setInitialized(true);
 329  0
                 layout.add(basicWidget.get());
 330  0
             }
 331  
         });
 332  0
     }
 333  
 
 334  
         private List<LookupMetadata> getLookupMetadataBasedOnWidget(List<LookupMetadata> additionalLookupMetadata, LookupMetadata.Widget widgetType) {
 335  
 
 336  
             //lookup does not need to have additional lookup e.g. if the lookup is for suggest box within advanced search lightbox
 337  0
             if (additionalLookupMetadata == null) {
 338  0
                 return null;
 339  
             }
 340  
 
 341  0
             List<LookupMetadata> lookups = new ArrayList<LookupMetadata>();
 342  0
             for (LookupMetadata addLookupData : additionalLookupMetadata) {
 343  0
                     if (addLookupData.getWidget() == widgetType) {
 344  0
                             lookups.add(addLookupData);
 345  
                     }
 346  
             }
 347  0
             return (lookups.size() > 0 ? lookups : null);
 348  
     }
 349  
 
 350  0
     public class BasicWidget implements HasDataValue, HasFocusLostCallbacks, TranslatableValueWidget {
 351  
                 private Widget basicWidget;
 352  
 
 353  0
                 public BasicWidget(Widget basicWidget){
 354  0
                         this.basicWidget = basicWidget;
 355  0
             initAccessibility();
 356  0
                 }
 357  
 
 358  
         private void initAccessibility() {
 359  0
             Element element = basicWidget.getElement();
 360  0
             element.setAttribute("role", "combobox");
 361  0
             element.setAttribute("aria-autocomplete", "list");
 362  0
             element.setAttribute("aria-haspopup", "true");
 363  0
         }
 364  
 
 365  
         public void setResults(List<SelectedResults> results) {
 366  0
                         if (basicWidget instanceof KSTextBox) {
 367  0
                                 ((KSTextBox)basicWidget).setText(results.get(0).getDisplayKey());  //FIXME: what about the result id?
 368  0
                         } else if (basicWidget.getClass().getName().contains("ContainerWidget")) {
 369  0
                                 List<String> selections = new ArrayList<String>();
 370  0
                                 for (SelectedResults result: results) {
 371  
                                         //selections.add(result.getDisplayKey());                                                  //FIXME: what about the result ids?
 372  0
                                         selections.add(result.getReturnKey());                            //we don't need display key, at least for now
 373  
                                 }
 374  0
                                 ((SelectionContainerWidget) basicWidget).setSelections(selections);
 375  0
                         } else if (basicWidget instanceof KSSuggestBox) {
 376  0
                 IdableSuggestion theSuggestion = new IdableSuggestion();
 377  0
                 theSuggestion.setReplacementString(results.get(0).getDisplayKey());
 378  0
                 theSuggestion.setId(results.get(0).getReturnKey());
 379  0
                                 ((KSSuggestBox) basicWidget).setValue(theSuggestion);
 380  
                         }
 381  0
                 }
 382  
                 public void clear() {
 383  0
                     if(basicWidget instanceof KSTextBox) {
 384  0
                 ((KSTextBox)basicWidget).setText(null);
 385  0
             } else if(basicWidget instanceof KSSuggestBox) {
 386  0
                 ((KSSuggestBox) basicWidget).setValue((String)null);
 387  0
             } else if(basicWidget instanceof KSLabel) {
 388  0
                 ((KSLabel)basicWidget).setText(null);
 389  0
             } else if(basicWidget instanceof KSDropDown) {
 390  0
                 ((KSDropDown)basicWidget).clear();
 391  
             } else {
 392  0
                 ((KSSuggestBox) basicWidget).setValue(null, false);
 393  
             }
 394  0
                 }
 395  
                 public void setValue(final String id, String translation) {
 396  0
                         if(basicWidget instanceof KSTextBox) {
 397  0
                                 ((KSTextBox)basicWidget).setText(translation);
 398  0
                         } else if(basicWidget instanceof KSSuggestBox) {
 399  0
                                 ((KSSuggestBox) basicWidget).setValue(id, translation);
 400  0
                         } else if(basicWidget instanceof KSLabel) {
 401  0
                             ((KSLabel)basicWidget).setText(translation);
 402  0
                         } else if(basicWidget instanceof KSSelectItemWidgetAbstract) {
 403  0
                             ListItems searchResults = ((KSSelectItemWidgetAbstract)basicWidget).getListItems();
 404  0
                             if (searchResults != null) {
 405  0
                                 ((KSSelectItemWidgetAbstract)basicWidget).selectItem(id);
 406  
                             }
 407  
                             else {
 408  0
                     ((KSSelectItemWidgetAbstract)basicWidget).addWidgetReadyCallback(new Callback<Widget>() {
 409  
                         @Override
 410  
                         public void exec(Widget widget) {
 411  0
                             final ListItems searchResults = ((KSSelectItemWidgetAbstract)widget).getListItems();
 412  
 
 413  0
                             if(id != null){
 414  0
                                 for (String itemId : searchResults.getItemIds()) {
 415  0
                                     if (itemId.equals(id.trim())) {
 416  0
                                         ((KSSelectItemWidgetAbstract)basicWidget).selectItem(itemId);
 417  0
                                         break;
 418  
                                     }
 419  
                                 }
 420  
                             } else {
 421  0
                                 ((KSSelectItemWidgetAbstract)basicWidget).clear();
 422  
                             }
 423  0
                         }
 424  
                     });
 425  
                 }
 426  
 
 427  0
             } else {
 428  0
                                 ((KSSuggestBox) basicWidget).setValue("", true);
 429  
                         }
 430  0
                 }
 431  
 
 432  
                 public void setValue(final Value value, boolean fireEvents) {
 433  0
                         if (basicWidget instanceof KSTextBox || basicWidget instanceof KSLabel) {
 434  0
                                 if(value != null){
 435  0
                                         ((HasText)basicWidget).setText((String) value.get());
 436  
                                 }
 437  
                                 else{
 438  0
                                         ((HasText)basicWidget).setText("");
 439  
                                 }
 440  0
                         } else if (basicWidget instanceof KSSuggestBox) {
 441  
                                 //Do check here
 442  0
                                 if(value != null){
 443  0
                                         if(!config.isRepeating){
 444  0
                                                 ((KSSuggestBox) basicWidget).setValue((String)value.get(), fireEvents);
 445  
                                         }
 446  
                                         else{
 447  0
                                                 DataValue dataValue = (DataValue)value;
 448  0
                                                 Data d = dataValue.get();
 449  0
                                                 QueryPath path = QueryPath.parse("0");
 450  0
                                                 String v = d.query(path);
 451  0
                                                 ((KSSuggestBox) basicWidget).setValue((String)v, fireEvents);
 452  0
                                         }
 453  
                                 }
 454  
                                 else{
 455  0
                                         ((KSSuggestBox) basicWidget).setValue("", fireEvents);
 456  
                                 }
 457  0
                         } else if(basicWidget instanceof KSSelectItemWidgetAbstract) {
 458  0
                                 SelectItemWidgetBinding.INSTANCE.setWidgetValue((KSSelectItemWidgetAbstract)basicWidget, value);
 459  
             }
 460  0
                 }
 461  
                 public String getDisplayValue() {
 462  0
                     String result = "";
 463  0
                     if (basicWidget instanceof KSTextBox) {
 464  0
                 result = ((KSTextBox)basicWidget).getText();
 465  0
             } else if (basicWidget instanceof KSSuggestBox) {
 466  0
                 IdableSuggestion suggestion = ((KSSuggestBox)basicWidget).getCurrentSuggestion();
 467  0
                 if(suggestion != null) {
 468  0
                     result = suggestion.getReplacementString();
 469  
                 }
 470  0
             }  else if (basicWidget instanceof KSDropDown) {
 471  0
                 KSDropDown dropDown = (KSDropDown)basicWidget;
 472  0
                 StringValue value = new StringValue(((KSDropDown) basicWidget).getSelectedItem());
 473  0
                 String itemId = dropDown.getSelectedItem();
 474  
 
 475  0
                 if(itemId != null && !itemId.isEmpty()) {
 476  0
                     result = dropDown.getListItems().getItemText(itemId);
 477  
                 }
 478  
             }
 479  0
                     return result;
 480  
                 }
 481  
                 public Value getValue() {
 482  0
                         if (basicWidget instanceof KSTextBox) {
 483  0
                                 StringValue value = new StringValue(((KSTextBox)basicWidget).getText());
 484  0
                                 return value;
 485  0
                         } else if (basicWidget instanceof KSSuggestBox) {
 486  
                                 //Do check here
 487  0
                                 if(!config.isRepeating){
 488  0
                                         StringValue value = new StringValue(((KSSuggestBox) basicWidget).getValue());
 489  0
                                         return value;
 490  
                                 }
 491  
                                 else{
 492  0
                                         Data data = new Data();
 493  0
                                         data.set(new Data.IntegerKey(0),((KSSuggestBox) basicWidget).getValue());
 494  0
                                         DataValue value = new DataValue(data);
 495  0
                                         return value;
 496  
                                 }
 497  0
                         }  else if (basicWidget instanceof KSSelectItemWidgetAbstract) {
 498  0
                                 return SelectItemWidgetBinding.INSTANCE.getWidgetValue((KSSelectItemWidgetAbstract)basicWidget);
 499  
                         }
 500  
 
 501  0
                         return null;
 502  
                 }
 503  
 
 504  
                 public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
 505  0
                         if (basicWidget instanceof KSTextBox) {
 506  0
                                 return ((KSTextBox)basicWidget).addValueChangeHandler(handler);
 507  0
                         } else if (basicWidget instanceof KSSuggestBox) {
 508  0
                                 return ((KSSuggestBox) basicWidget).addValueChangeHandler(handler);
 509  
                         }
 510  0
                         return null;
 511  
                 }
 512  
 
 513  
         public void addValuesChangeHandler(ValueChangeHandler<List<String>> handler) {
 514  0
             if (basicWidget.getClass().getName().contains("ContainerWidget")) {
 515  0
                 ((SelectionContainerWidget) basicWidget).addValueChangeHandler(handler);
 516  
             }
 517  0
         }
 518  
                 public void addSelectionChangeHandler(SelectionChangeHandler handler) {
 519  0
                     if (basicWidget instanceof KSSelectItemWidgetAbstract)  {
 520  0
                                 ((KSSelectItemWidgetAbstract) basicWidget).addSelectionChangeHandler(handler);
 521  
                         }
 522  0
                 }
 523  
 
 524  
                 @Override
 525  
                 public void addValueChangeCallback(final Callback<Value> callback) {
 526  0
                         ValueChangeHandler<String> handler = new ValueChangeHandler<String>(){
 527  
                                 @Override
 528  
                                 public void onValueChange(ValueChangeEvent<String> event) {
 529  0
                                         StringValue value = new StringValue(event.getValue());
 530  0
                                         callback.exec(value);
 531  0
                                 }
 532  
                         };
 533  0
                         addValueChangeHandler(handler);
 534  0
                 }
 535  
 
 536  
                 @Override
 537  
                 public void addFocusLostCallback(final Callback<Boolean> callback) {
 538  0
                         if (basicWidget instanceof KSTextBox) {
 539  0
                                 ((KSTextBox)basicWidget).addBlurHandler(new BlurHandler(){
 540  
                                         @Override
 541  
                                         public void onBlur(BlurEvent event) {
 542  0
                                                 callback.exec(true);
 543  
 
 544  0
                                         }
 545  
                                 });
 546  0
                         } else if (basicWidget instanceof KSSuggestBox) {
 547  0
                                 ((KSSuggestBox) basicWidget).getTextBox().addBlurHandler(new BlurHandler(){
 548  
                     @Override
 549  
                     public void onBlur(BlurEvent event) {
 550  
                             //Don't blur the widget if the suggestion list is showing
 551  0
                             if(!((KSSuggestBox) basicWidget).isSuggestionListShowing()){
 552  0
                             callback.exec(true);
 553  
                             }
 554  0
                     }
 555  
                                 });
 556  0
                         } else if (basicWidget instanceof KSSelectItemWidgetAbstract) {
 557  0
                 ((KSSelectItemWidgetAbstract) basicWidget).addBlurHandler(new BlurHandler(){
 558  
                     @Override
 559  
                     public void onBlur(BlurEvent event) {
 560  0
                         callback.exec(true);
 561  0
                     }
 562  
                 });
 563  
             }
 564  0
                 }
 565  
 
 566  
         @Override
 567  
         public void setValue(Value value) {
 568  0
             this.setValue(value, true);
 569  0
         }
 570  
 
 571  
         public Widget get() {
 572  0
             return basicWidget;
 573  
         }
 574  
 
 575  
         @Override
 576  
         public void setValue(final Map<String, String> translations) {
 577  
                 //TODO: Reviewed in M6 cleanup, unknown:  Update to also work with a KSLabelList that doesn't require pre-population of all list items
 578  0
                 if (basicWidget instanceof KSSelectItemWidgetAbstract){
 579  0
                         Callback<Widget> widgetReadyCallback = new Callback<Widget>(){
 580  
                                         public void exec(Widget widget) {
 581  0
                                                 ((KSSelectItemWidgetAbstract)widget).clear();
 582  0
                                         for (String id:translations.keySet()){
 583  0
                                                 ((KSSelectItemWidgetAbstract)widget).selectItem(id);
 584  
                                         }
 585  0
                                         }
 586  
                         };
 587  0
                         if (!((KSSelectItemWidgetAbstract)basicWidget).isInitialized()){
 588  0
                                 ((KSSelectItemWidgetAbstract)basicWidget).addWidgetReadyCallback(widgetReadyCallback);
 589  
                         } else{
 590  0
                                 widgetReadyCallback.exec(basicWidget);
 591  
                         }
 592  0
                 } else {
 593  0
                         GWT.log("Basic picker widget not coded to handle multiple translations", null);
 594  
                 }
 595  0
         }
 596  
 
 597  
     }
 598  
 
 599  
     private class SelectionContainerWidget extends Widget implements HasValueChangeHandlers<List<String>> {
 600  0
             private List<String> selections = new ArrayList<String>();
 601  
 
 602  0
             public SelectionContainerWidget(){
 603  0
                     this.setElement(DOM.createSpan());
 604  0
             }
 605  
 
 606  
                 public List<String> getSelections() {
 607  0
                         return selections;
 608  
                 }
 609  
 
 610  
                 public void setSelections(List<String> selections) {
 611  0
                         this.selections = selections;
 612  0
                         ValueChangeEvent.fire(this, this.selections);
 613  0
                 }
 614  
 
 615  
                 @Override
 616  
                 public HandlerRegistration addValueChangeHandler(ValueChangeHandler<List<String>> handler) {
 617  0
                         return super.addHandler(handler, ValueChangeEvent.getType());
 618  
                 }
 619  
     }
 620  
 
 621  
     private SearchRequest initializeSearchRequest(LookupMetadata lookup) {
 622  
 
 623  0
         SearchRequest sr = new SearchRequest();
 624  0
         List<SearchParam> params = new ArrayList<SearchParam>();
 625  
 
 626  0
         sr.setSearchKey(lookup.getSearchTypeId());
 627  
 
 628  0
         if (lookup.getResultSortKey() != null){
 629  0
                 sr.setSortColumn(lookup.getResultSortKey());
 630  
         }
 631  
 
 632  
         //initialize search parameters that are hidden from the UI because they are set to default context specific values
 633  0
         for(final LookupParamMetadata metaParam: lookup.getParams()){
 634  0
             if(metaParam.getWriteAccess() == WriteAccess.NEVER){
 635  0
                 if ((metaParam.getDefaultValueString() == null || metaParam.getDefaultValueString().isEmpty())&&
 636  
                     (metaParam.getDefaultValueList() == null || metaParam.getDefaultValueList().isEmpty())&&
 637  
                     (metaParam.getFieldPath() == null || metaParam.getFieldPath().isEmpty())) {
 638  
                     //FIXME throw an exception?
 639  0
                     GWT.log("Key = " + metaParam.getKey() + " has write access NEVER but has no default value!", null);
 640  0
                     continue;
 641  
                 }
 642  0
                 final SearchParam param = new SearchParam();
 643  0
                 param.setKey(metaParam.getKey());
 644  0
                 if(metaParam.getFieldPath()!=null){
 645  0
                         if(crossConstraints==null){
 646  0
                                 crossConstraints = new HashSet<String>();
 647  
                         }
 648  0
                         FieldDescriptor fd = null;
 649  
                         String finalPath;
 650  0
                         if(metaParam.getFieldPath().startsWith("/")){
 651  0
                                 finalPath=metaParam.getFieldPath().substring(1);
 652  
                         }else{
 653  0
                                 finalPath=Application.getApplicationContext().getParentPath()+metaParam.getFieldPath();
 654  
                         }
 655  0
                             crossConstraints.add(finalPath);
 656  0
                             fd = Application.getApplicationContext().getPathToFieldMapping(null, finalPath);
 657  0
                         if(fd!=null){
 658  0
                                 if(fd.getFieldElement().getFieldWidget() instanceof HasDataValue){
 659  0
                                         Value value = ((HasDataValue)fd.getFieldElement().getFieldWidget()).getValue();
 660  0
                                         if(value!=null&&value.get()!=null){
 661  0
                                                 if(value.get() instanceof Data){
 662  0
                                                         ArrayList<String> listValue = new ArrayList<String>();
 663  0
                                                         for(Iterator<Property> iter =((Data)value.get()).realPropertyIterator();iter.hasNext();){
 664  0
                                                                 listValue.add(iter.next().getValue().toString());
 665  
                                                         }
 666  0
                                                         param.setValue(listValue);
 667  0
                                                 }else{
 668  0
                                                         param.setValue(value.get().toString());        
 669  
                                                 }
 670  
                                         }else{
 671  0
                                                 param.setValue((String)null);
 672  
                                         }                                                
 673  
                                 }
 674  
                         }
 675  0
                         deferSearch=true;
 676  0
                 }else if(metaParam.getDefaultValueList()==null){
 677  0
                     param.setValue(metaParam.getDefaultValueString());
 678  
                 }else{
 679  0
                     param.setValue(metaParam.getDefaultValueList());
 680  
                 }
 681  0
                 params.add(param);
 682  0
             }
 683  0
             else if(metaParam.getWriteAccess() == WriteAccess.WHEN_NULL){
 684  0
                 if((metaParam.getDefaultValueString() != null && !metaParam.getDefaultValueString().isEmpty())||
 685  
                    (metaParam.getDefaultValueList() != null && !metaParam.getDefaultValueList().isEmpty())||
 686  
                    (metaParam.getFieldPath() != null && !metaParam.getFieldPath().isEmpty())){
 687  0
                     final SearchParam param = new SearchParam();
 688  0
                     param.setKey(metaParam.getKey());
 689  0
                     if(metaParam.getFieldPath()!=null){
 690  0
                             if(crossConstraints==null){
 691  0
                                     crossConstraints = new HashSet<String>();
 692  
                             }
 693  0
                             FieldDescriptor fd = null;
 694  
                             String finalPath;
 695  0
                             if(metaParam.getFieldPath().startsWith("/")){
 696  0
                                     finalPath=metaParam.getFieldPath().substring(1);
 697  
                             }else{
 698  0
                                     finalPath=Application.getApplicationContext().getParentPath()+metaParam.getFieldPath();
 699  
                             }
 700  0
                                 crossConstraints.add(finalPath);
 701  0
                                 fd = Application.getApplicationContext().getPathToFieldMapping(null, finalPath);
 702  0
                             if(fd!=null){
 703  0
                                     if(fd.getFieldElement().getFieldWidget() instanceof HasDataValue){
 704  0
                                             Value value = ((HasDataValue)fd.getFieldElement().getFieldWidget()).getValue();
 705  0
                                             param.setValue(value==null?null:value.get()==null?null:value.get().toString());
 706  
                                     }
 707  
                             }
 708  0
                             deferSearch=true;
 709  0
                     }else if(metaParam.getDefaultValueList()==null){
 710  0
                         param.setValue(metaParam.getDefaultValueString());
 711  
                     }else{
 712  0
                         param.setValue(metaParam.getDefaultValueList());
 713  
                     }
 714  0
                     params.add(param);
 715  0
                 }
 716  
             }
 717  
         }
 718  0
         sr.setParams(params);
 719  
 
 720  0
         return sr;
 721  
     }
 722  
 
 723  
     public AdvancedSearchWindow getSearchWindow(){
 724  0
         return advSearchWindow;
 725  
     }
 726  
 
 727  
     public void addBasicSelectionCompletedCallback(Callback<SelectedResults> callback) {
 728  0
         basicSelectionCallbacks.add(callback);
 729  0
     }
 730  
 
 731  
     public void addBasicSelectionTextChangeCallback(Callback<String> callback) {
 732  0
         basicSelectionTextChangeCallbacks.add(callback);
 733  0
     }
 734  
 
 735  
         @Override
 736  
         public void addValueChangeCallback(Callback<Value> callback) {
 737  0
                 basicWidget.addValueChangeCallback(callback);
 738  0
         }
 739  
 
 740  
         @Override
 741  
         public void setValue(Value value) {
 742  0
                 setValue(value, true);
 743  0
         }
 744  
 
 745  
     public void setValue(String value){
 746  0
         basicWidget.setValue(new StringValue(value));
 747  0
     }
 748  
 
 749  
         public void setValue(Value value, boolean fireEvents) {
 750  
                 //suggest.reset();
 751  0
                 basicWidget.setValue(value, fireEvents);
 752  0
         }
 753  
         public void clear() {
 754  0
             basicWidget.clear();
 755  0
         }
 756  
 
 757  
     @Override
 758  
     public void setValue(String id, String translation) {
 759  0
         basicWidget.setValue(id, translation);
 760  0
     }
 761  
 
 762  
     @Override
 763  
     public Value getValue() {
 764  0
         return basicWidget.getValue();
 765  
     }
 766  
         public String getDisplayValue() {
 767  0
             return basicWidget.getDisplayValue();
 768  
         }
 769  
         @Override
 770  
         public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
 771  0
                 return basicWidget.addValueChangeHandler(handler);
 772  
         }
 773  
 
 774  
         public void addValuesChangeHandler(ValueChangeHandler<List<String>> handler) {
 775  0
         if(basicWidget != null)
 776  0
                 basicWidget.addValuesChangeHandler(handler);
 777  0
         }
 778  
 
 779  
         public void addSelectionChangeHandler(SelectionChangeHandler handler) {
 780  0
         if(basicWidget != null)
 781  0
                 basicWidget.addSelectionChangeHandler(handler);
 782  0
         }
 783  
 
 784  
         
 785  
         @Override
 786  
         public void addFocusLostCallback(Callback<Boolean> callback) {
 787  0
                 basicWidget.addFocusLostCallback(callback);
 788  0
         }
 789  
 
 790  
     public void setAdvancedSearchCallback(Callback<List<SelectedResults>> advancedSearchCallback) {
 791  0
         this.advancedSearchCallback = advancedSearchCallback;
 792  0
     }
 793  
 
 794  
     @Override
 795  
     public void setValue(Map<String, String> translations) {
 796  0
         basicWidget.setValue(translations);
 797  0
     }
 798  
 
 799  
         @Override
 800  
     public HashSet<String> getCrossConstraints() {
 801  0
                 return crossConstraints;
 802  
         }
 803  
 
 804  
         @Override
 805  
         public void reprocessWithUpdatedConstraints() {
 806  0
                 SearchRequest sr = initializeSearchRequest(config.lookupMeta);
 807  0
                 populateListWidget(sr);
 808  0
         }
 809  
 
 810  
 }