diff options
author | Michael Valenta | 2003-09-16 13:10:45 +0000 |
---|---|---|
committer | Michael Valenta | 2003-09-16 13:10:45 +0000 |
commit | c112994846e89ae0a77e3a94799327ecad16e7eb (patch) | |
tree | 68a059c4a30a16327a73709a3affa96375c86095 | |
parent | c717812035c986bf4cdb03b7033f3082be55178d (diff) | |
download | eclipse.platform.team-c112994846e89ae0a77e3a94799327ecad16e7eb.tar.gz eclipse.platform.team-c112994846e89ae0a77e3a94799327ecad16e7eb.tar.xz eclipse.platform.team-c112994846e89ae0a77e3a94799327ecad16e7eb.zip |
Busy indicator shown in sync view while relevant jobs are runningRoot_branch_20030916_CachingFileContentsForCompareEditors
11 files changed, 336 insertions, 93 deletions
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/CVSNonblockingRunnableContext.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/CVSNonblockingRunnableContext.java index 6e3454e53..dc8ee0e79 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/CVSNonblockingRunnableContext.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/CVSNonblockingRunnableContext.java @@ -85,6 +85,10 @@ public class CVSNonblockingRunnableContext implements ICVSRunnableContext { if (listener != null) { job.addJobChangeListener(listener); } + schedule(job); + } + + protected void schedule(Job job) { job.schedule(); } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/CVSSubscriberNonblockingContext.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/CVSSubscriberNonblockingContext.java new file mode 100644 index 000000000..0a4edd55f --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/CVSSubscriberNonblockingContext.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.internal.ccvs.ui.operations; + +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.team.ui.sync.SubscriberAction; + +/** + * This context uses the JobStatusHandler from SubscriberAction to ensure + * proper busy indication in the sync view. + */ +public class CVSSubscriberNonblockingContext extends CVSNonblockingRunnableContext { + + /* (non-Javadoc) + * @see org.eclipse.team.internal.ccvs.ui.operations.CVSNonblockingRunnableContext#schedule(org.eclipse.core.runtime.jobs.Job) + */ + protected void schedule(Job job) { + SubscriberAction.getJobStatusHandler().schedule(job); + } + +} diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSSubscriberAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSSubscriberAction.java index 08a552f9a..c962b4fd8 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSSubscriberAction.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSSubscriberAction.java @@ -38,7 +38,7 @@ import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; import org.eclipse.team.internal.ccvs.ui.ICVSUIConstants; import org.eclipse.team.internal.ccvs.ui.Policy; import org.eclipse.team.internal.ccvs.ui.operations.CVSBlockingRunnableContext; -import org.eclipse.team.internal.ccvs.ui.operations.CVSNonblockingRunnableContext; +import org.eclipse.team.internal.ccvs.ui.operations.CVSSubscriberNonblockingContext; import org.eclipse.team.internal.ccvs.ui.operations.ICVSRunnableContext; import org.eclipse.team.ui.sync.SubscriberAction; import org.eclipse.team.ui.sync.SyncInfoSet; @@ -168,7 +168,7 @@ public abstract class CVSSubscriberAction extends SubscriberAction { */ private ICVSRunnableContext getCVSRunnableContext() { if (canRunAsJob() && areJobsEnabled()) { - return new CVSNonblockingRunnableContext(); + return new CVSSubscriberNonblockingContext(); } else { return new CVSBlockingRunnableContext(shell); } diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/TeamUIPlugin.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/TeamUIPlugin.java index 1ff8f2e97..c1ff81da9 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/TeamUIPlugin.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/TeamUIPlugin.java @@ -35,6 +35,7 @@ import org.eclipse.team.internal.ui.jobs.RefreshSubscriberJob; import org.eclipse.team.internal.ui.sync.actions.SyncViewerDirectionFilters; import org.eclipse.team.internal.ui.sync.views.SyncViewerTableSorter; import org.eclipse.team.ui.ISharedImages; +import org.eclipse.team.ui.sync.SubscriberAction; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.plugin.AbstractUIPlugin; @@ -196,7 +197,7 @@ public class TeamUIPlugin extends AbstractUIPlugin implements IPropertyChangeLis refreshJob.setRestartOnCancel(true); refreshJob.setReschedule(true); // start once the platform has started and stabilized - refreshJob.schedule(20000 /* 20 seconds */); + SubscriberAction.getJobStatusHandler().schedule(refreshJob, 20000 /* 20 seconds */); } } diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/jobs/IJobListener.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/jobs/IJobListener.java new file mode 100644 index 000000000..e09cf6d52 --- /dev/null +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/jobs/IJobListener.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.internal.ui.jobs; + +import org.eclipse.core.runtime.QualifiedName; + +/** + * This interface allows interested parties to receive notification + * when work has started or stopped for a given job type. The <code>started</code> + * method is invoked when the first job is started for the given <code>jobType</code>. + * The <code>finish</code> method is called when the last job of a given type stops. + * Several jobs for the job type may start and stop in the interum without causing + * notification to the listener. + */ +public interface IJobListener { + public void started(QualifiedName jobType); + public void finished(QualifiedName jobType); +} diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/jobs/JobStatusHandler.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/jobs/JobStatusHandler.java new file mode 100644 index 000000000..7d05049ff --- /dev/null +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/jobs/JobStatusHandler.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.internal.ui.jobs; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.core.runtime.QualifiedName; +import org.eclipse.core.runtime.jobs.IJobChangeEvent; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.core.runtime.jobs.JobChangeAdapter; + +/** + * This class is reponsible for notifying listeners when jobs registered + * with the handler start and stop. Start is invoked when the first registered job starts + * anf finish is invoked when the last registered job finishes. + */ +public class JobStatusHandler { + + private QualifiedName jobType; + private Set jobs = new HashSet(); + private List listeners = new ArrayList(); + + public JobStatusHandler(QualifiedName jobType) { + super(); + this.jobType = jobType; + } + + public void schedule(Job job) { + job.addJobChangeListener(getJobChangeListener()); + // indicate that the job has started since it will be schdulued immediatley + jobStarted(job); + job.schedule(); + } + + public void schedule(Job job, long delay) { + job.addJobChangeListener(getJobChangeListener()); + job.schedule(delay); + } + + private JobChangeAdapter getJobChangeListener() { + return new JobChangeAdapter() { + public void done(IJobChangeEvent event) { + jobDone(event.getJob()); + + } + public void running(IJobChangeEvent event) { + jobStarted(event.getJob()); + } + }; + } + + public void addJobListener(IJobListener listener) { + synchronized (listeners) { + listeners.add(listener); + } + } + public void removeJobListener(IJobListener listener) { + synchronized (listeners) { + listeners.remove(listener); + } + } + + private IJobListener[] getJobListeners() { + synchronized (listeners) { + return (IJobListener[]) listeners.toArray(new IJobListener[listeners.size()]); + } + } + + /* internal use only */ void jobStarted(Job job) { + if (recordJob(job)) { + fireStartNotification(); + } + } + + /* + * Record the job and return true if it's the first job of that type + */ + private boolean recordJob(Job job) { + if (!jobs.add(job)) { + // The job was already in the set. + return false; + } + return jobs.size() == 1; + } + + /* + * Remove the job and return true if it is the last job for the type + */ + private boolean removeJob(Job job) { + if (!jobs.remove(job)) { + // The job wasn't in the list. + return false; + } + return jobs.isEmpty(); + } + + private void fireStartNotification() { + IJobListener[] listenerArray = getJobListeners(); + for (int i = 0; i < listenerArray.length; i++) { + IJobListener listener = listenerArray[i]; + listener.started(jobType); + } + } + + /* internal use only */ void jobDone(Job job) { + if (removeJob(job)) { + fireEndNotification(); + } + } + + private void fireEndNotification() { + IJobListener[] listenerArray = getJobListeners(); + for (int i = 0; i < listenerArray.length; i++) { + IJobListener listener = listenerArray[i]; + listener.finished(jobType); + } + } + + public boolean hasRunningJobs() { + return !jobs.isEmpty(); + } + +} diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/messages.properties b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/messages.properties index 3be354f96..247c88e92 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/messages.properties +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/messages.properties @@ -100,7 +100,7 @@ LiveSyncView.titleTooltip=Working Set: {0} LiveSyncView.title=Synchronize LiveSyncView.titleSubscriber=Synchronize - {0} -SubscriberEventHandler.jobName=Updating synchronization state +SubscriberEventHandler.jobName=Updating synchronization states in the Synchronize view. SubscriberEventHandler.errors=Errors have occured while calculating the synchronization state. The Synchronize View may be out-of-date. Refresh the view or fix the errors and re-run the Synchronize command. SyncInfoCompareInput.localLabel=Local File @@ -431,3 +431,4 @@ CopyAction.errorMessage=There was a problem when accessing the system clipboard. PasteAction.title=&Paste PasteAction.toolTip=Paste RefactorActionGroup.0=Edi&t +SubscriberEventHandler.2=Calculating state for {0}. diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/sync/actions/RefreshAction.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/sync/actions/RefreshAction.java index 34cf4c6c2..0bcf17985 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/sync/actions/RefreshAction.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/sync/actions/RefreshAction.java @@ -28,6 +28,7 @@ import org.eclipse.team.internal.ui.actions.TeamAction; import org.eclipse.team.internal.ui.jobs.RefreshSubscriberJob; import org.eclipse.team.internal.ui.sync.sets.SubscriberInput; import org.eclipse.team.internal.ui.sync.views.SynchronizeView; +import org.eclipse.team.ui.sync.SubscriberAction; import org.eclipse.ui.actions.ActionContext; public class RefreshAction extends Action { @@ -68,7 +69,7 @@ public class RefreshAction extends Action { Platform.getJobManager().cancel(RefreshSubscriberJob.getFamily()); if(TeamUIPlugin.getPlugin().getPreferenceStore().getBoolean(IPreferenceIds.SYNCVIEW_BACKGROUND_SYNC)) { RefreshSubscriberJob job = new RefreshSubscriberJob(Policy.bind("SyncViewRefresh.taskName", new Integer(resources.length).toString(), subscriber.getName()), resources, subscriber); //$NON-NLS-1$ - job.schedule(); + SubscriberAction.getJobStatusHandler().schedule(job); } else { runBlocking(viewer, subscriber, resources); } diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/sync/sets/SubscriberEventHandler.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/sync/sets/SubscriberEventHandler.java index 91b932f03..a4d84e81c 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/sync/sets/SubscriberEventHandler.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/sync/sets/SubscriberEventHandler.java @@ -25,6 +25,7 @@ import org.eclipse.team.core.subscribers.SyncInfo; import org.eclipse.team.internal.core.ExceptionCollector; import org.eclipse.team.internal.ui.Policy; import org.eclipse.team.internal.ui.TeamUIPlugin; +import org.eclipse.team.ui.sync.SubscriberAction; /** * This handler collects changes and removals to resources and calculates their @@ -117,7 +118,7 @@ public class SubscriberEventHandler { * Schedule the job or process the events now. */ public void schedule() { - eventHandlerJob.schedule(); + SubscriberAction.getJobStatusHandler().schedule(eventHandlerJob); } /** * Initialize all resources for the subscriber associated with the set. This will basically recalculate @@ -202,7 +203,6 @@ public class SubscriberEventHandler { } }); eventHandlerJob.setPriority(Job.SHORT); - eventHandlerJob.setSystem(true); } /** @@ -213,7 +213,12 @@ public class SubscriberEventHandler { Event event; errors.clear(); try { - monitor.beginTask(null, 100); //$NON-NLS-1$ + // It's hard to know how much work is going to happen + // since the queue can grow. Use the current queue size as a hint to + // an infinite progress monitor + monitor.beginTask(null, 100); + IProgressMonitor subMonitor = Policy.subInfiniteMonitorFor(monitor, 90); + subMonitor.beginTask(null, 1024); while ((event = nextElement()) != null) { // Cancellation is dangerous because this will leave the sync info in a bad state. @@ -229,16 +234,17 @@ public class SubscriberEventHandler { collect( event.getResource(), event.getDepth(), - monitor, + subMonitor, results); resultCache.addAll(results); break; case Event.INITIALIZE : + monitor.subTask(Policy.bind("SubscriberEventHandler.2", event.getResource().getFullPath().toString())); //$NON-NLS-1$ Event[] events = getAllOutOfSync( new IResource[] { event.getResource()}, event.getDepth(), - monitor); + Policy.subMonitorFor(subMonitor, 64)); resultCache.addAll(Arrays.asList(events)); break; } @@ -270,7 +276,7 @@ public class SubscriberEventHandler { IProgressMonitor monitor, List results) throws TeamException { - + if (resource.getType() != IResource.FILE && depth != IResource.DEPTH_ZERO) { IResource[] members = @@ -286,6 +292,7 @@ public class SubscriberEventHandler { } } + monitor.subTask(Policy.bind("SubscriberEventHandler.2", resource.getFullPath().toString())); //$NON-NLS-1$ SyncInfo info = set.getSubscriber().getSyncInfo(resource, monitor); // resource is no longer under the subscriber control if (info == null) { @@ -295,6 +302,7 @@ public class SubscriberEventHandler { results.add( new Event(resource, Event.CHANGE, IResource.DEPTH_ZERO, info)); } + monitor.worked(1); } /** * Called to initialize to calculate the synchronization information using the optimized subscriber method. For @@ -310,30 +318,38 @@ public class SubscriberEventHandler { int depth, IProgressMonitor monitor) throws TeamException { - SyncInfo[] infos = - set.getSubscriber().getAllOutOfSync(resources, depth, monitor); - - // The subscriber hasn't cached out-of-sync resources. We will have to - // traverse all resources and calculate their state. - if (infos == null) { - List events = new ArrayList(); - for (int i = 0; i < resources.length; i++) { - collect( - resources[i], - IResource.DEPTH_INFINITE, - monitor, - events); - } - return (Event[]) events.toArray(new Event[events.size()]); - // The subscriber has returned the list of out-of-sync resources. - } else { - Event[] events = new Event[infos.length]; - for (int i = 0; i < infos.length; i++) { - SyncInfo info = infos[i]; - events[i] = - new Event(info.getLocal(), Event.CHANGE, depth, info); + + monitor.beginTask(null, 100); + try { + SyncInfo[] infos = + set.getSubscriber().getAllOutOfSync(resources, depth, Policy.subMonitorFor(monitor, 50)); + + // The subscriber hasn't cached out-of-sync resources. We will have to + // traverse all resources and calculate their state. + if (infos == null) { + List events = new ArrayList(); + IProgressMonitor subMonitor = Policy.subInfiniteMonitorFor(monitor, 50); + subMonitor.beginTask(null, resources.length); + for (int i = 0; i < resources.length; i++) { + collect( + resources[i], + IResource.DEPTH_INFINITE, + subMonitor, + events); + } + return (Event[]) events.toArray(new Event[events.size()]); + // The subscriber has returned the list of out-of-sync resources. + } else { + Event[] events = new Event[infos.length]; + for (int i = 0; i < infos.length; i++) { + SyncInfo info = infos[i]; + events[i] = + new Event(info.getLocal(), Event.CHANGE, depth, info); + } + return events; } - return events; + } finally { + monitor.done(); } } diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/sync/views/SynchronizeView.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/sync/views/SynchronizeView.java index 4f2c39eec..790f8a410 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/sync/views/SynchronizeView.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/sync/views/SynchronizeView.java @@ -17,11 +17,8 @@ import java.util.Map; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.QualifiedName; -import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; @@ -41,11 +38,12 @@ import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.TableLayout; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; @@ -66,18 +64,18 @@ import org.eclipse.team.internal.ui.Policy; import org.eclipse.team.internal.ui.TeamUIPlugin; import org.eclipse.team.internal.ui.Utils; import org.eclipse.team.internal.ui.actions.TeamAction; +import org.eclipse.team.internal.ui.jobs.IJobListener; import org.eclipse.team.internal.ui.jobs.RefreshSubscriberInputJob; -import org.eclipse.team.internal.ui.jobs.RefreshSubscriberJob; import org.eclipse.team.internal.ui.sync.actions.OpenInCompareAction; import org.eclipse.team.internal.ui.sync.actions.RefreshAction; import org.eclipse.team.internal.ui.sync.actions.SyncViewerActions; import org.eclipse.team.internal.ui.sync.sets.ISyncSetChangedListener; import org.eclipse.team.internal.ui.sync.sets.SubscriberInput; import org.eclipse.team.internal.ui.sync.sets.SyncSetChangedEvent; -import org.eclipse.team.ui.ISharedImages; import org.eclipse.team.ui.sync.AndSyncInfoFilter; import org.eclipse.team.ui.sync.ISynchronizeView; import org.eclipse.team.ui.sync.PseudoConflictFilter; +import org.eclipse.team.ui.sync.SubscriberAction; import org.eclipse.team.ui.sync.SyncInfoChangeTypeFilter; import org.eclipse.team.ui.sync.SyncInfoDirectionFilter; import org.eclipse.team.ui.sync.SyncInfoFilter; @@ -86,7 +84,6 @@ import org.eclipse.ui.IMemento; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkingSet; import org.eclipse.ui.PartInitException; @@ -131,10 +128,31 @@ public class SynchronizeView extends ViewPart implements ITeamResourceChangeList // be reset when the input changes. private SyncViewerActions actions; - // View images, registered with the plugin and disposed on shutdown. - private Image refreshingImg; - private Image initialImg; - private Image viewImage; + // Cursor used to indicate that work that affects the view is happening + private Cursor waitCursor; + + /* + * Listener to indicate when work is happening that affects the view. + * The methods are synchronized to allow the registration of the listener + * to properly set the cursor. + */ + private IJobListener jobListener = new IJobListener() { + public synchronized void started(QualifiedName jobType) { + Display.getDefault().asyncExec(new Runnable() { + public void run() { + showBusyCursor(); + } + }); + } + + public synchronized void finished(QualifiedName jobType) { + Display.getDefault().asyncExec(new Runnable() { + public void run() { + showNormalCursor(); + } + }); + } + }; /** * Constructs a new SynchronizeView. @@ -145,13 +163,7 @@ public class SynchronizeView extends ViewPart implements ITeamResourceChangeList currentViewType = TABLE_VIEW; } } - /*(non-Javadoc) - * Overriden to return a title image to show that a background refresh is being run. - * @see org.eclipse.ui.IWorkbenchPart#getTitleImage() - */ - public Image getTitleImage() { - return viewImage; - } + /* (non-Javadoc) * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite) */ @@ -161,7 +173,14 @@ public class SynchronizeView extends ViewPart implements ITeamResourceChangeList gridLayout.marginWidth= 0; gridLayout.marginHeight = 0; parent.setLayout(gridLayout); - + + // Create the cursor which indicates work is happening in the background + Display display = Display.getCurrent(); + if (display == null) { + display = Display.getDefault(); + } + waitCursor = new Cursor(display, SWT.CURSOR_APPSTARTING); + createViewer(parent); this.composite = parent; @@ -176,17 +195,9 @@ public class SynchronizeView extends ViewPart implements ITeamResourceChangeList addSubscriber(subscriber); } - // initialize images - initialImg = TeamUIPlugin.getImageDescriptor(ISharedImages.IMG_SYNC_VIEW).createImage(); - refreshingImg = TeamUIPlugin.getImageDescriptor(ISharedImages.IMG_SYNC_MODE_CATCHUP).createImage(); - TeamUIPlugin.disposeOnShutdown(initialImg); - TeamUIPlugin.disposeOnShutdown(refreshingImg); - setViewImage(initialImg); - updateStatusPanel(); updateTooltip(); - initializeJobListener(); actions.setContext(null); } /* (non-Javadoc) @@ -264,28 +275,7 @@ public class SynchronizeView extends ViewPart implements ITeamResourceChangeList updateStatusPanel(); } } - /** - * Listen to background refresh jobs to update the title image. Although - * the progres view is available, this gives the user direct feedback that the - * refresh is underway. - * Note: This may not be a good UI practice. - */ - protected void initializeJobListener() { - // add listeners - Platform.getJobManager().addJobChangeListener(new JobChangeAdapter() { - public void done(IJobChangeEvent event) { - if(event.getJob().belongsTo(RefreshSubscriberJob.getFamily())) { - setViewImage(initialImg); - } - } - - public void running(IJobChangeEvent event) { - if(event.getJob().belongsTo(RefreshSubscriberJob.getFamily())) { - setViewImage(refreshingImg); - } - } - }); - } + /** * Adds the listeners to the viewer. */ @@ -313,7 +303,17 @@ public class SynchronizeView extends ViewPart implements ITeamResourceChangeList // do nothing } }); + + // Register for feedback from subscriber jobs. + // Synchronize so the state doesn't change while setting the cursor + synchronized (jobListener) { + SubscriberAction.getJobStatusHandler().addJobListener(jobListener); + if (SubscriberAction.getJobStatusHandler().hasRunningJobs()) { + showBusyCursor(); + } + } } + protected void initializeActions() { actions = new SyncViewerActions(this); actions.restore(memento); @@ -336,15 +336,6 @@ public class SynchronizeView extends ViewPart implements ITeamResourceChangeList IActionBars bars = getViewSite().getActionBars(); actions.fillActionBars(bars); } - /** - * Changes the image for the view. A change event is generated such that getTitleImage - * will be called to get the new image and display it. - * @param image the new image - */ - protected void setViewImage(Image image) { - viewImage = image; - fireSafePropertyChange(IWorkbenchPart.PROP_TITLE); - } protected void createViewer(Composite parent) { if(input == null) { @@ -363,7 +354,7 @@ public class SynchronizeView extends ViewPart implements ITeamResourceChangeList viewer.setInput(input); viewer.getControl().setFocus(); hookContextMenu(); - initializeListeners(); + initializeListeners(); } } @@ -547,6 +538,12 @@ public class SynchronizeView extends ViewPart implements ITeamResourceChangeList SubscriberInput input = (SubscriberInput) it.next(); input.dispose(); } + + // Synchronize so we don't process an event after the cursor is disposed + synchronized (jobListener) { + SubscriberAction.getJobStatusHandler().removeJobListener(jobListener); + waitCursor.dispose(); + } } public void run(IRunnableWithProgress runnable) { @@ -869,4 +866,20 @@ public class SynchronizeView extends ViewPart implements ITeamResourceChangeList Utils.handleError(getSite().getShell(), e, Policy.bind("SynchronizeView.16"), e.getMessage()); //$NON-NLS-1$ } } + + /* internal use only */ void showBusyCursor() { + showCursor(waitCursor); + } + + /* internal use only */ void showNormalCursor() { + showCursor(null); + } + + private void showCursor(Cursor cursor) { + Viewer viewer = getViewer(); + if (viewer == null) return; + Control control = viewer.getControl(); + if (control.isDisposed()) return; + control.setCursor(cursor); + } }
\ No newline at end of file diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/sync/SubscriberAction.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/sync/SubscriberAction.java index 9a91a8205..daf4df22a 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/sync/SubscriberAction.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/sync/SubscriberAction.java @@ -16,10 +16,13 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import org.eclipse.core.runtime.QualifiedName; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.team.core.TeamException; import org.eclipse.team.core.subscribers.SyncInfo; +import org.eclipse.team.internal.ui.TeamUIPlugin; import org.eclipse.team.internal.ui.actions.TeamAction; +import org.eclipse.team.internal.ui.jobs.JobStatusHandler; /** * This is the abstract superclass for actions associated with a subscriber. @@ -27,6 +30,21 @@ import org.eclipse.team.internal.ui.actions.TeamAction; */ public abstract class SubscriberAction extends TeamAction { + public static final QualifiedName SUBSCRIBER_JOB_TYPE = new QualifiedName(TeamUIPlugin.ID, "subcriber_job"); //$NON-NLS-1$ + + private static final JobStatusHandler feedbackManager = new JobStatusHandler(SUBSCRIBER_JOB_TYPE); + + /** + * Return the <code>JobStatusHandler</code> that is used to show busy indication + * in the Synchronize view. Subscribers should use the handler to schedule jobs + * that affect the Synchronize view so that the view shows proper busy indication + * to the user. + * @return the JobStatusHandler linked to the Sychcronize view + */ + public static JobStatusHandler getJobStatusHandler() { + return feedbackManager; + } + /** * This method returns all instances of SynchronizeViewNode that are in the current * selection. For a table view, this is any resource that is directly selected. |