1 11 package org.eclipse.ui.views.markers.internal; 12 13 import java.util.ArrayList ; 14 import java.util.Collection ; 15 import java.util.Comparator ; 16 import java.util.HashSet ; 17 import java.util.Iterator ; 18 import java.util.List ; 19 import java.util.Set ; 20 import java.util.TreeSet ; 21 22 import org.eclipse.core.runtime.IProgressMonitor; 23 import org.eclipse.core.runtime.NullProgressMonitor; 24 import org.eclipse.core.runtime.SubProgressMonitor; 25 import org.eclipse.jface.viewers.TableViewer; 26 import org.eclipse.swt.widgets.Table; 27 28 34 final class DeferredQueue { 35 36 private static final String SETTING_CONTENTS = Messages 37 .getString("DeferredQueue.setting_contents"); 39 43 private static final int MAX_UPDATE = 40; 44 45 49 private static final int MIN_UPDATE = 1; 50 51 54 private static final int GROWTH_LIMIT = 20000; 55 56 58 62 private Comparator sortOrder; 63 64 67 private Set visibleItems = new HashSet (); 68 69 74 private Set insertionsAtEnd = new HashSet (); 75 76 81 private Set insertionsInMiddle = new HashSet (); 82 83 86 private Set pendingRemovals = new HashSet (); 87 88 91 private Set pendingChanges = new HashSet (); 92 93 97 private Object lastVisible = null; 98 99 105 private boolean lastDirty = false; 106 107 110 private TableViewer viewer; 111 112 private boolean hasPendingChanges = false; 113 114 119 public DeferredQueue(TableViewer viewer) { 120 this.viewer = viewer; 121 } 122 123 128 public Object [] getVisibleItems() { 129 synchronized (visibleItems) { 130 return visibleItems.toArray(); 131 } 132 } 133 134 142 public void change(Collection changes) { 143 Iterator iter = changes.iterator(); 144 145 while (iter.hasNext()) { 146 Object next = iter.next(); 147 boolean isVisible = false; 148 synchronized (visibleItems) { 149 if (visibleItems.contains(next)) { 150 visibleItems.remove(next); 151 visibleItems.add(next); 152 pendingChanges.add(next); 153 isVisible = true; 154 hasPendingChanges = true; 155 } 156 } 157 158 if (!isVisible) { 159 if (insertionsInMiddle.contains(next)) { 160 insertionsInMiddle.remove(next); 161 insertionsInMiddle.add(next); 162 hasPendingChanges = true; 163 } else if (insertionsAtEnd.contains(next)) { 164 insertionsAtEnd.remove(next); 165 insertionsAtEnd.add(next); 166 hasPendingChanges = true; 167 } 168 } 169 } 170 } 171 172 181 public void set(Collection newPendingContents, IProgressMonitor mon) { 182 mon.beginTask(SETTING_CONTENTS, 100); 183 184 Set newInsertions = new HashSet (); 186 187 Set newPendingRemovals = new HashSet (); 189 Set newInsertionsInMiddle = new HashSet (); 191 Set newInsertionsAtEnd = newEndSet(); 193 194 addWithProgress(newInsertions, newPendingContents, mon, 5); 195 synchronized (visibleItems) { 196 addWithProgress(newPendingRemovals, visibleItems, mon, 5); 197 removeWithProgress(newPendingRemovals, newInsertions, mon, 5); 198 removeWithProgress(newInsertions, visibleItems, mon, 5); 199 } 200 201 if (newInsertions.isEmpty() && newPendingRemovals.isEmpty()) { 202 return; 203 } 204 205 SubProgressMonitor sub = new SubProgressMonitor(mon, 80); 206 SortUtil.partition(newInsertionsInMiddle, newInsertionsAtEnd, 207 newInsertionsAtEnd, newInsertions, sortOrder, lastVisible, sub); 208 209 if (mon.isCanceled()) { 211 mon.done(); 212 return; 213 } 214 215 hasPendingChanges = true; 217 lastDirty = false; 218 insertionsAtEnd.clear(); 219 insertionsAtEnd = newInsertionsAtEnd; 220 221 insertionsInMiddle.clear(); 222 insertionsInMiddle = newInsertionsInMiddle; 223 224 pendingRemovals.clear(); 225 pendingRemovals = newPendingRemovals; 226 227 mon.done(); 228 } 229 230 237 private int nextChange(int maximumToChange) { 238 Collection result = SortUtil.removeFirst(pendingChanges, 239 maximumToChange); 240 241 viewer.update(result.toArray(), null); 242 243 return result.size(); 244 } 245 246 252 private int nextRemoval(int maximumToRemove) { 253 ArrayList result = new ArrayList (maximumToRemove); 254 255 int counter = maximumToRemove; 256 257 Iterator iter = pendingRemovals.iterator(); 258 while (iter.hasNext() && counter > 0) { 259 Object next = iter.next(); 260 261 result.add(next); 262 263 if (lastVisible != null && lastVisible.equals(next)) { 264 lastDirty = true; 265 } 266 267 iter.remove(); 268 counter--; 269 } 270 271 synchronized (visibleItems) { 272 visibleItems.removeAll(result); 273 } 274 275 viewer.remove(result.toArray()); 276 277 if (lastDirty) { 278 lastVisible = viewer 279 .getElementAt(viewer.getTable().getItemCount() - 1); 280 } 281 282 return result.size(); 283 } 284 285 291 private int nextInsertionInMiddle(int maximumToInsert) { 292 293 refreshQueues(new NullProgressMonitor()); 294 295 Collection result = SortUtil.removeFirst(insertionsInMiddle, 296 maximumToInsert); 297 298 synchronized (visibleItems) { 299 visibleItems.addAll(result); 300 } 301 302 306 Iterator iter = result.iterator(); 307 while (iter.hasNext()) { 308 Object element = iter.next(); 309 310 int insertionPos = getInsertPosition(element); 311 viewer.insert(element, insertionPos); 312 } 313 314 return result.size(); 315 } 316 317 325 private int nextInsertionAtEnd(int maximumToInsert) { 326 refreshQueues(new NullProgressMonitor()); 327 328 List result = new ArrayList (maximumToInsert); 329 330 Iterator iter = insertionsAtEnd.iterator(); 331 for (int counter = 0; counter < maximumToInsert && iter.hasNext(); counter++) { 332 lastVisible = iter.next(); 333 334 result.add(lastVisible); 335 336 iter.remove(); 337 } 338 339 synchronized (visibleItems) { 340 visibleItems.addAll(result); 341 } 342 343 viewer.add(result.toArray()); 344 345 return result.size(); 346 } 347 348 351 public void reset() { 352 synchronized (visibleItems) { 353 visibleItems.removeAll(pendingRemovals); 354 355 insertionsInMiddle.addAll(visibleItems); 356 lastVisible = null; 357 lastDirty = true; 358 359 visibleItems.clear(); 360 } 361 pendingRemovals.clear(); 362 hasPendingChanges = true; 363 } 364 365 370 public boolean hasPendingChanges() { 371 return hasPendingChanges; 372 } 373 374 380 public int workRemaining() { 381 return pendingRemovals.size() + insertionsAtEnd.size() 382 + insertionsInMiddle.size() + pendingChanges.size(); 383 } 384 385 389 public void cancelPending() { 390 insertionsAtEnd.clear(); 391 insertionsInMiddle.clear(); 392 pendingRemovals.clear(); 393 hasPendingChanges = false; 394 } 395 396 public void setComparator(Comparator c) { 397 if (sortOrder == c) { 398 return; 399 } 400 401 sortOrder = c; 402 403 lastVisible = null; 404 405 insertionsInMiddle.addAll(insertionsAtEnd); 406 insertionsAtEnd = newEndSet(); 407 lastDirty = true; 408 409 reset(); 410 } 411 412 416 public void refreshQueues(IProgressMonitor mon) { 417 if (lastDirty) { 418 if (mon.isCanceled()) { 419 return; 420 } 421 HashSet newInsertionsInMiddle = new HashSet (); 422 SortUtil.partition(newInsertionsInMiddle, insertionsAtEnd, 423 insertionsAtEnd, insertionsInMiddle, sortOrder, 424 lastVisible, mon); 425 426 if (mon.isCanceled()) { 427 insertionsInMiddle.removeAll(insertionsAtEnd); 428 } else { 429 insertionsInMiddle = newInsertionsInMiddle; 430 lastDirty = false; 431 } 432 } 433 } 434 435 444 private int getInsertPosition(Object element) { 445 Table table = viewer.getTable(); 446 if (sortOrder == null) 447 return table.getItemCount(); 448 int count = table.getItemCount(); 449 int min = 0, max = count - 1; 450 while (min <= max) { 451 int mid = (min + max) / 2; 452 Object data = table.getItem(mid).getData(); 453 int compare = sortOrder.compare(data, element); 454 if (compare == 0) { 455 while (compare == 0) { 457 ++mid; 458 if (mid >= count) { 459 break; 460 } 461 data = table.getItem(mid).getData(); 462 compare = sortOrder.compare(data, element); 463 } 464 return mid; 465 } 466 if (compare < 0) 467 min = mid + 1; 468 else 469 max = mid - 1; 470 } 471 return min; 472 } 473 474 481 public int nextUpdate() { 482 483 int pendingRemovalsSize = pendingRemovals.size(); 484 485 if (pendingRemovalsSize > 0) { 486 int currentSize = countVisibleItems(); 487 int finalSize = currentSize - pendingRemovalsSize; 489 490 if (finalSize * finalSize * 2 <= currentSize * currentSize) { 491 492 495 reset(); 496 getViewer().refresh(); 497 498 return 0; 499 } 500 501 return nextRemoval(nextUpdateSize()); 502 } else if (insertionsInMiddle.size() > 0) { 503 return nextInsertionInMiddle(nextUpdateSize()); 504 } else if (insertionsAtEnd.size() > 0) { 505 return nextInsertionAtEnd(MAX_UPDATE); 506 } else if (pendingChanges.size() > 0) { 507 return nextChange(MAX_UPDATE); 508 } 509 510 hasPendingChanges = false; 511 512 return 0; 513 } 514 515 518 int countVisibleItems() { 519 synchronized (visibleItems) { 520 return visibleItems.size(); 521 } 522 } 523 524 531 private int nextUpdateSize() { 532 int size = GROWTH_LIMIT * (MAX_UPDATE - MIN_UPDATE) 533 / (GROWTH_LIMIT + countVisibleItems()) + MIN_UPDATE; 534 535 return size; 536 } 537 538 543 public TableViewer getViewer() { 544 return viewer; 545 } 546 547 552 private Set newEndSet() { 553 if (sortOrder == null) { 554 return new HashSet (); 555 } else { 556 return new TreeSet (sortOrder); 557 } 558 } 559 560 570 private static void removeWithProgress(Collection target, 571 Collection toRemove, IProgressMonitor mon, int worked) { 572 if (mon.isCanceled()) { 573 return; 574 } 575 576 target.removeAll(toRemove); 577 578 mon.worked(worked); 579 } 580 581 591 private static void addWithProgress(Collection target, Collection toInsert, 592 IProgressMonitor mon, int worked) { 593 if (mon.isCanceled()) { 594 return; 595 } 596 597 target.addAll(toInsert); 598 599 mon.worked(worked); 600 } 601 602 605 public Comparator getSorter() { 606 return sortOrder; 607 } 608 609 } 610 | Popular Tags |