KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > internal > ccvs > ui > subscriber > ChangeLogModelProvider


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

11 package org.eclipse.team.internal.ccvs.ui.subscriber;
12
13 import java.util.*;
14 import org.eclipse.compare.structuremergeviewer.IDiffContainer;
15 import org.eclipse.compare.structuremergeviewer.IDiffElement;
16 import org.eclipse.core.resources.IResource;
17 import org.eclipse.core.runtime.*;
18 import org.eclipse.core.runtime.jobs.Job;
19 import org.eclipse.jface.action.Action;
20 import org.eclipse.jface.action.MenuManager;
21 import org.eclipse.jface.dialogs.IDialogSettings;
22 import org.eclipse.jface.resource.ImageDescriptor;
23 import org.eclipse.jface.viewers.*;
24 import org.eclipse.swt.custom.BusyIndicator;
25 import org.eclipse.team.core.TeamException;
26 import org.eclipse.team.core.subscribers.Subscriber;
27 import org.eclipse.team.core.synchronize.*;
28 import org.eclipse.team.core.variants.IResourceVariant;
29 import org.eclipse.team.internal.ccvs.core.*;
30 import org.eclipse.team.internal.ccvs.core.resources.*;
31 import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
32 import org.eclipse.team.internal.ccvs.ui.*;
33 import org.eclipse.team.internal.ccvs.ui.Policy;
34 import org.eclipse.team.internal.ccvs.ui.operations.RemoteLogOperation;
35 import org.eclipse.team.internal.ui.TeamUIPlugin;
36 import org.eclipse.team.internal.ui.Utils;
37 import org.eclipse.team.internal.ui.synchronize.*;
38 import org.eclipse.team.ui.synchronize.*;
39 import org.eclipse.ui.progress.UIJob;
40
41 /**
42  * Disclamer:
43  * This is a prototype layout using *internal* team classes. It is not meant
44  * to be an example or sanctioned use of team. These classes and the classes
45  * references here may change or be deleted in the future.
46  *
47  * This provider groups changes into commit sets and fetches the log history for
48  * files in the background. Changes that can't be grouped into commit sets (e.g. outgoing
49  * changes) are shown in a flat list.
50  *
51  * @since 3.0
52  */

