1 16 package com.google.gwt.user.client.ui; 17 18 import com.google.gwt.user.client.rpc.IsSerializable; 19 20 import java.util.ArrayList ; 21 import java.util.Collection ; 22 import java.util.Collections ; 23 import java.util.HashMap ; 24 import java.util.HashSet ; 25 import java.util.Iterator ; 26 import java.util.List ; 27 28 62 public final class MultiWordSuggestOracle extends SuggestOracle { 63 64 67 public static class MultiWordSuggestion implements Suggestion, IsSerializable { 68 private String value; 69 private String displayString; 70 71 74 public MultiWordSuggestion() { 75 } 76 77 83 public MultiWordSuggestion(String value, String displayString) { 84 this.value = value; 85 this.displayString = displayString; 86 } 87 88 public String getDisplayString() { 89 return displayString; 90 } 91 92 public Object getValue() { 93 return value; 94 } 95 } 96 97 private static final char WHITESPACE_CHAR = ' '; 98 private static final String WHITESPACE_STRING = " "; 99 100 103 private static final String NORMALIZE_TO_SINGLE_WHITE_SPACE = "\\s+"; 104 105 private static HTML convertMe = new HTML(); 106 107 110 private final PrefixTree tree = new PrefixTree(); 111 112 115 private HashMap toCandidates = new HashMap (); 116 117 120 private HashMap toRealSuggestions = new HashMap (); 121 122 126 private char[] whitespaceChars; 127 128 134 public MultiWordSuggestOracle() { 135 this(" "); 136 } 137 138 151 public MultiWordSuggestOracle(String whitespaceChars) { 152 this.whitespaceChars = new char[whitespaceChars.length()]; 153 for (int i = 0; i < whitespaceChars.length(); i++) { 154 this.whitespaceChars[i] = whitespaceChars.charAt(i); 155 } 156 } 157 158 163 public void add(String suggestion) { 164 String candidate = normalizeSuggestion(suggestion); 165 toRealSuggestions.put(candidate, suggestion); 167 168 String [] words = candidate.split(WHITESPACE_STRING); 170 for (int i = 0; i < words.length; i++) { 171 String word = words[i]; 172 tree.add(word); 173 HashSet l = (HashSet ) toCandidates.get(word); 174 if (l == null) { 175 l = new HashSet (); 176 toCandidates.put(word, l); 177 } 178 l.add(candidate); 179 } 180 } 181 182 187 public void addAll(Collection collection) { 188 Iterator suggestions = collection.iterator(); 189 while (suggestions.hasNext()) { 190 add((String ) suggestions.next()); 191 } 192 } 193 194 public boolean isDisplayStringHTML() { 195 return true; 196 } 197 198 public void requestSuggestions(Request request, Callback callback) { 199 final List suggestions = computeItemsFor(request.getQuery(), request 200 .getLimit()); 201 Response response = new Response(suggestions); 202 callback.onSuggestionsReady(request, response); 203 } 204 205 String escapeText(String escapeMe) { 206 convertMe.setText(escapeMe); 207 String escaped = convertMe.getHTML(); 208 return escaped; 209 } 210 211 218 private List computeItemsFor(String query, int limit) { 219 query = normalizeSearch(query); 220 221 List candidates = createCandidatesFromSearch(query, limit); 223 224 return convertToFormattedSuggestions(query, candidates); 226 } 227 228 236 private List convertToFormattedSuggestions(String query, List candidates) { 237 List suggestions = new ArrayList (); 238 239 for (int i = 0; i < candidates.size(); i++) { 240 String candidate = (String ) candidates.get(i); 241 int index = 0; 242 int cursor = 0; 243 String formattedSuggestion = (String ) toRealSuggestions.get(candidate); 245 246 StringBuffer accum = new StringBuffer (); 248 249 while (true) { 250 index = candidate.indexOf(query, index); 251 if (index == -1) { 252 break; 253 } 254 int endIndex = index + query.length(); 255 if (index == 0 || (WHITESPACE_CHAR == candidate.charAt(index - 1))) { 256 String part1 = escapeText(formattedSuggestion 257 .substring(cursor, index)); 258 String part2 = escapeText(formattedSuggestion.substring(index, 259 endIndex)); 260 cursor = endIndex; 261 accum.append(part1).append("<strong>").append(part2).append( 262 "</strong>"); 263 } 264 index = endIndex; 265 } 266 267 if (cursor == 0) { 269 continue; 270 } 271 272 String end = escapeText(formattedSuggestion.substring(cursor)); 274 accum.append(end); 275 MultiWordSuggestion suggestion = new MultiWordSuggestion( 276 formattedSuggestion, accum.toString()); 277 suggestions.add(suggestion); 278 } 279 return suggestions; 280 } 281 282 285 private List createCandidatesFromSearch(String query, int limit) { 286 ArrayList candidates = new ArrayList (); 287 288 if (query.length() == 0) { 289 return candidates; 290 } 291 292 String [] searchWords = query.split(WHITESPACE_STRING); 294 HashSet candidateSet = null; 295 for (int i = 0; i < searchWords.length; i++) { 296 String word = searchWords[i]; 297 298 if (word.length() == 0 || word.matches(WHITESPACE_STRING)) { 300 continue; 301 } 302 303 HashSet thisWordChoices = createCandidatesFromWord(word); 306 if (candidateSet == null) { 307 candidateSet = thisWordChoices; 308 } else { 309 candidateSet.retainAll(thisWordChoices); 310 311 if (candidateSet.size() < 2) { 312 break; 316 } 317 } 318 } 319 if (candidateSet != null) { 320 candidates.addAll(candidateSet); 321 Collections.sort(candidates); 322 for (int i = candidates.size() - 1; i > limit; i--) { 324 candidates.remove(i); 325 } 326 } 327 return candidates; 328 } 329 330 337 private HashSet createCandidatesFromWord(String query) { 338 HashSet candidateSet = new HashSet (); 339 List words = tree.getSuggestions(query, Integer.MAX_VALUE); 340 if (words != null) { 341 for (int i = 0; i < words.size(); i++) { 344 Collection belongsTo = (Collection ) toCandidates.get(words.get(i)); 345 if (belongsTo != null) { 346 candidateSet.addAll(belongsTo); 347 } 348 } 349 } 350 return candidateSet; 351 } 352 353 357 private String normalizeSearch(String search) { 358 search = normalizeSuggestion(search); 361 362 search = search.replaceAll(NORMALIZE_TO_SINGLE_WHITE_SPACE, 364 WHITESPACE_STRING); 365 366 return search.trim(); 367 } 368 369 373 private String normalizeSuggestion(String formattedSuggestion) { 374 377 formattedSuggestion = formattedSuggestion.toLowerCase(); 379 380 if (whitespaceChars != null) { 382 for (int i = 0; i < whitespaceChars.length; i++) { 383 char ignore = whitespaceChars[i]; 384 formattedSuggestion = formattedSuggestion.replace(ignore, 385 WHITESPACE_CHAR); 386 } 387 } 388 return formattedSuggestion; 389 } 390 } 391 | Popular Tags |