1 12 package org.eclipse.team.internal.ui.synchronize; 13 14 import java.util.ArrayList ; 15 import java.util.List ; 16 17 import org.eclipse.core.resources.ResourcesPlugin; 18 import org.eclipse.core.runtime.*; 19 import org.eclipse.core.runtime.jobs.*; 20 import org.eclipse.jface.action.IAction; 21 import org.eclipse.jface.dialogs.ErrorDialog; 22 import org.eclipse.jface.util.IPropertyChangeListener; 23 import org.eclipse.jface.util.PropertyChangeEvent; 24 import org.eclipse.osgi.util.NLS; 25 import org.eclipse.team.core.subscribers.Subscriber; 26 import org.eclipse.team.internal.ui.*; 27 import org.eclipse.team.ui.synchronize.*; 28 import org.eclipse.ui.actions.ActionFactory; 29 import org.eclipse.ui.progress.IProgressConstants; 30 import org.eclipse.ui.progress.UIJob; 31 32 45 public abstract class RefreshParticipantJob extends Job { 46 47 50 private final static Object FAMILY_ID = new Object (); 51 52 55 private boolean reschedule = false; 56 57 60 private boolean restartOnCancel = true; 61 62 65 private static long scheduleDelay; 66 67 70 private ISynchronizeParticipant participant; 71 72 76 private String taskName; 77 78 81 private static List listeners = new ArrayList (1); 82 private static final int STARTED = 1; 83 private static final int DONE = 2; 84 85 88 private static final ILock lock = Platform.getJobManager().newLock(); 89 90 93 private static final IStatus POSTPONED = new Status(IStatus.CANCEL, TeamUIPlugin.ID, 0, "Scheduled refresh postponed due to conflicting operation", null); 95 100 private final class GotoActionWrapper extends WorkbenchAction { 101 private ActionFactory.IWorkbenchAction gotoAction; 102 private IStatus status; 103 public void run() { 104 if (status != null && !status.isOK()) { 105 ErrorDialog.openError(Utils.getShell(null), null, TeamUIMessages.RefreshSubscriberJob_3, status); 106 } else if(gotoAction != null) { 107 gotoAction.run(); 108 } 109 } 110 public boolean isEnabled() { 111 if(gotoAction != null) { 112 return gotoAction.isEnabled(); 113 } 114 return true; 115 } 116 public String getText() { 117 if(gotoAction != null) { 118 return gotoAction.getText(); 119 } 120 return null; 121 } 122 public String getToolTipText() { 123 if (status != null && !status.isOK()) { 124 return status.getMessage(); 125 } 126 if(gotoAction != null) { 127 return gotoAction.getToolTipText(); 128 } 129 return Utils.shortenText(SynchronizeView.MAX_NAME_LENGTH, RefreshParticipantJob.this.getName()); 130 } 131 public void dispose() { 132 super.dispose(); 133 if(gotoAction != null) { 134 gotoAction.dispose(); 135 } 136 } 137 public void setGotoAction(ActionFactory.IWorkbenchAction gotoAction) { 138 this.gotoAction = gotoAction; 139 setEnabled(isEnabled()); 140 setToolTipText(getToolTipText()); 141 gotoAction.addPropertyChangeListener(new IPropertyChangeListener() { 142 public void propertyChange(PropertyChangeEvent event) { 143 if(event.getProperty().equals(IAction.ENABLED)) { 144 Boolean bool = (Boolean ) event.getNewValue(); 145 GotoActionWrapper.this.setEnabled(bool.booleanValue()); 146 } 147 } 148 }); 149 } 150 public void setStatus(IStatus status) { 151 this.status = status; 152 } 153 } 154 155 158 private abstract class Notification implements ISafeRunnable { 159 private IRefreshSubscriberListener listener; 160 public void handleException(Throwable exception) { 161 } 163 public void run(IRefreshSubscriberListener listener) { 164 this.listener = listener; 165 SafeRunner.run(this); 166 } 167 public void run() throws Exception { 168 notify(listener); 169 } 170 174 protected abstract void notify(IRefreshSubscriberListener listener); 175 } 176 177 181 private class NonblockingProgressMonitor extends ProgressMonitorWrapper { 182 private final RefreshParticipantJob job; 183 private long blockTime; 184 private static final int THRESHOLD = 250; 185 private boolean wasBlocking = false; 186 protected NonblockingProgressMonitor(IProgressMonitor monitor, RefreshParticipantJob job) { 187 super(monitor); 188 this.job = job; 189 } 190 public boolean isCanceled() { 191 if (super.isCanceled()) { 192 return true; 193 } 194 if (job.shouldReschedule() && job.isBlocking()) { 195 if (blockTime == 0) { 196 blockTime = System.currentTimeMillis(); 197 } else if (System.currentTimeMillis() - blockTime > THRESHOLD) { 198 wasBlocking = true; 200 return true; 201 } 202 } else { 203 blockTime = 0; 204 } 205 wasBlocking = false; 206 return false; 207 } 208 public boolean wasBlocking() { 209 return wasBlocking; 210 } 211 } 212 213 public static interface IChangeDescription { 214 int getChangeCount(); 215 } 216 217 225 public RefreshParticipantJob(ISynchronizeParticipant participant, String jobName, String taskName, IRefreshSubscriberListener listener) { 226 super(jobName); 227 Assert.isNotNull(participant); 228 this.participant = participant; 229 this.taskName = taskName; 230 setPriority(Job.DECORATE); 231 setRefreshInterval(3600 ); 232 233 addJobChangeListener(new JobChangeAdapter() { 235 public void done(IJobChangeEvent event) { 236 if(shouldReschedule()) { 237 IStatus result = event.getResult(); 238 if(result.getSeverity() == IStatus.CANCEL && ! restartOnCancel) { 239 return; 240 } 241 long delay = scheduleDelay; 242 if (result == POSTPONED) { 243 delay = 5000; 245 } 246 RefreshParticipantJob.this.schedule(delay); 247 restartOnCancel = true; 248 } 249 } 250 }); 251 if(listener != null) 252 initialize(listener); 253 } 254 255 public boolean belongsTo(Object family) { 256 if (family instanceof SubscriberParticipant) { 257 return family == participant; 258 } else { 259 return (family == getFamily() || family == ISynchronizeManager.FAMILY_SYNCHRONIZE_OPERATION); 260 } 261 } 262 263 public static Object getFamily() { 264 return FAMILY_ID; 265 } 266 267 271 public IStatus run(IProgressMonitor monitor) { 272 if (shouldReschedule() && 275 (isJobInFamilyRunning(ResourcesPlugin.FAMILY_AUTO_BUILD) 276 || isJobInFamilyRunning(ResourcesPlugin.FAMILY_MANUAL_BUILD))) { 277 return POSTPONED; 278 } 279 boolean acquired = false; 285 try { 286 while (!acquired) { 287 try { 288 acquired = lock.acquire(1000); 289 } catch (InterruptedException e1) { 290 acquired = false; 291 } 292 Policy.checkCanceled(monitor); 293 } 294 295 IChangeDescription changeDescription = createChangeDescription(); 296 RefreshEvent event = new RefreshEvent(reschedule ? IRefreshEvent.SCHEDULED_REFRESH : IRefreshEvent.USER_REFRESH, participant, changeDescription); 297 IStatus status = null; 298 NonblockingProgressMonitor wrappedMonitor = null; 299 try { 300 event.setStartTime(System.currentTimeMillis()); 301 if(monitor.isCanceled()) { 302 return Status.CANCEL_STATUS; 303 } 304 notifyListeners(STARTED, event); 306 monitor.setTaskName(getName()); 308 wrappedMonitor = new NonblockingProgressMonitor(monitor, this); 309 doRefresh(changeDescription, wrappedMonitor); 310 setProperty(IProgressConstants.KEEPONE_PROPERTY, Boolean.valueOf(! isJobModal())); 312 } catch(OperationCanceledException e2) { 313 if (monitor.isCanceled()) { 314 status = Status.CANCEL_STATUS; 316 } else { 317 if (wrappedMonitor != null && wrappedMonitor.wasBlocking()) { 319 status = POSTPONED; 320 } else { 321 status = Status.CANCEL_STATUS; 322 } 323 } 324 } catch(CoreException e) { 325 status = e.getStatus(); 327 if (!isUser()) { 328 Object prop = getProperty(IProgressConstants.ACTION_PROPERTY); 330 if (prop instanceof GotoActionWrapper) { 331 GotoActionWrapper wrapper = (GotoActionWrapper)prop; 332 wrapper.setStatus(e.getStatus()); 333 status = new Status(IStatus.OK, TeamUIPlugin.ID, IStatus.OK, e.getStatus().getMessage(), e); 334 } 335 } 336 if (!isUser() && status.getSeverity() == IStatus.ERROR) { 337 setProperty(IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY, Boolean.TRUE); 339 } 340 } finally { 341 event.setStopTime(System.currentTimeMillis()); 342 } 343 344 if (status == null) { 346 status = calculateStatus(event); 347 } 348 event.setStatus(status); 349 notifyListeners(DONE, event); 350 if (event.getChangeDescription().getChangeCount() > 0) { 351 if (participant instanceof AbstractSynchronizeParticipant) { 352 AbstractSynchronizeParticipant asp = (AbstractSynchronizeParticipant) participant; 353 asp.firePropertyChange(participant, ISynchronizeParticipant.P_CONTENT, null, event.getChangeDescription()); 354 } 355 } 356 return event.getStatus(); 357 } finally { 358 if (acquired) lock.release(); 359 monitor.done(); 360 } 361 } 362 363 protected abstract void doRefresh(IChangeDescription changeListener, IProgressMonitor monitor) throws CoreException; 364 365 371 protected abstract int getChangeCount(); 372 373 protected abstract int getIncomingChangeCount(); 374 protected abstract int getOutgoingChangeCount(); 375 376 private boolean isJobInFamilyRunning(Object family) { 377 Job[] jobs = Platform.getJobManager().find(family); 378 if (jobs != null && jobs.length > 0) { 379 for (int i = 0; i < jobs.length; i++) { 380 Job job = jobs[i]; 381 if (job.getState() != Job.NONE) { 382 return true; 383 } 384 } 385 } 386 return false; 387 } 388 389 private IStatus calculateStatus(IRefreshEvent event) { 390 StringBuffer text = new StringBuffer (); 391 int code = IStatus.OK; 392 int changeCount = event.getChangeDescription().getChangeCount(); 393 int numChanges = getChangeCount(); 394 if (numChanges > 0) { 395 code = IRefreshEvent.STATUS_CHANGES; 396 397 int incomingChanges = getIncomingChangeCount(); 398 String numIncomingChanges = incomingChanges==0 ? "" : NLS.bind(TeamUIMessages.RefreshCompleteDialog_incomingChanges, Integer.toString(incomingChanges)); 400 401 int outgoingChanges = getOutgoingChangeCount(); 402 String numOutgoingChanges = outgoingChanges==0 ? "" : NLS.bind(TeamUIMessages.RefreshCompleteDialog_outgoingChanges, Integer.toString(outgoingChanges)); 404 405 String sep = incomingChanges>0 && outgoingChanges>0 ? "; " : ""; 407 if (changeCount > 0) { 408 code = IRefreshEvent.STATUS_NEW_CHANGES; 410 String numNewChanges = Integer.toString(changeCount); 411 if (changeCount == 1) { 412 text.append(NLS.bind(TeamUIMessages.RefreshCompleteDialog_newChangesSingular, (new Object []{getName(), numNewChanges, numIncomingChanges, sep, numOutgoingChanges}))); 413 } else { 414 text.append(NLS.bind(TeamUIMessages.RefreshCompleteDialog_newChangesPlural, (new Object []{getName(), numNewChanges, numIncomingChanges, sep, numOutgoingChanges}))); 415 } 416 } else { 417 if (numChanges == 1) { 419 text.append(NLS.bind(TeamUIMessages.RefreshCompleteDialog_changesSingular, (new Object []{getName(), new Integer (numChanges), numIncomingChanges, sep, numOutgoingChanges}))); 420 } else { 421 text.append(NLS.bind(TeamUIMessages.RefreshCompleteDialog_changesPlural, (new Object []{getName(), new Integer (numChanges), numIncomingChanges, sep, numOutgoingChanges}))); 422 } 423 } 424 } else { 425 code = IRefreshEvent.STATUS_NO_CHANGES; 427 text.append(NLS.bind(TeamUIMessages.RefreshCompleteDialog_6, new String [] { getName() })); 428 } 429 return new Status(IStatus.OK, TeamUIPlugin.ID, code, text.toString(), null); 430 } 431 432 private void initialize(final IRefreshSubscriberListener listener) { 433 final GotoActionWrapper actionWrapper = new GotoActionWrapper(); 434 435 IProgressMonitor group = Platform.getJobManager().createProgressGroup(); 436 group.beginTask(taskName, 100); 437 setProgressGroup(group, 80); 438 handleProgressGroupSet(group, 20); 439 setProperty(IProgressConstants.ICON_PROPERTY, participant.getImageDescriptor()); 440 setProperty(IProgressConstants.ACTION_PROPERTY, actionWrapper); 441 setProperty(IProgressConstants.KEEPONE_PROPERTY, Boolean.valueOf(! isJobModal())); 442 IRefreshSubscriberListener autoListener = new IRefreshSubscriberListener() { 444 public void refreshStarted(IRefreshEvent event) { 445 if(listener != null) { 446 listener.refreshStarted(event); 447 } 448 } 449 public ActionFactory.IWorkbenchAction refreshDone(IRefreshEvent event) { 450 if(listener != null) { 451 boolean isModal = isJobModal(); 452 event.setIsLink(!isModal); 453 final ActionFactory.IWorkbenchAction runnable = listener.refreshDone(event); 454 if(runnable != null) { 455 if(isModal) { 457 if(runnable != null) { 458 Job update = new UIJob("") { public IStatus runInUIThread(IProgressMonitor monitor) { 460 runnable.run(); 461 return Status.OK_STATUS; 462 } 463 }; 464 update.setSystem(true); 465 update.schedule(); 466 } 467 } else { 468 actionWrapper.setGotoAction(runnable); 471 } 472 } 473 RefreshParticipantJob.removeRefreshListener(this); 474 } 475 return null; 476 } 477 }; 478 479 if (listener != null) { 480 RefreshParticipantJob.addRefreshListener(autoListener); 481 } 482 } 483 484 491 protected abstract void handleProgressGroupSet(IProgressMonitor group, int ticks); 492 493 protected abstract IChangeDescription createChangeDescription(); 494 495 public long getScheduleDelay() { 496 return scheduleDelay; 497 } 498 499 protected void start() { 500 if(getState() == Job.NONE) { 501 if(shouldReschedule()) { 502 schedule(getScheduleDelay()); 503 } 504 } 505 } 506 507 511 public void setRefreshInterval(long seconds) { 512 boolean restart = false; 513 if(getState() == Job.SLEEPING) { 514 restart = true; 515 cancel(); 516 } 517 scheduleDelay = seconds * 1000; 518 if(restart) { 519 start(); 520 } 521 } 522 523 public void setRestartOnCancel(boolean restartOnCancel) { 524 this.restartOnCancel = restartOnCancel; 525 } 526 527 public void setReschedule(boolean reschedule) { 528 this.reschedule = reschedule; 529 } 530 531 public boolean shouldReschedule() { 532 return reschedule; 533 } 534 535 public static void addRefreshListener(IRefreshSubscriberListener listener) { 536 synchronized(listeners) { 537 if(! listeners.contains(listener)) { 538 listeners.add(listener); 539 } 540 } 541 } 542 543 public static void removeRefreshListener(IRefreshSubscriberListener listener) { 544 synchronized(listeners) { 545 listeners.remove(listener); 546 } 547 } 548 549 protected void notifyListeners(final int state, final IRefreshEvent event) { 550 IRefreshSubscriberListener[] listenerArray; 552 synchronized (listeners) { 553 listenerArray = (IRefreshSubscriberListener[]) listeners.toArray(new IRefreshSubscriberListener[listeners.size()]); 554 } 555 for (int i = 0; i < listenerArray.length; i++) { 557 IRefreshSubscriberListener listener = listenerArray[i]; 558 Notification notification = new Notification() { 559 protected void notify(IRefreshSubscriberListener listener) { 560 switch (state) { 561 case STARTED: 562 listener.refreshStarted(event); 563 break; 564 case DONE: 565 listener.refreshDone(event); 566 break; 567 default: 568 break; 569 } 570 } 571 }; 572 notification.run(listener); 573 } 574 } 575 576 private boolean isJobModal() { 577 Boolean isModal = (Boolean )getProperty(IProgressConstants.PROPERTY_IN_DIALOG); 578 if(isModal == null) return false; 579 return isModal.booleanValue(); 580 } 581 582 public ISynchronizeParticipant getParticipant() { 583 return participant; 584 } 585 } 586 | Popular Tags |