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