Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Valenta2003-09-16 13:10:45 +0000
committerMichael Valenta2003-09-16 13:10:45 +0000
commitc112994846e89ae0a77e3a94799327ecad16e7eb (patch)
tree68a059c4a30a16327a73709a3affa96375c86095
parentc717812035c986bf4cdb03b7033f3082be55178d (diff)
downloadeclipse.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
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/CVSNonblockingRunnableContext.java4
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/CVSSubscriberNonblockingContext.java29
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSSubscriberAction.java4
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/TeamUIPlugin.java3
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/jobs/IJobListener.java26
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/jobs/JobStatusHandler.java134
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/messages.properties3
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/sync/actions/RefreshAction.java3
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/sync/sets/SubscriberEventHandler.java74
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/sync/views/SynchronizeView.java131
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/sync/SubscriberAction.java18
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.

Back to the top