1 11 package org.eclipse.ui.internal.decorators; 12 13 import java.util.ArrayList ; 14 import java.util.Collection ; 15 import java.util.Collections ; 16 import java.util.HashMap ; 17 import java.util.HashSet ; 18 import java.util.List ; 19 import java.util.Map ; 20 import java.util.Set ; 21 22 import org.eclipse.core.runtime.IProgressMonitor; 23 import org.eclipse.core.runtime.IStatus; 24 import org.eclipse.core.runtime.Status; 25 import org.eclipse.core.runtime.jobs.Job; 26 import org.eclipse.jface.viewers.DecorationContext; 27 import org.eclipse.jface.viewers.IDecorationContext; 28 import org.eclipse.jface.viewers.ILabelProviderListener; 29 import org.eclipse.jface.viewers.LabelProviderChangedEvent; 30 import org.eclipse.swt.graphics.Color; 31 import org.eclipse.swt.graphics.Font; 32 import org.eclipse.swt.graphics.Image; 33 import org.eclipse.ui.PlatformUI; 34 import org.eclipse.ui.internal.WorkbenchMessages; 35 import org.eclipse.ui.progress.UIJob; 36 import org.eclipse.ui.progress.WorkbenchJob; 37 38 42 public class DecorationScheduler { 43 44 static final ILabelProviderListener[] EMPTY_LISTENER_LIST = new ILabelProviderListener[0]; 45 46 Map resultCache = new HashMap (); 49 50 List awaitingDecoration = new ArrayList (); 52 53 Set pendingUpdate = new HashSet (); 55 56 Object pendingKey = new Object (); 58 59 Map awaitingDecorationValues = new HashMap (); 60 61 DecoratorManager decoratorManager; 62 63 boolean shutdown = false; 64 65 Job decorationJob; 66 67 UIJob updateJob; 68 69 private Collection removedListeners = Collections 70 .synchronizedSet(new HashSet ()); 71 72 private Job clearJob; 73 74 static final int NEEDS_INIT = -1; 76 77 78 static final int UPDATE_DELAY = 100; 79 80 86 DecorationScheduler(DecoratorManager manager) { 87 decoratorManager = manager; 88 createDecorationJob(); 89 } 90 91 103 104 public String decorateWithText(String text, Object element, 105 Object adaptedElement, IDecorationContext context) { 106 107 DecorationResult decoration = getResult(element, adaptedElement, 108 context); 109 110 if (decoration == null) { 111 return text; 112 } 113 114 return decoration.decorateWithText(text); 115 116 } 117 118 132 133 synchronized void queueForDecoration(Object element, Object adaptedElement, 134 boolean forceUpdate, String undecoratedText, 135 IDecorationContext context) { 136 137 DecorationReference reference = (DecorationReference) awaitingDecorationValues 138 .get(element); 139 if (reference != null) { 140 if (forceUpdate) { reference.setForceUpdate(forceUpdate); 142 } 143 reference.addContext(context); 144 } else { 145 reference = new DecorationReference(element, adaptedElement, 146 context); 147 reference.setForceUpdate(forceUpdate); 148 reference.setUndecoratedText(undecoratedText); 149 awaitingDecorationValues.put(element, reference); 150 awaitingDecoration.add(element); 151 if (shutdown) { 152 return; 153 } 154 if (decorationJob.getState() == Job.SLEEPING) { 155 decorationJob.wakeUp(); 156 } 157 decorationJob.schedule(); 158 } 159 160 } 161 162 174 public Image decorateWithOverlays(Image image, Object element, 175 Object adaptedElement, IDecorationContext context) { 176 177 DecorationResult decoration = getResult(element, adaptedElement, 178 context); 179 180 if (decoration == null) { 181 return image; 182 } 183 return decoration.decorateWithOverlays(image, decoratorManager 184 .getLightweightManager().getOverlayCache()); 185 } 186 187 200 private DecorationResult getResult(Object element, Object adaptedElement, 201 IDecorationContext context) { 202 203 if (element == null) { 205 return null; 206 } 207 208 DecorationResult decoration = internalGetResult(element, context); 209 210 if (decoration == null) { 211 queueForDecoration(element, adaptedElement, false, null, context); 212 return null; 213 } 214 return decoration; 215 216 } 217 218 private DecorationResult internalGetResult(Object element, 219 IDecorationContext context) { 220 Map results = (Map ) resultCache.get(context); 221 if (results != null) { 222 return (DecorationResult) results.get(element); 223 } 224 return null; 225 } 226 227 protected void internalPutResult(Object element, 228 IDecorationContext context, DecorationResult result) { 229 Map results = (Map ) resultCache.get(context); 230 if (results == null) { 231 results = new HashMap (); 232 resultCache.put(context, results); 233 } 234 results.put(element, result); 235 } 236 237 240 synchronized void decorated() { 241 242 if (shutdown) { 244 return; 245 } 246 247 if (updateJob == null) { 249 updateJob = getUpdateJob(); 250 } 251 252 updateJob.schedule(UPDATE_DELAY); 254 } 255 256 259 synchronized void shutdown() { 260 shutdown = true; 261 } 262 263 268 synchronized DecorationReference nextElement() { 269 270 if (shutdown || awaitingDecoration.isEmpty()) { 271 return null; 272 } 273 Object element = awaitingDecoration.remove(0); 274 275 return (DecorationReference) awaitingDecorationValues.remove(element); 276 } 277 278 281 private void createDecorationJob() { 282 decorationJob = new Job( 283 WorkbenchMessages.DecorationScheduler_CalculationJobName) { 284 289 public IStatus run(IProgressMonitor monitor) { 290 291 synchronized (DecorationScheduler.this) { 292 if (shutdown) { 293 return Status.CANCEL_STATUS; 294 } 295 } 296 297 while (updatesPending()) { 298 299 try { 300 Thread.sleep(100); 301 } catch (InterruptedException e) { 302 schedule(); 304 return Status.CANCEL_STATUS; 305 } 306 } 307 308 monitor.beginTask( 309 WorkbenchMessages.DecorationScheduler_CalculatingTask, 310 100); 311 DecorationReference reference; 313 monitor.worked(5); 314 int workCount = 5; 315 while ((reference = nextElement()) != null) { 316 317 if (workCount < 90) { 319 monitor.worked(1); 320 workCount++; 321 } 322 323 monitor.subTask(reference.getSubTask()); 324 Object element = reference.getElement(); 325 boolean force = reference.shouldForceUpdate(); 326 IDecorationContext[] contexts = reference.getContexts(); 327 for (int i = 0; i < contexts.length; i++) { 328 IDecorationContext context = contexts[i]; 329 ensureResultCached(element, force, context); 330 } 331 332 synchronized (DecorationScheduler.this) { 335 if (awaitingDecoration.isEmpty()) { 336 decorated(); 337 } 338 } 339 } 340 monitor.worked(100 - workCount); 341 monitor.done(); 342 return Status.OK_STATUS; 343 } 344 345 355 private void ensureResultCached(Object element, boolean force, 356 IDecorationContext context) { 357 boolean elementIsCached = internalGetResult(element, context) != null; 358 if (elementIsCached) { 359 synchronized (pendingKey) { 360 pendingUpdate.add(element); 361 } 362 363 } 364 365 if (!elementIsCached) { 366 DecorationBuilder cacheResult = new DecorationBuilder( 367 context); 368 decoratorManager.getLightweightManager().getDecorations( 370 element, cacheResult); 371 372 if (cacheResult.hasValue() || force) { 375 376 382 internalPutResult(element, context, cacheResult 386 .createResult()); 387 388 pendingUpdate.add(element); 392 393 } 394 } 395 } 396 397 402 public boolean belongsTo(Object family) { 403 return DecoratorManager.FAMILY_DECORATE == family; 404 } 405 406 411 public boolean shouldRun() { 412 return PlatformUI.isWorkbenchRunning(); 413 } 414 }; 415 416 decorationJob.setSystem(true); 417 decorationJob.setPriority(Job.DECORATE); 418 decorationJob.schedule(); 419 } 420 421 426 protected boolean updatesPending() { 427 if (updateJob != null && updateJob.getState() != Job.NONE) { 428 return true; 429 } 430 if (clearJob != null && clearJob.getState() != Job.NONE) { 431 return true; 432 } 433 return false; 434 } 435 436 440 void clearResults() { 441 if (clearJob == null) { 442 clearJob = getClearJob(); 443 } 444 clearJob.schedule(); 445 } 446 447 private Job getClearJob() { 448 Job clear = new Job( 449 WorkbenchMessages.DecorationScheduler_ClearResultsJob) { 450 451 456 protected IStatus run(IProgressMonitor monitor) { 457 resultCache.clear(); 458 return Status.OK_STATUS; 459 } 460 461 466 public boolean shouldRun() { 467 return PlatformUI.isWorkbenchRunning(); 468 } 469 470 }; 471 clear.setSystem(true); 472 473 return clear; 474 } 475 476 481 private WorkbenchJob getUpdateJob() { 482 WorkbenchJob job = new WorkbenchJob( 483 WorkbenchMessages.DecorationScheduler_UpdateJobName) { 484 485 int currentIndex = NEEDS_INIT; 486 487 LabelProviderChangedEvent labelProviderChangedEvent; 488 489 ILabelProviderListener[] listeners; 490 491 public IStatus runInUIThread(IProgressMonitor monitor) { 492 493 synchronized (DecorationScheduler.this) { 494 if (shutdown) { 495 return Status.CANCEL_STATUS; 496 } 497 } 498 499 if (currentIndex == NEEDS_INIT) { 502 if (hasPendingUpdates()) { 503 removedListeners.clear(); 506 return Status.OK_STATUS; 507 } 508 setUpUpdates(); 509 } 510 511 if (listeners.length == 0) { 512 return Status.OK_STATUS; 513 } 514 515 monitor.beginTask( 516 WorkbenchMessages.DecorationScheduler_UpdatingTask, 517 IProgressMonitor.UNKNOWN); 518 519 long startTime = System.currentTimeMillis(); 520 while (currentIndex < listeners.length) { 521 ILabelProviderListener listener = listeners[currentIndex]; 522 currentIndex++; 523 524 if (!removedListeners.contains(listener)) { 526 decoratorManager.fireListener( 527 labelProviderChangedEvent, listener); 528 } 529 530 if ((System.currentTimeMillis() - startTime) >= UPDATE_DELAY / 2) { 534 break; 535 } 536 } 537 538 monitor.done(); 539 540 if (currentIndex >= listeners.length) { 541 if (awaitingDecoration.isEmpty()) { 545 resultCache.clear(); 546 } 547 548 if (!hasPendingUpdates()) { 549 decorated(); 550 } 551 currentIndex = NEEDS_INIT; labelProviderChangedEvent = null; 553 removedListeners.clear(); 554 listeners = EMPTY_LISTENER_LIST; 555 } else { 556 schedule(UPDATE_DELAY); } 558 return Status.OK_STATUS; 559 } 560 561 private void setUpUpdates() { 562 removedListeners.clear(); 565 currentIndex = 0; 566 synchronized (pendingKey) { 567 Object [] elements = pendingUpdate 568 .toArray(new Object [pendingUpdate.size()]); 569 pendingUpdate.clear(); 570 labelProviderChangedEvent = new LabelProviderChangedEvent( 571 decoratorManager, elements); 572 } 573 listeners = decoratorManager.getListeners(); 574 } 575 576 581 public boolean belongsTo(Object family) { 582 return DecoratorManager.FAMILY_DECORATE == family; 583 } 584 585 590 public boolean shouldRun() { 591 return PlatformUI.isWorkbenchRunning(); 592 } 593 }; 594 595 job.setSystem(true); 596 return job; 597 } 598 599 607 public boolean isDecorationReady(Object element, IDecorationContext context) { 608 return internalGetResult(element, context) != null; 609 } 610 611 621 public Color getBackgroundColor(Object element, Object adaptedElement) { 622 DecorationResult decoration = getResult(element, adaptedElement, 623 DecorationContext.DEFAULT_CONTEXT); 624 625 if (decoration == null) { 626 return null; 627 } 628 return decoration.getBackgroundColor(); 629 } 630 631 641 public Font getFont(Object element, Object adaptedElement) { 642 DecorationResult decoration = getResult(element, adaptedElement, 643 DecorationContext.DEFAULT_CONTEXT); 644 645 if (decoration == null) { 646 return null; 647 } 648 return decoration.getFont(); 649 } 650 651 661 public Color getForegroundColor(Object element, Object adaptedElement) { 662 DecorationResult decoration = getResult(element, adaptedElement, 663 DecorationContext.DEFAULT_CONTEXT); 664 665 if (decoration == null) { 666 return null; 667 } 668 return decoration.getForegroundColor(); 669 } 670 671 676 public boolean processingUpdates() { 677 return !hasPendingUpdates() && !awaitingDecoration.isEmpty(); 678 } 679 680 685 void listenerRemoved(ILabelProviderListener listener) { 686 if (updatesPending()) { removedListeners.add(listener); 689 } 690 if (!updatesPending()) { 691 removedListeners.remove(listener); 692 } 693 694 } 695 696 701 boolean hasPendingUpdates() { 702 synchronized (pendingKey) { 703 return pendingUpdate.isEmpty(); 704 } 705 706 } 707 } 708 | Popular Tags |