KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > ui > synchronize > SubscriberParticipant


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.team.ui.synchronize;
12
13 import java.util.Arrays JavaDoc;
14
15 import org.eclipse.core.resources.IResource;
16 import org.eclipse.core.runtime.IProgressMonitor;
17 import org.eclipse.core.runtime.IStatus;
18 import org.eclipse.core.runtime.jobs.Job;
19 import org.eclipse.jface.util.IPropertyChangeListener;
20 import org.eclipse.jface.util.PropertyChangeEvent;
21 import org.eclipse.jface.viewers.IBasicPropertyConstants;
22 import org.eclipse.osgi.util.NLS;
23 import org.eclipse.swt.widgets.Shell;
24 import org.eclipse.team.core.TeamException;
25 import org.eclipse.team.core.subscribers.Subscriber;
26 import org.eclipse.team.core.synchronize.SyncInfoFilter;
27 import org.eclipse.team.core.synchronize.SyncInfoTree;
28 import org.eclipse.team.internal.core.subscribers.SubscriberSyncInfoCollector;
29 import org.eclipse.team.internal.ui.*;
30 import org.eclipse.team.internal.ui.synchronize.*;
31 import org.eclipse.team.ui.TeamUI;
32 import org.eclipse.ui.*;
33 import org.eclipse.ui.part.IPageBookViewPage;
34
35 /**
36  * A synchronize participant that displays synchronization information for local resources that are
37  * managed via a {@link Subscriber}. It maintains a dynamic collection of all out-of-sync resources
38  * by listening to workspace resource changes and remote changes thus creating a live view of
39  * changes in the workspace.
40  * <p>
41  * The subscriber can be configured to be synchronized in the background based on a schedule. This
42  * effectively refreshes the subscriber and updates the dynamic sync set.
43  * </p><p>
44  * Subclasses will typically want to override the following methods:
45  * <ul>
46  * <li>initializeConfiguration: participants can add toolbar actions, configure the context menu, decorator.
47  * <li>saveState and init: persist settings between sessions.
48  * </ul>
49  * This class is intended to be subclassed.
50  * </p>
51  * @since 3.0
52  */