53 public class ChangeLogModelProvider extends SynchronizeModelProvider {
54     // Log operation that is used to fetch revision histories from the server. It also
55
// provides caching so we keep it around.
56
private RemoteLogOperation logOperation;
57     
58     // Job that builds the layout in the background.
59
private boolean shutdown = false;
60     private FetchLogEntriesJob fetchLogEntriesJob;
61     
62     // Sorters for the commit sets and resources
63
private ChangeLogActionGroup sortGroup;
64     
65     // Tag ranges for fetching revision histories. If no tags are specified then
66
// the history for the remote revision in the sync info is used.
67
private CVSTag tag1;
68     private CVSTag tag2;
69     private Map multipleResourceMap;
70     
71     // Constants for persisting sorting options
72
private final static String JavaDoc SORT_ORDER_GROUP = "changelog_sort"; //$NON-NLS-1$
73
private static final String JavaDoc P_LAST_COMMENTSORT = TeamUIPlugin.ID + ".P_LAST_COMMENT_SORT"; //$NON-NLS-1$
74
private static final String JavaDoc P_LAST_RESOURCESORT = TeamUIPlugin.ID + ".P_LAST_RESOURCE_SORT"; //$NON-NLS-1$
75

76     /* *****************************************************************************
77      * Action that allows changing the model providers sort order.
78      */

79     private class ToggleSortOrderAction extends Action {
80         private int criteria;
81         private int sortType;
82         public final static int RESOURCE_NAME = 1;
83         public final static int COMMENT = 2;
84         protected ToggleSortOrderAction(String JavaDoc name, int criteria, int sortType, int defaultCriteria) {
85             super(name, Action.AS_RADIO_BUTTON);
86             this.criteria = criteria;
87             this.sortType = sortType;
88             setChecked(criteria == defaultCriteria);
89         }
90
91         public void run() {
92             StructuredViewer viewer = getViewer();
93             if (viewer != null && !viewer.getControl().isDisposed()) {
94                 ChangeLogModelSorter sorter = (ChangeLogModelSorter) viewer.getSorter();
95                 if (isChecked() && sorter != null && getCriteria(sorter) != criteria) {
96                     viewer.setSorter(createSorter(sorter));
97                     String JavaDoc key = sortType == RESOURCE_NAME ? P_LAST_RESOURCESORT : P_LAST_COMMENTSORT;
98                     IDialogSettings pageSettings = getConfiguration().getSite().getPageSettings();
99                     if(pageSettings != null) {
100                         pageSettings.put(key, criteria);
101                     }
102                     update();
103                 }
104             }
105         }
106         
107         public void update() {
108             StructuredViewer viewer = getViewer();
109             if (viewer != null && !viewer.getControl().isDisposed()) {
110                 ChangeLogModelSorter sorter = (ChangeLogModelSorter) viewer.getSorter();
111                 if (sorter != null) {
112                     setChecked(getCriteria(sorter) == criteria);
113                 }
114             }
115         }
116         
117         protected ChangeLogModelSorter createSorter(ChangeLogModelSorter sorter) {
118             if(sortType == COMMENT) {
119                 return new ChangeLogModelSorter(criteria, sorter.getResourceCriteria());
120             } else {
121                 return new ChangeLogModelSorter(sorter.getCommentCriteria(), criteria);
122             }
123         }
124         
125         protected int getCriteria(ChangeLogModelSorter sorter) {
126             if(sortType == COMMENT)
127                 return sorter.getCommentCriteria();
128             else
129                 return sorter.getResourceCriteria();
130         }
131     }
132     
133     /* *****************************************************************************
134      * Action group for this layout. It is added and removed for this layout only.
135      */

136     public class ChangeLogActionGroup extends SynchronizePageActionGroup {
137         private MenuManager sortByComment;
138         private MenuManager sortByResource;
139         public void initialize(ISynchronizePageConfiguration configuration) {
140             super.initialize(configuration);
141             sortByComment = new MenuManager(Policy.bind("ChangeLogModelProvider.0")); //$NON-NLS-1$
142
sortByResource = new MenuManager(Policy.bind("ChangeLogModelProvider.6")); //$NON-NLS-1$
143

144             appendToGroup(
145                     ISynchronizePageConfiguration.P_CONTEXT_MENU,
146                     SORT_ORDER_GROUP,
147                     sortByComment);
148             appendToGroup(
149                     ISynchronizePageConfiguration.P_CONTEXT_MENU,
150                     SORT_ORDER_GROUP,
151                     sortByResource);
152             
153             ChangeLogModelSorter sorter = (ChangeLogModelSorter)getViewerSorter();
154             
155             sortByComment.add(new ToggleSortOrderAction(Policy.bind("ChangeLogModelProvider.1"), ChangeLogModelSorter.COMMENT, ToggleSortOrderAction.COMMENT, sorter.getCommentCriteria())); //$NON-NLS-1$
156
sortByComment.add(new ToggleSortOrderAction(Policy.bind("ChangeLogModelProvider.2"), ChangeLogModelSorter.DATE, ToggleSortOrderAction.COMMENT, sorter.getCommentCriteria())); //$NON-NLS-1$
157
sortByComment.add(new ToggleSortOrderAction(Policy.bind("ChangeLogModelProvider.3"), ChangeLogModelSorter.USER, ToggleSortOrderAction.COMMENT, sorter.getCommentCriteria())); //$NON-NLS-1$
158

159             sortByResource.add( new ToggleSortOrderAction(Policy.bind("ChangeLogModelProvider.8"), ChangeLogModelSorter.PATH, ToggleSortOrderAction.RESOURCE_NAME, sorter.getResourceCriteria())); //$NON-NLS-1$
160
sortByResource.add(new ToggleSortOrderAction(Policy.bind("ChangeLogModelProvider.7"), ChangeLogModelSorter.NAME, ToggleSortOrderAction.RESOURCE_NAME, sorter.getResourceCriteria())); //$NON-NLS-1$
161
sortByResource.add(new ToggleSortOrderAction(Policy.bind("ChangeLogModelProvider.9"), ChangeLogModelSorter.PARENT_NAME, ToggleSortOrderAction.RESOURCE_NAME, sorter.getResourceCriteria())); //$NON-NLS-1$
162
}
163         
164         /* (non-Javadoc)
165          * @see org.eclipse.team.ui.synchronize.SynchronizePageActionGroup#dispose()
166          */

167         public void dispose() {
168             sortByComment.dispose();
169             sortByResource.dispose();
170             sortByComment.removeAll();
171             sortByResource.removeAll();
172             super.dispose();
173         }
174     }
175     
176     /* *****************************************************************************
177      * Model element for the resources in this layout. They are displayed with filename and path
178      * onto the same line.
179      */

180     public static class FullPathSyncInfoElement extends SyncInfoModelElement {
181         public FullPathSyncInfoElement(IDiffContainer parent, SyncInfo info) {
182             super(parent, info);
183         }
184         public String JavaDoc getName() {
185             IResource resource = getResource();
186             return resource.getName() + " - " + resource.getFullPath().toString(); //$NON-NLS-1$
187
}
188     }
189     
190     /* *****************************************************************************
191      * Special sync info that has its kind already calculated.
192      */

193     public class CVSUpdatableSyncInfo extends CVSSyncInfo {
194         public int kind;
195         public CVSUpdatableSyncInfo(int kind, IResource local, IResourceVariant base, IResourceVariant remote, Subscriber s) {
196             super(local, base, remote, s);
197             this.kind = kind;
198         }
199
200         protected int calculateKind() throws TeamException {
201             return kind;
202         }
203     }
204     
205     /* *****************************************************************************
206      * Action group for this layout. It is added and removed for this layout only.
207      */

208     
209     private class FetchLogEntriesJob extends Job {
210         private Set syncSets = new HashSet();
211         public FetchLogEntriesJob() {
212             super(Policy.bind("ChangeLogModelProvider.4")); //$NON-NLS-1$
213
setUser(false);
214         }
215         public boolean belongsTo(Object JavaDoc family) {
216             return family == ISynchronizeManager.FAMILY_SYNCHRONIZE_OPERATION;
217         }
218         public IStatus run(IProgressMonitor monitor) {
219             
220                 if (syncSets != null && !shutdown) {
221                     // Determine the sync sets for which to fetch comment nodes
222
SyncInfoSet[] updates;
223                     synchronized (syncSets) {
224                         updates = (SyncInfoSet[]) syncSets.toArray(new SyncInfoSet[syncSets.size()]);
225                         syncSets.clear();
226                     }
227                     for (int i = 0; i < updates.length; i++) {
228                         calculateRoots(updates[i], monitor);
229                     }
230                     refreshViewer();
231                 }
232                 return Status.OK_STATUS;
233         
234         }
235         public void add(SyncInfoSet set) {
236             synchronized(syncSets) {
237                 syncSets.add(set);
238             }
239             schedule();
240         }
241         public boolean shouldRun() {
242             return !syncSets.isEmpty();
243         }
244     };
245     
246     /* *****************************************************************************
247      * Descriptor for this model provider
248      */

249     public static class ChangeLogModelProviderDescriptor implements ISynchronizeModelProviderDescriptor {
250         public static final String JavaDoc ID = TeamUIPlugin.ID + ".modelprovider_cvs_changelog"; //$NON-NLS-1$
251
public String JavaDoc getId() {
252             return ID;
253         }
254         public String JavaDoc getName() {
255             return Policy.bind("ChangeLogModelProvider.5"); //$NON-NLS-1$
256
}
257         public ImageDescriptor getImageDescriptor() {
258             return CVSUIPlugin.getPlugin().getImageDescriptor(ICVSUIConstants.IMG_CHANGELOG);
259         }
260     };
261     private static final ChangeLogModelProviderDescriptor descriptor = new ChangeLogModelProviderDescriptor();
262     
263     public ChangeLogModelProvider(ISynchronizePageConfiguration configuration, SyncInfoSet set, CVSTag tag1, CVSTag tag2) {
264         super(configuration, set);
265         this.tag1 = tag1;
266         this.tag2 = tag2;
267         configuration.addMenuGroup(ISynchronizePageConfiguration.P_CONTEXT_MENU, SORT_ORDER_GROUP);
268         this.sortGroup = new ChangeLogActionGroup();
269         configuration.addActionContribution(sortGroup);
270     }
271     
272     /* (non-Javadoc)
273      * @see org.eclipse.team.internal.ui.synchronize.ISynchronizeModelProvider#getDescriptor()
274      */

275     public ISynchronizeModelProviderDescriptor getDescriptor() {
276         return descriptor;
277     }
278     
279     /*
280      * (non-Javadoc)
281      * @see org.eclipse.team.ui.synchronize.viewers.HierarchicalModelProvider#buildModelObjects(org.eclipse.compare.structuremergeviewer.DiffNode)
282      */

283     protected IDiffElement[] buildModelObjects(ISynchronizeModelElement node) {
284         if (node == getModelRoot()) {
285             // Cancel any existing fetching jobs
286
try {
287                 if (fetchLogEntriesJob != null && fetchLogEntriesJob.getState() != Job.NONE) {
288                     fetchLogEntriesJob.cancel();
289                     fetchLogEntriesJob.join();
290                 }
291             } catch (InterruptedException JavaDoc e) {
292             }
293
294             // Start building the model from scratch
295
startUpdateJob(getSyncInfoSet());
296         }
297         return new IDiffElement[0];
298     }
299
300     private void startUpdateJob(SyncInfoSet set) {
301         if(fetchLogEntriesJob == null) {
302             fetchLogEntriesJob = new FetchLogEntriesJob();
303         }
304         fetchLogEntriesJob.add(set);
305     }
306     
307     private void refreshViewer() {
308         UIJob updateUI = new UIJob("") { //$NON-NLS-1$
309
public IStatus runInUIThread(IProgressMonitor monitor) {
310                 BusyIndicator.showWhile(getDisplay(), new Runnable JavaDoc() {
311                     public void run() {
312                         StructuredViewer tree = getViewer();
313                         tree.refresh();
314                         ISynchronizeModelElement root = getModelRoot();
315                         if(root instanceof SynchronizeModelElement)
316                             ((SynchronizeModelElement)root).fireChanges();
317                     }
318                 });
319
320                 return Status.OK_STATUS;
321             }
322         };
323         updateUI.setSystem(true);
324         updateUI.schedule();
325     }
326     
327     private void calculateRoots(SyncInfoSet set, IProgressMonitor monitor) {
328         try {
329             monitor.beginTask(null, 100);
330             // Decide which nodes we have to fetch log histories
331
SyncInfo[] infos = set.getSyncInfos();
332             ArrayList commentNodes = new ArrayList();
333             ArrayList resourceNodes = new ArrayList();
334             for (int i = 0; i < infos.length; i++) {
335                 SyncInfo info = infos[i];
336                 if(isInterestingChange(info)) {
337                     commentNodes.add(info);
338                 } else {
339                     resourceNodes.add(info);
340                 }
341             }
342             // Show elements that don't need their log histories retreived
343
for (Iterator it = resourceNodes.iterator(); it.hasNext();) {
344                 SyncInfo info = (SyncInfo) it.next();
345                 addNewElementFor(info, null, null);
346             }
347             if(! resourceNodes.isEmpty())
348                 refreshViewer();
349             
350             // Fetch log histories then add elements
351
SyncInfo[] commentInfos = (SyncInfo[]) commentNodes.toArray(new SyncInfo[commentNodes.size()]);
352             RemoteLogOperation logs = getSyncInfoComment(commentInfos, Policy.subMonitorFor(monitor, 80));
353             addLogEntries(commentInfos, logs, Policy.subMonitorFor(monitor, 20));
354         } catch (CVSException e) {
355             Utils.handle(e);
356         } catch (InterruptedException JavaDoc e) {
357         } finally {
358             monitor.done();
359         }
360     }
361     
362     /**
363      * Add the followinf sync info elements to the viewer. It is assumed that these elements have associated
364      * log entries cached in the log operation.
365      */

366     private void addLogEntries(SyncInfo[] commentInfos, RemoteLogOperation logs, IProgressMonitor monitor) {
367         try {
368             monitor.beginTask(null, commentInfos.length * 10);
369             if (logs != null) {
370                 for (int i = 0; i < commentInfos.length; i++) {
371                     addSyncInfoToCommentNode(commentInfos[i], logs);
372                     monitor.worked(10);
373                 }
374                 // Don't cache log entries when in two way mode.
375
if (getConfiguration().getComparisonType().equals(ISynchronizePageConfiguration.TWO_WAY)) {
376                     logs.clearEntries();
377                 }
378             }
379         } finally {
380             monitor.done();
381         }
382     }
383
384     /**
385      * Create a node for the given sync info object. The logs should contain the log for this info.
386      *
387      * @param info the info for which to create a node in the model
388      * @param log the cvs log for this node
389      */

390     private void addSyncInfoToCommentNode(SyncInfo info, RemoteLogOperation logs) {
391         ICVSRemoteResource remoteResource = getRemoteResource((CVSSyncInfo)info);
392         if(tag1 != null && tag2 != null) {
393             addMultipleRevisions(info, logs, remoteResource);
394         } else {
395             addSingleRevision(info, logs, remoteResource);
396         }
397     }
398     
399     /**
400      * Add multiple log entries to the model.
401      *
402      * @param info
403      * @param logs
404      * @param remoteResource
405      */

406     private void addMultipleRevisions(SyncInfo info, RemoteLogOperation logs, ICVSRemoteResource remoteResource) {
407         ILogEntry[] logEntries = logs.getLogEntries(remoteResource);
408         if(logEntries == null || logEntries.length == 0) {
409             // If for some reason we don't have a log entry, try the latest
410
// remote.
411
addNewElementFor(info, null, null);
412         } else {
413             for (int i = 0; i < logEntries.length; i++) {
414                 ILogEntry entry = logEntries[i];
415                 addNewElementFor(info, remoteResource, entry);
416             }
417         }
418     }
419
420     /**
421      * Add a single log entry to the model.
422      *
423      * @param info
424      * @param logs
425      * @param remoteResource
426      */

427     private void addSingleRevision(SyncInfo info, RemoteLogOperation logs, ICVSRemoteResource remoteResource) {
428         ILogEntry logEntry = logs.getLogEntry(remoteResource);
429         // For incoming deletions grab the comment for the latest on the same branch
430
// which is now in the attic.
431
try {
432             String JavaDoc remoteRevision = ((ICVSRemoteFile) remoteResource).getRevision();
433             if (isDeletedRemotely(info)) {
434                 ILogEntry[] logEntries = logs.getLogEntries(remoteResource);
435                 for (int i = 0; i < logEntries.length; i++) {
436                     ILogEntry entry = logEntries[i];
437                     String JavaDoc revision = entry.getRevision();
438                     if (entry.isDeletion() && ResourceSyncInfo.isLaterRevision(revision, remoteRevision)) {
439                         logEntry = entry;
440                     }
441                 }
442             }
443         } catch (TeamException e) {
444             // continue and skip deletion checks
445
}
446         addNewElementFor(info, remoteResource, logEntry);
447     }
448
449     private boolean isDeletedRemotely(SyncInfo info) {
450         int kind = info.getKind();
451         if(kind == (SyncInfo.INCOMING | SyncInfo.DELETION)) return true;
452         if(SyncInfo.getDirection(kind) == SyncInfo.CONFLICTING && info.getRemote() == null) return true;
453         return false;
454     }
455     
456     private void addNewElementFor(SyncInfo info, ICVSRemoteResource remoteResource, ILogEntry logEntry) {
457         ISynchronizeModelElement element;
458         // If the element has a comment then group with common comment
459
if(remoteResource != null && logEntry != null && isInterestingChange(info)) {
460             ChangeLogDiffNode changeRoot = getChangeLogDiffNodeFor(logEntry);
461             if (changeRoot == null) {
462                 changeRoot = new ChangeLogDiffNode(getModelRoot(), logEntry);
463                 addToViewer(changeRoot);
464             }
465             if(requiresCustomSyncInfo(info, remoteResource, logEntry)) {
466                 info = new CVSUpdatableSyncInfo(info.getKind(), info.getLocal(), info.getBase(), (RemoteResource)logEntry.getRemoteFile(), ((CVSSyncInfo)info).getSubscriber());
467                 try {
468                     info.init();
469                 } catch (TeamException e) {
470                     // this shouldn't happen, we've provided our own calculate kind
471
}
472             }
473             element = new FullPathSyncInfoElement(changeRoot, info);
474         } else {
475             // For nodes without comments, simply parent with the root. These will be outgoing
476
// additions.
477
element = new FullPathSyncInfoElement(getModelRoot(), info);
478         }
479         addToViewer(element);
480     }
481     
482     private boolean requiresCustomSyncInfo(SyncInfo info, ICVSRemoteResource remoteResource, ILogEntry logEntry) {
483         // Only interested in non-deletions
484
if (logEntry.isDeletion() || !(info instanceof CVSSyncInfo)) return false;
485         // Only require a custom sync info if the remote of the sync info
486
// differs from the remote in the log entry
487
IResourceVariant remote = info.getRemote();
488         if (remote == null) return true;
489         return !remote.equals(remoteResource);
490     }
491
492     /*
493      * Find an existing comment set
494      * TODO: we could do better than a linear lookup?
495      */

496     private ChangeLogDiffNode getChangeLogDiffNodeFor(ILogEntry entry) {
497         IDiffElement[] elements = getModelRoot().getChildren();
498         for (int i = 0; i < elements.length; i++) {
499             IDiffElement element = elements[i];
500             if(element instanceof ChangeLogDiffNode) {
501                 ChangeLogDiffNode other = (ChangeLogDiffNode)element;
502                 ILogEntry thisLog = other.getComment();
503                 if(thisLog.getComment().equals(entry.getComment()) && thisLog.getAuthor().equals(entry.getAuthor())) {
504                     return other;
505                 }
506             }
507         }
508         return null;
509     }
510     
511     /*
512      * Return if this sync info should be considered as part of a commit set.
513      */

514     private boolean isInterestingChange(SyncInfo info) {
515         int kind = info.getKind();
516         if(info.getLocal().getType() != IResource.FILE) return false;
517         if(info.getComparator().isThreeWay()) {
518             return (kind & SyncInfo.DIRECTION_MASK) != SyncInfo.OUTGOING;
519         }
520         return true;
521     }
522
523     /**
524      * How do we tell which revision has the interesting log message? Use the later
525      * revision, since it probably has the most up-to-date comment.
526      */

527     private RemoteLogOperation getSyncInfoComment(SyncInfo[] infos, IProgressMonitor monitor) throws CVSException, InterruptedException JavaDoc {
528         List remotes = new ArrayList();
529         for (int i = 0; i < infos.length; i++) {
530             CVSSyncInfo info = (CVSSyncInfo)infos[i];
531             if (info.getLocal().getType() != IResource.FILE) {
532                 continue;
533             }
534             ICVSRemoteResource remote = getRemoteResource(info);
535             if(remote != null) {
536                 remotes.add(remote);
537             }
538         }
539         ICVSRemoteResource[] remoteResources = (ICVSRemoteResource[]) remotes.toArray(new ICVSRemoteResource[remotes.size()]);
540         if(logOperation == null) {
541             logOperation = new RemoteLogOperation(null, remoteResources, tag1, tag2);
542         }
543         if(! remotes.isEmpty()) {
544             logOperation.setRemoteResources(remoteResources);
545             logOperation.execute(monitor);
546         }
547         return logOperation;
548     }
549     
550     private ICVSRemoteResource getRemoteResource(CVSSyncInfo info) {
551         try {
552             ICVSRemoteResource remote = (ICVSRemoteResource) info.getRemote();
553             ICVSRemoteResource local = (ICVSRemoteFile) CVSWorkspaceRoot.getRemoteResourceFor(info.getLocal());
554             if(local == null) {
555                 local = (ICVSRemoteResource)info.getBase();
556             }
557
558             String JavaDoc remoteRevision = getRevisionString(remote);
559             String JavaDoc localRevision = getRevisionString(local);
560             
561             boolean useRemote = true;
562             if (local != null && remote != null) {
563                 useRemote = ResourceSyncInfo.isLaterRevision(remoteRevision, localRevision);
564             } else if (remote == null) {
565                 useRemote = false;
566             }
567             if (useRemote) {
568                 return remote;
569             } else if (local != null) {
570                 return local;
571             }
572             return null;
573         } catch (CVSException e) {
574             CVSUIPlugin.log(e);
575             return null;
576         }
577     }
578     
579     private String JavaDoc getRevisionString(ICVSRemoteResource remoteFile) {
580         if(remoteFile instanceof RemoteFile) {
581             return ((RemoteFile)remoteFile).getRevision();
582         }
583         return null;
584     }
585     
586     /* (non-Javadoc)
587      * @see org.eclipse.team.ui.synchronize.views.HierarchicalModelProvider#dispose()
588      */

589     public void dispose() {
590         shutdown = true;
591         if(fetchLogEntriesJob != null && fetchLogEntriesJob.getState() != Job.NONE) {
592             fetchLogEntriesJob.cancel();
593         }
594         sortGroup.dispose();
595         super.dispose();
596     }
597
598     /* (non-Javadoc)
599      * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#getViewerSorter()
600      */

601     public ViewerSorter getViewerSorter() {
602         int commentSort = ChangeLogModelSorter.DATE;
603         int resourceSort = ChangeLogModelSorter.PATH;
604         try {
605             IDialogSettings pageSettings = getConfiguration().getSite().getPageSettings();
606             if(pageSettings != null) {
607                 commentSort = pageSettings.getInt(P_LAST_COMMENTSORT);
608                 resourceSort = pageSettings.getInt(P_LAST_RESOURCESORT);
609             }
610         } catch(NumberFormatException JavaDoc e) {
611             // ignore and use the defaults.
612
}
613         return new ChangeLogModelSorter(commentSort, resourceSort);
614     }
615
616     /* (non-Javadoc)
617      * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#doAdd(org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement, org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement)
618      */

619     protected void doAdd(ISynchronizeModelElement parent, ISynchronizeModelElement element) {
620         AbstractTreeViewer viewer = (AbstractTreeViewer)getViewer();
621         viewer.add(parent, element);
622     }
623
624     /* (non-Javadoc)
625      * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#doRemove(org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement)
626      */

627     protected void doRemove(ISynchronizeModelElement element) {
628         AbstractTreeViewer viewer = (AbstractTreeViewer)getViewer();
629         viewer.remove(element);
630     }
631
632     /* (non-Javadoc)
633      * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#handleResourceAdditions(org.eclipse.team.core.synchronize.ISyncInfoTreeChangeEvent)
634      */

635     protected void handleResourceAdditions(ISyncInfoTreeChangeEvent event) {
636         startUpdateJob(new SyncInfoSet(event.getAddedResources()));
637     }
638
639     /* (non-Javadoc)
640      * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#handleResourceChanges(org.eclipse.team.core.synchronize.ISyncInfoTreeChangeEvent)
641      */

642     protected void handleResourceChanges(ISyncInfoTreeChangeEvent event) {
643         // Refresh the viewer for each changed resource
644
SyncInfo[] infos = event.getChangedResources();
645         for (int i = 0; i < infos.length; i++) {
646             SyncInfo info = infos[i];
647             IResource local = info.getLocal();
648             removeFromViewer(local);
649         }
650         startUpdateJob(new SyncInfoSet(event.getChangedResources()));
651     }
652
653     /* (non-Javadoc)
654      * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#handleResourceRemovals(org.eclipse.team.core.synchronize.ISyncInfoTreeChangeEvent)
655      */

656     protected void handleResourceRemovals(ISyncInfoTreeChangeEvent event) {
657         IResource[] removedRoots = event.getRemovedSubtreeRoots();
658         for (int i = 0; i < removedRoots.length; i++) {
659             removeFromViewer(removedRoots[i]);
660         }
661         // We have to look for folders that may no longer be in the set
662
// (i.e. are in-sync) but still have descendants in the set
663
IResource[] removedResources = event.getRemovedResources();
664         for (int i = 0; i < removedResources.length; i++) {
665             removeFromViewer(removedResources[i]);
666         }
667     }
668     
669     /* (non-Javadoc)
670      * @see org.eclipse.team.internal.ui.synchronize.SynchronizeModelProvider#removeFromViewer(org.eclipse.core.resources.IResource)
671      */

672     protected void removeFromViewer(IResource resource) {
673         // First clear the log history cache for the remote element
674
if (logOperation != null) {
675             ISynchronizeModelElement element = getModelObject(resource);
676             if (element instanceof FullPathSyncInfoElement) {
677                 CVSSyncInfo info = (CVSSyncInfo) ((FullPathSyncInfoElement) element).getSyncInfo();
678                 if (info != null) {
679                     ICVSRemoteResource remote = getRemoteResource(info);
680                     logOperation.clearEntriesFor(remote);
681                 }
682             }
683         }
684         // Clear the multiple element cache
685
if(multipleResourceMap != null) {
686             List elements = (List)multipleResourceMap.get(resource);
687             if(elements != null) {
688                 for (Iterator it = elements.iterator(); it.hasNext();) {
689                     ISynchronizeModelElement element = (ISynchronizeModelElement) it.next();
690                     super.removeFromViewer(element);
691                 }
692                 multipleResourceMap.remove(resource);
693             }
694         }
695         // Remove the object now
696
super.removeFromViewer(resource);
697     }
698     
699     /* (non-Javadoc)
700      * @see org.eclipse.team.internal.ui.synchronize.SynchronizeModelProvider#addToViewer(org.eclipse.team.ui.synchronize.ISynchronizeModelElement)
701      */

702     protected void addToViewer(ISynchronizeModelElement node) {
703         // Save model elements in our own mapper so that we
704
// can support multiple elements for the same resource.
705
IResource r = node.getResource();
706         if(r != null) {
707             if(multipleResourceMap == null) {
708                 multipleResourceMap = new HashMap(5);
709             }
710             List elements = (List)multipleResourceMap.get(r);
711             if(elements == null) {
712                 elements = new ArrayList(2);
713                 multipleResourceMap.put(r, elements);
714             }
715             elements.add(node);
716         }
717         // The super class will do all the interesting work.
718
super.addToViewer(node);
719     }
720 }
721
Popular Tags