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