53 public abstract class SubscriberParticipant extends AbstractSynchronizeParticipant implements IPropertyChangeListener {
54     
55     /*
56      * Collects and maintains set of all out-of-sync resources of the subscriber
57      */

58     private SubscriberSyncInfoCollector collector;
59     
60     /*
61      * Controls the automatic synchronization of this participant
62      */

63     private SubscriberRefreshSchedule refreshSchedule;
64     
65     /*
66      * Provides the resource scope for this participant
67      */

68     private ISynchronizeScope scope;
69     
70     /*
71      * Key for settings in memento
72      */

73     private static final String JavaDoc CTX_SUBSCRIBER_PARTICIPANT_SETTINGS = TeamUIPlugin.ID + ".TEAMSUBSRCIBERSETTINGS"; //$NON-NLS-1$
74

75     /*
76      * Key for schedule in memento
77      */

78     private static final String JavaDoc CTX_SUBSCRIBER_SCHEDULE_SETTINGS = TeamUIPlugin.ID + ".TEAMSUBSRCIBER_REFRESHSCHEDULE"; //$NON-NLS-1$
79

80     /**
81      * Constructor initializes the schedule. Subclasses must call this method.
82      */

83     public SubscriberParticipant() {
84         refreshSchedule = new SubscriberRefreshSchedule(createRefreshable());
85     }
86
87     private IRefreshable createRefreshable() {
88         return new IRefreshable() {
89             public RefreshParticipantJob createJob(String JavaDoc interval) {
90                 return new RefreshSubscriberParticipantJob(SubscriberParticipant.this,
91                         TeamUIMessages.RefreshSchedule_14,
92                         NLS.bind(TeamUIMessages.RefreshSchedule_15, new String JavaDoc[] { SubscriberParticipant.this.getName(), interval }), getResources(),
93                         new RefreshUserNotificationPolicy(SubscriberParticipant.this));
94             }
95             public ISynchronizeParticipant getParticipant() {
96                 return SubscriberParticipant.this;
97             }
98             public void setRefreshSchedule(SubscriberRefreshSchedule schedule) {
99                 SubscriberParticipant.this.setRefreshSchedule(schedule);
100             }
101             public SubscriberRefreshSchedule getRefreshSchedule() {
102                 return SubscriberParticipant.this.getRefreshSchedule();
103             }
104         
105         };
106     }
107     
108     /**
109      * Constructor which should be called when creating a participant whose resources
110      * are to be scoped.
111      *
112      * @param scope a synchronize scope
113      */

114     public SubscriberParticipant(ISynchronizeScope scope) {
115         this();
116         this.scope = scope;
117         scope.addPropertyChangeListener(this);
118     }
119     
120     /* (non-Javadoc)
121      * @see org.eclipse.team.ui.sync.ISynchronizeViewPage#createPage(org.eclipse.team.ui.sync.ISynchronizeView)
122      */

123     public final IPageBookViewPage createPage(ISynchronizePageConfiguration configuration) {
124         validateConfiguration(configuration);
125         return new SubscriberParticipantPage(configuration, getSubscriberSyncInfoCollector());
126     }
127     
128     /**
129      * Returns the resources supervised by this participant. It will
130      * either be the roots of the subscriber or the resource scope
131      * provided when the subscriber was set.
132      *
133      * @return the resources supervised by this participant.
134      */

135     public IResource[] getResources() {
136         return collector.getRoots();
137     }
138     
139     /*
140      * Set the resources supervised by this participant. If <code>null</code>,
141      * the participant will include all roots of its subscriber
142      *
143      * @param roots the root resources to consider or <code>null</code>
144      * to consider all roots of the subscriber
145      */

146     private void setResources(IResource[] roots) {
147         collector.setRoots(roots);
148     }
149     
150     /**
151      * Refresh this participants synchronization state and displays the result in a model dialog.
152      * @param shell
153      *
154      * @param resources
155      * @param jobName
156      * @param taskName
157      * @param configuration
158      * @param site
159      */

160     public final void refreshInDialog(Shell shell, IResource[] resources, String JavaDoc jobName, String JavaDoc taskName, ISynchronizePageConfiguration configuration, IWorkbenchSite site) {
161         IRefreshSubscriberListener listener = new RefreshUserNotificationPolicyInModalDialog(shell, taskName, configuration, this);
162         internalRefresh(resources, jobName, taskName, site, listener);
163     }
164
165     /**
166      * Refresh a participant in the background the result of the refresh are shown in the progress view. Refreshing
167      * can also be considered synchronizing, or refreshing the synchronization state. Basically this is a long
168      * running operation that will update the participants sync info sets with new changes detected on the
169      * server. Either or both of the <code>shortTaskName</code> and <code>longTaskName</code> can be <code>null</code>
170      * in which case, the default values for these are returned by the methods <code>getShortTaskName()</code> and
171      * <code>getLongTaskName(IResource[])</code> will be used.
172      *
173      * @param resources the resources to be refreshed.
174      * @param shortTaskName the taskName of the background job that will run the synchronize or <code>null</code>
175      * if the default job name is desired.
176      * @param longTaskName the taskName of the progress monitor running the synchronize or <code>null</code>
177      * if the default job name is desired.
178      * @param site the workbench site the synchronize is running from. This can be used to notify the site
179      * that a job is running.
180      */

181     public final void refresh(IResource[] resources, String JavaDoc shortTaskName, String JavaDoc longTaskName, IWorkbenchSite site) {
182         IRefreshSubscriberListener listener = new RefreshUserNotificationPolicy(this);
183         internalRefresh(resources, shortTaskName, longTaskName, site, listener);
184     }
185
186     /**
187      * Refresh a participant. The returned status describes the result of the refresh.
188      * @param resources
189      * @param taskName
190      * @param monitor
191      * @return a status
192      */

193     public final IStatus refreshNow(IResource[] resources, String JavaDoc taskName, IProgressMonitor monitor) {
194         Job.getJobManager().cancel(this);
195         RefreshParticipantJob job = new RefreshSubscriberParticipantJob(this, taskName, taskName, resources, null);
196         return job.run(monitor);
197     }
198     
199     /* (non-Javadoc)
200      * @see org.eclipse.team.ui.sync.AbstractSynchronizeViewPage#dispose()
201      */

202     public void dispose() {
203         Job.getJobManager().cancel(this);
204         refreshSchedule.dispose();
205         TeamUI.removePropertyChangeListener(this);
206         collector.dispose();
207         scope.dispose();
208     }
209     
210     /* (non-Javadoc)
211      * @see org.eclipse.team.ui.synchronize.AbstractSynchronizeParticipant#getName()
212      */

213     public String JavaDoc getName() {
214         String JavaDoc name = super.getName();
215         return NLS.bind(TeamUIMessages.SubscriberParticipant_namePattern, new String JavaDoc[] { name, scope.getName() });
216     }
217     
218     /**
219      * Return the name of the participant as specified in the plugin manifest file.
220      * This method is provided to give access to this name since it is masked by
221      * the <code>getName()</code> method defined in this class.
222      * @return the name of the participant as specified in the plugin manifest file
223      * @since 3.1
224      */

225     protected final String JavaDoc getShortName() {
226         return super.getName();
227     }
228     
229     /**
230      * Returns the <code>SyncInfoTree</code> for this participant. This set
231      * contains the out-of-sync resources supervised by this participant.
232      *
233      * @return the sync info set that contains the out-of-sync resources
234      * for this participant.
235      */

236     public SyncInfoTree getSyncInfoSet() {
237         return getSubscriberSyncInfoCollector().getSyncInfoSet();
238     }
239     
240     /**
241      * Return the <code>Subscriber</code> associated with this this participant. This
242      * method will only return <code>null</code> if the participant has not been initialized
243      * yet.
244      *
245      * @return the <code>Subscriber</code> associated with this this participant.
246      */

247     public Subscriber getSubscriber() {
248         if (collector == null) return null;
249         return collector.getSubscriber();
250     }
251     
252     /**
253      * Returns a participant that matches the given resource scoping
254      *
255      * @param ID the type id of participants to match
256      * @param resources the resources to match in the scope
257      * @return a participant that matches the given resource scoping
258      */

259     public static SubscriberParticipant getMatchingParticipant(String JavaDoc ID, IResource[] resources) {
260         ISynchronizeParticipantReference[] refs = TeamUI.getSynchronizeManager().getSynchronizeParticipants();
261             for (int i = 0; i < refs.length; i++) {
262             ISynchronizeParticipantReference reference = refs[i];
263             if(reference.getId().equals(ID)) {
264                     SubscriberParticipant p;
265                     try {
266                         p = (SubscriberParticipant)reference.getParticipant();
267                     } catch (TeamException e) {
268                         continue;
269                     }
270                     IResource[] roots = p.getResources();
271                     Arrays.sort(resources, Utils.resourceComparator);
272                     Arrays.sort(roots, Utils.resourceComparator);
273                     if (Arrays.equals(resources, roots)) {
274                         return p;
275                     }
276             }
277         }
278         return null;
279     }
280         
281     /* (non-Javadoc)
282      * @see IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
283      */

284     public void propertyChange(PropertyChangeEvent event) {
285         if (event.getProperty().equals(TeamUI.GLOBAL_IGNORES_CHANGED)) {
286             collector.reset();
287         }
288         if (event.getProperty().equals(ISynchronizeScope.ROOTS)) {
289             setResources(scope.getRoots());
290         }
291         if (event.getProperty().equals(ISynchronizeScope.NAME)) {
292             // Force a name change event, which will cause this classes getName to be called
293
// and updated with the correct working set name.
294
firePropertyChange(this, IBasicPropertyConstants.P_TEXT, null, getName());
295         }
296     }
297     
298     /* (non-Javadoc)
299      * @see org.eclipse.team.ui.synchronize.ISynchronizeParticipant#init(org.eclipse.ui.IMemento)
300      */

301     public void init(String JavaDoc secondaryId, IMemento memento) throws PartInitException {
302         super.init(secondaryId, memento);
303         if(memento != null) {
304             IMemento settings = memento.getChild(CTX_SUBSCRIBER_PARTICIPANT_SETTINGS);
305             if(settings != null) {
306                 SubscriberRefreshSchedule schedule = SubscriberRefreshSchedule.init(settings.getChild(CTX_SUBSCRIBER_SCHEDULE_SETTINGS), createRefreshable());
307                 setRefreshSchedule(schedule);
308                 this.scope = AbstractSynchronizeScope.createScope(settings);
309                 scope.addPropertyChangeListener(this);
310             }
311         }
312     }
313
314     /* (non-Javadoc)
315      * @see org.eclipse.team.ui.synchronize.ISynchronizeParticipant#saveState(org.eclipse.ui.IMemento)
316      */

317     public void saveState(IMemento memento) {
318         super.saveState(memento);
319         IMemento settings = memento.createChild(CTX_SUBSCRIBER_PARTICIPANT_SETTINGS);
320         refreshSchedule.saveState(settings.createChild(CTX_SUBSCRIBER_SCHEDULE_SETTINGS));
321         AbstractSynchronizeScope.saveScope(scope, settings);
322     }
323
324     /**
325      * Reset the sync set of the participant by repopulating it from scratch.
326      */

327     public void reset() {
328         getSubscriberSyncInfoCollector().reset();
329     }
330     
331     /* (non-Javadoc)
332      * Return the <code>SubscriberSyncInfoCollector</code> for the participant.
333      * This collector maintains the set of all out-of-sync resources for the subscriber.
334      *
335      * @return the <code>SubscriberSyncInfoCollector</code> for this participant
336      */

337     public SubscriberSyncInfoCollector getSubscriberSyncInfoCollector() {
338         return collector;
339     }
340     
341     /*(non-Javadoc)
342      * Not to be called by clients.
343      */

344     public void setRefreshSchedule(SubscriberRefreshSchedule schedule) {
345         if (refreshSchedule != schedule) {
346             if (refreshSchedule != null) {
347                 refreshSchedule.dispose();
348             }
349             this.refreshSchedule = schedule;
350         }
351         // Always fir the event since the schedule may have been changed
352
firePropertyChange(this, AbstractSynchronizeParticipant.P_SCHEDULED, schedule, schedule);
353     }
354     
355     /* (non-Javadoc)
356      * Not to be called by clients.
357      */

358     public SubscriberRefreshSchedule getRefreshSchedule() {
359         return refreshSchedule;
360     }
361     
362     /* (non-Javadoc)
363      * @see org.eclipse.team.ui.synchronize.AbstractSynchronizeParticipant#initializeConfiguration(org.eclipse.team.ui.synchronize.ISynchronizePageConfiguration)
364      */

365     protected void initializeConfiguration(ISynchronizePageConfiguration configuration) {
366         configuration.setProperty(SynchronizePageConfiguration.P_PARTICIPANT_SYNC_INFO_SET, collector.getSyncInfoSet());
367     }
368     
369     /* (non-Javadoc)
370      * @see org.eclipse.team.ui.synchronize.ISynchronizeParticipant#run(org.eclipse.ui.IWorkbenchPart)
371      */

372     public void run(IWorkbenchPart part) {
373         refresh(getResources(), null, null, part != null ? part.getSite() : null);
374     }
375     
376     /**
377      * Returns the short task name (e.g. no more than 25 characters) to describe the behavior of the
378      * refresh operation to the user. This is typically shown in the status line when this subscriber is refreshed
379      * in the background. When refreshed in the foreground, only the long task name is shown.
380      *
381      * @return the short task name to show in the status line.
382      */

383     protected String JavaDoc getShortTaskName() {
384         return TeamUIMessages.Participant_synchronizing;
385     }
386     
387     /**
388      * Returns the long task name to describe the behavior of the
389      * refresh operation to the user. This is typically shown in the status line when this subscriber is refreshed
390      * in the background.
391      *
392      * @return the long task name
393      * @deprecated use <code>getLongTaskName(IResource[]) instead</code>
394      */

395     protected String JavaDoc getLongTaskName() {
396         return TeamUIMessages.Participant_synchronizing;
397     }
398     
399     /**
400      * Returns the long task name to describe the behavior of the
401      * refresh operation to the user. This is typically shown in the status line when this subscriber is refreshed
402      * in the background.
403      * @param resources
404      * @return the long task name
405      * @since 3.1
406      */

407     protected String JavaDoc getLongTaskName(IResource[] resources) {
408         int resourceCount = 0;
409         if (getResources().length == resources.length) {
410             // Assume that the resources are the same as the roots.
411
// If we are wrong, the message may no mention the specific resources which is OK
412
ISynchronizeScope scope = getScope();
413             if (scope instanceof ResourceScope) {
414                 resourceCount = scope.getRoots().length;
415             }
416         } else {
417             resourceCount = resources.length;
418         }
419         if (resourceCount == 1) {
420             return NLS.bind(TeamUIMessages.Participant_synchronizingMoreDetails, new String JavaDoc[] { getShortName(), resources[0].getFullPath().toString() });
421         } else if (resourceCount > 1) {
422             return NLS.bind(TeamUIMessages.Participant_synchronizingResources, new String JavaDoc[] { getShortName(), Integer.toString(resourceCount) });
423         }
424         // A resource count of zero means that it is a non-resource scope so we can print the scope name
425
return NLS.bind(TeamUIMessages.Participant_synchronizingDetails, new String JavaDoc[] { getName() });
426     }
427
428     /**
429      * This method is invoked before the given configuration is used to
430      * create the page (see <code>createPage(ISynchronizePageConfiguration)</code>).
431      * The configuration would have been initialized by
432      * <code>initializeConfiguration(ISynchronizePageConfiguration)</code>
433      * but may have also been tailored further. This method gives the participant
434      * a chance to validate those changes before the page is created.
435      *
436      * @param configuration the page configuration that is about to be used to create a page.
437      */

438     protected void validateConfiguration(ISynchronizePageConfiguration configuration) {
439         // Do nothing by default
440
}
441     
442     /**
443      * Subclasses must call this method to initialize the participant. Typically this
444      * method is called in {@link #init(String, IMemento)}. This method will initialize
445      * the sync info collector.
446      *
447      * @param subscriber the subscriber to associate with this participant.
448      */

449     protected void setSubscriber(Subscriber subscriber) {
450         if (scope == null) {
451             scope = new WorkspaceScope();
452         }
453         collector = new SubscriberSyncInfoCollector(subscriber, scope.getRoots());
454         
455         // listen for global ignore changes
456
TeamUI.addPropertyChangeListener(this);
457         
458         // Start collecting changes
459
collector.start();
460         
461         // Start the refresh now that a subscriber has been added
462
SubscriberRefreshSchedule schedule = getRefreshSchedule();
463         if(schedule.isEnabled()) {
464             getRefreshSchedule().startJob();
465         }
466     }
467     
468     /**
469      * Provide a filter that is used to filter the contents of the sync info set for the participant. Normally, all out-of-sync
470      * resources from the subscriber will be included in the participant's set. However, a filter can be used to exclude
471      * some of these out-of-sync resources, if desired.
472      * <p>
473      * Subclasses can invoke this method any time after <code>setSubscriber</code> has been invoked.
474      * </p>
475      * @param filter a sync info filter
476      */

477     protected void setSyncInfoFilter(SyncInfoFilter filter) {
478         collector.setFilter(filter);
479     }
480     
481     /*
482      * Create and schedule a subscriber refresh job.
483      *
484      * @param resources resources to be synchronized
485      * @param taskName the task name to be shown to the user
486      * @param site the site in which to run the refresh
487      * @param listener the listener to handle the refresh workflow
488      */

489     private void internalRefresh(IResource[] resources, String JavaDoc jobName, String JavaDoc taskName, IWorkbenchSite site, IRefreshSubscriberListener listener) {
490         if (jobName == null)
491             jobName = getShortTaskName();
492         if (taskName == null)
493             taskName = getLongTaskName(resources);
494         Job.getJobManager().cancel(this);
495         RefreshParticipantJob job = new RefreshSubscriberParticipantJob(this, jobName, taskName, resources, listener);
496         job.setUser(true);
497         Utils.schedule(job, site);
498         
499         // Remember the last participant synchronized
500
TeamUIPlugin.getPlugin().getPreferenceStore().setValue(IPreferenceIds.SYNCHRONIZING_DEFAULT_PARTICIPANT, getId());
501         TeamUIPlugin.getPlugin().getPreferenceStore().setValue(IPreferenceIds.SYNCHRONIZING_DEFAULT_PARTICIPANT_SEC_ID, getSecondaryId());
502     }
503     
504     /**
505      * Return the scope that defines the resources displayed by this participant.
506      *
507      * @return Returns the scope.
508      */

509     public ISynchronizeScope getScope() {
510         return scope;
511     }
512     
513     /* (non-Javadoc)
514      * @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class)
515      */

516     public Object JavaDoc getAdapter(Class JavaDoc adapter) {
517         if (adapter == IRefreshable.class && refreshSchedule != null) {
518             return refreshSchedule.getRefreshable();
519             
520         }
521         return super.getAdapter(adapter);
522     }
523 }
524
Popular Tags