View Javadoc

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.suggestbox;
17  
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import org.kuali.student.common.ui.client.application.KSAsyncCallback;
22  import org.kuali.student.common.ui.client.service.SearchRpcService;
23  import org.kuali.student.common.ui.client.service.SearchRpcServiceAsync;
24  import org.kuali.student.common.ui.client.widgets.KSErrorDialog;
25  import org.kuali.student.common.ui.client.widgets.notification.LoadingDiv;
26  import org.kuali.student.core.assembly.data.LookupMetadata;
27  import org.kuali.student.core.assembly.data.LookupParamMetadata;
28  import org.kuali.student.core.assembly.data.Metadata.WriteAccess;
29  import org.kuali.student.core.search.dto.SearchParam;
30  import org.kuali.student.core.search.dto.SearchRequest;
31  import org.kuali.student.core.search.dto.SearchResult;
32  import org.kuali.student.core.search.dto.SearchResultCell;
33  import org.kuali.student.core.search.dto.SearchResultRow;
34  
35  import com.google.gwt.core.client.GWT;
36  import com.google.gwt.user.client.ui.HasText;
37  import com.google.gwt.user.client.ui.Widget;
38  import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
39  
40  public class SearchSuggestOracle extends IdableSuggestOracle{
41      
42      private String searchTypeKey;
43      private String searchIdKey;
44      private String searchTextKey;
45      private String resultIdKey;
46      private Callback currentCallback;
47      private Request pendingRequest;
48      private Callback pendingCallback;
49      private HasText textWidget;
50      private String resultDisplayKey;
51      private List<SearchParam> additionalParams = new ArrayList<SearchParam>();
52      private List<IdableSuggestion> lastSuggestions = new ArrayList<IdableSuggestion>();
53      
54      private LookupMetadata lookupMetaData;
55      private SearchRpcServiceAsync searchRpcServiceAsync = GWT.create(SearchRpcService.class);
56      
57      private List<org.kuali.student.common.ui.client.mvc.Callback<IdableSuggestion>> searchCompletedCallbacks = new ArrayList<org.kuali.student.common.ui.client.mvc.Callback<IdableSuggestion>>();
58      
59      private LoadingDiv loading = new LoadingDiv();
60      
61      /**
62       * @deprecated
63       * @param searchTypeKey the type to be search on
64       * @param searchTextKey the column/key that to search on
65       * @param idKey the column/key that is the primary key for this type
66       */
67      public SearchSuggestOracle(String searchTypeKey, String searchTextKey, String searchIdKey, String resultIdKey, String resultDisplayKey){
68          this.searchTypeKey = searchTypeKey;
69          this.searchTextKey = searchTextKey;
70          this.searchIdKey = searchIdKey;
71          this.resultIdKey = resultIdKey;
72          this.resultDisplayKey = resultDisplayKey;
73      }
74      
75      /*
76       * 
77       */
78      public SearchSuggestOracle(LookupMetadata lookupMetadata) {
79      	this.lookupMetaData = lookupMetadata;
80          this.searchTypeKey = lookupMetaData.getSearchTypeId();
81          
82          for (LookupParamMetadata param : lookupMetadata.getParams()) {
83          	if ((param.getUsage() != null) && param.getUsage().name().equals("DEFAULT")) {
84          		this.searchTextKey = param.getKey();
85          	}
86          	//Add in any writeaccess never default values to the additional params
87          	if(WriteAccess.NEVER.equals(param.getWriteAccess())||param.getDefaultValueString()!=null||param.getDefaultValueList()!=null){
88          		SearchParam searchParam = new SearchParam();
89          		searchParam.setKey(param.getKey());
90  				if(param.getDefaultValueList()==null){
91  					searchParam.setValue(param.getDefaultValueString());
92  				}else{
93  					searchParam.setValue(param.getDefaultValueList());
94  				}
95          		additionalParams.add(searchParam);
96          	}
97          }
98          if (this.searchTextKey == null) {
99          	KSErrorDialog.show(new Throwable("Cannot find searchTextKey for " + searchTypeKey) );
100         }
101         
102         this.searchIdKey = lookupMetadata.getSearchParamIdKey();
103         this.resultIdKey = lookupMetadata.getResultReturnKey();
104         this.resultDisplayKey = lookupMetadata.getResultDisplayKey();
105     }
106 
107     public void setAdditionalSearchParams(List<SearchParam> params){
108         additionalParams = params;
109     }
110     
111     private Callback wrappedCallback = new Callback() {
112 
113         public void onSuggestionsReady(Request request, Response response) {
114           if (textWidget.getText().equals(request.getQuery())) {
115             currentCallback.onSuggestionsReady(request, response);
116             pendingRequest = null;
117             pendingCallback = null;
118           }
119           currentCallback = null;
120           if (pendingCallback != null) {
121             requestSuggestions(pendingRequest, pendingCallback);
122             pendingRequest = null;
123             pendingCallback = null;
124           }
125         }
126 
127     };
128     
129     @Override
130     public void requestSuggestions(Request request, Callback callback) {
131         if (currentCallback == null) {
132           final int x = ((Widget)this.textWidget).getAbsoluteLeft() + ((Widget)this.textWidget).getOffsetWidth();
133   		  final int y = ((Widget)this.textWidget).getAbsoluteTop() + ((Widget)this.textWidget).getOffsetHeight();
134   		  loading.setPopupPositionAndShow(new PositionCallback(){
135 
136   				@Override
137   				public void setPosition(int offsetWidth, int offsetHeight) {
138   					loading.setPopupPosition(x - offsetWidth, y + 1);
139   				}
140   			});
141           currentCallback = callback;
142           sendRequest(request, wrappedCallback);
143         } else {
144           pendingRequest = request;
145           pendingCallback = callback;
146         }        
147     }
148     
149     private SearchRequest buildSearchRequest(String query, String searchId) {
150     	SearchRequest sr = new SearchRequest();
151     	sr.setNeededTotalResults(false);
152     	sr.setSearchKey(this.searchTypeKey);
153 
154 		List<SearchParam> searchParams = new ArrayList<SearchParam>();
155 		SearchParam param1 = createParam(this.searchTextKey, query);
156 		searchParams.add(param1);
157 		
158     	sr.setParams(searchParams);
159     	
160     	sr.getParams().addAll(additionalParams);
161 
162         return sr;
163     }
164     
165     private SearchRequest buildSearchRequestById(String query, String searchId) {
166     	SearchRequest sr = new SearchRequest();
167     	sr.setNeededTotalResults(false);
168     	sr.setSearchKey(this.searchTypeKey);
169 
170 		List<SearchParam> searchParams = new ArrayList<SearchParam>();
171 		SearchParam param2 = createParam(this.searchIdKey, searchId);
172 		searchParams.add(param2);
173 		
174     	sr.setParams(searchParams);
175     	
176     	sr.getParams().addAll(additionalParams);
177 
178         return sr;
179     }
180     
181     private SearchParam createParam(String key, String value) {
182     	SearchParam param = new SearchParam();
183     	
184     	if(key == null) {
185 			param.setKey("");
186 		} else {
187 			param.setKey(key);
188 		}
189 
190     	if(value == null) {
191 			param.setValue("");
192 		} else {
193 			param.setValue(value);
194 		}
195     	
196     	return param;
197     }
198 
199     public void sendRequest(final Request request, final Callback callback){
200         String query = request.getQuery().trim();
201         SearchRequest searchRequest = buildSearchRequest(query, null);
202         
203         //case-sensitive?
204         if(query.length() > 0){
205         	searchRpcServiceAsync.search(searchRequest, new KSAsyncCallback<SearchResult>(){
206     
207                 @Override
208                 public void onSuccess(SearchResult results) {
209                     lastSuggestions = createSuggestions(results, request.getLimit());
210                     Response response = new Response(lastSuggestions);
211                     loading.hide();
212                     callback.onSuggestionsReady(request, response);
213                     if (searchCompletedCallbacks != null &&
214                             lastSuggestions != null && lastSuggestions.size() == 1) {
215                         for (org.kuali.student.common.ui.client.mvc.Callback<IdableSuggestion> callback : searchCompletedCallbacks) {
216                             callback.exec(lastSuggestions.get(0));
217                         }
218                     }
219                 }
220                 
221                 @Override
222                 public void onFailure(Throwable caught) {
223                 	loading.hide();
224                 	super.onFailure(caught);
225                 }
226                 
227                 private List<IdableSuggestion> createSuggestions(SearchResult results, int limit){
228                     List<IdableSuggestion> suggestionsList = new ArrayList<IdableSuggestion>();
229                     String query = request.getQuery();
230                     query = query.trim();
231                     int count = 0;
232                     if(results != null){
233                         for (SearchResultRow r: results.getRows()){
234                             if(count == limit){
235                                 break;
236                             }
237 
238                             IdableSuggestion theSuggestion = new IdableSuggestion();
239                             for(SearchResultCell c: r.getCells()){
240                                 if(c.getKey().equals(resultDisplayKey)){
241                                     String itemText = c.getValue();
242                                     theSuggestion.addAttr(c.getKey(), c.getValue());
243                                     int index = (" " + itemText).toLowerCase().indexOf(" " + query.toLowerCase().trim());
244                                     
245                                     if (index < 0) {
246                                         //temporary fix to stop index out of bound exception in hosted mode
247 //                                        continue;
248                                         //Including fuzzy search results in the display list.
249                                         theSuggestion.setDisplayString(itemText);
250                                         theSuggestion.setReplacementString(itemText);
251                                     	//FIXME handle case when search for text is not appearing within search result - should not happen (misconfiguration)
252                                         continue;
253                                     }
254                                     
255                                     String htmlString = itemText.substring(0,index) + "<b>" + itemText.substring(index, index + query.length()) + "</b>" + itemText.substring(index + query.length(), itemText.length());
256                                     theSuggestion.setDisplayString(htmlString);
257                                     theSuggestion.setReplacementString(itemText);
258 
259                                 } else if(c.getKey().equals(resultIdKey)){
260                                      theSuggestion.setId(c.getValue());
261                                      theSuggestion.addAttr(c.getKey(), c.getValue());
262                                 } else{
263                                     theSuggestion.addAttr(c.getKey(), c.getValue());
264                                 }
265                             }
266                             suggestionsList.add(theSuggestion);
267                             count++;
268                         }
269                     }
270                     return suggestionsList;
271                 }
272             });
273         }
274     }
275 
276     @Override
277     public boolean isDisplayStringHTML() {
278         return true;
279     }
280 
281 /*    
282     public IdableSuggestion getSuggestionById(String id) {
283         IdableSuggestion suggestion = null;
284         if(!(lastSuggestions.isEmpty())){
285             for(IdableSuggestion is: lastSuggestions){
286                 if(is.getId().equals(id)){
287                     suggestion = is;
288                     break;
289                 }
290             }
291         }
292         if(suggestion == null){
293             searchOnId(id);
294         }
295         return suggestion;
296     }*/
297 
298     @Override
299     public IdableSuggestion getSuggestionByText(String text){
300         IdableSuggestion suggestion = null;
301         for(IdableSuggestion is: lastSuggestions){
302             if(is.getReplacementString().trim().equalsIgnoreCase(text.trim())){
303                 suggestion = is;
304                 break;
305             }
306         }
307         return suggestion;
308     }
309     
310     public void setTextWidget(HasText widget){
311         textWidget = widget;
312     }
313 
314     @Override
315     public void getSuggestionByIdSearch(String id, final org.kuali.student.common.ui.client.mvc.Callback<IdableSuggestion> callback) {
316         SearchRequest searchRequest = buildSearchRequestById(null, id);
317         searchRpcServiceAsync.search(searchRequest, new KSAsyncCallback<SearchResult>(){            
318             @Override
319             public void onSuccess(SearchResult results) {
320                 IdableSuggestion theSuggestion = null;
321                 if(results != null && !results.getRows().isEmpty()){
322                 	SearchResultRow r = results.getRows().get(0);
323                     theSuggestion = new IdableSuggestion();
324                     for(SearchResultCell c: r.getCells()){
325                         if(c.getKey().equals(resultDisplayKey)){
326                             String itemText = c.getValue();
327                             theSuggestion.addAttr(c.getKey(), c.getValue());
328                             theSuggestion.setDisplayString(itemText);
329                             theSuggestion.setReplacementString(itemText);
330                         } else if(c.getKey().equals(resultIdKey)){
331                              theSuggestion.setId(c.getValue());
332                              theSuggestion.addAttr(c.getKey(), c.getValue());
333                         } else {
334                             theSuggestion.addAttr(c.getKey(), c.getValue());
335                         }
336                     }
337                 }
338                 callback.exec(theSuggestion);
339             }
340         });
341     }
342 
343     @Override
344     public void addSearchCompletedCallback(org.kuali.student.common.ui.client.mvc.Callback<IdableSuggestion> callback) {
345         searchCompletedCallbacks.add(callback);
346     }
347     
348 }