1 11 package org.eclipse.team.internal.ui.synchronize; 12 13 import com.ibm.icu.text.DateFormat; 14 import com.ibm.icu.text.SimpleDateFormat; 15 import java.util.Collections ; 16 import java.util.Date ; 17 import java.util.HashMap ; 18 import java.util.HashSet ; 19 import java.util.Iterator ; 20 import java.util.Map ; 21 import java.util.Set ; 22 23 import org.eclipse.core.resources.*; 24 import org.eclipse.core.runtime.*; 25 import org.eclipse.jface.util.IPropertyChangeListener; 26 import org.eclipse.jface.util.PropertyChangeEvent; 27 import org.eclipse.jface.viewers.AbstractTreeViewer; 28 import org.eclipse.jface.viewers.StructuredViewer; 29 import org.eclipse.swt.custom.BusyIndicator; 30 import org.eclipse.swt.widgets.Control; 31 import org.eclipse.team.core.ITeamStatus; 32 import org.eclipse.team.core.TeamException; 33 import org.eclipse.team.core.synchronize.*; 34 import org.eclipse.team.internal.core.BackgroundEventHandler; 35 import org.eclipse.team.internal.ui.*; 36 import org.eclipse.team.ui.synchronize.ISynchronizeModelElement; 37 38 43 public class SynchronizeModelUpdateHandler extends BackgroundEventHandler implements IResourceChangeListener, ISyncInfoSetChangeListener { 44 45 private static final boolean DEBUG = Policy.DEBUG_SYNC_MODELS; 46 47 private static final IWorkspaceRoot ROOT = ResourcesPlugin.getWorkspace().getRoot(); 48 49 private static final int MARKERS_CHANGED = 1; 51 private static final int BUSY_STATE_CHANGED = 2; 52 private static final int RESET = 3; 53 private static final int SYNC_INFO_SET_CHANGED = 4; 54 55 private AbstractSynchronizeModelProvider provider; 56 57 private Set pendingLabelUpdates = Collections.synchronizedSet(new HashSet ()); 58 59 private boolean dispatchEarly = false; 62 63 private static final int EARLY_DISPATCH_INCREMENT = 100; 64 65 68 class MarkerChangeEvent extends Event { 69 private final ISynchronizeModelElement[] elements; 70 public MarkerChangeEvent(ISynchronizeModelElement[] elements) { 71 super(MARKERS_CHANGED); 72 this.elements = elements; 73 } 74 public ISynchronizeModelElement[] getElements() { 75 return elements; 76 } 77 } 78 79 82 class BusyStateChangeEvent extends Event { 83 84 private final ISynchronizeModelElement element; 85 private final boolean isBusy; 86 public BusyStateChangeEvent(ISynchronizeModelElement element, boolean isBusy) { 87 super(BUSY_STATE_CHANGED); 88 this.element = element; 89 this.isBusy = isBusy; 90 } 91 public ISynchronizeModelElement getElement() { 92 return element; 93 } 94 public boolean isBusy() { 95 return isBusy; 96 } 97 } 98 99 102 class SyncInfoSetChangeEvent extends Event { 103 private final ISyncInfoSetChangeEvent event; 104 public SyncInfoSetChangeEvent(ISyncInfoSetChangeEvent event) { 105 super(SYNC_INFO_SET_CHANGED); 106 this.event = event; 107 } 108 public ISyncInfoSetChangeEvent getEvent() { 109 return event; 110 } 111 } 112 113 private IPropertyChangeListener listener = new IPropertyChangeListener() { 114 public void propertyChange(final PropertyChangeEvent event) { 115 if (event.getProperty() == ISynchronizeModelElement.BUSY_PROPERTY) { 116 Object source = event.getSource(); 117 if (source instanceof ISynchronizeModelElement) 118 updateBusyState((ISynchronizeModelElement)source, ((Boolean )event.getNewValue()).booleanValue()); 119 } 120 } 121 }; 122 123 private boolean performingBackgroundUpdate; 124 125 128 private Map additionsMap; 129 130 133 public SynchronizeModelUpdateHandler(AbstractSynchronizeModelProvider provider) { 134 super(TeamUIMessages.SynchronizeModelProvider_0, TeamUIMessages.SynchronizeModelUpdateHandler_0); this.provider = provider; 136 ResourcesPlugin.getWorkspace().addResourceChangeListener(this); 137 provider.getSyncInfoSet().addSyncSetChangedListener(this); 138 } 139 140 144 protected String [] getMarkerTypes() { 145 return new String [] {IMarker.PROBLEM}; 146 } 147 148 153 public StructuredViewer getViewer() { 154 return provider.getViewer(); 155 } 156 157 160 public void resourceChanged(final IResourceChangeEvent event) { 161 String [] markerTypes = getMarkerTypes(); 162 Set handledResources = new HashSet (); 163 Set changes = new HashSet (); 164 165 for (int idx = 0; idx < markerTypes.length; idx++) { 168 IMarkerDelta[] markerDeltas = event.findMarkerDeltas(markerTypes[idx], true); 169 for (int i = 0; i < markerDeltas.length; i++) { 170 IMarkerDelta delta = markerDeltas[i]; 171 IResource resource = delta.getResource(); 172 if (!handledResources.contains(resource)) { 173 handledResources.add(resource); 174 ISynchronizeModelElement[] elements = provider.getClosestExistingParents(delta.getResource()); 175 if(elements != null && elements.length > 0) { 176 for (int j = 0; j < elements.length; j++) { 177 ISynchronizeModelElement element = elements[j]; 178 changes.add(element); 179 } 180 } 181 } 182 } 183 } 184 185 if (!changes.isEmpty()) { 186 updateMarkersFor((ISynchronizeModelElement[]) changes.toArray(new ISynchronizeModelElement[changes.size()])); 187 } 188 } 189 190 private void updateMarkersFor(ISynchronizeModelElement[] elements) { 191 queueEvent(new MarkerChangeEvent(elements), false ); 192 } 193 194 protected void updateBusyState(ISynchronizeModelElement element, boolean isBusy) { 195 queueEvent(new BusyStateChangeEvent(element, isBusy), false ); 196 } 197 198 201 protected void processEvent(Event event, IProgressMonitor monitor) throws CoreException { 202 switch (event.getType()) { 203 case BackgroundEventHandler.RUNNABLE_EVENT : 204 executeRunnable(event, monitor); 205 break; 206 case MARKERS_CHANGED: 207 long start = System.currentTimeMillis(); 209 ISynchronizeModelElement[] elements = getChangedElements(event); 210 for (int i = 0; i < elements.length; i++) { 211 ISynchronizeModelElement element = elements[i]; 212 propagateProblemMarkers(element); 213 updateParentLabels(element); 214 } 215 if (DEBUG) { 216 long time = System.currentTimeMillis() - start; 217 DateFormat TIME_FORMAT = new SimpleDateFormat("m:ss.SSS"); String took = TIME_FORMAT.format(new Date (time)); 219 System.out.println(took + " for " + elements.length + " files"); } 221 break; 222 case BUSY_STATE_CHANGED: 223 BusyStateChangeEvent e = (BusyStateChangeEvent)event; 224 queueForLabelUpdate(e.getElement()); 225 if (e.isBusy()) { 226 dispatchEarly = true; 228 } 229 break; 230 case RESET: 231 pendingLabelUpdates.clear(); 233 provider.reset(); 234 break; 235 case SYNC_INFO_SET_CHANGED: 236 handleChanges(((SyncInfoSetChangeEvent)event).getEvent(), monitor); 238 default: 239 break; 240 } 241 } 242 243 private ISynchronizeModelElement[] getChangedElements(Event event) { 244 if (event.getType() == MARKERS_CHANGED) { 245 return ((MarkerChangeEvent)event).getElements(); 246 } 247 return new ISynchronizeModelElement[0]; 248 } 249 250 253 protected boolean doDispatchEvents(IProgressMonitor monitor) throws TeamException { 254 dispatchEarly = false; 256 if (pendingLabelUpdates.isEmpty()) { 257 return false; 258 } else { 259 Utils.asyncExec(new Runnable () { 260 public void run() { 261 firePendingLabelUpdates(); 262 } 263 }, getViewer()); 264 return true; 265 } 266 } 267 268 273 protected void firePendingLabelUpdates() { 274 if (!Utils.canUpdateViewer(getViewer())) return; 275 try { 276 Object [] updates = pendingLabelUpdates.toArray(new Object [pendingLabelUpdates.size()]); 277 updateLabels(updates); 278 } finally { 279 pendingLabelUpdates.clear(); 280 } 281 } 282 283 286 private void updateLabels(Object [] elements) { 287 StructuredViewer tree = getViewer(); 288 if (Utils.canUpdateViewer(tree)) { 289 tree.update(elements, null); 290 } 291 } 292 293 297 public void updateParentLabels(ISynchronizeModelElement element) { 298 queueForLabelUpdate(element); 299 while (element.getParent() != null) { 300 element = (ISynchronizeModelElement)element.getParent(); 301 queueForLabelUpdate(element); 302 } 303 } 304 305 310 protected void queueForLabelUpdate(ISynchronizeModelElement diffNode) { 311 pendingLabelUpdates.add(diffNode); 312 } 313 314 318 private void propagateProblemMarkers(ISynchronizeModelElement element) { 319 IResource resource = element.getResource(); 320 if (resource != null) { 321 String property = provider.calculateProblemMarker(element); 322 boolean recalculateParentDecorations = hadProblemProperty(element, property); 324 if (recalculateParentDecorations) { 325 ISynchronizeModelElement parent = (ISynchronizeModelElement) element.getParent(); 326 if (parent != null) { 327 propagateProblemMarkers(parent); 328 } 329 } 330 } 331 } 332 333 private boolean hadProblemProperty(ISynchronizeModelElement element, String property) { 340 boolean hadError = element.getProperty(ISynchronizeModelElement.PROPAGATED_ERROR_MARKER_PROPERTY); 341 boolean hadWarning = element.getProperty(ISynchronizeModelElement.PROPAGATED_WARNING_MARKER_PROPERTY); 342 343 IResource resource = element.getResource(); 345 if(resource != null && resource.isPhantom()) { 346 return true; 347 } 348 349 if(hadError) { 350 if(! (property == ISynchronizeModelElement.PROPAGATED_ERROR_MARKER_PROPERTY)) { 351 element.setPropertyToRoot(ISynchronizeModelElement.PROPAGATED_ERROR_MARKER_PROPERTY, false); 352 if(property != null) { 353 element.setPropertyToRoot(property, true); 355 } 356 return true; 359 } 360 return false; 361 } else if(hadWarning) { 362 if(! (property == ISynchronizeModelElement.PROPAGATED_WARNING_MARKER_PROPERTY)) { 363 element.setPropertyToRoot(ISynchronizeModelElement.PROPAGATED_WARNING_MARKER_PROPERTY, false); 364 if(property != null) { 365 element.setPropertyToRoot(property, true); 367 return false; 368 } 369 return true; 371 } 372 return false; 373 } else { 374 if(property == ISynchronizeModelElement.PROPAGATED_ERROR_MARKER_PROPERTY) { 375 element.setPropertyToRoot(property, true); 377 return false; 378 } else if(property == ISynchronizeModelElement.PROPAGATED_WARNING_MARKER_PROPERTY) { 379 element.setPropertyToRoot(property, true); 381 return true; 382 } 383 return false; 384 } 385 } 386 387 390 private void reset() { 391 queueEvent(new ResourceEvent(ROOT, RESET, IResource.DEPTH_INFINITE), false); 392 } 393 394 public void dispose() { 395 shutdown(); 396 ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); 397 provider.getSyncInfoSet().removeSyncSetChangedListener(this); 398 } 399 400 403 protected long getShortDispatchDelay() { 404 if (dispatchEarly) { 405 dispatchEarly = false; 406 return EARLY_DISPATCH_INCREMENT; 407 } 408 return super.getShortDispatchDelay(); 409 } 410 411 419 public void nodeAdded(ISynchronizeModelElement element, AbstractSynchronizeModelProvider provider) { 420 element.addPropertyChangeListener(listener); 421 this.provider.nodeAdded(element, provider); 422 if (DEBUG) { 423 System.out.println("Node added: " + getDebugDisplayLabel(element) + " -> " + getDebugDisplayLabel((ISynchronizeModelElement)element.getParent()) + " : " + getDebugDisplayLabel(provider)); } 425 } 426 427 436 public void nodeRemoved(ISynchronizeModelElement element, AbstractSynchronizeModelProvider provider) { 437 element.removePropertyChangeListener(listener); 438 this.provider.nodeRemoved(element, provider); 439 if (DEBUG) { 440 System.out.println("Node removed: " + getDebugDisplayLabel(element) + " -> " + getDebugDisplayLabel((ISynchronizeModelElement)element.getParent()) + " : " + getDebugDisplayLabel(provider)); } 442 } 443 444 450 public void modelObjectCleared(ISynchronizeModelElement node) { 451 node.removePropertyChangeListener(listener); 452 this.provider.modelObjectCleared(node); 453 if (DEBUG) { 454 System.out.println("Node cleared: " + getDebugDisplayLabel(node)); } 456 } 457 458 private String getDebugDisplayLabel(ISynchronizeModelElement node) { 459 if (node == null) { 460 return "ROOT"; } 462 if (node.getResource() != null) { 463 return node.getResource().getFullPath().toString(); 464 } 465 return node.getName(); 466 } 467 468 private String getDebugDisplayLabel(AbstractSynchronizeModelProvider provider2) { 469 return provider2.toString(); 470 } 471 472 475 public void syncInfoSetReset(SyncInfoSet set, IProgressMonitor monitor) { 476 if(provider.isDisposed()) { 477 set.removeSyncSetChangedListener(this); 478 } else { 479 reset(); 480 } 481 } 482 483 486 public void syncInfoChanged(final ISyncInfoSetChangeEvent event, IProgressMonitor monitor) { 487 if (! (event instanceof ISyncInfoTreeChangeEvent)) { 488 reset(); 489 } else { 490 queueEvent(new SyncInfoSetChangeEvent(event), false); 491 } 492 } 493 494 497 private void handleChanges(final ISyncInfoSetChangeEvent event, final IProgressMonitor monitor) { 498 runViewUpdate(new Runnable () { 499 public void run() { 500 provider.handleChanges((ISyncInfoTreeChangeEvent)event, monitor); 501 firePendingLabelUpdates(); 502 } 503 }, true ); 504 } 505 506 509 public void syncInfoSetErrors(SyncInfoSet set, ITeamStatus[] errors, IProgressMonitor monitor) { 510 } 514 515 public ISynchronizeModelProvider getProvider() { 516 return provider; 517 } 518 519 public void connect(IProgressMonitor monitor) { 520 getProvider().getSyncInfoSet().connect(this, monitor); 521 } 522 523 public void runViewUpdate(final Runnable runnable, final boolean preserveExpansion) { 524 if (Utils.canUpdateViewer(getViewer()) || isPerformingBackgroundUpdate()) { 525 internalRunViewUpdate(runnable, preserveExpansion); 526 } else { 527 if (Thread.currentThread() != getEventHandlerJob().getThread()) { 528 TeamUIPlugin.log(IStatus.WARNING, "View update invoked from invalid thread", new TeamException("View update invoked from invalid thread")); } 533 final Control ctrl = getViewer().getControl(); 534 if (ctrl != null && !ctrl.isDisposed()) { 535 ctrl.getDisplay().syncExec(new Runnable () { 536 public void run() { 537 if (!ctrl.isDisposed()) { 538 BusyIndicator.showWhile(ctrl.getDisplay(), new Runnable () { 539 public void run() { 540 internalRunViewUpdate(runnable, preserveExpansion); 541 } 542 }); 543 } 544 } 545 }); 546 } 547 } 548 } 549 550 554 public boolean isPerformingBackgroundUpdate() { 555 return Thread.currentThread() == getEventHandlerJob().getThread() && performingBackgroundUpdate; 556 } 557 558 561 private void internalRunViewUpdate(final Runnable runnable, boolean preserveExpansion) { 562 StructuredViewer viewer = getViewer(); 563 IResource[] expanded = null; 564 IResource[] selected = null; 565 try { 566 if (Utils.canUpdateViewer(viewer)) { 567 viewer.getControl().setRedraw(false); 568 if (preserveExpansion) { 569 expanded = provider.getExpandedResources(); 570 selected = provider.getSelectedResources(); 571 } 572 if (viewer instanceof AbstractTreeViewer && additionsMap == null) 573 additionsMap = new HashMap (); 574 } 575 runnable.run(); 576 } finally { 577 if (Utils.canUpdateViewer(viewer)) { 578 try { 579 if (additionsMap != null && !additionsMap.isEmpty() && Utils.canUpdateViewer(viewer)) { 580 for (Iterator iter = additionsMap.keySet().iterator(); iter.hasNext();) { 581 ISynchronizeModelElement parent = (ISynchronizeModelElement) iter.next(); 582 if (DEBUG) { 583 System.out.println("Adding child view items of " + parent.getName()); } 585 Set toAdd = (Set )additionsMap.get(parent); 586 ((AbstractTreeViewer)viewer).add(parent, toAdd.toArray(new Object [toAdd.size()])); 587 } 588 additionsMap = null; 589 } 590 if (expanded != null) { 591 provider.expandResources(expanded); 592 } 593 if (selected != null) { 594 provider.selectResources(selected); 595 } 596 } finally { 597 viewer.getControl().setRedraw(true); 598 } 599 } 600 } 601 602 ISynchronizeModelElement root = provider.getModelRoot(); 603 if(root instanceof SynchronizeModelElement) 604 ((SynchronizeModelElement)root).fireChanges(); 605 } 606 607 617 public void performUpdate(final IWorkspaceRunnable runnable, boolean preserveExpansion, boolean updateInUIThread) { 618 if (updateInUIThread) { 619 queueEvent(new BackgroundEventHandler.RunnableEvent(getUIUpdateRunnable(runnable, preserveExpansion), true), true); 620 } else { 621 queueEvent(new BackgroundEventHandler.RunnableEvent(getBackgroundUpdateRunnable(runnable, preserveExpansion), true), true); 622 } 623 } 624 625 628 private IWorkspaceRunnable getUIUpdateRunnable(final IWorkspaceRunnable runnable, final boolean preserveExpansion) { 629 return new IWorkspaceRunnable() { 630 public void run(final IProgressMonitor monitor) throws CoreException { 631 final CoreException[] exception = new CoreException[] { null }; 632 runViewUpdate(new Runnable () { 633 public void run() { 634 try { 635 runnable.run(monitor); 636 } catch (CoreException e) { 637 exception[0] = e; 638 } 639 } 640 }, true ); 641 if (exception[0] != null) 642 throw exception[0]; 643 } 644 }; 645 } 646 647 651 private IWorkspaceRunnable getBackgroundUpdateRunnable(final IWorkspaceRunnable runnable, final boolean preserveExpansion) { 652 return new IWorkspaceRunnable() { 653 IResource[] expanded; 654 IResource[] selected; 655 public void run(IProgressMonitor monitor) throws CoreException { 656 if (preserveExpansion) 657 recordExpandedResources(); 658 try { 659 performingBackgroundUpdate = true; 660 runnable.run(monitor); 661 } finally { 662 performingBackgroundUpdate = false; 663 } 664 updateView(); 665 666 } 667 private void recordExpandedResources() { 668 final StructuredViewer viewer = getViewer(); 669 if (viewer != null && !viewer.getControl().isDisposed() && viewer instanceof AbstractTreeViewer) { 670 viewer.getControl().getDisplay().syncExec(new Runnable () { 671 public void run() { 672 if (viewer != null && !viewer.getControl().isDisposed()) { 673 expanded = provider.getExpandedResources(); 674 selected = provider.getSelectedResources(); 675 } 676 } 677 }); 678 } 679 } 680 private void updateView() { 681 runViewUpdate(new Runnable () { 683 public void run() { 684 provider.getViewer().refresh(); 685 if (expanded != null) 686 provider.expandResources(expanded); 687 if (selected != null) 688 provider.selectResources(selected); 689 } 690 }, false ); 691 } 692 }; 693 } 694 695 698 private void executeRunnable(Event event, IProgressMonitor monitor) { 699 try { 700 dispatchEvents(Policy.subMonitorFor(monitor, 1)); 702 } catch (TeamException e) { 703 handleException(e); 704 } 705 try { 706 ((RunnableEvent)event).run(Policy.subMonitorFor(monitor, 1)); 707 } catch (CoreException e) { 708 handleException(e); 709 } 710 } 711 712 717 protected void doAdd(ISynchronizeModelElement parent, ISynchronizeModelElement element) { 718 if (additionsMap == null) { 719 if (DEBUG) { 720 System.out.println("Added view item " + element.getName()); } 722 AbstractTreeViewer viewer = (AbstractTreeViewer)getViewer(); 723 viewer.add(parent, element); 724 } else { 725 if (DEBUG) { 727 System.out.println("Queueing view item for addition " + element.getName()); } 729 Set toAdd = (Set )additionsMap.get(parent); 730 if (toAdd == null) { 731 toAdd = new HashSet (); 732 additionsMap.put(parent, toAdd); 733 } 734 toAdd.add(element); 735 } 736 } 737 } 738 | Popular Tags |