1 11 package org.eclipse.search.ui.text; 12 13 import java.util.ArrayList ; 14 import java.util.Collection ; 15 import java.util.HashMap ; 16 import java.util.HashSet ; 17 import java.util.Iterator ; 18 import java.util.List ; 19 import java.util.Map ; 20 21 import org.eclipse.search.ui.ISearchResult; 22 import org.eclipse.search.ui.ISearchResultListener; 23 import org.eclipse.search.ui.SearchResultEvent; 24 25 32 public abstract class AbstractTextSearchResult implements ISearchResult { 33 34 private static final Match[] EMPTY_ARRAY= new Match[0]; 35 36 private final Map fElementsToMatches; 37 private final List fListeners; 38 private final MatchEvent fMatchEvent; 39 40 private MatchFilter[] fMatchFilters; 41 42 45 protected AbstractTextSearchResult() { 46 fElementsToMatches= new HashMap (); 47 fListeners= new ArrayList (); 48 fMatchEvent= new MatchEvent(this); 49 50 fMatchFilters= null; } 52 53 61 public Match[] getMatches(Object element) { 62 synchronized (fElementsToMatches) { 63 List matches= (List ) fElementsToMatches.get(element); 64 if (matches != null) 65 return (Match[]) matches.toArray(new Match[matches.size()]); 66 return EMPTY_ARRAY; 67 } 68 } 69 70 79 public void addMatch(Match match) { 80 boolean hasAdded= false; 81 synchronized (fElementsToMatches) { 82 hasAdded= doAddMatch(match); 83 } 84 if (hasAdded) 85 fireChange(getSearchResultEvent(match, MatchEvent.ADDED)); 86 } 87 88 96 public void addMatches(Match[] matches) { 97 Collection reallyAdded= new ArrayList (); 98 synchronized (fElementsToMatches) { 99 for (int i = 0; i < matches.length; i++) { 100 if (doAddMatch(matches[i])) 101 reallyAdded.add(matches[i]); 102 } 103 } 104 if (!reallyAdded.isEmpty()) 105 fireChange(getSearchResultEvent(reallyAdded, MatchEvent.ADDED)); 106 } 107 108 private MatchEvent getSearchResultEvent(Match match, int eventKind) { 109 fMatchEvent.setKind(eventKind); 110 fMatchEvent.setMatch(match); 111 return fMatchEvent; 112 } 113 114 private MatchEvent getSearchResultEvent(Collection matches, int eventKind) { 115 fMatchEvent.setKind(eventKind); 116 Match[] matchArray= (Match[]) matches.toArray(new Match[matches.size()]); 117 fMatchEvent.setMatches(matchArray); 118 return fMatchEvent; 119 } 120 121 private boolean doAddMatch(Match match) { 122 updateFilterState(match); 123 124 List matches= (List ) fElementsToMatches.get(match.getElement()); 125 if (matches == null) { 126 matches= new ArrayList (); 127 fElementsToMatches.put(match.getElement(), matches); 128 matches.add(match); 129 return true; 130 } 131 if (!matches.contains(match)) { 132 insertSorted(matches, match); 133 return true; 134 } 135 return false; 136 } 137 138 private static void insertSorted(List matches, Match match) { 139 int insertIndex= getInsertIndex(matches, match); 140 matches.add(insertIndex, match); 141 } 142 143 private static int getInsertIndex(List matches, Match match) { 144 int count= matches.size(); 145 int min = 0, max = count - 1; 146 while (min <= max) { 147 int mid = (min + max) / 2; 148 Match data = (Match) matches.get(mid); 149 int compare = compare(match, data); 150 if (compare > 0) 151 max = mid - 1; 152 else 153 min = mid + 1; 154 } 155 return min; 156 } 157 158 159 private static int compare(Match match1, Match match2) { 160 int diff= match2.getOffset()-match1.getOffset(); 161 if (diff != 0) 162 return diff; 163 return match2.getLength()-match1.getLength(); 164 } 165 166 172 public void removeAll() { 173 synchronized (fElementsToMatches) { 174 doRemoveAll(); 175 } 176 fireChange(new RemoveAllEvent(this)); 177 } 178 private void doRemoveAll() { 179 fElementsToMatches.clear(); 180 } 181 182 190 public void removeMatch(Match match) { 191 boolean existed= false; 192 synchronized (fElementsToMatches) { 193 existed= doRemoveMatch(match); 194 } 195 if (existed) 196 fireChange(getSearchResultEvent(match, MatchEvent.REMOVED)); 197 } 198 199 208 public void removeMatches(Match[] matches) { 209 Collection existing= new ArrayList (); 210 synchronized (fElementsToMatches) { 211 for (int i = 0; i < matches.length; i++) { 212 if (doRemoveMatch(matches[i])) 213 existing.add(matches[i]); } 215 } 216 if (!existing.isEmpty()) 217 fireChange(getSearchResultEvent(existing, MatchEvent.REMOVED)); 218 } 219 220 221 private boolean doRemoveMatch(Match match) { 222 boolean existed= false; 223 List matches= (List ) fElementsToMatches.get(match.getElement()); 224 if (matches != null) { 225 existed= matches.remove(match); 226 if (matches.isEmpty()) 227 fElementsToMatches.remove(match.getElement()); 228 } 229 return existed; 230 } 231 232 235 public void addListener(ISearchResultListener l) { 236 synchronized (fListeners) { 237 fListeners.add(l); 238 } 239 } 240 241 244 public void removeListener(ISearchResultListener l) { 245 synchronized (fListeners) { 246 fListeners.remove(l); 247 } 248 } 249 250 258 protected void fireChange(SearchResultEvent e) { 259 HashSet copiedListeners= new HashSet (); 260 synchronized (fListeners) { 261 copiedListeners.addAll(fListeners); 262 } 263 Iterator listeners= copiedListeners.iterator(); 264 while (listeners.hasNext()) { 265 ((ISearchResultListener) listeners.next()).searchResultChanged(e); 266 } 267 } 268 269 private void updateFilterStateForAllMatches() { 270 boolean disableFiltering= getActiveMatchFilters() == null; 271 ArrayList changed= new ArrayList (); 272 Object [] elements= getElements(); 273 for (int i= 0; i < elements.length; i++) { 274 Match[] matches= getMatches(elements[i]); 275 for (int k= 0; k < matches.length; k++) { 276 if (disableFiltering || updateFilterState(matches[k])) { 277 changed.add(matches[k]); 278 } 279 } 280 } 281 Match[] allChanges= (Match[]) changed.toArray(new Match[changed.size()]); 282 fireChange(new FilterUpdateEvent(this, allChanges, getActiveMatchFilters())); 283 } 284 285 288 private boolean updateFilterState(Match match) { 289 MatchFilter[] matchFilters= getActiveMatchFilters(); 290 if (matchFilters == null) { 291 return false; } 293 294 boolean oldState= match.isFiltered(); 295 for (int i= 0; i < matchFilters.length; i++) { 296 if (matchFilters[i].filters(match)) { 297 match.setFiltered(true); 298 return !oldState; 299 } 300 } 301 match.setFiltered(false); 302 return oldState; 303 } 304 305 311 public int getMatchCount() { 312 int count= 0; 313 synchronized (fElementsToMatches) { 314 for (Iterator elements= fElementsToMatches.values().iterator(); elements.hasNext();) { 315 List element= (List ) elements.next(); 316 if (element != null) 317 count+= element.size(); 318 } 319 } 320 return count; 321 } 322 323 331 public int getMatchCount(Object element) { 332 List matches= (List ) fElementsToMatches.get(element); 333 if (matches != null) 334 return matches.size(); 335 return 0; 336 } 337 338 345 public Object [] getElements() { 346 synchronized (fElementsToMatches) { 347 return fElementsToMatches.keySet().toArray(); 348 } 349 } 350 351 364 public void setActiveMatchFilters(MatchFilter[] filters) { 365 fMatchFilters= filters; 366 updateFilterStateForAllMatches(); 367 } 368 369 381 public MatchFilter[] getActiveMatchFilters() { 382 return fMatchFilters; 383 } 384 385 393 public MatchFilter[] getAllMatchFilters() { 394 return null; 395 } 396 397 398 406 public abstract IEditorMatchAdapter getEditorMatchAdapter(); 407 408 409 417 public abstract IFileMatchAdapter getFileMatchAdapter(); 418 } 419 | Popular Tags |