diff options
author | Pawel Piech | 2009-09-25 22:44:00 +0000 |
---|---|---|
committer | Pawel Piech | 2009-09-25 22:44:00 +0000 |
commit | 819f593395137640fa5faf8124751f93e40a4f78 (patch) | |
tree | 9a3d789a87b8bdeea91966a550f88e0e4a94d548 | |
parent | 66c6f5f8b5a34ba152ed2e08b166a9a167967a31 (diff) | |
download | eclipse.platform.debug-819f593395137640fa5faf8124751f93e40a4f78.tar.gz eclipse.platform.debug-819f593395137640fa5faf8124751f93e40a4f78.tar.xz eclipse.platform.debug-819f593395137640fa5faf8124751f93e40a4f78.zip |
Bug 241336 - [flexible hierarchy] IModelProxyFactory.createModelProxy() should take the full path to element.
8 files changed, 452 insertions, 104 deletions
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/DeltaTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/DeltaTests.java index 87c326548..79fb7a56a 100644 --- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/DeltaTests.java +++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/DeltaTests.java @@ -121,9 +121,9 @@ abstract public class DeltaTests extends TestCase { TestElement element = model.getRootElement().getChildren()[0]; TreePath elementPath = new TreePath(new Object[] { element }); TestElement[] newChildren = new TestElement[] { - model.new TestElement("1.1", new TestElement[0]), - model.new TestElement("1.2", new TestElement[0]), - model.new TestElement("1.3", new TestElement[0]), + new TestElement(model, "1.1", new TestElement[0]), + new TestElement(model, "1.2", new TestElement[0]), + new TestElement(model, "1.3", new TestElement[0]), }; ModelDelta delta = model.setElementChildren(elementPath, newChildren); @@ -148,7 +148,7 @@ abstract public class DeltaTests extends TestCase { model.validateData(fViewer, TreePath.EMPTY); // Update the model - TestElement element = model.new TestElement("7", new TestElement[0]); + TestElement element = new TestElement(model, "7", new TestElement[0]); TreePath elementPath = new TreePath(new Object[] { element }); ModelDelta delta = model.insertElementChild(TreePath.EMPTY, 6, element); @@ -182,7 +182,7 @@ abstract public class DeltaTests extends TestCase { model.validateData(fViewer, TreePath.EMPTY); // Update the model - TestElement element = model.new TestElement("7", new TestElement[0]); + TestElement element = new TestElement(model, "7", new TestElement[0]); TreePath elementPath = new TreePath(new Object[] { element }); ModelDelta delta = model.addElementChild(TreePath.EMPTY, 6, element); @@ -304,5 +304,67 @@ abstract public class DeltaTests extends TestCase { } } + public void testCompositeModelRefreshStruct() { + //TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer); + + TestModel model = TestModel.compositeMultiLevel(); + fViewer.setAutoExpandLevel(-1); + + // Create the listener + // TODO: redundant updates on install deltas + fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, false, false); + + // Set the input into the view and update the view. + fViewer.setInput(model.getRootElement()); + while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) fDisplay.sleep (); + model.validateData(fViewer, TreePath.EMPTY, true); + // Update the model + TreePath m4_2_1Path = model.findElement("m4.2.1"); + TestElement m4_2_1 = model.getElement(m4_2_1Path); + TestModel m4 = m4_2_1.getModel(); + TestElement[] newChildren = new TestElement[] { + new TestElement(m4, "4.2.1.new-1", new TestElement[0]), + new TestElement(m4, "4.2.1.new-2", new TestElement[0]), + new TestElement(m4, "4.2.1.new-3", new TestElement[0]), + }; + + ModelDelta delta = m4.setElementChildren(m4_2_1Path, newChildren); + + fListener.reset(m4_2_1Path, m4_2_1, -1, true, false); + model.postDelta(delta); + while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) fDisplay.sleep (); + model.validateData(fViewer, TreePath.EMPTY); + } + + public void testCompositeModelAddElement() { + TestModel model = TestModel.compositeMultiLevel(); + fViewer.setAutoExpandLevel(-1); + + // Create the listener + // TODO: redundant updates on install deltas + fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, false, false); + + // Set the input into the view and update the view. + fViewer.setInput(model.getRootElement()); + while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) fDisplay.sleep (); + model.validateData(fViewer, TreePath.EMPTY, true); + + TreePath m3_1Path = model.findElement("m3.1"); + TestElement m3_1 = model.getElement(m3_1Path); + TestModel m3 = m3_1.getModel(); + TestElement m3_1_new = new TestElement(m3, "m3.1-new", new TestElement[0]); + TreePath m3_1_newPath = m3_1Path.createChildPath(m3_1_new); + ModelDelta delta = m3.addElementChild(m3_1Path, 0, m3_1_new); + + fListener.reset(m3_1_newPath, m3_1_new, -1, true, false); + fListener.addChildreUpdate(m3_1Path, 0); + fListener.setFailOnRedundantUpdates(false); + + m3.postDelta(delta); + while (!fListener.isFinished(TestModelUpdatesListener.ALL_UPDATES_COMPLETE | TestModelUpdatesListener.MODEL_CHANGED_COMPLETE)) + if (!fDisplay.readAndDispatch ()) fDisplay.sleep (); + + model.validateData(fViewer, TreePath.EMPTY); + } } diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModel.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModel.java index f484fd8a3..201650697 100644 --- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModel.java +++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModel.java @@ -27,11 +27,12 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdat import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory2; import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta; import org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy; import org.eclipse.jface.viewers.TreePath; +import org.eclipse.jface.viewers.Viewer; /** * Test model for the use in unit tests. This test model contains a set of @@ -40,9 +41,10 @@ import org.eclipse.jface.viewers.TreePath; * * @since 3.6 */ -public class TestModel implements IElementContentProvider, IElementLabelProvider, IModelProxyFactory /*, IElementCheckReceiver */ { +public class TestModel implements IElementContentProvider, IElementLabelProvider, IModelProxyFactory2 /*, IElementCheckReceiver */ { - public class TestElement extends PlatformObject { + public static class TestElement extends PlatformObject { + private final TestModel fModel; private final String fID; TestElement[] fChildren; String fLabelAppendix = ""; @@ -50,20 +52,25 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider boolean fChecked; boolean fGrayed; - public TestElement(String text, TestElement[] children) { - this (text, false, false, children); + public TestElement(TestModel model, String text, TestElement[] children) { + this (model, text, false, false, children); } - public TestElement(String text, boolean checked, boolean grayed, TestElement[] children) { + public TestElement(TestModel model, String text, boolean checked, boolean grayed, TestElement[] children) { + fModel = model; fID = text; fChildren = children; fChecked = checked; fGrayed = grayed; } + public TestModel getModel() { + return fModel; + } + public Object getAdapter(Class adapter) { - if (adapter.isInstance(TestModel.this)) { - return TestModel.this; + if (adapter.isInstance(fModel)) { + return fModel; } return null; } @@ -114,9 +121,32 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider } } - private class ModelProxy extends AbstractModelProxy {} + private class ModelProxy extends AbstractModelProxy { + public void installed(Viewer viewer) { + super.installed(viewer); + ModelDelta rootDelta = TestModel.this.getBaseDelta(new ModelDelta(fInput, IModelDelta.NO_CHANGE)); + installSubModelProxies(fRootPath, rootDelta); + fireModelChanged(rootDelta); + } + + private void installSubModelProxies(TreePath path, ModelDelta delta) { + TestElement element = getElement(path); + if (element.fModel != TestModel.this) { + // Found an element from a different model. Install its proxy and return. + delta.setFlags(delta.getFlags() | IModelDelta.INSTALL); + } else { + TestElement[] children = element.getChildren(); + + for (int i = 0; i < children.length; i++) { + installSubModelProxies(path.createChildPath(children[i]), delta.addNode(children[i], IModelDelta.NO_CHANGE)); + } + } + } + } private TestElement fRoot; + private Object fInput = null; + private TreePath fRootPath = TreePath.EMPTY; private ModelProxy fModelProxy; /** @@ -128,6 +158,14 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider return fRoot; } + ModelDelta getBaseDelta(ModelDelta rootDelta) { + ModelDelta delta = rootDelta; + for (int i = 0; i < fRootPath.getSegmentCount(); i++) { + delta = delta.addNode(fRootPath.getSegment(i), IModelDelta.NO_CHANGE); + } + return delta; + } + public int getModelDepth() { return getDepth(getRootElement(), 0); } @@ -193,8 +231,14 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider element.setChecked(checked, false); } - public IModelProxy createModelProxy(Object element, IPresentationContext context) { + public IModelProxy createTreeModelProxy(Object input, TreePath path, IPresentationContext context) { fModelProxy = new ModelProxy(); + fInput = input; + fRootPath = path; + return fModelProxy; + } + + public IModelProxy getModelProxy() { return fModelProxy; } @@ -258,14 +302,15 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider TestElement[] children = element.getChildren(); delta.setChildCount(children.length); Object segment = path.getSegment(i); - int j = 0; - for (j = 0; j < element.getChildren().length; j++) { - if (segment.equals(element.getChildren()[j])) { - element = element.getChildren()[j]; + int j; + for (j = 0; j < children.length; j++) { + if (segment.equals(children[j])) { + element = children[j]; delta = delta.addNode(element, j, IModelDelta.NO_CHANGE); + break; } } - if (j == element.getChildren().length) { + if (j == children.length) { throw new IllegalArgumentException("Invalid path"); } } @@ -273,32 +318,49 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider } + private TreePath getRelativePath(TreePath path) { + Object[] segments = new Object[path.getSegmentCount() - fRootPath.getSegmentCount()]; + for (int i = fRootPath.getSegmentCount(), _i = 0; i < path.getSegmentCount(); i++, _i++) { + segments[_i] = path.getSegment(i); + } + return new TreePath(segments); + } + public ModelDelta appendElementLabel(TreePath path, String labelAppendix) { - ModelDelta baseDelta = new ModelDelta(getRootElement(), IModelDelta.NO_CHANGE); - TestElement element = getElement(path); - ModelDelta delta = getElementDelta(baseDelta, path); + Assert.assertTrue(path.startsWith(fRootPath, null)); + ModelDelta rootDelta = new ModelDelta(fInput, IModelDelta.NO_CHANGE); + ModelDelta baseDelta = getBaseDelta(rootDelta); + TreePath relativePath = getRelativePath(path); + TestElement element = getElement(relativePath); + ModelDelta delta = getElementDelta(baseDelta, relativePath); element.setLabelAppendix(labelAppendix); delta.setFlags(delta.getFlags() | IModelDelta.STATE); - return baseDelta; + return rootDelta; } public ModelDelta setElementChecked(TreePath path, boolean checked, boolean grayed) { - ModelDelta baseDelta = new ModelDelta(getRootElement(), IModelDelta.NO_CHANGE); - TestElement element = getElement(path); - ModelDelta delta = getElementDelta(baseDelta, path); + Assert.assertTrue(path.startsWith(fRootPath, null)); + ModelDelta rootDelta = new ModelDelta(fInput, IModelDelta.NO_CHANGE); + ModelDelta baseDelta = getBaseDelta(rootDelta); + TreePath relativePath = getRelativePath(path); + TestElement element = getElement(relativePath); + ModelDelta delta = getElementDelta(baseDelta, relativePath); element.setChecked(checked, grayed); delta.setFlags(delta.getFlags() | IModelDelta.STATE); - return baseDelta; + return rootDelta; } public ModelDelta setElementChildren(TreePath path, TestElement[] children) { - ModelDelta baseDelta = new ModelDelta(getRootElement(), IModelDelta.NO_CHANGE); + Assert.assertTrue(path.startsWith(fRootPath, null)); + ModelDelta rootDelta = new ModelDelta(fInput, IModelDelta.NO_CHANGE); + ModelDelta baseDelta = getBaseDelta(rootDelta); + TreePath relativePath = getRelativePath(path); // Find the parent element and generate the delta node for it. - TestElement element = getElement(path); - ModelDelta delta = getElementDelta(baseDelta, path); + TestElement element = getElement(relativePath); + ModelDelta delta = getElementDelta(baseDelta, relativePath); // Set the new children array element.fChildren = children; @@ -307,28 +369,32 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider delta.setFlags(delta.getFlags() | IModelDelta.CONTENT); delta.setChildCount(children.length); - return baseDelta; + return rootDelta; } public ModelDelta replaceElementChild(TreePath parentPath, int index, TestElement child) { - ModelDelta baseDelta = new ModelDelta(getRootElement(), IModelDelta.NO_CHANGE); + ModelDelta rootDelta = new ModelDelta(fInput, IModelDelta.NO_CHANGE); + ModelDelta baseDelta = getBaseDelta(rootDelta); + TreePath relativePath = getRelativePath(parentPath); - TestElement element = getElement(parentPath); - ModelDelta delta= getElementDelta(baseDelta, parentPath); + TestElement element = getElement(relativePath); + ModelDelta delta= getElementDelta(baseDelta, relativePath); TestElement oldChild = element.fChildren[index]; element.fChildren[index] = child; delta.addNode(oldChild, child, IModelDelta.REPLACED); // TODO: set replacement index!?! - return baseDelta; + return rootDelta; } public ModelDelta addElementChild(TreePath parentPath, int index, TestElement newChild) { - ModelDelta baseDelta = new ModelDelta(getRootElement(), IModelDelta.NO_CHANGE); + ModelDelta rootDelta = new ModelDelta(fInput, IModelDelta.NO_CHANGE); + ModelDelta baseDelta = getBaseDelta(rootDelta); + TreePath relativePath = getRelativePath(parentPath); // Find the parent element and generate the delta node for it. - TestElement element = getElement(parentPath); - ModelDelta delta= getElementDelta(baseDelta, parentPath); + TestElement element = getElement(relativePath); + ModelDelta delta= getElementDelta(baseDelta, relativePath); // Add the new element element.fChildren = doInsertElementInArray(element.fChildren, index, newChild); @@ -337,15 +403,17 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider delta.setChildCount(element.getChildren().length); delta.addNode(newChild, IModelDelta.ADDED); - return baseDelta; + return rootDelta; } public ModelDelta insertElementChild(TreePath parentPath, int index, TestElement newChild) { - ModelDelta baseDelta = new ModelDelta(getRootElement(), IModelDelta.NO_CHANGE); + ModelDelta rootDelta = new ModelDelta(fInput, IModelDelta.NO_CHANGE); + ModelDelta baseDelta = getBaseDelta(rootDelta); + TreePath relativePath = getRelativePath(parentPath); // Find the parent element and generate the delta node for it. - TestElement element = getElement(parentPath); - ModelDelta delta= getElementDelta(baseDelta, parentPath); + TestElement element = getElement(relativePath); + ModelDelta delta= getElementDelta(baseDelta, relativePath); // Add the new element element.fChildren = doInsertElementInArray(element.fChildren, index, newChild); @@ -354,7 +422,7 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider delta.setChildCount(element.getChildren().length); delta.addNode(newChild, index, IModelDelta.INSERTED); - return baseDelta; + return rootDelta; } private TestElement[] doInsertElementInArray(TestElement[] children, int index, TestElement newChild) { @@ -368,7 +436,8 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider } public ModelDelta removeElementChild(TreePath parentPath, int index) { - ModelDelta baseDelta = new ModelDelta(getRootElement(), IModelDelta.NO_CHANGE); + ModelDelta rootDelta = new ModelDelta(fInput, IModelDelta.NO_CHANGE); + ModelDelta baseDelta = getBaseDelta(rootDelta); // Find the parent element and generate the delta node for it. TestElement element = getElement(parentPath); @@ -386,7 +455,7 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider delta.setChildCount(element.getChildren().length); delta.addNode(childToRemove, index, IModelDelta.REMOVED); - return baseDelta; + return rootDelta; } public TreePath findElement(String label) { @@ -410,46 +479,108 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider return null; } + public String toString() { + return getElementString(fRoot, ""); + } + + public String getElementString(TestElement element, String indent) { + StringBuffer builder = new StringBuffer(); + builder.append(indent); + builder.append(element.toString()); + builder.append('\n'); + TestElement[] children = element.getChildren(); + for (int i = 0; i < children.length; i++) { + builder.append(getElementString(children[i], indent + " ")); + } + return builder.toString(); + } + public static TestModel simpleSingleLevel() { TestModel model = new TestModel(); - model.setRoot( model.new TestElement("root", new TestElement[] { - model.new TestElement("1", true, true, new TestElement[0]), - model.new TestElement("2", true, false, new TestElement[0]), - model.new TestElement("3", false, true, new TestElement[0]), - model.new TestElement("4", false, false, new TestElement[0]), - model.new TestElement("5", new TestElement[0]), - model.new TestElement("6", new TestElement[0]) + model.setRoot( new TestElement(model, "root", new TestElement[] { + new TestElement(model, "1", true, true, new TestElement[0]), + new TestElement(model, "2", true, false, new TestElement[0]), + new TestElement(model, "3", false, true, new TestElement[0]), + new TestElement(model, "4", false, false, new TestElement[0]), + new TestElement(model, "5", new TestElement[0]), + new TestElement(model, "6", new TestElement[0]) }) ); return model; } public static TestModel simpleMultiLevel() { TestModel model = new TestModel(); - model.setRoot( model.new TestElement("root", new TestElement[] { - model.new TestElement("1", new TestElement[0]), - model.new TestElement("2", true, false, new TestElement[] { - model.new TestElement("2.1", true, true, new TestElement[0]), - model.new TestElement("2.2", false, true, new TestElement[0]), - model.new TestElement("2.3", true, false, new TestElement[0]), + model.setRoot( new TestElement(model, "root", new TestElement[] { + new TestElement(model, "1", new TestElement[0]), + new TestElement(model, "2", true, false, new TestElement[] { + new TestElement(model, "2.1", true, true, new TestElement[0]), + new TestElement(model, "2.2", false, true, new TestElement[0]), + new TestElement(model, "2.3", true, false, new TestElement[0]), }), - model.new TestElement("3", new TestElement[] { - model.new TestElement("3.1", new TestElement[] { - model.new TestElement("3.1.1", new TestElement[0]), - model.new TestElement("3.1.2", new TestElement[0]), - model.new TestElement("3.1.3", new TestElement[0]), + new TestElement(model, "3", new TestElement[] { + new TestElement(model, "3.1", new TestElement[] { + new TestElement(model, "3.1.1", new TestElement[0]), + new TestElement(model, "3.1.2", new TestElement[0]), + new TestElement(model, "3.1.3", new TestElement[0]), }), - model.new TestElement("3.2", new TestElement[] { - model.new TestElement("3.2.1", new TestElement[0]), - model.new TestElement("3.2.2", new TestElement[0]), - model.new TestElement("3.2.3", new TestElement[0]), + new TestElement(model, "3.2", new TestElement[] { + new TestElement(model, "3.2.1", new TestElement[0]), + new TestElement(model, "3.2.2", new TestElement[0]), + new TestElement(model, "3.2.3", new TestElement[0]), }), - model.new TestElement("3.3", new TestElement[] { - model.new TestElement("3.3.1", new TestElement[0]), - model.new TestElement("3.3.2", new TestElement[0]), - model.new TestElement("3.3.3", new TestElement[0]), + new TestElement(model, "3.3", new TestElement[] { + new TestElement(model, "3.3.1", new TestElement[0]), + new TestElement(model, "3.3.2", new TestElement[0]), + new TestElement(model, "3.3.3", new TestElement[0]), }), }) }) ); return model; } + + public static TestModel compositeMultiLevel() { + TestModel m2 = new TestModel(); + m2.setRoot( new TestElement(m2, "m2.root", new TestElement[] { + new TestElement(m2, "m2.1", new TestElement[0]), + new TestElement(m2, "m2.2", true, false, new TestElement[] { + new TestElement(m2, "m2.2.1", true, true, new TestElement[0]), + new TestElement(m2, "m2.2.2", false, true, new TestElement[0]), + new TestElement(m2, "m2.2.3", true, false, new TestElement[0]), + }), + }) ); + + TestModel m3 = new TestModel(); + m3.setRoot( new TestElement(m3, "m3.root", new TestElement[] { + new TestElement(m3, "m3.1", new TestElement[0]), + new TestElement(m3, "m3.2", true, false, new TestElement[] { + new TestElement(m3, "m3.2.1", true, true, new TestElement[0]), + new TestElement(m3, "m3.2.2", false, true, new TestElement[0]), + new TestElement(m3, "m3.2.3", true, false, new TestElement[0]), + }), + }) ); + + TestModel m4 = new TestModel(); + m4.setRoot( new TestElement(m4, "m4.root", new TestElement[] { + new TestElement(m4, "m4.1", new TestElement[0]), + new TestElement(m4, "m4.2", true, false, new TestElement[] { + new TestElement(m4, "m4.2.1", true, true, new TestElement[0]), + new TestElement(m4, "m4.2.2", false, true, new TestElement[0]), + new TestElement(m4, "m4.2.3", true, false, new TestElement[0]), + }), + }) ); + + TestModel m1 = new TestModel(); + m1.setRoot( new TestElement(m1, "m1.root", new TestElement[] { + new TestElement(m1, "m1.1", new TestElement[0]), + new TestElement(m1, "m1.2", true, false, new TestElement[] { + m2.fRoot, + m3.fRoot, + m4.fRoot, + }), + }) ); + + + return m1; + } + } diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModelUpdatesListener.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModelUpdatesListener.java index d0995fe2a..e6e2ecf8d 100644 --- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModelUpdatesListener.java +++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModelUpdatesListener.java @@ -12,6 +12,7 @@ package org.eclipe.debug.tests.viewer.model; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -39,13 +40,14 @@ public class TestModelUpdatesListener implements IViewerUpdateListener, ILabelUp public static final int CHILDREN_COUNT_UPDATES = 0X0010; public static final int CHILDREN_UPDATES = 0X0020; public static final int MODEL_CHANGED_COMPLETE = 0X0040; + public static final int MODEL_PROXIES_INSTALLED = 0X0080; public static final int LABEL_COMPLETE = LABEL_UPDATES_COMPLETE | LABEL_UPDATES; public static final int CONTENT_COMPLETE = CONTENT_UPDATES_COMPLETE | HAS_CHILDREN_UPDATES | CHILDREN_COUNT_UPDATES | CHILDREN_UPDATES; - public static final int ALL_UPDATES_COMPLETE = LABEL_COMPLETE | CONTENT_COMPLETE; + public static final int ALL_UPDATES_COMPLETE = LABEL_COMPLETE | CONTENT_COMPLETE | MODEL_PROXIES_INSTALLED; private boolean fFailOnRedundantUpdates; private boolean fFailOnMultipleUpdateSequences; @@ -54,6 +56,7 @@ public class TestModelUpdatesListener implements IViewerUpdateListener, ILabelUp private Map fChildrenUpdates = new HashMap(); private Set fChildCountUpdates = new HashSet(); private Set fLabelUpdates = new HashSet(); + private Set fProxyModels = new HashSet(); private boolean fViewerUpdatesComplete; private boolean fLabelUpdatesComplete; private boolean fModelChangedComplete; @@ -74,7 +77,8 @@ public class TestModelUpdatesListener implements IViewerUpdateListener, ILabelUp public void reset(TreePath path, TestElement element, int levels, boolean failOnRedundantUpdates, boolean failOnMultipleUpdateSequences) { reset(); - addUpdates(path, element, levels); + addUpdates(path, element, levels); + addProxies(element); setFailOnRedundantUpdates(failOnRedundantUpdates); setFailOnMultipleUpdateSequences(failOnMultipleUpdateSequences); } @@ -84,6 +88,7 @@ public class TestModelUpdatesListener implements IViewerUpdateListener, ILabelUp fChildrenUpdates.clear(); fChildCountUpdates.clear(); fLabelUpdates.clear(); + fProxyModels.clear(); fViewerUpdatesComplete = false; fLabelUpdatesComplete = false; fModelChangedComplete = false; @@ -156,6 +161,17 @@ public class TestModelUpdatesListener implements IViewerUpdateListener, ILabelUp } } } + + private void addProxies(TestElement element) { + TestModel model = element.getModel(); + if (model.getModelProxy() == null) { + fProxyModels.add(element.getModel()); + } + TestElement[] children = element.getChildren(); + for (int i = 0; i < children.length; i++) { + addProxies(children[i]); + } + } public boolean isFinished() { return isFinished(ALL_UPDATES_COMPLETE); @@ -183,6 +199,9 @@ public class TestModelUpdatesListener implements IViewerUpdateListener, ILabelUp if ( (flags & MODEL_CHANGED_COMPLETE) != 0) { if (!fModelChangedComplete) return false; } + if ( (flags & MODEL_PROXIES_INSTALLED) != 0) { + if (fProxyModels.size() != 0) return false; + } return true; } @@ -256,6 +275,14 @@ public class TestModelUpdatesListener implements IViewerUpdateListener, ILabelUp Assert.fail("Multiple model changed sequences detected"); } fModelChangedComplete = true; + + for (Iterator itr = fProxyModels.iterator(); itr.hasNext();) { + TestModel model = (TestModel)itr.next(); + if (model.getModelProxy() == proxy) { + itr.remove(); + break; + } + } } } diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/UpdateTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/UpdateTests.java index 5bc65f6bb..eff52f495 100644 --- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/UpdateTests.java +++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/UpdateTests.java @@ -94,9 +94,9 @@ abstract public class UpdateTests extends TestCase { TestElement root = model.getRootElement(); TreePath rootPath = new TreePath(new Object[] {}); TestElement[] newElements = new TestElement[] { - model.new TestElement("1", new TestElement[0]), - model.new TestElement("2", new TestElement[0]), - model.new TestElement("3", new TestElement[0]), + new TestElement(model, "1", new TestElement[0]), + new TestElement(model, "2", new TestElement[0]), + new TestElement(model, "3", new TestElement[0]), }; model.setElementChildren(rootPath, newElements); @@ -133,9 +133,9 @@ abstract public class UpdateTests extends TestCase { TestElement element = model.getRootElement().getChildren()[0]; TreePath elementPath = new TreePath(new Object[] { element }); TestElement[] newChildren = new TestElement[] { - model.new TestElement("1.1", new TestElement[0]), - model.new TestElement("1.2", new TestElement[0]), - model.new TestElement("1.3", new TestElement[0]), + new TestElement(model, "1.1", new TestElement[0]), + new TestElement(model, "1.2", new TestElement[0]), + new TestElement(model, "1.3", new TestElement[0]), }; model.setElementChildren(elementPath, newChildren); @@ -166,7 +166,7 @@ abstract public class UpdateTests extends TestCase { } private void addElement(TestModel model, String label, int position) { - ModelDelta delta = model.addElementChild(TreePath.EMPTY, position, model.new TestElement(label, new TestElement[0])); + ModelDelta delta = model.addElementChild(TreePath.EMPTY, position, new TestElement(model, label, new TestElement[0])); // Remove delta should generate no new updates, but we still need to wait for the event to // be processed. diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ModelContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ModelContentProvider.java index c61ddad00..ff8e90bbd 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ModelContentProvider.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ModelContentProvider.java @@ -45,6 +45,7 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDeltaVisitor; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory2; import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate; import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener; @@ -73,7 +74,20 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi */ private boolean fSuppressModelControlRequests = false; - private Map fModelProxies = new LinkedHashMap(); // model proxy by element + /** + * Map tree paths to model proxy responsible for element + * + * Used to install different model proxy instances for one element depending on the tree path. + */ + private Map fTreeModelProxies = new HashMap(); // tree model proxy by element tree path + + /** + * Map element to model proxy responsible for it. + * + * Used to install a single model proxy which is responsible + * for all instances of an element in the model tree. + */ + private Map fModelProxies = new HashMap(); // model proxy by element /** * Map of nodes that have been filtered from the viewer. @@ -273,7 +287,7 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi cancelSubtreeUpdates(TreePath.EMPTY); fTransform.clear(); if (newInput != null) { - installModelProxy(newInput); + installModelProxy(newInput, TreePath.EMPTY); restoreViewerState(newInput); } } @@ -757,8 +771,12 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi * * @param element */ - protected synchronized void disposeModelProxy(Object element) { - IModelProxy proxy = (IModelProxy) fModelProxies.remove(element); + protected synchronized void disposeModelProxy(TreePath path) { + IModelProxy proxy = (IModelProxy) fTreeModelProxies.remove(path); + if (proxy != null) { + proxy.dispose(); + } + proxy = (IModelProxy) fModelProxies.remove(path.getLastSegment()); if (proxy != null) { proxy.dispose(); } @@ -774,19 +792,36 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi proxy.dispose(); } fModelProxies.clear(); + + updatePolicies = fTreeModelProxies.values().iterator(); + while (updatePolicies.hasNext()) { + IModelProxy proxy = (IModelProxy) updatePolicies.next(); + proxy.dispose(); + } + fTreeModelProxies.clear(); } protected synchronized IModelProxy[] getModelProxies() { - return (IModelProxy[])fModelProxies.values().toArray(new IModelProxy[fModelProxies.size()]); + IModelProxy[] proxies = new IModelProxy[fTreeModelProxies.size() + fModelProxies.size()]; + fTreeModelProxies.values().toArray(proxies); + System.arraycopy(fModelProxies.values().toArray(), 0, proxies, fModelProxies.size(), fModelProxies.size()); + return proxies; } protected synchronized IModelProxy getElementProxy(TreePath path) { - for (int i = path.getSegmentCount() - 1; i >= 0; i--) { - IModelProxy proxy = (IModelProxy)fModelProxies.get(path.getSegment(i)); + while (path != null) { + IModelProxy proxy = (IModelProxy)fTreeModelProxies.get(path); if (proxy != null) { return proxy; } - } + + proxy = (IModelProxy)fModelProxies.get(path.getLastSegment()); + if (proxy != null) { + return proxy; + } + + path = path.getParentPath(); + } return null; } @@ -797,14 +832,30 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi * @param element * element to install an update policy for */ - protected synchronized void installModelProxy(Object element) { - if (!fModelProxies.containsKey(element)) { - IModelProxyFactory modelProxyFactory = ViewerAdapterService.getModelProxyFactory(element); - if (modelProxyFactory != null) { - final IModelProxy proxy = modelProxyFactory.createModelProxy( - element, getPresentationContext()); + protected synchronized void installModelProxy(Object input, TreePath path) { + if (!fTreeModelProxies.containsKey(path) && !fModelProxies.containsKey(path.getLastSegment())) { + Object element = path.getSegmentCount() != 0 ? path.getLastSegment() : input; + IModelProxy proxy = null; + IModelProxyFactory2 modelProxyFactory2 = ViewerAdapterService.getModelProxyFactory2(element); + if (modelProxyFactory2 != null) { + proxy = modelProxyFactory2.createTreeModelProxy(input, path, getPresentationContext()); + if (proxy != null) { + fTreeModelProxies.put(path, proxy); + } + } + if (proxy == null) { + IModelProxyFactory modelProxyFactory = ViewerAdapterService.getModelProxyFactory(element); + if (modelProxyFactory != null) { + proxy = modelProxyFactory.createModelProxy(element, getPresentationContext()); + if (proxy != null) { + fModelProxies.put(element, proxy); + } + } + } + + if (proxy != null) { + final IModelProxy finalProxy = proxy; if (proxy != null) { - fModelProxies.put(element, proxy); Job job = new Job("Model Proxy installed notification job") {//$NON-NLS-1$ protected IStatus run(IProgressMonitor monitor) { if (!monitor.isCanceled()) { @@ -816,10 +867,10 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi viewer = (Viewer)getViewer(); } } - if (context != null && !proxy.isDisposed()) { - proxy.init(context); - proxy.addModelChangedListener(ModelContentProvider.this); - proxy.installed(viewer); + if (context != null && !finalProxy.isDisposed()) { + finalProxy.init(context); + finalProxy.addModelChangedListener(ModelContentProvider.this); + finalProxy.installed(viewer); } } return Status.OK_STATUS; @@ -975,14 +1026,30 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi protected abstract void handleReveal(IModelDelta delta); protected void handleInstall(IModelDelta delta) { - installModelProxy(delta.getElement()); + installModelProxy(getViewer().getInput(), getFullTreePath(delta)); } protected void handleUninstall(IModelDelta delta) { - disposeModelProxy(delta.getElement()); + disposeModelProxy(getFullTreePath(delta)); } /** + * Returns a tree path for the node including the root element. + * + * @param node + * model delta + * @return corresponding tree path + */ + protected TreePath getFullTreePath(IModelDelta node) { + ArrayList list = new ArrayList(); + while (node.getParentDelta() != null) { + list.add(0, node.getElement()); + node = node.getParentDelta(); + } + return new TreePath(list.toArray()); + } + + /** * Returns a tree path for the node, *not* including the root element. * * @param node diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeModelContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeModelContentProvider.java index 0c550e8ba..07041e627 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeModelContentProvider.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeModelContentProvider.java @@ -107,6 +107,7 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT System.out.println("handleAdd(" + delta.getElement() + ") viewIndex: " + viewCount + " modelIndex: " + modelIndex); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } getViewer().setChildCount(parentPath, viewCount); + getViewer().autoExpand(parentPath); int viewIndex = modelToViewIndex(parentPath, modelIndex); getViewer().replace(parentPath, viewIndex, element); TreePath childPath = parentPath.createChildPath(element); diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerAdapterService.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerAdapterService.java index 7f4a82268..539e806c4 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerAdapterService.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerAdapterService.java @@ -18,6 +18,7 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor; import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory2; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicyFactory; import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; @@ -72,7 +73,7 @@ public class ViewerAdapterService { } /** - * Returns the model proxy factory for the given element or + * Returns the model proxy factory for the given element or * <code>null</code> if none. * * @param element element to retrieve adapter for @@ -81,7 +82,18 @@ public class ViewerAdapterService { public static IModelProxyFactory getModelProxyFactory(Object element) { return (IModelProxyFactory)getAdapter(element, IModelProxyFactory.class); } - + + /** + * Returns the model proxy factory v.2 for the given element or + * <code>null</code> if none. + * + * @param element element to retrieve adapter for + * @return model proxy factory or <code>null</code> + */ + public static IModelProxyFactory2 getModelProxyFactory2(Object element) { + return (IModelProxyFactory2)getAdapter(element, IModelProxyFactory2.class); + } + /** * Returns the memento provider for the given element or * <code>null</code> if none. diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelProxyFactory2.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelProxyFactory2.java new file mode 100644 index 000000000..2bbd8114e --- /dev/null +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelProxyFactory2.java @@ -0,0 +1,48 @@ +/*******************************************************************************
+ * Copyright (c) 2009 Freescale Semiconductor and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Freescale Semiconductor - initial API and implementation � Bug 241336
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.viewers.model.provisional;
+
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * A model proxy factory creates model proxies for elements based on
+ * specific presentation contexts. A model proxy factory is provided for
+ * a model element by registering a model proxy factory adapter for
+ * an element.
+ * <p>
+ * This interface is an alternative to the {@link IModelProxyFactory}
+ * interface. Unlike its predecessor <code>IModelProxyFactory2</code> allows
+ * the full path to the tree element to be specified when creating an
+ * <code>IModelProxy<code> instance. Using the full patch allows models to
+ * provide proper model deltas even if the root element of this proxy is at
+ * variable or unknown location in the viewer.
+ * </p>
+ * <p>
+ * Clients may implement this interface.
+ * </p>
+ * @see IModelProxyFactory
+ * @see IModelProxy
+ * @see IModelDelta
+ *
+ * @since 3.6
+ */
+public interface IModelProxyFactory2 {
+ /**
+ * Creates and returns a model proxy for the given element in the specified
+ * context or <code>null</code> if none.
+ *
+ * @param input viewer input context
+ * @param path to model element to create a model proxy for
+ * @param context presentation context
+ * @return model proxy or <code>null</code>
+ */
+ public IModelProxy createTreeModelProxy(Object input, TreePath path, IPresentationContext context);
+}
|