Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSSynchronizeViewPage.java5
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/ChangeLogDiffNode.java21
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/ChangeLogModelProvider.java164
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CompareParticipantPage.java41
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/ISynchronizeView.java2
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/subscriber/SynchronizeViewerAdvisor.java4
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/CompressedFoldersModelProvider.java6
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/HierarchicalModelProvider.java470
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/StructuredViewerAdvisor.java210
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SynchronizeModelElement.java6
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SynchronizeModelElementLabelProvider.java3
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SynchronizeModelProvider.java414
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/TreeViewerAdvisor.java371
-rw-r--r--tests/org.eclipse.team.tests.core/plugin.xml13
14 files changed, 924 insertions, 806 deletions
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSSynchronizeViewPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSSynchronizeViewPage.java
index 5d62ed9dd..4c272d51a 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSSynchronizeViewPage.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSSynchronizeViewPage.java
@@ -88,6 +88,7 @@ public class CVSSynchronizeViewPage extends SubscriberParticipantPage implements
super.setActionBars(actionBars);
IMenuManager mgr = actionBars.getMenuManager();
mgr.add(new Separator());
+ //mgr.add(groupByComment);
}
/*
@@ -132,9 +133,7 @@ public class CVSSynchronizeViewPage extends SubscriberParticipantPage implements
private SyncInfoTree getSyncInfoSet() {
return getParticipant().getSubscriberSyncInfoCollector().getSyncInfoTree();
}
-
-
-
+
/* (non-Javadoc)
* @see org.eclipse.team.ui.synchronize.SubscriberParticipantPage#createSyncInfoSetCompareConfiguration()
*/
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/ChangeLogDiffNode.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/ChangeLogDiffNode.java
index 896f1f7fa..90d327647 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/ChangeLogDiffNode.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/ChangeLogDiffNode.java
@@ -13,20 +13,19 @@ package org.eclipse.team.internal.ccvs.ui.subscriber;
import java.text.DateFormat;
import org.eclipse.compare.structuremergeviewer.DiffNode;
+import org.eclipse.core.resources.IResource;
import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.team.core.synchronize.SyncInfo;
import org.eclipse.team.internal.ccvs.core.ILogEntry;
import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin;
import org.eclipse.team.internal.ccvs.ui.ICVSUIConstants;
-import org.eclipse.team.ui.synchronize.viewers.SyncInfoModelElement;
+import org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement;
-public class ChangeLogDiffNode extends SyncInfoModelElement {
+public class ChangeLogDiffNode extends SynchronizeModelElement {
private ILogEntry logEntry;
public ChangeLogDiffNode(DiffNode parent, ILogEntry logEntry) {
- //super(parent, new SyncInfoTree(), ResourcesPlugin.getWorkspace().getRoot());
- super(null, null);
+ super(parent);
this.logEntry = logEntry;
}
@@ -54,10 +53,6 @@ public class ChangeLogDiffNode extends SyncInfoModelElement {
String date = DateFormat.getDateTimeInstance().format(logEntry.getDate());
return date + ": " + logEntry.getComment() + " (" + logEntry.getAuthor() +")";
}
-
- public void add(SyncInfo info) {
- //((SubscriberSyncInfoSet)getSyncInfoTree()).add(info);
- }
/* (non-Javadoc)
* @see org.eclipse.team.ui.synchronize.SyncInfoModelElement#toString()
@@ -65,4 +60,12 @@ public class ChangeLogDiffNode extends SyncInfoModelElement {
public String toString() {
return getLabel(null);
}
+
+ /* (non-Javadoc)
+ * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement#getResource()
+ */
+ public IResource getResource() {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/ChangeLogModelProvider.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/ChangeLogModelProvider.java
index 26cea8ed0..ae1924d85 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/ChangeLogModelProvider.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/ChangeLogModelProvider.java
@@ -12,12 +12,12 @@ package org.eclipse.team.internal.ccvs.ui.subscriber;
import java.util.*;
+import org.eclipse.compare.structuremergeviewer.IDiffContainer;
import org.eclipse.compare.structuremergeviewer.IDiffElement;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.Job;
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.*;
import org.eclipse.team.core.synchronize.*;
import org.eclipse.team.internal.ccvs.core.*;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
@@ -25,7 +25,6 @@ import org.eclipse.team.internal.ccvs.core.resources.RemoteFile;
import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin;
import org.eclipse.team.ui.synchronize.viewers.*;
-import org.eclipse.ui.model.IWorkbenchAdapter;
import org.eclipse.ui.progress.UIJob;
/**
@@ -40,10 +39,9 @@ import org.eclipse.ui.progress.UIJob;
*
* {date/time, comment, user} -> {*files}
*/
-public class ChangeLogModelProvider extends HierarchicalModelProvider {
+public class ChangeLogModelProvider extends SynchronizeModelProvider {
private Map commentRoots = new HashMap();
- private PendingUpdateAdapter pendingItem;
private boolean shutdown = false;
private FetchLogEntriesJob fetchLogEntriesJob;
@@ -85,54 +83,12 @@ public class ChangeLogModelProvider extends HierarchicalModelProvider {
}
}
- /**
- * The PendingUpdateAdapter is a convenience object that can be used
- * by a BaseWorkbenchContentProvider that wants to show a pending update.
- */
- public static class PendingUpdateAdapter implements IWorkbenchAdapter, IAdaptable {
-
- /**
- * Create a new instance of the receiver.
- */
- public PendingUpdateAdapter() {
- //No initial behavior
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
- */
- public Object getAdapter(Class adapter) {
- if (adapter == IWorkbenchAdapter.class)
- return this;
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ui.model.IWorkbenchAdapter#getChildren(java.lang.Object)
- */
- public Object[] getChildren(Object o) {
- return new Object[0];
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ui.model.IWorkbenchAdapter#getImageDescriptor(java.lang.Object)
- */
- public ImageDescriptor getImageDescriptor(Object object) {
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ui.model.IWorkbenchAdapter#getLabel(java.lang.Object)
- */
- public String getLabel(Object o) {
- return "Fetching logs from server. Please wait...";
+ public static class FullPathSyncInfoElement extends SyncInfoModelElement {
+ public FullPathSyncInfoElement(IDiffContainer parent, SyncInfo info) {
+ super(parent, info);
}
-
- /* (non-Javadoc)
- * @see org.eclipse.ui.model.IWorkbenchAdapter#getParent(java.lang.Object)
- */
- public Object getParent(Object o) {
- return null;
+ public String getName() {
+ return getResource().getFullPath().toString();
}
}
@@ -146,17 +102,11 @@ public class ChangeLogModelProvider extends HierarchicalModelProvider {
}
public IStatus run(IProgressMonitor monitor) {
if (set != null && !shutdown) {
- final SyncInfoModelElement[] nodes = calculateRoots(getSyncInfoTree(), monitor);
+ final SynchronizeModelElement[] nodes = calculateRoots(getSyncInfoSet(), monitor);
UIJob updateUI = new UIJob("updating change log viewers") {
public IStatus runInUIThread(IProgressMonitor monitor) {
- AbstractTreeViewer tree = getTreeViewer();
- if(pendingItem != null && tree != null && !tree.getControl().isDisposed()) {
- tree.remove(pendingItem);
- }
- for (int i = 0; i < nodes.length; i++) {
- addToViewer(nodes[i]);
- buildModelObjects(nodes[i]);
- }
+ StructuredViewer tree = getViewer();
+ tree.refresh();
return Status.OK_STATUS;
}
};
@@ -167,7 +117,7 @@ public class ChangeLogModelProvider extends HierarchicalModelProvider {
}
};
- public ChangeLogModelProvider(SyncInfoTree set) {
+ public ChangeLogModelProvider(SyncInfoSet set) {
super(set);
}
@@ -176,25 +126,7 @@ public class ChangeLogModelProvider extends HierarchicalModelProvider {
* @see org.eclipse.team.ui.synchronize.viewers.HierarchicalModelProvider#buildModelObjects(org.eclipse.compare.structuremergeviewer.DiffNode)
*/
protected IDiffElement[] buildModelObjects(SynchronizeModelElement node) {
- /*if(node == this) {
- UIJob job = new UIJob("") {
- public IStatus runInUIThread(IProgressMonitor monitor) {
- AbstractTreeViewer tree = getTreeViewer();
- if (tree != null && !tree.getControl().isDisposed()) {
- if(pendingItem == null) {
- pendingItem = new PendingUpdateAdapter();
- }
- IDiffElement[] elements = getChildren();
- for (int i = 0; i < elements.length; i++) {
- tree.remove(elements[i]);
- }
- tree.add(ChangeLogViewerInput.this, pendingItem);
- }
- return Status.OK_STATUS;
- }
- };
- job.schedule();
-
+ if(node == getModelRoot()) {
if(fetchLogEntriesJob == null) {
fetchLogEntriesJob = new FetchLogEntriesJob();
}
@@ -205,17 +137,15 @@ public class ChangeLogModelProvider extends HierarchicalModelProvider {
} catch (InterruptedException e) {
}
}
- fetchLogEntriesJob.setSyncInfoSet(getSyncInfoTree());
+ fetchLogEntriesJob.setSyncInfoSet(getSyncInfoSet());
fetchLogEntriesJob.schedule();
- } else {
- return super.buildModelObjects(node);
- }*/
+ }
return new IDiffElement[0];
}
- private SyncInfoModelElement[] calculateRoots(SyncInfoSet set, IProgressMonitor monitor) {
+ private SynchronizeModelElement[] calculateRoots(SyncInfoSet set, IProgressMonitor monitor) {
commentRoots.clear();
- /*SyncInfo[] infos = set.getSyncInfos();
+ SyncInfo[] infos = set.getSyncInfos();
monitor.beginTask("fetching from server", set.size() * 100);
for (int i = 0; i < infos.length; i++) {
if(monitor.isCanceled()) {
@@ -226,13 +156,15 @@ public class ChangeLogModelProvider extends HierarchicalModelProvider {
DateComment dateComment = new DateComment(logEntry.getDate(), logEntry.getComment(), logEntry.getAuthor());
ChangeLogDiffNode changeRoot = (ChangeLogDiffNode) commentRoots.get(dateComment);
if (changeRoot == null) {
- changeRoot = new ChangeLogDiffNode(this, logEntry);
+ changeRoot = new ChangeLogDiffNode(getModelRoot(), logEntry);
commentRoots.put(dateComment, changeRoot);
}
- changeRoot.add(infos[i]);
+ SynchronizeModelElement element = new FullPathSyncInfoElement(changeRoot, infos[i]);
+ associateDiffNode(element);
+ changeRoot.add(element);
}
monitor.worked(100);
- }*/
+ }
return (ChangeLogDiffNode[]) commentRoots.values().toArray(new ChangeLogDiffNode[commentRoots.size()]);
}
@@ -253,6 +185,7 @@ public class ChangeLogModelProvider extends HierarchicalModelProvider {
String baseRevision = getRevisionString(base);
String remoteRevision = getRevisionString(remote);
String localRevision = getRevisionString(local);
+
// TODO: handle new files where there is no local or remote
boolean useRemote = true;
if(local != null && remote != null) {
@@ -280,13 +213,6 @@ public class ChangeLogModelProvider extends HierarchicalModelProvider {
}
/* (non-Javadoc)
- * @see org.eclipse.team.ui.synchronize.views.HierarchicalModelProvider#syncSetChanged(org.eclipse.team.core.subscribers.ISyncInfoSetChangeEvent)
- */
- protected void syncSetChanged(ISyncInfoSetChangeEvent event) {
- reset();
- }
-
- /* (non-Javadoc)
* @see org.eclipse.team.ui.synchronize.views.HierarchicalModelProvider#dispose()
*/
public void dispose() {
@@ -296,4 +222,48 @@ public class ChangeLogModelProvider extends HierarchicalModelProvider {
}
super.dispose();
}
+
+ /* (non-Javadoc)
+ * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#getViewerSorter()
+ */
+ public ViewerSorter getViewerSorter() {
+ return new SynchronizeModelElementSorter();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#doAdd(org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement, org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement)
+ */
+ protected void doAdd(SynchronizeModelElement parent, SynchronizeModelElement element) {
+ AbstractTreeViewer viewer = (AbstractTreeViewer)getViewer();
+ viewer.add(parent, element);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#doRemove(org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement)
+ */
+ protected void doRemove(SynchronizeModelElement element) {
+ AbstractTreeViewer viewer = (AbstractTreeViewer)getViewer();
+ viewer.remove(element);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#handleResourceAdditions(org.eclipse.team.core.synchronize.ISyncInfoTreeChangeEvent)
+ */
+ protected void handleResourceAdditions(ISyncInfoTreeChangeEvent event) {
+ reset();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#handleResourceChanges(org.eclipse.team.core.synchronize.ISyncInfoTreeChangeEvent)
+ */
+ protected void handleResourceChanges(ISyncInfoTreeChangeEvent event) {
+ reset();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#handleResourceRemovals(org.eclipse.team.core.synchronize.ISyncInfoTreeChangeEvent)
+ */
+ protected void handleResourceRemovals(ISyncInfoTreeChangeEvent event) {
+ reset();
+ }
}
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CompareParticipantPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CompareParticipantPage.java
index 30ef265d1..8c1f9e5d8 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CompareParticipantPage.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CompareParticipantPage.java
@@ -13,19 +13,44 @@ package org.eclipse.team.internal.ccvs.ui.subscriber;
import org.eclipse.jface.action.*;
import org.eclipse.team.internal.ui.synchronize.actions.RemoveSynchronizeParticipantAction;
import org.eclipse.team.ui.synchronize.ISynchronizeView;
-import org.eclipse.team.ui.synchronize.subscriber.DirectionFilterActionGroup;
import org.eclipse.team.ui.synchronize.subscriber.SubscriberParticipant;
+import org.eclipse.team.ui.synchronize.subscriber.SynchronizeViewerAdvisor;
+import org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider;
import org.eclipse.ui.IActionBars;
public class CompareParticipantPage extends CVSSynchronizeViewPage {
private RemoveSynchronizeParticipantAction removeAction;
- private DirectionFilterActionGroup modes;
- private Action updateAdapter;
+ private Action groupByCommentAction;
+ private boolean groupByComment = true;
+ private class CompareAdvisor extends CVSSynchronizeViewerAdvisor {
+ public CompareAdvisor(ISynchronizeView view, SubscriberParticipant participant) {
+ super(view, participant);
+ }
+
+ protected SynchronizeModelProvider getModelProvider() {
+ if (groupByComment) {
+ return new ChangeLogModelProvider(getSyncInfoSet());
+ }
+ return super.getModelProvider();
+ }
+
+ public void refreshModel() {
+ setInput(getViewer());
+ }
+ }
+
public CompareParticipantPage(SubscriberParticipant participant, ISynchronizeView view) {
super(participant, view);
removeAction = new RemoveSynchronizeParticipantAction(getParticipant());
+ groupByCommentAction = new Action("Show as Change Log", Action.AS_CHECK_BOX) { //$NON-NLS-1$
+ public void run() {
+ groupByComment = ! groupByComment;
+ setChecked(groupByComment);
+ ((CompareAdvisor)CompareParticipantPage.this.getViewerConfiguration()).refreshModel();
+ }
+ };
}
/* (non-Javadoc)
@@ -37,6 +62,16 @@ public class CompareParticipantPage extends CVSSynchronizeViewPage {
IToolBarManager toolbar = actionBars.getToolBarManager();
toolbar.add(new Separator());
toolbar.add(removeAction);
+ IMenuManager mgr = actionBars.getMenuManager();
+ mgr.add(new Separator());
+ mgr.add(groupByCommentAction);
}
}
+
+ /* (non-Javadoc)
+ * @see org.eclipse.team.internal.ccvs.ui.subscriber.CVSSynchronizeViewPage#createSynchronizeViewerAdvisor()
+ */
+ protected SynchronizeViewerAdvisor createSynchronizeViewerAdvisor() {
+ return new CompareAdvisor(getSynchronizeView(), getParticipant());
+ }
}
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/ISynchronizeView.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/ISynchronizeView.java
index 0fdf85d87..387158033 100644
--- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/ISynchronizeView.java
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/ISynchronizeView.java
@@ -21,7 +21,7 @@ import org.eclipse.ui.IViewPart;
* <p>
* Clients should not add viewActions to this view because they will be global
* to all participants. Instead, add participant specific actions as described
- * in {@link TreeViewerAdvisor}.
+ * in {@link StructuredViewerAdvisor}.
* </p>
* <p>
* Clients are not intended to implement this interface.
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/subscriber/SynchronizeViewerAdvisor.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/subscriber/SynchronizeViewerAdvisor.java
index 364a98827..31a3d86ba 100644
--- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/subscriber/SynchronizeViewerAdvisor.java
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/subscriber/SynchronizeViewerAdvisor.java
@@ -80,13 +80,13 @@ public class SynchronizeViewerAdvisor extends TreeViewerAdvisor {
protected void initializeListeners(StructuredViewer viewer) {
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
- public void selectionChanged(SelectionChangedEvent event) {
+ public void selectionChanged(SelectionChangedEvent event) {
updateStatusLine((IStructuredSelection) event.getSelection());
}
});
viewer.addOpenListener(new IOpenListener() {
- public void open(OpenEvent event) {
+ public void open(OpenEvent event) {
handleOpen();
}
});
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/CompressedFoldersModelProvider.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/CompressedFoldersModelProvider.java
index 2480c5f61..0a02d8a62 100644
--- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/CompressedFoldersModelProvider.java
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/CompressedFoldersModelProvider.java
@@ -92,7 +92,7 @@ public class CompressedFoldersModelProvider extends HierarchicalModelProvider {
*/
protected IDiffElement[] createModelObjects(SynchronizeModelElement container) {
IResource resource = null;
- if (container == getRoot()) {
+ if (container == getModelRoot()) {
resource = ResourcesPlugin.getWorkspace().getRoot();
} else {
resource = container.getResource();
@@ -193,7 +193,7 @@ public class CompressedFoldersModelProvider extends HierarchicalModelProvider {
if (parentNode == null) {
SynchronizeModelElement projectNode = getModelObject(local.getProject());
if (projectNode == null) {
- projectNode = createModelObject(getRoot(), local.getProject());
+ projectNode = createModelObject(getModelRoot(), local.getProject());
}
if (local.getParent().getType() == IResource.PROJECT) {
parentNode = projectNode;
@@ -205,7 +205,7 @@ public class CompressedFoldersModelProvider extends HierarchicalModelProvider {
} else {
SynchronizeModelElement projectNode = getModelObject(local.getProject());
if (projectNode == null) {
- projectNode = createModelObject(getRoot(), local.getProject());
+ projectNode = createModelObject(getModelRoot(), local.getProject());
}
createModelObject(projectNode, local);
}
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/HierarchicalModelProvider.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/HierarchicalModelProvider.java
index 873abbbae..a537e8da4 100644
--- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/HierarchicalModelProvider.java
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/HierarchicalModelProvider.java
@@ -10,26 +10,12 @@
*******************************************************************************/
package org.eclipse.team.ui.synchronize.viewers;
-import java.util.*;
-
-import org.eclipse.compare.structuremergeviewer.IDiffContainer;
import org.eclipse.compare.structuremergeviewer.IDiffElement;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.*;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.jface.util.IPropertyChangeListener;
-import org.eclipse.jface.util.PropertyChangeEvent;
-import org.eclipse.jface.viewers.*;
-import org.eclipse.swt.custom.BusyIndicator;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.team.core.ITeamStatus;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.team.core.synchronize.*;
-import org.eclipse.team.internal.core.Assert;
-import org.eclipse.team.internal.ui.TeamUIPlugin;
-import org.eclipse.ui.progress.UIJob;
-import org.eclipse.team.internal.ui.Policy;
/**
* An input that can be used with both {@link } and
@@ -47,72 +33,8 @@ import org.eclipse.team.internal.ui.Policy;
* NOT ON DEMAND - model is created then maintained!
* @since 3.0
*/
-public class HierarchicalModelProvider extends SynchronizeModelProvider implements ISyncInfoSetChangeListener {
-
- // Map from resources to model objects. This allows effecient lookup
- // of model objects based on changes occuring to resources.
- private Map resourceMap = Collections.synchronizedMap(new HashMap());
-
- // The viewer this input is being displayed in
- private AbstractTreeViewer viewer;
-
- // Flasg to indicate if tree control should be updated while
- // building the model.
- private boolean refreshViewer;
-
- private RootDiffNode root;
-
- private SyncInfoTree set;
-
- private Set pendingLabelUpdates = new HashSet();
-
- private LabelUpdateJob labelUpdater = new LabelUpdateJob();
-
- class LabelUpdateJob extends UIJob {
- public static final int BATCH_WAIT_INCREMENT = 100;
- Set nodes = new HashSet();
- public LabelUpdateJob() {
- super(Policy.bind("HierarchicalModelProvider.0")); //$NON-NLS-1$
- setSystem(true);
- }
- public IStatus runInUIThread(IProgressMonitor monitor) {
- Object[] updates;
- synchronized(nodes) {
- updates = nodes.toArray(new Object[nodes.size()]);
- nodes.clear();
- }
- if (canUpdateViewer()) {
- AbstractTreeViewer tree = getTreeViewer();
- tree.update(updates, null);
- }
- schedule(BATCH_WAIT_INCREMENT);
- return Status.OK_STATUS;
- }
- public void add(Object node, boolean isBusy) {
- synchronized(nodes) {
- nodes.add(node);
- }
- if (isBusy) {
- schedule(BATCH_WAIT_INCREMENT);
- } else {
- // Wait when unbusying to give the events a chance to propogate through
- // the collector
- schedule(BATCH_WAIT_INCREMENT * 10);
- }
- }
- public boolean shouldRun() {
- return !nodes.isEmpty();
- }
- }
-
- private IPropertyChangeListener listener = new IPropertyChangeListener() {
- public void propertyChange(final PropertyChangeEvent event) {
- if (event.getProperty() == SynchronizeModelElement.BUSY_PROPERTY) {
- labelUpdater.add(event.getSource(), ((Boolean)event.getNewValue()).booleanValue());
- }
- }
- };
-
+public class HierarchicalModelProvider extends SynchronizeModelProvider {
+
/**
* Create an input based on the provide sync set. The input is not initialized
* until <code>prepareInput</code> is called.
@@ -120,98 +42,15 @@ public class HierarchicalModelProvider extends SynchronizeModelProvider implemen
* @param set the sync set used as the basis for the model created by this input.
*/
public HierarchicalModelProvider(SyncInfoTree set) {
- Assert.isNotNull(set);
- this.root = new RootDiffNode();
- this.set = set;
- }
-
- /**
- * Return the model object (i.e. an instance of <code>SyncInfoModelElement</code>
- * or one of its subclasses) for the given IResource.
- * @param resource
- * the resource
- * @return the <code>SyncInfoModelElement</code> for the given resource
- */
- protected SynchronizeModelElement getModelObject(IResource resource) {
- return (SynchronizeModelElement) resourceMap.get(resource);
- }
-
- /**
- * Return the <code>AbstractTreeViewer</code> asociated with this content
- * provider or <code>null</code> if the viewer is not of the proper type.
- * @return
- */
- public AbstractTreeViewer getTreeViewer() {
- return viewer;
- }
-
- public void setViewer(StructuredViewer viewer) {
- Assert.isTrue(viewer instanceof AbstractTreeViewer);
- this.viewer = (AbstractTreeViewer)viewer;
+ super(set);
}
public ViewerSorter getViewerSorter() {
return new SynchronizeModelElementSorter();
}
- /**
- * Builds the viewer model based on the contents of the sync set.
- */
- public SynchronizeModelElement prepareInput(IProgressMonitor monitor) {
- // Connect to the sync set which will register us as a listener and give us a reset event
- // in a background thread
- getSyncInfoTree().connect(this, monitor);
- return getRoot();
- }
-
- /**
- * Dispose of the builder
- */
- public void dispose() {
- resourceMap.clear();
- getSyncInfoTree().removeSyncSetChangedListener(this);
- }
-
- /*
- * (non-Javadoc)
- * @see org.eclipse.team.ccvs.syncviews.views.ISyncSetChangedListener#syncSetChanged()
- */
- public void syncInfoChanged(final ISyncInfoSetChangeEvent event, IProgressMonitor monitor) {
- if (! (event instanceof ISyncInfoTreeChangeEvent)) {
- reset();
- } else {
- final Control ctrl = viewer.getControl();
- if (ctrl != null && !ctrl.isDisposed()) {
- ctrl.getDisplay().syncExec(new Runnable() {
- public void run() {
- if (!ctrl.isDisposed()) {
- BusyIndicator.showWhile(ctrl.getDisplay(), new Runnable() {
- public void run() {
- handleChanges((ISyncInfoTreeChangeEvent)event);
- getRoot().fireChanges();
- }
- });
- }
- }
- });
- }
- }
- }
-
- /**
- * For each node create children based on the contents of
- * @param node
- * @return
- */
- protected IDiffElement[] buildModelObjects(SynchronizeModelElement node) {
- IDiffElement[] children = createModelObjects(node);
- for (int i = 0; i < children.length; i++) {
- IDiffElement element = children[i];
- if (element instanceof SynchronizeModelElement) {
- buildModelObjects((SynchronizeModelElement) element);
- }
- }
- return children;
+ protected SyncInfoTree getSyncInfoTree() {
+ return (SyncInfoTree)getSyncInfoSet();
}
/**
@@ -223,7 +62,7 @@ public class HierarchicalModelProvider extends SynchronizeModelProvider implemen
*/
protected IDiffElement[] createModelObjects(SynchronizeModelElement container) {
IResource resource = null;
- if (container == getRoot()) {
+ if (container == getModelRoot()) {
resource = ResourcesPlugin.getWorkspace().getRoot();
} else {
resource = container.getResource();
@@ -253,32 +92,6 @@ public class HierarchicalModelProvider extends SynchronizeModelProvider implemen
}
/**
- * Clear the model objects from the diff tree, cleaning up any cached state
- * (such as resource to model object map). This method recurses deeply on
- * the tree to allow the cleanup of any cached state for the children as
- * well.
- * @param node
- * the root node
- */
- protected void clearModelObjects(SynchronizeModelElement node) {
- IDiffElement[] children = node.getChildren();
- for (int i = 0; i < children.length; i++) {
- IDiffElement element = children[i];
- if (element instanceof SynchronizeModelElement) {
- clearModelObjects((SynchronizeModelElement) element);
- }
- }
- IResource resource = node.getResource();
- if (resource != null) {
- unassociateDiffNode(resource);
- }
- IDiffContainer parent = node.getParent();
- if (parent != null) {
- parent.removeToRoot(node);
- }
- }
-
- /**
* Invokes <code>getModelObject(Object)</code> on an array of resources.
* @param resources
* the resources
@@ -292,70 +105,6 @@ public class HierarchicalModelProvider extends SynchronizeModelProvider implemen
return result;
}
- protected void associateDiffNode(SynchronizeModelElement node) {
- IResource resource = node.getResource();
- if(resource != null) {
- resourceMap.put(resource, node);
- }
- }
-
- protected void unassociateDiffNode(IResource resource) {
- resourceMap.remove(resource);
- }
-
- /**
- * Handle the changes made to the viewer's <code>SyncInfoSet</code>.
- * This method delegates the changes to the three methods <code>handleResourceChanges(ISyncInfoSetChangeEvent)</code>,
- * <code>handleResourceRemovals(ISyncInfoSetChangeEvent)</code> and
- * <code>handleResourceAdditions(ISyncInfoSetChangeEvent)</code>.
- * @param event
- * the event containing the changed resourcses.
- */
- protected void handleChanges(ISyncInfoTreeChangeEvent event) {
- try {
- viewer.getControl().setRedraw(false);
- handleResourceChanges(event);
- handleResourceRemovals(event);
- handleResourceAdditions(event);
- firePendingLabelUpdates();
- } finally {
- viewer.getControl().setRedraw(true);
- }
- }
-
- /**
- * Update the viewer for the sync set additions in the provided event. This
- * method is invoked by <code>handleChanges(ISyncInfoSetChangeEvent)</code>.
- * Subclasses may override.
- * @param event
- */
- protected void handleResourceAdditions(ISyncInfoTreeChangeEvent event) {
- IResource[] added = event.getAddedSubtreeRoots();
- addResources(added);
- }
-
- /**
- * Update the viewer for the sync set changes in the provided event. This
- * method is invoked by <code>handleChanges(ISyncInfoSetChangeEvent)</code>.
- * Subclasses may override.
- * @param event
- */
- protected void handleResourceChanges(ISyncInfoTreeChangeEvent event) {
- // Refresh the viewer for each changed resource
- SyncInfo[] infos = event.getChangedResources();
- for (int i = 0; i < infos.length; i++) {
- SyncInfo info = infos[i];
- IResource local = info.getLocal();
- SynchronizeModelElement diffNode = getModelObject(local);
- // If a sync info diff node already exists then just update
- // it, otherwise remove the old diff node and create a new
- // sub-tree.
- if (diffNode != null) {
- handleChange(diffNode, info);
- }
- }
- }
-
/**
* Handle the change for the existing diff node. The diff node
* should be changed to have the given sync info
@@ -383,107 +132,6 @@ public class HierarchicalModelProvider extends SynchronizeModelProvider implemen
// TODO: set any additional sync info bits
}
- protected boolean isConflicting(SynchronizeModelElement diffNode) {
- return (diffNode.getKind() & SyncInfo.DIRECTION_MASK) == SyncInfo.CONFLICTING;
- }
-
- /**
- * Update the viewer for the sync set removals in the provided event. This
- * method is invoked by <code>handleChanges(ISyncInfoSetChangeEvent)</code>.
- * Subclasses may override.
- * @param event
- */
- protected void handleResourceRemovals(ISyncInfoTreeChangeEvent event) {
- // Remove the removed subtrees
- IResource[] removedRoots = event.getRemovedSubtreeRoots();
- for (int i = 0; i < removedRoots.length; i++) {
- removeFromViewer(removedRoots[i]);
- }
- // We have to look for folders that may no longer be in the set
- // (i.e. are in-sync) but still have descendants in the set
- IResource[] removedResources = event.getRemovedResources();
- for (int i = 0; i < removedResources.length; i++) {
- IResource resource = removedResources[i];
- if (resource.getType() != IResource.FILE) {
- SynchronizeModelElement node = getModelObject(resource);
- if (node != null) {
- removeFromViewer(resource);
- addResources(new IResource[] {resource});
- }
- }
- }
- }
-
- protected void reset() {
- try {
- refreshViewer = false;
-
- // Clear existing model, but keep the root node
- resourceMap.clear();
- clearModelObjects(getRoot());
- // remove all from tree viewer
- IDiffElement[] elements = getRoot().getChildren();
- for (int i = 0; i < elements.length; i++) {
- viewer.remove(elements[i]);
- }
-
- // Rebuild the model
- associateDiffNode(getRoot());
- buildModelObjects(getRoot());
-
- // Notify listeners that model has changed
- getRoot().fireChanges();
- } finally {
- refreshViewer = true;
- }
- TeamUIPlugin.getStandardDisplay().asyncExec(new Runnable() {
- public void run() {
- if (viewer != null && !viewer.getControl().isDisposed()) {
- viewer.refresh();
- }
- }
- });
- }
-
- protected RootDiffNode getRoot() {
- return root;
- }
-
- protected SyncInfoTree getSyncInfoTree() {
- return set;
- }
-
- /**
- * Remove any traces of the resource and any of it's descendants in the
- * hiearchy defined by the content provider from the content provider and
- * the viewer it is associated with.
- * @param resource
- */
- protected void removeFromViewer(IResource resource) {
- SynchronizeModelElement node = getModelObject(resource);
- if (node == null) return;
- if (isConflicting(node)) {
- setParentConflict(node, false);
- }
- clearModelObjects(node);
- if (canUpdateViewer()) {
- AbstractTreeViewer tree = getTreeViewer();
- tree.remove(node);
- }
- }
-
- protected void addToViewer(SynchronizeModelElement node) {
- associateDiffNode(node);
- node.addPropertyChangeListener(listener);
- if (isConflicting(node)) {
- setParentConflict(node, true);
- }
- if (canUpdateViewer()) {
- AbstractTreeViewer tree = getTreeViewer();
- tree.add(node.getParent(), node);
- }
- }
-
protected void addResources(IResource[] added) {
for (int i = 0; i < added.length; i++) {
IResource resource = added[i];
@@ -501,70 +149,82 @@ public class HierarchicalModelProvider extends SynchronizeModelProvider implemen
}
}
}
-
- /**
- * @param tree
- * @return
- */
- private boolean canUpdateViewer() {
- return refreshViewer && getTreeViewer() != null;
- }
/* (non-Javadoc)
- * @see org.eclipse.team.core.subscribers.ISyncInfoSetChangeListener#syncInfoSetReset(org.eclipse.team.core.subscribers.SyncInfoSet, org.eclipse.core.runtime.IProgressMonitor)
+ * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#buildModelObjects(org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement)
*/
- public void syncInfoSetReset(SyncInfoSet set, IProgressMonitor monitor) {
- reset();
+ protected IDiffElement[] buildModelObjects(SynchronizeModelElement node) {
+ IDiffElement[] children = createModelObjects(node);
+ for (int i = 0; i < children.length; i++) {
+ IDiffElement element = children[i];
+ if (element instanceof SynchronizeModelElement) {
+ buildModelObjects((SynchronizeModelElement) element);
+ }
+ }
+ return children;
}
/* (non-Javadoc)
- * @see org.eclipse.team.core.subscribers.ISyncInfoSetChangeListener#syncInfoSetError(org.eclipse.team.core.subscribers.SyncInfoSet, org.eclipse.team.core.ITeamStatus[], org.eclipse.core.runtime.IProgressMonitor)
+ * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#doAdd(org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement, org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement)
*/
- public void syncInfoSetErrors(SyncInfoSet set, ITeamStatus[] errors, IProgressMonitor monitor) {
- // TODO Auto-generated method stub
+ protected void doAdd(SynchronizeModelElement parent, SynchronizeModelElement element) {
+ AbstractTreeViewer viewer = (AbstractTreeViewer)getViewer();
+ viewer.add(parent, element);
}
/* (non-Javadoc)
- * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#getInput()
+ * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#doRemove(org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement)
*/
- public SynchronizeModelElement getInput() {
- return getRoot();
+ protected void doRemove(SynchronizeModelElement element) {
+ AbstractTreeViewer viewer = (AbstractTreeViewer)getViewer();
+ viewer.remove(element);
}
-
- /**
- * Update the label of the given diff node. Diff nodes
- * are accumulated and updated in a single call.
- * @param diffNode the diff node to be updated
+
+ /* (non-Javadoc)
+ * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#handleResourceAdditions(org.eclipse.team.core.synchronize.ISyncInfoTreeChangeEvent)
*/
- protected void updateLabel(SynchronizeModelElement diffNode) {
- pendingLabelUpdates.add(diffNode);
+ protected void handleResourceAdditions(ISyncInfoTreeChangeEvent event) {
+ IResource[] added = event.getAddedSubtreeRoots();
+ addResources(added);
}
- /**
- * Forces the viewer to update the labels for parents whose children have
- * changed during this round of sync set changes.
+ /* (non-Javadoc)
+ * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#handleResourceChanges(org.eclipse.team.core.synchronize.ISyncInfoTreeChangeEvent)
*/
- protected void firePendingLabelUpdates() {
- try {
- if (canUpdateViewer()) {
- AbstractTreeViewer tree = getTreeViewer();
- tree.update(pendingLabelUpdates.toArray(new Object[pendingLabelUpdates.size()]), null);
+ protected void handleResourceChanges(ISyncInfoTreeChangeEvent event) {
+ // Refresh the viewer for each changed resource
+ SyncInfo[] infos = event.getChangedResources();
+ for (int i = 0; i < infos.length; i++) {
+ SyncInfo info = infos[i];
+ IResource local = info.getLocal();
+ SynchronizeModelElement diffNode = getModelObject(local);
+ if (diffNode != null) {
+ handleChange(diffNode, info);
}
- } finally {
- pendingLabelUpdates.clear();
- }
+ }
}
- protected void setParentConflict(SynchronizeModelElement diffNode, boolean value) {
- diffNode.setPropertyToRoot(SynchronizeModelElement.PROPAGATED_CONFLICT_PROPERTY, value);
- updateParentLabels(diffNode);
- }
-
- private void updateParentLabels(SynchronizeModelElement diffNode) {
- updateLabel(diffNode);
- while (diffNode.getParent() != null) {
- diffNode = (SynchronizeModelElement)diffNode.getParent();
- updateLabel(diffNode);
+ /* (non-Javadoc)
+ * @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#handleResourceRemovals(org.eclipse.team.core.synchronize.ISyncInfoTreeChangeEvent)
+ */
+ protected void handleResourceRemovals(ISyncInfoTreeChangeEvent event) {
+ // Remove the removed subtrees
+ IResource[] removedRoots = event.getRemovedSubtreeRoots();
+ for (int i = 0; i < removedRoots.length; i++) {
+ removeFromViewer(removedRoots[i]);
+ }
+ // We have to look for folders that may no longer be in the set
+ // (i.e. are in-sync) but still have descendants in the set
+ IResource[] removedResources = event.getRemovedResources();
+ for (int i = 0; i < removedResources.length; i++) {
+ IResource resource = removedResources[i];
+ if (resource.getType() != IResource.FILE) {
+ SynchronizeModelElement node = getModelObject(resource);
+ if (node != null) {
+ removeFromViewer(resource);
+ addResources(new IResource[] {resource});
+ }
+ }
}
}
}
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/StructuredViewerAdvisor.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/StructuredViewerAdvisor.java
index 12511b87a..fa5b10140 100644
--- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/StructuredViewerAdvisor.java
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/StructuredViewerAdvisor.java
@@ -37,9 +37,12 @@ import org.eclipse.ui.internal.PluginAction;
import org.eclipse.ui.model.BaseWorkbenchContentProvider;
/**
- * A <code>StructuredViewerAdvisor</code> object controls various UI
- * aspects of viewers that show {@link SyncInfoSet} like the context menu, toolbar, content
- * provider, label provider, and model provider.
+ * A <code>StructuredViewerAdvisor</code> controls various UI
+ * aspects of viewers that show {@link SyncInfoSet} like the context menu, toolbar,
+ * content provider, label provider, navigation, and model provider. The
+ * advisor allows decoupling viewer behavior from the viewers presentation. This
+ * allows viewers that aren't in the same class hierarchy to re-use basic
+ * behavior.
* <p>
* This advisor allows viewer contributions made in a plug-in manifest to
* be scoped to a particular unique id. As a result the context menu for the
@@ -61,40 +64,55 @@ import org.eclipse.ui.model.BaseWorkbenchContentProvider;
* <li>Create a configuration instance with a <code>menuID</code> that
* matches the targetID in the viewer contribution.
* </ul>
- * <p>
- * Clients may use this class as is, or subclass to add new state and behavior.
- * The default behavior is to show sync info in a tree
+ * </p><p>
+ * Clients may subclass to add behavior for concrete structured viewers.
* </p>
+ *
+ * @see TreeViewerAdvisor
* @since 3.0
*/
public abstract class StructuredViewerAdvisor {
+
private SynchronizeModelProvider modelProvider;
private ListenerList listeners;
- private String menuId;
+ private String targetID;
private SyncInfoSet set;
private StructuredViewer viewer;
- public StructuredViewerAdvisor(String menuId, SyncInfoSet set) {
+ /**
+ * Create an advisor that will allow viewer contributions with the given <code>targetID</code>. This
+ * advisor will provide a presentation model based on the given sync info set. Note that it's important
+ * to call {@link #dispose()} when finished with an advisor.
+ *
+ * @param targetID the targetID defined in the viewer contributions in a plugin.xml file.
+ * @param set the set of <code>SyncInfo</code> objects that are to be shown to the user.
+ */
+ public StructuredViewerAdvisor(String targetID, SyncInfoSet set) {
this.set = set;
- this.menuId = menuId;
+ this.targetID = targetID;
}
+ /**
+ * Create an advisor that will provide a presentation model based on the given sync info set.
+ * Note that it's important to call {@link #dispose()} when finished with an advisor.
+ *
+ * @param set the set of <code>SyncInfo</code> objects that are to be shown to the user.
+ */
public StructuredViewerAdvisor(SyncInfoSet set) {
this(null, set);
}
/**
- * Initialize the viewer with the elements of this configuration, including
- * content and label providers, sorter, input and menus. This method is
- * invoked from the constructor of <code>SyncInfoDiffTreeViewer</code> to
- * initialize the viewers. A configuration instance may only be used with
- * one viewer.
+ * Install a viewer to be configured with this advisor. An advisor can only be installed with
+ * one viewer at a time. When this method completes the viewer is considered initialized and
+ * can be shown to the user.
- * @param viewer the viewer being initialized
+ * @param viewer the viewer being installed
*/
- public void initializeViewer(StructuredViewer viewer) {
+ public final void initializeViewer(StructuredViewer viewer) {
Assert.isTrue(this.viewer == null, "Can only be initialized once."); //$NON-NLS-1$
+ Assert.isTrue(validateViewer(viewer));
this.viewer = viewer;
initializeListeners(viewer);
@@ -112,6 +130,12 @@ public abstract class StructuredViewerAdvisor {
setInput(viewer);
}
+ /**
+ * This is called to add a listener to the model shown in the viewer. The listener is
+ * called when the model is changed or updated.
+ *
+ * @param listener the listener to add
+ */
public void addInputChangedListener(ISynchronizeModelChangeListener listener) {
if (listeners == null)
listeners= new ListenerList();
@@ -119,7 +143,20 @@ public abstract class StructuredViewerAdvisor {
}
/**
- * Cleanup listeners
+ * Remove a model listener.
+ *
+ * @param listener the listener to remove.
+ */
+ public void removeInputChangedListener(ISynchronizeModelChangeListener listener) {
+ if (listeners != null) {
+ listeners.remove(listener);
+ if (listeners.isEmpty())
+ listeners= null;
+ }
+ }
+
+ /**
+ * Must be called when an advisor is no longer needed.
*/
public void dispose() {
if(modelProvider != null) {
@@ -128,31 +165,45 @@ public abstract class StructuredViewerAdvisor {
}
/**
- * Return the menu id that is used to obtain context menu items from the
- * workbench.
- * @return the menuId.
+ * Return the targetID that is used to obtain context menu items from the workbench. When
+ * a context menu is added to the viewer, this ID is registered with the workbench to allow
+ * viewer contributions.
+ *
+ * @return the targetID or <code>null</code> if this advisor doesn't allow contributions.
*/
- public String getMenuId() {
- return menuId;
+ public String getTargetID() {
+ return targetID;
}
/**
- * Return the <code>SyncInfoSet</code> being shown by the viewer
- * associated with this configuration.
- * @return a <code>SyncInfoSet</code>
+ * Return the <code>SyncInfoSet</code> used to create the model shown by this advisor.
+ *
+ * @return the <code>SyncInfoSet</code> used to create the model shown by this advisor.
*/
public SyncInfoSet getSyncInfoSet() {
return set;
}
+ /**
+ * Subclasses must implement to allow navigation of their viewers.
+ *
+ * @param next if <code>true</code> then navigate forwards, otherwise navigate
+ * backwards.
+ * @return <code>true</code> if the end is reached, and <code>false</code> otherwise.
+ */
public abstract boolean navigate(boolean next);
/**
- * Creates the input for this view and initializes it. At the time this method
- * is called the viewer may not of been created yet.
- *
- * @param monitor shows progress while preparing the input
- * @return the input that can be shown in a viewer
+ * Creates the model that will be shown in the viewers. This can be called before the
+ * viewer has been created.
+ * <p>
+ * The result of this method can be shown used as the input to a viewer. However, the
+ * prefered method of initializing a viewer is to call {@link #initializeViewer(StructuredViewer)}
+ * directly. This method only exists when the model must be created before the
+ * viewer.
+ * </p>
+ * @param monitor shows progress while preparing the model
+ * @return the model that can be shown in a viewer
*/
public Object prepareInput(IProgressMonitor monitor) throws TeamException {
if(modelProvider != null) {
@@ -162,42 +213,16 @@ public abstract class StructuredViewerAdvisor {
return modelProvider.prepareInput(monitor);
}
- public void removeInputChangedListener(ISynchronizeModelChangeListener listener) {
- if (listeners != null) {
- listeners.remove(listener);
- if (listeners.isEmpty())
- listeners= null;
- }
- }
-
- /**
- * Method invoked from <code>initializeViewer(Composite, StructuredViewer)</code>
- * in order to initialize any listeners for the viewer.
- * @param viewer
- * the viewer being initialize
- */
- protected abstract void initializeListeners(final StructuredViewer viewer);
-
- /**
- * Get the input that will be assigned to the viewer initialized by this
- * configuration. Subclass may override.
- * @return the viewer input
- */
- protected abstract SynchronizeModelProvider getModelProvider();
-
/**
* Callback that is invoked when a context menu is about to be shown in the
* viewer. Subsclasses must implement to contribute menus. Also, menus can
* contributed by creating a viewer contribution with a <code>targetID</code>
* that groups sets of actions that are related.
*
- * @param viewer
- * the viewer
- * @param manager
- * the menu manager
+ * @param viewer the viewer in which the context menu is being shown.
+ * @param manager the menu manager to which actions can be added.
*/
protected void fillContextMenu(final StructuredViewer viewer, IMenuManager manager) {
- // subclasses will add actions
}
/**
@@ -209,20 +234,46 @@ public abstract class StructuredViewerAdvisor {
* <p>
* The default behavior is to add the up and down navigation nuttons to the
* toolbar. Subclasses can override.
- * @param viewer
- * the viewer being initialize
+ * </p>
+ * @param viewer the viewer being initialize
*/
protected void initializeActions(StructuredViewer viewer) {
}
/**
+ * Method invoked from <code>initializeViewer(Composite, StructuredViewer)</code>
+ * in order to initialize any listeners for the viewer.
+ *
+ * @param viewer the viewer being initialize
+ */
+ protected void initializeListeners(final StructuredViewer viewer) {
+ }
+
+ /**
+ * Get the input that will be assigned to the viewer initialized by this
+ * configuration. Subclass may override.
+ * @return the viewer input
+ */
+ protected abstract SynchronizeModelProvider getModelProvider();
+
+
+ /**
+ * Subclasses can validate that the viewer being initialized with this advisor
+ * is of the correct type.
+ *
+ * @param viewer the viewer to validate
+ * @return <code>true</code> if the viewer is valid, <code>false</code> otherwise.
+ */
+ protected abstract boolean validateViewer(StructuredViewer viewer);
+
+ /**
* Returns whether workbench menu items whould be included in the context
* menu. By default, this returns <code>true</code> if there is a menu id
* and <code>false</code> otherwise
* @return whether to include workbench context menu items
*/
protected boolean allowParticipantMenuContributions() {
- return getMenuId() != null;
+ return getTargetID() != null;
}
/**
@@ -236,14 +287,19 @@ public abstract class StructuredViewerAdvisor {
}
}
- protected void fireChanges() {
+ private void fireChanges() {
if (listeners != null) {
Object[] l= listeners.getListeners();
for (int i= 0; i < l.length; i++)
- ((ISynchronizeModelChangeListener) l[i]).modelChanged(modelProvider.getInput());
+ ((ISynchronizeModelChangeListener) l[i]).modelChanged(modelProvider.getModelRoot());
}
}
+ /**
+ * Returns the content provider for the viewer.
+ *
+ * @return the content provider for the viewer.
+ */
protected IStructuredContentProvider getContentProvider() {
return new BaseWorkbenchContentProvider();
}
@@ -264,20 +320,25 @@ public abstract class StructuredViewerAdvisor {
return new SynchronizeModelElementLabelProvider();
}
+ /**
+ * Returns the viewer configured by this advisor.
+ *
+ * @return the viewer configured by this advisor.
+ */
protected StructuredViewer getViewer() {
return viewer;
}
/**
- * Method invoked from <code>initializeViewer(Composite, StructuredViewer)</code>
+ * Method invoked from <code>initializeViewer(StructuredViewer)</code>
* in order to configure the viewer to call <code>fillContextMenu(StructuredViewer, IMenuManager)</code>
- * when a context menu is being displayed in the diff tree viewer.
- * @param viewer
- * the viewer being initialized
+ * when a context menu is being displayed in viewer.
+ *
+ * @param viewer the viewer being initialized
* @see fillContextMenu(StructuredViewer, IMenuManager)
*/
protected final void hookContextMenu(final StructuredViewer viewer) {
- final MenuManager menuMgr = new MenuManager(getMenuId()); //$NON-NLS-1$
+ final MenuManager menuMgr = new MenuManager(getTargetID()); //$NON-NLS-1$
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
@@ -315,23 +376,26 @@ public abstract class StructuredViewerAdvisor {
site = Utils.findSite();
}
if (site != null) {
- site.registerContextMenu(getMenuId(), menuMgr, viewer);
+ site.registerContextMenu(getTargetID(), menuMgr, viewer);
}
}
}
/**
- * @param viewer
+ * Called to set the input to a viewer. The input to a viewer is always the model created
+ * by the model provider.
+ *
+ * @param viewer the viewer to set the input.
*/
protected final void setInput(StructuredViewer viewer) {
modelProvider.setViewer(viewer);
viewer.setSorter(modelProvider.getViewerSorter());
- DiffNode input = modelProvider.getInput();
+ DiffNode input = modelProvider.getModelRoot();
input.addCompareInputChangeListener(new ICompareInputChangeListener() {
public void compareInputChanged(ICompareInput source) {
fireChanges();
}
});
- viewer.setInput(modelProvider.getInput());
+ viewer.setInput(modelProvider.getModelRoot());
}
-}
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SynchronizeModelElement.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SynchronizeModelElement.java
index 62921579a..0c05f4ace 100644
--- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SynchronizeModelElement.java
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SynchronizeModelElement.java
@@ -20,7 +20,8 @@ import org.eclipse.team.internal.ui.TeamUIPlugin;
import org.eclipse.ui.model.IWorkbenchAdapter;
/**
- * A node that represents synchronization state between elements.
+ * A model element that can be shown in viewers.
+ *
* @since 3.0
*/
public abstract class SynchronizeModelElement extends DiffNode implements IAdaptable {
@@ -102,6 +103,9 @@ public abstract class SynchronizeModelElement extends DiffNode implements IAdapt
}
}
+ public void fireChanges() {
+ fireChange();
+ }
public ImageDescriptor getImageDescriptor(Object object) {
IResource resource = getResource();
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SynchronizeModelElementLabelProvider.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SynchronizeModelElementLabelProvider.java
index 094edbd44..ca14ae936 100644
--- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SynchronizeModelElementLabelProvider.java
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SynchronizeModelElementLabelProvider.java
@@ -25,6 +25,9 @@ import org.eclipse.ui.internal.WorkbenchColors;
import org.eclipse.ui.model.WorkbenchLabelProvider;
/**
+ * A label provider that decorates viewers showing
+ * {@link org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement}.
+ *
* @since 3.0
*/
public class SynchronizeModelElementLabelProvider extends LabelProvider implements IColorProvider {
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SynchronizeModelProvider.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SynchronizeModelProvider.java
index dbda6b191..8633c6ecf 100644
--- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SynchronizeModelProvider.java
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SynchronizeModelProvider.java
@@ -10,53 +10,417 @@
*******************************************************************************/
package org.eclipse.team.ui.synchronize.viewers;
+import java.util.*;
+
+import org.eclipse.compare.structuremergeviewer.IDiffContainer;
+import org.eclipse.compare.structuremergeviewer.IDiffElement;
+import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jface.viewers.StructuredViewer;
-import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.*;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.team.core.ITeamStatus;
+import org.eclipse.team.core.synchronize.*;
+import org.eclipse.team.internal.core.Assert;
+import org.eclipse.team.internal.ui.Policy;
+import org.eclipse.team.internal.ui.TeamUIPlugin;
+import org.eclipse.ui.progress.UIJob;
/**
- * This class is reponsible for creating and maintaining model of
- * DiffNodes that can be shown in a viewer.
+ * This class is reponsible for creating and maintaining a presentation model of
+ * {@link SynchronizeModelElement} elements that can be shown in a viewer. The model
+ * is based on the synchronization information contained in the provided {@link SyncInfoSet}.
+ * <p>
+ * label updates (property propagation to parent nodes)
+ * sync change listener (changes, additions, removals, reset)
+ * batching busy updates
+ * </p>
*
+ * @see HierarchicalModelProvider
+ * @see CompressedFoldersModelProvider
* @since 3.0
*/
-public abstract class SynchronizeModelProvider {
+public abstract class SynchronizeModelProvider implements ISyncInfoSetChangeListener {
- protected class RootDiffNode extends UnchangedResourceModelElement {
- public RootDiffNode() {
- super(null, ResourcesPlugin.getWorkspace().getRoot());
+ // Flasg to indicate if tree control should be updated while
+ // building the model.
+ private boolean refreshViewer;
+
+ protected Map resourceMap = Collections.synchronizedMap(new HashMap());
+
+ protected SynchronizeModelElement root;
+
+ // The viewer this input is being displayed in
+ private StructuredViewer viewer;
+
+ private Set pendingLabelUpdates = new HashSet();
+
+ private LabelUpdateJob labelUpdater = new LabelUpdateJob();
+
+ private IPropertyChangeListener listener = new IPropertyChangeListener() {
+ public void propertyChange(final PropertyChangeEvent event) {
+ if (event.getProperty() == SynchronizeModelElement.BUSY_PROPERTY) {
+ labelUpdater.add(event.getSource(), ((Boolean)event.getNewValue()).booleanValue());
+ }
+ }
+ };
+
+ class LabelUpdateJob extends UIJob {
+ public static final int BATCH_WAIT_INCREMENT = 100;
+ Set nodes = new HashSet();
+ public LabelUpdateJob() {
+ super(Policy.bind("HierarchicalModelProvider.0")); //$NON-NLS-1$
+ setSystem(true);
+ }
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ Object[] updates;
+ synchronized(nodes) {
+ updates = nodes.toArray(new Object[nodes.size()]);
+ nodes.clear();
+ }
+ if (canUpdateViewer()) {
+ StructuredViewer tree = getViewer();
+ tree.update(updates, null);
+ }
+ schedule(BATCH_WAIT_INCREMENT);
+ return Status.OK_STATUS;
}
- public void fireChanges() {
- fireChange();
+ public void add(Object node, boolean isBusy) {
+ synchronized(nodes) {
+ nodes.add(node);
+ }
+ if (isBusy) {
+ schedule(BATCH_WAIT_INCREMENT);
+ } else {
+ // Wait when unbusying to give the events a chance to propogate through
+ // the collector
+ schedule(BATCH_WAIT_INCREMENT * 10);
+ }
}
- public boolean hasChildren() {
- // This is required to allow the sync framework to be used in wizards
- // where the input is not populated until after the compare input is
- // created
- // (i.e. the compare input will only create the diff viewer if the
- // input has children
- return true;
+ public boolean shouldRun() {
+ return !nodes.isEmpty();
}
}
+ private SyncInfoSet set;
+
/**
- * Called to initialize this controller and returns the input created by this controller.
- * @param monitor
+ * Create an input based on the provide sync set. The input is not
+ * initialized until <code>prepareInput</code> is called.
+ * @param set
+ * the sync set used as the basis for the model created by this
+ * input.
+ */
+ public SynchronizeModelProvider(SyncInfoSet set) {
+ this(new UnchangedResourceModelElement(null, ResourcesPlugin.getWorkspace().getRoot()), set);
+ }
+
+ public SynchronizeModelProvider(SynchronizeModelElement parent, SyncInfoSet set) {
+ Assert.isNotNull(set);
+ Assert.isNotNull(parent);
+ this.root = parent;
+ this.set = set;
+ }
+
+ public SyncInfoSet getSyncInfoSet() {
+ return set;
+ }
+
+ /**
+ * Return the <code>AbstractTreeViewer</code> asociated with this content
+ * provider or <code>null</code> if the viewer is not of the proper type.
* @return
*/
- public abstract SynchronizeModelElement prepareInput(IProgressMonitor monitor);
+ public StructuredViewer getViewer() {
+ return viewer;
+ }
+
+ public void setViewer(StructuredViewer viewer) {
+ Assert.isTrue(viewer instanceof AbstractTreeViewer);
+ this.viewer = (AbstractTreeViewer) viewer;
+ }
+
+ /**
+ * Builds the viewer model based on the contents of the sync set.
+ */
+ public SynchronizeModelElement prepareInput(IProgressMonitor monitor) {
+ // Connect to the sync set which will register us as a listener and give us a reset event
+ // in a background thread
+ getSyncInfoSet().connect(this, monitor);
+ return getModelRoot();
+ }
+
+ /**
+ * Dispose of the builder
+ */
+ public void dispose() {
+ resourceMap.clear();
+ getSyncInfoSet().removeSyncSetChangedListener(this);
+ }
/**
* Returns the input created by this controller or <code>null</code> if
* {@link #prepareInput(IProgressMonitor)} hasn't been called on this object yet.
* @return
*/
- public abstract SynchronizeModelElement getInput();
-
- public abstract void setViewer(StructuredViewer viewer);
+ public SynchronizeModelElement getModelRoot() {
+ return root;
+ }
public abstract ViewerSorter getViewerSorter();
- public abstract void dispose();
+ /**
+ * Return the model object (i.e. an instance of <code>SyncInfoModelElement</code>
+ * or one of its subclasses) for the given IResource.
+ * @param resource
+ * the resource
+ * @return the <code>SyncInfoModelElement</code> for the given resource
+ */
+ protected SynchronizeModelElement getModelObject(IResource resource) {
+ return (SynchronizeModelElement) resourceMap.get(resource);
+ }
+
+ public void syncInfoChanged(final ISyncInfoSetChangeEvent event, IProgressMonitor monitor) {
+ if (! (event instanceof ISyncInfoTreeChangeEvent)) {
+ reset();
+ } else {
+ final Control ctrl = getViewer().getControl();
+ if (ctrl != null && !ctrl.isDisposed()) {
+ ctrl.getDisplay().syncExec(new Runnable() {
+ public void run() {
+ if (!ctrl.isDisposed()) {
+ BusyIndicator.showWhile(ctrl.getDisplay(), new Runnable() {
+ public void run() {
+ handleChanges((ISyncInfoTreeChangeEvent)event);
+ getModelRoot().fireChanges();
+ }
+ });
+ }
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * For each node create children based on the contents of
+ * @param node
+ * @return
+ */
+ protected abstract IDiffElement[] buildModelObjects(SynchronizeModelElement node);
+
+ protected abstract void doAdd(SynchronizeModelElement parent, SynchronizeModelElement element);
+
+ protected abstract void doRemove(SynchronizeModelElement element);
+
+ protected void associateDiffNode(SynchronizeModelElement node) {
+ IResource resource = node.getResource();
+ if(resource != null) {
+ resourceMap.put(resource, node);
+ }
+ }
+
+ protected void unassociateDiffNode(IResource resource) {
+ resourceMap.remove(resource);
+ }
+
+ /**
+ * Handle the changes made to the viewer's <code>SyncInfoSet</code>.
+ * This method delegates the changes to the three methods <code>handleResourceChanges(ISyncInfoSetChangeEvent)</code>,
+ * <code>handleResourceRemovals(ISyncInfoSetChangeEvent)</code> and
+ * <code>handleResourceAdditions(ISyncInfoSetChangeEvent)</code>.
+ * @param event
+ * the event containing the changed resourcses.
+ */
+ protected void handleChanges(ISyncInfoTreeChangeEvent event) {
+ StructuredViewer viewer = getViewer();
+ try {
+ viewer.getControl().setRedraw(false);
+ handleResourceChanges(event);
+ handleResourceRemovals(event);
+ handleResourceAdditions(event);
+ firePendingLabelUpdates();
+ } finally {
+ viewer.getControl().setRedraw(true);
+ }
+ }
+
+ /**
+ * Update the viewer for the sync set additions in the provided event. This
+ * method is invoked by <code>handleChanges(ISyncInfoSetChangeEvent)</code>.
+ * Subclasses may override.
+ * @param event
+ */
+ protected abstract void handleResourceAdditions(ISyncInfoTreeChangeEvent event);
+
+ /**
+ * Update the viewer for the sync set changes in the provided event. This
+ * method is invoked by <code>handleChanges(ISyncInfoSetChangeEvent)</code>.
+ * Subclasses may override.
+ * @param event
+ */
+ protected abstract void handleResourceChanges(ISyncInfoTreeChangeEvent event);
+
+ protected boolean isConflicting(SynchronizeModelElement diffNode) {
+ return (diffNode.getKind() & SyncInfo.DIRECTION_MASK) == SyncInfo.CONFLICTING;
+ }
+
+ /**
+ * Update the viewer for the sync set removals in the provided event. This
+ * method is invoked by <code>handleChanges(ISyncInfoSetChangeEvent)</code>.
+ * Subclasses may override.
+ * @param event
+ */
+ protected abstract void handleResourceRemovals(ISyncInfoTreeChangeEvent event);
+
+ protected void reset() {
+ try {
+ refreshViewer = false;
+
+ // Clear existing model, but keep the root node
+ resourceMap.clear();
+ clearModelObjects(getModelRoot());
+ // remove all from tree viewer
+ IDiffElement[] elements = getModelRoot().getChildren();
+ for (int i = 0; i < elements.length; i++) {
+ doRemove((SynchronizeModelElement)elements[i]);
+ }
+
+ // Rebuild the model
+ associateDiffNode(getModelRoot());
+ buildModelObjects(getModelRoot());
+
+ // Notify listeners that model has changed
+ getModelRoot().fireChanges();
+ } finally {
+ refreshViewer = true;
+ }
+ TeamUIPlugin.getStandardDisplay().asyncExec(new Runnable() {
+ public void run() {
+ StructuredViewer viewer = getViewer();
+ if (viewer != null && !viewer.getControl().isDisposed()) {
+ viewer.refresh();
+ }
+ }
+ });
+ }
+
+ /**
+ * Remove any traces of the resource and any of it's descendants in the
+ * hiearchy defined by the content provider from the content provider and
+ * the viewer it is associated with.
+ * @param resource
+ */
+ protected void removeFromViewer(IResource resource) {
+ SynchronizeModelElement node = getModelObject(resource);
+ if (node == null) return;
+ if (isConflicting(node)) {
+ setParentConflict(node, false);
+ }
+ clearModelObjects(node);
+ if (canUpdateViewer()) {
+ doRemove(node);
+ }
+ }
+
+ /**
+ * Clear the model objects from the diff tree, cleaning up any cached state
+ * (such as resource to model object map). This method recurses deeply on
+ * the tree to allow the cleanup of any cached state for the children as
+ * well.
+ * @param node
+ * the root node
+ */
+ protected void clearModelObjects(SynchronizeModelElement node) {
+ IDiffElement[] children = node.getChildren();
+ for (int i = 0; i < children.length; i++) {
+ IDiffElement element = children[i];
+ if (element instanceof SynchronizeModelElement) {
+ clearModelObjects((SynchronizeModelElement) element);
+ }
+ }
+ IResource resource = node.getResource();
+ if (resource != null) {
+ unassociateDiffNode(resource);
+ }
+ IDiffContainer parent = node.getParent();
+ if (parent != null) {
+ parent.removeToRoot(node);
+ }
+ }
+
+ protected void addToViewer(SynchronizeModelElement node) {
+ associateDiffNode(node);
+ node.addPropertyChangeListener(listener);
+ if (isConflicting(node)) {
+ setParentConflict(node, true);
+ }
+ if (canUpdateViewer()) {
+ doAdd((SynchronizeModelElement)node.getParent(), node);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.team.core.synchronize.ISyncInfoSetChangeListener#syncInfoSetReset(org.eclipse.team.core.synchronize.SyncInfoSet, org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public void syncInfoSetReset(SyncInfoSet set, IProgressMonitor monitor) {
+ reset();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.team.core.synchronize.ISyncInfoSetChangeListener#syncInfoSetErrors(org.eclipse.team.core.synchronize.SyncInfoSet, org.eclipse.team.core.ITeamStatus[], org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public void syncInfoSetErrors(SyncInfoSet set, ITeamStatus[] errors, IProgressMonitor monitor) {
+ // When errors occur we currently don't process them. It may be possible to decorate
+ // elements in the model with errors, but currently we prefer to let ignore and except
+ // another listener to display them.
+ }
+
+ /**
+ * Update the label of the given diff node. Diff nodes
+ * are accumulated and updated in a single call.
+ * @param diffNode the diff node to be updated
+ */
+ protected void updateLabel(SynchronizeModelElement diffNode) {
+ pendingLabelUpdates.add(diffNode);
+ }
+
+ /**
+ * @param tree
+ * @return
+ */
+ private boolean canUpdateViewer() {
+ return refreshViewer && getViewer() != null;
+ }
+
+ /**
+ * Forces the viewer to update the labels for parents whose children have
+ * changed during this round of sync set changes.
+ */
+ protected void firePendingLabelUpdates() {
+ try {
+ if (canUpdateViewer()) {
+ StructuredViewer tree = getViewer();
+ tree.update(pendingLabelUpdates.toArray(new Object[pendingLabelUpdates.size()]), null);
+ }
+ } finally {
+ pendingLabelUpdates.clear();
+ }
+ }
+
+ protected void setParentConflict(SynchronizeModelElement diffNode, boolean value) {
+ diffNode.setPropertyToRoot(SynchronizeModelElement.PROPAGATED_CONFLICT_PROPERTY, value);
+ updateParentLabels(diffNode);
+ }
+
+ private void updateParentLabels(SynchronizeModelElement diffNode) {
+ updateLabel(diffNode);
+ while (diffNode.getParent() != null) {
+ diffNode = (SynchronizeModelElement)diffNode.getParent();
+ updateLabel(diffNode);
+ }
+ }
} \ No newline at end of file
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/TreeViewerAdvisor.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/TreeViewerAdvisor.java
index 39b059c18..4e688fc6e 100644
--- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/TreeViewerAdvisor.java
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/TreeViewerAdvisor.java
@@ -14,123 +14,117 @@ import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
-import org.eclipse.jface.viewers.*;
-import org.eclipse.swt.widgets.*;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.OpenEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.team.core.TeamException;
-import org.eclipse.team.core.synchronize.*;
-import org.eclipse.team.internal.core.Assert;
-import org.eclipse.team.internal.ui.*;
+import org.eclipse.team.core.synchronize.SyncInfoTree;
+import org.eclipse.team.internal.ui.IPreferenceIds;
+import org.eclipse.team.internal.ui.TeamUIPlugin;
+import org.eclipse.team.internal.ui.Utils;
import org.eclipse.team.internal.ui.synchronize.actions.ExpandAllAction;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.internal.dialogs.ContainerCheckedTreeViewer;
/**
- * A <code>TreeViewerAdvisor</code> object controls various UI
- * aspects of sync info viewers like the context menu, toolbar, content
- * provider, and label provider. A configuration is created to display
- * {@link SyncInfo} objects contained in the provided {@link SyncInfoSet}.
+ * A <code>TreeViewerAdvisor</code> that works with TreeViewers. Two default
+ * tree viewers are provided that support navigation: <code>NavigableTreeViewer</code>
+ * and <code>NavigableCheckboxTreeViewer</code>.
* <p>
- * This configuration allows viewer contributions made in a plug-in manifest to
- * be scoped to a particular unique id. As a result the context menu for the
- * viewer can be configured to show object contributions for random id schemes.
- * To enable declarative action contributions for a configuration there are two
- * steps required:
- * <ul>
- * <li>Create a viewer contribution with a <code>targetID</code> that groups
- * sets of actions that are related. A common pratice for synchronize view
- * configurations is to use the participant id as the targetID.
- *
- * <pre>
- * &lt;viewerContribution
- * id=&quot;org.eclipse.team.ccvs.ui.CVSCompareSubscriberContributions&quot;
- * targetID=&quot;org.eclipse.team.cvs.ui.compare-participant&quot;&gt;
- * ...
- * </pre>
- *
- * <li>Create a configuration instance with a <code>menuID</code> that
- * matches the targetID in the viewer contribution.
- * </ul>
+ * Note that this advisor can be used with any tree viewer. By default it provides an
+ * expand all action, double click behavior on containers, and navigation support for
+ * tree viewers.
+ * </p><p>
+ * By default this advisor supports hierarchical models and honour the compressed
+ * folder Team preference for showing the sync set as compressed folders. Subclasses
+ * can provide their own presentation models.
* <p>
- * Clients may use this class as is, or subclass to add new state and behavior.
- * The default behavior is to show sync info in a tree
- * </p>
* @since 3.0
*/
public class TreeViewerAdvisor extends StructuredViewerAdvisor implements IPropertyChangeListener {
-
- private ExpandAllAction expandAllAction;
+ /**
+ * Interface used to implement navigation for tree viewers. This interface is used by
+ * {@link TreeViewerAdvisor#navigate(TreeViewer, boolean, boolean, boolean) to open
+ * selections and navigate.
+ */
public interface ITreeViewerAccessor {
- public void openSelection();
public void createChildren(TreeItem item);
+ public void openSelection();
}
- public static class NavigableTreeViewer extends TreeViewer implements ITreeViewerAccessor {
- public NavigableTreeViewer(Composite parent, int style) {
+ /**
+ * A navigable checkboxec tree viewer that will work with the <code>navigate</code> method of
+ * this advisor.
+ */
+ public static class NavigableCheckboxTreeViewer extends ContainerCheckedTreeViewer implements ITreeViewerAccessor {
+ public NavigableCheckboxTreeViewer(Composite parent, int style) {
super(parent, style);
}
- public void openSelection() {
- fireOpen(new OpenEvent(this, getSelection()));
- }
-
public void createChildren(TreeItem item) {
super.createChildren(item);
}
- }
-
- public static class NavigableCheckboxTreeViewer extends ContainerCheckedTreeViewer implements ITreeViewerAccessor {
- public NavigableCheckboxTreeViewer(Composite parent, int style) {
- super(parent, style);
- }
public void openSelection() {
fireOpen(new OpenEvent(this, getSelection()));
}
+ }
+
+ /**
+ * A navigable tree viewer that will work with the <code>navigate</code> method of
+ * this advisor.
+ */
+ public static class NavigableTreeViewer extends TreeViewer implements ITreeViewerAccessor {
+ public NavigableTreeViewer(Composite parent, int style) {
+ super(parent, style);
+ }
public void createChildren(TreeItem item) {
super.createChildren(item);
}
+
+ public void openSelection() {
+ fireOpen(new OpenEvent(this, getSelection()));
+ }
}
- /**
- * Create a <code>SyncInfoSetCompareConfiguration</code> for the given
- * sync set.
- * @param set
- * the <code>SyncInfoSet</code> to be displayed in the
- * resulting diff viewer.
- */
- public TreeViewerAdvisor(SyncInfoTree set) {
- this(null, set);
- }
+ private ExpandAllAction expandAllAction;
/**
- * Create a <code>SyncInfoSetCompareConfiguration</code> for the given
- * sync set and menuId. If the menuId is <code>null</code>, then no
- * contributed menus will be shown in the diff viewer created from this
- * configuration.
- * @param menuId
- * the id of <code>targetID</code> specified in <code>viewerContribution</code>
- * extension points.
- * @param set
- * the <code>SyncInfoSet</code> to be displayed in the
- * resulting diff viewer
+ * Create an advisor that will allow viewer contributions with the given <code>targetID</code>. This
+ * advisor will provide a presentation model based on the given sync info set. Note that it's important
+ * to call {@link #dispose()} when finished with an advisor.
+ *
+ * @param targetID the targetID defined in the viewer contributions in a plugin.xml file.
+ * @param set the set of <code>SyncInfo</code> objects that are to be shown to the user.
*/
public TreeViewerAdvisor(String menuId, SyncInfoTree set) {
super(menuId, set);
TeamUIPlugin.getPlugin().getPreferenceStore().addPropertyChangeListener(this);
}
- /* (non-Javadoc)
- * @see org.eclipse.team.ui.synchronize.viewers.StructuredViewerAdvisor#initializeViewer(org.eclipse.jface.viewers.StructuredViewer)
+ /**
+ * Create a tree viewer advisor that will provide a presentation model based on the given
+ * sync info set. Note that it's important to call {@link #dispose()} when finished with
+ * an advisor.
+ *
+ * @param set the set of <code>SyncInfo</code> objects that are to be shown to the user.
*/
- public void initializeViewer(StructuredViewer viewer) {
- super.initializeViewer(viewer);
- Assert.isTrue(viewer instanceof AbstractTreeViewer);
+ public TreeViewerAdvisor(SyncInfoTree set) {
+ this(null, set);
}
-
/* (non-Javadoc)
* @see org.eclipse.team.ui.synchronize.viewers.StructuredViewerAdvisor#dispose()
*/
@@ -140,61 +134,13 @@ public class TreeViewerAdvisor extends StructuredViewerAdvisor implements IPrope
}
/* (non-Javadoc)
- * @see org.eclipse.team.ui.synchronize.viewers.StructuredViewerAdvisor#initializeListeners(org.eclipse.jface.viewers.StructuredViewer)
- */
- protected void initializeListeners(StructuredViewer viewer) {
- viewer.addDoubleClickListener(new IDoubleClickListener() {
- public void doubleClick(DoubleClickEvent event) {
- handleDoubleClick(getViewer(), event);
- }
- });
- }
-
-
- /* (non-Javadoc)
- * @see org.eclipse.team.ui.synchronize.viewers.StructuredViewerAdvisor#initializeActions(org.eclipse.jface.viewers.StructuredViewer)
+ * @see org.eclipse.team.ui.synchronize.viewers.StructuredViewerAdvisor#navigate(boolean)
*/
- protected void initializeActions(StructuredViewer viewer) {
- super.initializeActions(viewer);
- expandAllAction = new ExpandAllAction((AbstractTreeViewer) viewer);
- Utils.initAction(expandAllAction, "action.expandAll."); //$NON-NLS-1$
+ public boolean navigate(boolean next) {
+ return TreeViewerAdvisor.navigate((TreeViewer)getViewer(), next, true, false);
}
- /**
- * Handles a double-click event from the viewer. Expands or collapses a
- * folder when double-clicked.
- * @param viewer
- * the viewer
- * @param event
- * the double-click event
- */
- protected void handleDoubleClick(StructuredViewer viewer, DoubleClickEvent event) {
- IStructuredSelection selection = (IStructuredSelection) event.getSelection();
- Object element = selection.getFirstElement();
- AbstractTreeViewer treeViewer = (AbstractTreeViewer) getViewer();
- if (treeViewer.getExpandedState(element)) {
- treeViewer.collapseToLevel(element, AbstractTreeViewer.ALL_LEVELS);
- } else {
- TreeViewerAdvisor.navigate((TreeViewer)getViewer(), true /* next */, false /* no-open */, true /* only-expand */);
- }
- }
-
/* (non-Javadoc)
- * @see org.eclipse.team.ui.synchronize.viewers.StructuredViewerAdvisor#getDiffNodeController()
- */
- protected SynchronizeModelProvider getModelProvider() {
- if(getShowCompressedFolders()) {
- return new CompressedFoldersModelProvider((SyncInfoTree)getSyncInfoSet());
- }
- return new HierarchicalModelProvider((SyncInfoTree)getSyncInfoSet());
- }
-
- private boolean getShowCompressedFolders() {
- return TeamUIPlugin.getPlugin().getPreferenceStore().getBoolean(IPreferenceIds.SYNCVIEW_COMPRESS_FOLDERS);
- }
-
- /*
- * (non-Javadoc)
* @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
@@ -208,7 +154,13 @@ public class TreeViewerAdvisor extends StructuredViewerAdvisor implements IPrope
}
}
-
+ /* (non-Javadoc)
+ * @see org.eclipse.team.ui.synchronize.viewers.StructuredViewerAdvisor#initializeViewer(org.eclipse.jface.viewers.StructuredViewer)
+ */
+ public boolean validateViewer(StructuredViewer viewer) {
+ return viewer instanceof AbstractTreeViewer;
+ }
+
/* (non-Javadoc)
* @see org.eclipse.team.ui.synchronize.viewers.StructuredViewerAdvisor#fillContextMenu(org.eclipse.jface.viewers.StructuredViewer, org.eclipse.jface.action.IMenuManager)
*/
@@ -216,73 +168,62 @@ public class TreeViewerAdvisor extends StructuredViewerAdvisor implements IPrope
manager.add(expandAllAction);
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
-
+
+
/* (non-Javadoc)
- * @see org.eclipse.team.ui.synchronize.viewers.StructuredViewerAdvisor#navigate(boolean)
+ * @see org.eclipse.team.ui.synchronize.viewers.StructuredViewerAdvisor#getDiffNodeController()
*/
- public boolean navigate(boolean next) {
- return TreeViewerAdvisor.navigate((TreeViewer)getViewer(), next, true, false);
+ protected SynchronizeModelProvider getModelProvider() {
+ if(getShowCompressedFolders()) {
+ return new CompressedFoldersModelProvider((SyncInfoTree)getSyncInfoSet());
+ }
+ return new HierarchicalModelProvider((SyncInfoTree)getSyncInfoSet());
}
+
/**
- * Selects the next (or previous) node of the current selection.
- * If there is no current selection the first (last) node in the tree is selected.
- * Wraps around at end or beginning.
- * Clients may override.
- *
- * @param next if <code>true</code> the next node is selected, otherwise the previous node
- * @return <code>true</code> if at end (or beginning)
+ * Handles a double-click event from the viewer. Expands or collapses a folder when double-clicked.
+ *
+ * @param viewer the viewer
+ * @param event the double-click event
*/
- public static boolean navigate(TreeViewer viewer, boolean next, boolean fireOpen, boolean expandOnly) {
- Tree tree = viewer.getTree();
- if (tree == null)
- return false;
- TreeItem item = null;
- TreeItem children[] = tree.getSelection();
- if (children != null && children.length > 0)
- item = children[0];
- if (item == null) {
- children = tree.getItems();
- if (children != null && children.length > 0) {
- item = children[0];
- if (item != null && item.getItemCount() <= 0) {
- setSelection(viewer, item, fireOpen, expandOnly); // Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
- return false;
- }
- }
- }
- while (true) {
- item = findNextPrev(viewer, item, next);
- if (item == null)
- break;
- if (item.getItemCount() <= 0)
- break;
- }
- if (item != null) {
- setSelection(viewer, item, fireOpen, expandOnly); // Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
- return false;
+ protected void handleDoubleClick(StructuredViewer viewer, DoubleClickEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) event.getSelection();
+ Object element = selection.getFirstElement();
+ AbstractTreeViewer treeViewer = (AbstractTreeViewer) getViewer();
+ if (treeViewer.getExpandedState(element)) {
+ treeViewer.collapseToLevel(element, AbstractTreeViewer.ALL_LEVELS);
+ } else {
+ TreeViewerAdvisor.navigate((TreeViewer)getViewer(), true /* next */, false /* no-open */, true /* only-expand */);
}
- return true;
}
-
- private static void setSelection(TreeViewer viewer, TreeItem ti, boolean fireOpen, boolean expandOnly) {
- if (ti != null) {
- Object data= ti.getData();
- if (data != null) {
- // Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
- ISelection selection = new StructuredSelection(data);
- if (expandOnly) {
- viewer.expandToLevel(data, 0);
- } else {
- viewer.setSelection(selection, true);
- ISelection currentSelection = viewer.getSelection();
- if (fireOpen && currentSelection != null && selection.equals(currentSelection)) {
- if (viewer instanceof ITreeViewerAccessor) {
- ((ITreeViewerAccessor) viewer).openSelection();
- }
- }
- }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.team.ui.synchronize.viewers.StructuredViewerAdvisor#initializeActions(org.eclipse.jface.viewers.StructuredViewer)
+ */
+ protected void initializeActions(StructuredViewer viewer) {
+ super.initializeActions(viewer);
+ expandAllAction = new ExpandAllAction((AbstractTreeViewer) viewer);
+ Utils.initAction(expandAllAction, "action.expandAll."); //$NON-NLS-1$
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.team.ui.synchronize.viewers.StructuredViewerAdvisor#initializeListeners(org.eclipse.jface.viewers.StructuredViewer)
+ */
+ protected void initializeListeners(StructuredViewer viewer) {
+ viewer.addDoubleClickListener(new IDoubleClickListener() {
+ public void doubleClick(DoubleClickEvent event) {
+ handleDoubleClick(getViewer(), event);
}
- }
+ });
+ }
+
+ /**
+ * Return the state of the compressed folder setting.
+ *
+ * @return the state of the compressed folder setting.
+ */
+ private boolean getShowCompressedFolders() {
+ return TeamUIPlugin.getPlugin().getPreferenceStore().getBoolean(IPreferenceIds.SYNCVIEW_COMPRESS_FOLDERS);
}
private static TreeItem findNextPrev(TreeViewer viewer, TreeItem item, boolean next) {
@@ -350,4 +291,66 @@ public class TreeViewerAdvisor extends StructuredViewerAdvisor implements IPrope
}
return item;
}
+
+ private static void setSelection(TreeViewer viewer, TreeItem ti, boolean fireOpen, boolean expandOnly) {
+ if (ti != null) {
+ Object data= ti.getData();
+ if (data != null) {
+ // Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
+ ISelection selection = new StructuredSelection(data);
+ if (expandOnly) {
+ viewer.expandToLevel(data, 0);
+ } else {
+ viewer.setSelection(selection, true);
+ ISelection currentSelection = viewer.getSelection();
+ if (fireOpen && currentSelection != null && selection.equals(currentSelection)) {
+ if (viewer instanceof ITreeViewerAccessor) {
+ ((ITreeViewerAccessor) viewer).openSelection();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Selects the next (or previous) node of the current selection.
+ * If there is no current selection the first (last) node in the tree is selected.
+ * Wraps around at end or beginning.
+ * Clients may not override.
+ *
+ * @param next if <code>true</code> the next node is selected, otherwise the previous node
+ * @return <code>true</code> if at end (or beginning)
+ */
+ public static boolean navigate(TreeViewer viewer, boolean next, boolean fireOpen, boolean expandOnly) {
+ Tree tree = viewer.getTree();
+ if (tree == null)
+ return false;
+ TreeItem item = null;
+ TreeItem children[] = tree.getSelection();
+ if (children != null && children.length > 0)
+ item = children[0];
+ if (item == null) {
+ children = tree.getItems();
+ if (children != null && children.length > 0) {
+ item = children[0];
+ if (item != null && item.getItemCount() <= 0) {
+ setSelection(viewer, item, fireOpen, expandOnly); // Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
+ return false;
+ }
+ }
+ }
+ while (true) {
+ item = findNextPrev(viewer, item, next);
+ if (item == null)
+ break;
+ if (item.getItemCount() <= 0)
+ break;
+ }
+ if (item != null) {
+ setSelection(viewer, item, fireOpen, expandOnly); // Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
+ return false;
+ }
+ return true;
+ }
} \ No newline at end of file
diff --git a/tests/org.eclipse.team.tests.core/plugin.xml b/tests/org.eclipse.team.tests.core/plugin.xml
index 332327000..6b1b468a1 100644
--- a/tests/org.eclipse.team.tests.core/plugin.xml
+++ b/tests/org.eclipse.team.tests.core/plugin.xml
@@ -91,6 +91,19 @@
id="org.eclipse.team.tests.core.linking">
</repository>
</extension>
+ <extension
+ point="org.eclipse.ui.views">
+ <category
+ name="Team Test Views"
+ id="org.eclipse.team.tests.core">
+ </category>
+ <view
+ name="Content Provider Test View"
+ category="org.eclipse.team.tests.core"
+ class="org.eclipse.team.tests.ui.views.ContentProviderTestView"
+ id="org.eclipse.team.tests.ui.views.ContentProviderTestView">
+ </view>
+ </extension>
</plugin>

Back to the top