--- /dev/null
+package org.simantics.g3d.ui;\r
+\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+\r
+import org.eclipse.jface.viewers.ITreeContentProvider;\r
+import org.eclipse.jface.viewers.LabelProvider;\r
+import org.eclipse.jface.viewers.TreeViewer;\r
+import org.eclipse.jface.viewers.Viewer;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.ui.views.contentoutline.ContentOutlinePage;\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.g3d.scenegraph.base.NodeListener;\r
+import org.simantics.g3d.scenegraph.base.ParentNode;\r
+\r
+public class ScenegraphOutlinePage extends ContentOutlinePage implements NodeListener {\r
+ \r
+ private ParentNode<? extends INode> rootNode;\r
+ \r
+ public ScenegraphOutlinePage(ParentNode<? extends INode> rootNode) {\r
+ if (rootNode == null)\r
+ throw new NullPointerException();\r
+ this.rootNode = rootNode;\r
+ }\r
+\r
+ \r
+ @Override\r
+ public void createControl(Composite parent) {\r
+ super.createControl(parent);\r
+ if (rootNode == null)\r
+ return;\r
+ TreeViewer viewer = getTreeViewer();\r
+ createProviders(viewer);\r
+ viewer.setInput(rootNode);\r
+ listen(rootNode);\r
+ }\r
+ \r
+ protected void createProviders(TreeViewer viewer) {\r
+ viewer.setContentProvider(new ScenegraphContentProvider());\r
+ viewer.setLabelProvider(new ScenegraphLabelProvider());\r
+ }\r
+ \r
+ \r
+ \r
+ @SuppressWarnings("unchecked")\r
+ protected void listen(INode node) {\r
+ node.addListener(this);\r
+ if (node instanceof ParentNode<?>) {\r
+ ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
+ for (INode n : parentNode.getNodes())\r
+ listen(n);\r
+ }\r
+ }\r
+ \r
+ @SuppressWarnings("unchecked")\r
+ protected void stopListening(INode node) {\r
+ node.removeListener(this);\r
+ if (node instanceof ParentNode<?>) {\r
+ ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
+ for (INode n : parentNode.getNodes())\r
+ stopListening(n);\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void propertyChanged(INode node, String id) {\r
+ refershViewer(node);\r
+ }\r
+ \r
+ @Override\r
+ public <T extends INode> void nodeAdded(ParentNode<T> node, INode child,\r
+ String rel) {\r
+ listen(child);\r
+ refershViewer(node);\r
+ }\r
+ \r
+ \r
+ \r
+ @Override\r
+ public <T extends INode> void nodeRemoved(ParentNode<T> node, INode child,\r
+ String rel) {\r
+ stopListening(child);\r
+ refershViewer(node);\r
+ }\r
+ \r
+ //private Queue<INode> toRefresh = new LinkedList<INode>();\r
+ private Set<INode> toRefresh = new HashSet<INode>();\r
+ private NodeUpdater updater;\r
+ \r
+ protected void refershViewer(final INode node) {\r
+ if (getTreeViewer() == null)\r
+ return;\r
+ synchronized (toRefresh) {\r
+ toRefresh.add(node);\r
+ if (updater != null)\r
+ return;\r
+ }\r
+ \r
+ updater = new NodeUpdater();\r
+ Display.getDefault().asyncExec(updater);\r
+ }\r
+ \r
+ private class NodeUpdater implements Runnable {\r
+ @Override\r
+ public void run() {\r
+ if (getTreeViewer().getTree().isDisposed()) {\r
+ updater =null;\r
+ return;\r
+ }\r
+ int count = 0;\r
+ // limit the amount of refreshes.\r
+ while (count < 100) {\r
+ INode node = null;\r
+ synchronized (toRefresh) {\r
+ // if the queue becomes too long, refresh the whole tree\r
+// if (toRefresh.size() > 100) {\r
+// toRefresh.clear();\r
+// getTreeViewer().refresh();\r
+// updater = null;\r
+// return;\r
+// }\r
+ \r
+ //node = toRefresh.poll();\r
+ if (toRefresh.size() > 0) {\r
+ node = toRefresh.iterator().next();\r
+ toRefresh.remove(node);\r
+ }\r
+ if (node == null) {\r
+ updater = null;\r
+ return;\r
+ }\r
+ }\r
+ getTreeViewer().refresh(node);\r
+ count++;\r
+ }\r
+ if (toRefresh.size() > 0) {\r
+ Display.getDefault().asyncExec(this);\r
+ }\r
+ }\r
+ }\r
+ \r
+ public static class ScenegraphContentProvider implements ITreeContentProvider {\r
+ \r
+ public ScenegraphContentProvider() {\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public Object[] getChildren(Object parentElement) {\r
+ if (parentElement instanceof ParentNode<?>) {\r
+ ParentNode<?> parentNode = (ParentNode<?>)parentElement;\r
+ return parentNode.getNodes().toArray();\r
+ }\r
+ return new Object[0];\r
+ }\r
+ \r
+ @Override\r
+ public Object[] getElements(Object inputElement) {\r
+ return getChildren(inputElement);\r
+ }\r
+ \r
+ @Override\r
+ public Object getParent(Object element) {\r
+ if (element instanceof INode) {\r
+ INode node = (INode) element;\r
+ return node.getParent();\r
+ }\r
+ return null;\r
+ }\r
+ \r
+ @Override\r
+ public boolean hasChildren(Object element) {\r
+ if (element instanceof ParentNode<?>) {\r
+ ParentNode<?> parentNode = (ParentNode<?>)element;\r
+ return parentNode.getNodes().size() > 0;\r
+ }\r
+ return false;\r
+ }\r
+ \r
+ @Override\r
+ public void dispose() {\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
+ \r
+ }\r
+ }\r
+ \r
+ public class ScenegraphLabelProvider extends LabelProvider {\r
+ \r
+ }\r
+}\r