X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.scenegraph.ui%2Fsrc%2Forg%2Fsimantics%2Fscenegraph%2Fui%2FSceneGraphViewPart.java;fp=bundles%2Forg.simantics.scenegraph.ui%2Fsrc%2Forg%2Fsimantics%2Fscenegraph%2Fui%2FSceneGraphViewPart.java;h=b1b60949f128e215b62d3834803805807c3a39cb;hp=d6e95399355b01726d287bf9aa127ecf5c2610d8;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hpb=24e2b34260f219f0d1644ca7a138894980e25b14 diff --git a/bundles/org.simantics.scenegraph.ui/src/org/simantics/scenegraph/ui/SceneGraphViewPart.java b/bundles/org.simantics.scenegraph.ui/src/org/simantics/scenegraph/ui/SceneGraphViewPart.java index d6e953993..b1b60949f 100644 --- a/bundles/org.simantics.scenegraph.ui/src/org/simantics/scenegraph/ui/SceneGraphViewPart.java +++ b/bundles/org.simantics.scenegraph.ui/src/org/simantics/scenegraph/ui/SceneGraphViewPart.java @@ -1,549 +1,549 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 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.scenegraph.ui; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import java.lang.ref.WeakReference; -import java.util.List; - -import org.eclipse.core.commands.Command; -import org.eclipse.core.commands.State; -import org.eclipse.jface.layout.TreeColumnLayout; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.jface.resource.LocalResourceManager; -import org.eclipse.jface.viewers.ColumnLabelProvider; -import org.eclipse.jface.viewers.ColumnWeightData; -import org.eclipse.jface.viewers.DoubleClickEvent; -import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.TreePath; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.TreeViewerColumn; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.jface.viewers.ViewerCell; -import org.eclipse.swt.SWT; -import org.eclipse.swt.dnd.Clipboard; -import org.eclipse.swt.dnd.TextTransfer; -import org.eclipse.swt.dnd.Transfer; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.IPartListener2; -import org.eclipse.ui.IPartService; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.IWorkbenchPartReference; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.commands.ICommandService; -import org.eclipse.ui.contexts.IContextActivation; -import org.eclipse.ui.contexts.IContextService; -import org.eclipse.ui.part.ViewPart; -import org.simantics.scenegraph.ILookupService; -import org.simantics.scenegraph.INode; -import org.simantics.scenegraph.g2d.G2DParentNode; -import org.simantics.scenegraph.g2d.G2DSceneGraph; -import org.simantics.scenegraph.g2d.IG2DNode; -import org.simantics.scenegraph.g2d.nodes.BoundsNode; -import org.simantics.scenegraph.g2d.nodes.BranchPointNode; -import org.simantics.scenegraph.g2d.nodes.EdgeNode; -import org.simantics.scenegraph.g2d.nodes.GridNode; -import org.simantics.scenegraph.g2d.nodes.LinkNode; -import org.simantics.scenegraph.g2d.nodes.NavigationNode; -import org.simantics.scenegraph.g2d.nodes.PageBorderNode; -import org.simantics.scenegraph.g2d.nodes.RulerNode; -import org.simantics.scenegraph.g2d.nodes.SVGNode; -import org.simantics.scenegraph.g2d.nodes.ShapeNode; -import org.simantics.scenegraph.g2d.nodes.SingleElementNode; -import org.simantics.scenegraph.g2d.nodes.TransformNode; -import org.simantics.scenegraph.utils.NodeUtil; -import org.simantics.scenegraph.utils.NodeUtil.NodeProcedure; - -/** - * This view shows the contents of a 2D/3D canvas scenegraph through a tree - * viewer. - * - *

- * The viewer sources its scene graph input from the currently active workbench - * editor. It does not automatically track the active editor part but instead - * has to be refreshed manually (F5). - *

- * - *

- * References to actual scene graph nodes are only kept as {@link WeakReference} - * instances allowing them to be garbage collected if the scene graph is - * disposed of. - *

- * - * @author Tuukka Lehtonen - */ -public class SceneGraphViewPart extends ViewPart { - - TreeViewer tree; - LocalResourceManager resourceManager; - boolean bootstrapped = false; - IContextActivation contextActivation; - int currentNodeCount = 0; - boolean linkToPart; - IWorkbenchPart lastPart; - AttributeDialog attributeDialog; - - final ImageDescriptor ROOT = ImageDescriptor.createFromURL(getClass().getResource("bullet_home.png")); - final ImageDescriptor CANVAS_BOUNDS = ImageDescriptor.createFromURL(getClass().getResource("application.png")); - final ImageDescriptor SHAPE = ImageDescriptor.createFromURL(getClass().getResource("shape_shadow.png")); - final ImageDescriptor NAVIGATION = ImageDescriptor.createFromURL(getClass().getResource("arrow_out_longer.png")); - final ImageDescriptor SVG = ImageDescriptor.createFromURL(getClass().getResource("script_code.png")); - final ImageDescriptor TRANSFORM = ImageDescriptor.createFromURL(getClass().getResource("arrow_nsew.png")); - final ImageDescriptor ELEMENT = ImageDescriptor.createFromURL(getClass().getResource("shape_handles.png")); - final ImageDescriptor PARENT = ImageDescriptor.createFromURL(getClass().getResource("share.png")); - final ImageDescriptor GRID = ImageDescriptor.createFromURL(getClass().getResource("border_all.png")); - final ImageDescriptor RULER = ImageDescriptor.createFromURL(getClass().getResource("text_ruler.png")); - final ImageDescriptor PAGE_BORDER = ImageDescriptor.createFromURL(getClass().getResource("page_white.png")); - final ImageDescriptor EDGE = ImageDescriptor.createFromURL(getClass().getResource("arrow_ew.png")); - final ImageDescriptor BRANCH_POINT = ImageDescriptor.createFromURL(getClass().getResource("bullet_black.png")); - final ImageDescriptor LINK = ImageDescriptor.createFromURL(getClass().getResource("link.png")); - - NodeProcedure nodeProcedure = new NodeProcedure() { - @Override - public NodeProxy execute(INode node, String id) { - return new NodeProxy(node, id); - } - }; - - class ContentProvider implements ITreeContentProvider { - - @Override - public Object[] getChildren(Object parentElement) { - if (parentElement instanceof NodeProxy) { - NodeProxy np = (NodeProxy) parentElement; - INode n = np.getNode(); - if (n != null) { - List children = NodeUtil.forChildren(n, nodeProcedure); - return children.toArray(); - } - } - return new Object[0]; - } - - @Override - public Object getParent(Object element) { - return null; - } - - @Override - public boolean hasChildren(Object element) { - if (element instanceof NodeProxy) { - NodeProxy np = (NodeProxy) element; - INode n = np.getNode(); - if (n != null) - return NodeUtil.hasChildren(n); - } - return false; - } - - @Override - public Object[] getElements(Object inputElement) { - if (inputElement instanceof INode[]) { - INode[] ns = (INode[]) inputElement; - NodeProxy[] result = new NodeProxy[ns.length]; - for (int i = 0; i < ns.length; ++i) - result[i] = new NodeProxy(ns[i], "root"); - return result; - } - if (inputElement instanceof INode) { - INode n = (INode) inputElement; - return new Object[] { new NodeProxy(n, "root") }; - } - return new Object[0]; - } - - @Override - public void dispose() { - } - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - } - - private Image toImage(NodeProxy proxy) { - INode n = proxy.getNode(); - if (n == null) - return null; - - if (n instanceof G2DSceneGraph) { - return resourceManager.createImage(ROOT); - } else if (n instanceof SingleElementNode) { - return resourceManager.createImage(ELEMENT); - } else if (n instanceof TransformNode) { - return resourceManager.createImage(TRANSFORM); - } else if (n instanceof NavigationNode) { - return resourceManager.createImage(NAVIGATION); - } else if (n instanceof BoundsNode) { - return resourceManager.createImage(CANVAS_BOUNDS); - } else if (n instanceof EdgeNode) { - return resourceManager.createImage(EDGE); - } else if (n instanceof BranchPointNode) { - return resourceManager.createImage(BRANCH_POINT); - } else if (n instanceof ShapeNode) { - return resourceManager.createImage(SHAPE); - } else if (n instanceof SVGNode) { - return resourceManager.createImage(SVG); - } else if (n instanceof G2DParentNode) { - return resourceManager.createImage(PARENT); - } else if (n instanceof GridNode) { - return resourceManager.createImage(GRID); - } else if (n instanceof RulerNode) { - return resourceManager.createImage(RULER); - } else if (n instanceof PageBorderNode) { - return resourceManager.createImage(PAGE_BORDER); - } else if (n instanceof LinkNode) { - return resourceManager.createImage(LINK); - } - return null; - } - - class InternalIdLabelProvider extends ColumnLabelProvider { - @Override - public void update(ViewerCell cell) { - NodeProxy proxy = (NodeProxy) cell.getElement(); - cell.setText(proxy.getInternalId()); - //cell.setImage(toImage(proxy)); - } - } - class TypeLabelProvider extends ColumnLabelProvider { - @Override - public void update(ViewerCell cell) { - NodeProxy proxy = (NodeProxy) cell.getElement(); - cell.setText(proxy.getTypeName()); - //cell.setImage(toImage(proxy)); - } - } - class IdLabelProvider extends ColumnLabelProvider { - @Override - public void update(ViewerCell cell) { - NodeProxy proxy = (NodeProxy) cell.getElement(); - cell.setText(proxy.getId()); - cell.setImage(toImage(proxy)); - } - } - class LookupIdLabelProvider extends ColumnLabelProvider { - @Override - public void update(ViewerCell cell) { - NodeProxy proxy = (NodeProxy) cell.getElement(); - INode node = proxy.getNode(); - String lookupId = null; - if (node != null) { - ILookupService lut = NodeUtil.tryGetLookupService(node); - if (lut != null) - lookupId = lut.lookupId(node); - } - cell.setText(lookupId != null ? lookupId : ""); - } - } - class ZLabelProvider extends ColumnLabelProvider { - @Override - public void update(ViewerCell cell) { - NodeProxy proxy = (NodeProxy) cell.getElement(); - INode node = proxy.getNode(); - if (node instanceof IG2DNode) { - IG2DNode n = (IG2DNode) node; - cell.setText(String.valueOf(n.getZIndex())); - } else { - cell.setText("-"); - } - } - } - - @Override - public void createPartControl(Composite parent) { - - tree = new TreeViewer(parent, SWT.SINGLE | SWT.FULL_SELECTION); - resourceManager = new LocalResourceManager(JFaceResources.getResources(), tree.getTree()); - - TreeColumnLayout ad = new TreeColumnLayout(); - parent.setLayout(ad); - - //tree.getTree().setLayout(new FillLayout()); - tree.setContentProvider(new ContentProvider()); - tree.getTree().setHeaderVisible(true); - //tree.getTree().setLinesVisible(true); - tree.setUseHashlookup(true); - tree.setAutoExpandLevel(3); - - TreeViewerColumn nameColumn = new TreeViewerColumn(tree, SWT.LEFT); - TreeViewerColumn typeColumn = new TreeViewerColumn(tree, SWT.LEFT); - TreeViewerColumn idColumn = new TreeViewerColumn(tree, SWT.LEFT); - TreeViewerColumn lookupIdColumn = new TreeViewerColumn(tree, SWT.LEFT); - TreeViewerColumn zColumn = new TreeViewerColumn(tree, SWT.LEFT); - - nameColumn.setLabelProvider(new IdLabelProvider()); - typeColumn.setLabelProvider(new TypeLabelProvider()); - idColumn.setLabelProvider(new InternalIdLabelProvider()); - lookupIdColumn.setLabelProvider(new LookupIdLabelProvider()); - zColumn.setLabelProvider(new ZLabelProvider()); - - nameColumn.getColumn().setText("Name"); - nameColumn.getColumn().setWidth(20); - ad.setColumnData(nameColumn.getColumn(), new ColumnWeightData(80, 100)); - typeColumn.getColumn().setText("Type"); - typeColumn.getColumn().setWidth(20); - ad.setColumnData(typeColumn.getColumn(), new ColumnWeightData(20, 120)); - idColumn.getColumn().setText("ID"); - idColumn.getColumn().setWidth(20); - ad.setColumnData(idColumn.getColumn(), new ColumnWeightData(10, 50)); - lookupIdColumn.getColumn().setText("Lookup ID"); - lookupIdColumn.getColumn().setWidth(20); - ad.setColumnData(lookupIdColumn.getColumn(), new ColumnWeightData(50, 100)); - zColumn.getColumn().setText("Z"); - zColumn.getColumn().setWidth(70); - ad.setColumnData(zColumn.getColumn(), new ColumnWeightData(10, 70)); - - tree.addSelectionChangedListener(new ISelectionChangedListener() { - @Override - public void selectionChanged(SelectionChangedEvent event) { - updateContentDescription(); - } - }); - tree.addDoubleClickListener(new IDoubleClickListener() { - @Override - public void doubleClick(DoubleClickEvent event) { - openAttributeDialog(); - } - }); - - contextActivation = ((IContextService) getSite() - .getService(IContextService.class)) - .activateContext("org.simantics.scenegraph.viewer"); - - ICommandService commandService = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class); - Command command = commandService.getCommand(LinkToActiveWorkbenchPartHandler.COMMAND); - State state = command.getState(LinkToActiveWorkbenchPartHandler.STATE); - this.linkToPart = Boolean.TRUE.equals(state.getValue()); - - // No need to remove this listener, the part service is local to this site. - IPartService partService = (IPartService) getSite().getService(IPartService.class); - partService.addPartListener(partListener); - } - - @Override - public void dispose() { - closeAttributeDialog(); - } - - protected void openAttributeDialog() { - if (attributeDialog != null) { - Shell shell = attributeDialog.getShell(); - if (shell == null || shell.isDisposed()) - attributeDialog = null; - } - if (attributeDialog == null) { - attributeDialog = new AttributeDialog(getSite().getShell(), tree); - attributeDialog.setBlockOnOpen(false); - attributeDialog.open(); - } - } - - protected void closeAttributeDialog() { - if (attributeDialog != null) { - attributeDialog.close(); - attributeDialog = null; - } - } - - IPartListener2 partListener = new IPartListener2() { - @Override - public void partVisible(IWorkbenchPartReference partRef) { - } - @Override - public void partOpened(IWorkbenchPartReference partRef) { - } - @Override - public void partInputChanged(IWorkbenchPartReference partRef) { - } - @Override - public void partHidden(IWorkbenchPartReference partRef) { - } - @Override - public void partDeactivated(IWorkbenchPartReference partRef) { - } - @Override - public void partClosed(IWorkbenchPartReference partRef) { - if (linkToPart) { - IWorkbenchPart part = partRef.getPart(false); - if (part != null) - refresh(null); - } - } - @Override - public void partBroughtToTop(IWorkbenchPartReference partRef) { - } - @Override - public void partActivated(IWorkbenchPartReference partRef) { - if (linkToPart) { - IWorkbenchPart part = partRef.getPart(false); - if (part != null) { - if (part != lastPart) { - refresh(part); - } - } - } - } - }; - - @Override - public void setFocus() { - tree.getTree().setFocus(); - if (!bootstrapped) { - bootstrapped = true; - refresh(); - } - } - - protected void refresh() { - IWorkbenchPart part = null; - try { - IWorkbenchWindow window = getSite().getWorkbenchWindow(); - if (window == null) - return; - IWorkbenchPage page = window.getActivePage(); - if (page == null) - return; - part = page.getActiveEditor(); - if (part == null) - return; - } finally { - if (part == null) { - setContentDescription("No scene graph nodes available."); - // TODO: Show info page instead of tree view. - } - } - - refresh(part); - } - - /** - * @param part null to reset the view to a blank state. - * @return - */ - protected boolean refresh(IWorkbenchPart part) { - boolean foundInput = true; - try { - Object obj = null; - if (part != null) { - obj = part.getAdapter(INode[].class); - if (obj == null) - obj = part.getAdapter(INode.class); - } - - if (obj != null) { - TreePath[] expanded = tree.getExpandedTreePaths(); - tree.setInput(obj); - tree.setExpandedTreePaths(expanded); - this.currentNodeCount = countNodes(obj); - updateContentDescription(); - foundInput = true; - } - lastPart = part; - return foundInput; - } finally { - if (!foundInput) { - setContentDescription("No scene graph nodes available."); - // TODO: Show info page instead of tree view. - } - } - } - - private void updateContentDescription() { - StringBuilder desc = new StringBuilder(); - desc.append(currentNodeCount + " nodes in total."); - - IStructuredSelection ss = (IStructuredSelection) tree.getSelection(); - Object obj = ss.getFirstElement(); - if (obj instanceof NodeProxy) { - NodeProxy np = (NodeProxy) obj; - INode n = np.getNode(); - if (n != null) { - int depth = NodeUtil.getDepth(n); - desc.append(" Selection "); - desc.append("at depth "); - desc.append(depth); - desc.append("."); - } - } - - setContentDescription(desc.toString()); - } - - private int countNodes(Object obj) { - if (obj instanceof INode) { - INode n = (INode) obj; - return NodeUtil.countTreeNodes(n); - } else if (obj instanceof INode[]) { - INode[] ns = (INode[]) obj; - int result = 0; - for (INode n : ns) - result += NodeUtil.countTreeNodes(n); - return result; - } - return 0; - } - - void copySelectionToClipboard() { - IStructuredSelection selection = (IStructuredSelection) tree.getSelection(); - Object obj = selection.getFirstElement(); - if (!(obj instanceof NodeProxy)) - return; - - NodeProxy np = (NodeProxy) obj; - INode n = np.getNode(); - if (n == null) - return; - - ByteArrayOutputStream bytes = new ByteArrayOutputStream(100000); - PrintStream stream = new PrintStream(bytes); - NodeUtil.printSceneGraph(stream, 0, n); - String textData = new String(bytes.toByteArray()); - if (textData.isEmpty()) - return; - - Clipboard clipboard = new Clipboard(tree.getControl().getDisplay()); - TextTransfer textTransfer = TextTransfer.getInstance(); - Transfer[] transfers = new Transfer[]{textTransfer}; - Object[] data = new Object[]{textData}; - clipboard.setContents(data, transfers); - clipboard.dispose(); - } - - void collapseAll() { - for (Object obj : tree.getExpandedElements()) { - tree.setExpandedState(obj, false); - } - } - - void expandSelectedNode() { - IStructuredSelection ss = (IStructuredSelection) tree.getSelection(); - for (Object obj : ss.toList()) { - tree.expandToLevel(obj, TreeViewer.ALL_LEVELS); - } - } - - public void linkToActiveWorkbenchPart(boolean value) { - this.linkToPart = value; - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2010 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.scenegraph.ui; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.lang.ref.WeakReference; +import java.util.List; + +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.State; +import org.eclipse.jface.layout.TreeColumnLayout; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.resource.LocalResourceManager; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TreePath; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.TreeViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerCell; +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IPartListener2; +import org.eclipse.ui.IPartService; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchPartReference; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.contexts.IContextActivation; +import org.eclipse.ui.contexts.IContextService; +import org.eclipse.ui.part.ViewPart; +import org.simantics.scenegraph.ILookupService; +import org.simantics.scenegraph.INode; +import org.simantics.scenegraph.g2d.G2DParentNode; +import org.simantics.scenegraph.g2d.G2DSceneGraph; +import org.simantics.scenegraph.g2d.IG2DNode; +import org.simantics.scenegraph.g2d.nodes.BoundsNode; +import org.simantics.scenegraph.g2d.nodes.BranchPointNode; +import org.simantics.scenegraph.g2d.nodes.EdgeNode; +import org.simantics.scenegraph.g2d.nodes.GridNode; +import org.simantics.scenegraph.g2d.nodes.LinkNode; +import org.simantics.scenegraph.g2d.nodes.NavigationNode; +import org.simantics.scenegraph.g2d.nodes.PageBorderNode; +import org.simantics.scenegraph.g2d.nodes.RulerNode; +import org.simantics.scenegraph.g2d.nodes.SVGNode; +import org.simantics.scenegraph.g2d.nodes.ShapeNode; +import org.simantics.scenegraph.g2d.nodes.SingleElementNode; +import org.simantics.scenegraph.g2d.nodes.TransformNode; +import org.simantics.scenegraph.utils.NodeUtil; +import org.simantics.scenegraph.utils.NodeUtil.NodeProcedure; + +/** + * This view shows the contents of a 2D/3D canvas scenegraph through a tree + * viewer. + * + *

+ * The viewer sources its scene graph input from the currently active workbench + * editor. It does not automatically track the active editor part but instead + * has to be refreshed manually (F5). + *

+ * + *

+ * References to actual scene graph nodes are only kept as {@link WeakReference} + * instances allowing them to be garbage collected if the scene graph is + * disposed of. + *

+ * + * @author Tuukka Lehtonen + */ +public class SceneGraphViewPart extends ViewPart { + + TreeViewer tree; + LocalResourceManager resourceManager; + boolean bootstrapped = false; + IContextActivation contextActivation; + int currentNodeCount = 0; + boolean linkToPart; + IWorkbenchPart lastPart; + AttributeDialog attributeDialog; + + final ImageDescriptor ROOT = ImageDescriptor.createFromURL(getClass().getResource("bullet_home.png")); + final ImageDescriptor CANVAS_BOUNDS = ImageDescriptor.createFromURL(getClass().getResource("application.png")); + final ImageDescriptor SHAPE = ImageDescriptor.createFromURL(getClass().getResource("shape_shadow.png")); + final ImageDescriptor NAVIGATION = ImageDescriptor.createFromURL(getClass().getResource("arrow_out_longer.png")); + final ImageDescriptor SVG = ImageDescriptor.createFromURL(getClass().getResource("script_code.png")); + final ImageDescriptor TRANSFORM = ImageDescriptor.createFromURL(getClass().getResource("arrow_nsew.png")); + final ImageDescriptor ELEMENT = ImageDescriptor.createFromURL(getClass().getResource("shape_handles.png")); + final ImageDescriptor PARENT = ImageDescriptor.createFromURL(getClass().getResource("share.png")); + final ImageDescriptor GRID = ImageDescriptor.createFromURL(getClass().getResource("border_all.png")); + final ImageDescriptor RULER = ImageDescriptor.createFromURL(getClass().getResource("text_ruler.png")); + final ImageDescriptor PAGE_BORDER = ImageDescriptor.createFromURL(getClass().getResource("page_white.png")); + final ImageDescriptor EDGE = ImageDescriptor.createFromURL(getClass().getResource("arrow_ew.png")); + final ImageDescriptor BRANCH_POINT = ImageDescriptor.createFromURL(getClass().getResource("bullet_black.png")); + final ImageDescriptor LINK = ImageDescriptor.createFromURL(getClass().getResource("link.png")); + + NodeProcedure nodeProcedure = new NodeProcedure() { + @Override + public NodeProxy execute(INode node, String id) { + return new NodeProxy(node, id); + } + }; + + class ContentProvider implements ITreeContentProvider { + + @Override + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof NodeProxy) { + NodeProxy np = (NodeProxy) parentElement; + INode n = np.getNode(); + if (n != null) { + List children = NodeUtil.forChildren(n, nodeProcedure); + return children.toArray(); + } + } + return new Object[0]; + } + + @Override + public Object getParent(Object element) { + return null; + } + + @Override + public boolean hasChildren(Object element) { + if (element instanceof NodeProxy) { + NodeProxy np = (NodeProxy) element; + INode n = np.getNode(); + if (n != null) + return NodeUtil.hasChildren(n); + } + return false; + } + + @Override + public Object[] getElements(Object inputElement) { + if (inputElement instanceof INode[]) { + INode[] ns = (INode[]) inputElement; + NodeProxy[] result = new NodeProxy[ns.length]; + for (int i = 0; i < ns.length; ++i) + result[i] = new NodeProxy(ns[i], "root"); + return result; + } + if (inputElement instanceof INode) { + INode n = (INode) inputElement; + return new Object[] { new NodeProxy(n, "root") }; + } + return new Object[0]; + } + + @Override + public void dispose() { + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + } + + private Image toImage(NodeProxy proxy) { + INode n = proxy.getNode(); + if (n == null) + return null; + + if (n instanceof G2DSceneGraph) { + return resourceManager.createImage(ROOT); + } else if (n instanceof SingleElementNode) { + return resourceManager.createImage(ELEMENT); + } else if (n instanceof TransformNode) { + return resourceManager.createImage(TRANSFORM); + } else if (n instanceof NavigationNode) { + return resourceManager.createImage(NAVIGATION); + } else if (n instanceof BoundsNode) { + return resourceManager.createImage(CANVAS_BOUNDS); + } else if (n instanceof EdgeNode) { + return resourceManager.createImage(EDGE); + } else if (n instanceof BranchPointNode) { + return resourceManager.createImage(BRANCH_POINT); + } else if (n instanceof ShapeNode) { + return resourceManager.createImage(SHAPE); + } else if (n instanceof SVGNode) { + return resourceManager.createImage(SVG); + } else if (n instanceof G2DParentNode) { + return resourceManager.createImage(PARENT); + } else if (n instanceof GridNode) { + return resourceManager.createImage(GRID); + } else if (n instanceof RulerNode) { + return resourceManager.createImage(RULER); + } else if (n instanceof PageBorderNode) { + return resourceManager.createImage(PAGE_BORDER); + } else if (n instanceof LinkNode) { + return resourceManager.createImage(LINK); + } + return null; + } + + class InternalIdLabelProvider extends ColumnLabelProvider { + @Override + public void update(ViewerCell cell) { + NodeProxy proxy = (NodeProxy) cell.getElement(); + cell.setText(proxy.getInternalId()); + //cell.setImage(toImage(proxy)); + } + } + class TypeLabelProvider extends ColumnLabelProvider { + @Override + public void update(ViewerCell cell) { + NodeProxy proxy = (NodeProxy) cell.getElement(); + cell.setText(proxy.getTypeName()); + //cell.setImage(toImage(proxy)); + } + } + class IdLabelProvider extends ColumnLabelProvider { + @Override + public void update(ViewerCell cell) { + NodeProxy proxy = (NodeProxy) cell.getElement(); + cell.setText(proxy.getId()); + cell.setImage(toImage(proxy)); + } + } + class LookupIdLabelProvider extends ColumnLabelProvider { + @Override + public void update(ViewerCell cell) { + NodeProxy proxy = (NodeProxy) cell.getElement(); + INode node = proxy.getNode(); + String lookupId = null; + if (node != null) { + ILookupService lut = NodeUtil.tryGetLookupService(node); + if (lut != null) + lookupId = lut.lookupId(node); + } + cell.setText(lookupId != null ? lookupId : ""); + } + } + class ZLabelProvider extends ColumnLabelProvider { + @Override + public void update(ViewerCell cell) { + NodeProxy proxy = (NodeProxy) cell.getElement(); + INode node = proxy.getNode(); + if (node instanceof IG2DNode) { + IG2DNode n = (IG2DNode) node; + cell.setText(String.valueOf(n.getZIndex())); + } else { + cell.setText("-"); + } + } + } + + @Override + public void createPartControl(Composite parent) { + + tree = new TreeViewer(parent, SWT.SINGLE | SWT.FULL_SELECTION); + resourceManager = new LocalResourceManager(JFaceResources.getResources(), tree.getTree()); + + TreeColumnLayout ad = new TreeColumnLayout(); + parent.setLayout(ad); + + //tree.getTree().setLayout(new FillLayout()); + tree.setContentProvider(new ContentProvider()); + tree.getTree().setHeaderVisible(true); + //tree.getTree().setLinesVisible(true); + tree.setUseHashlookup(true); + tree.setAutoExpandLevel(3); + + TreeViewerColumn nameColumn = new TreeViewerColumn(tree, SWT.LEFT); + TreeViewerColumn typeColumn = new TreeViewerColumn(tree, SWT.LEFT); + TreeViewerColumn idColumn = new TreeViewerColumn(tree, SWT.LEFT); + TreeViewerColumn lookupIdColumn = new TreeViewerColumn(tree, SWT.LEFT); + TreeViewerColumn zColumn = new TreeViewerColumn(tree, SWT.LEFT); + + nameColumn.setLabelProvider(new IdLabelProvider()); + typeColumn.setLabelProvider(new TypeLabelProvider()); + idColumn.setLabelProvider(new InternalIdLabelProvider()); + lookupIdColumn.setLabelProvider(new LookupIdLabelProvider()); + zColumn.setLabelProvider(new ZLabelProvider()); + + nameColumn.getColumn().setText("Name"); + nameColumn.getColumn().setWidth(20); + ad.setColumnData(nameColumn.getColumn(), new ColumnWeightData(80, 100)); + typeColumn.getColumn().setText("Type"); + typeColumn.getColumn().setWidth(20); + ad.setColumnData(typeColumn.getColumn(), new ColumnWeightData(20, 120)); + idColumn.getColumn().setText("ID"); + idColumn.getColumn().setWidth(20); + ad.setColumnData(idColumn.getColumn(), new ColumnWeightData(10, 50)); + lookupIdColumn.getColumn().setText("Lookup ID"); + lookupIdColumn.getColumn().setWidth(20); + ad.setColumnData(lookupIdColumn.getColumn(), new ColumnWeightData(50, 100)); + zColumn.getColumn().setText("Z"); + zColumn.getColumn().setWidth(70); + ad.setColumnData(zColumn.getColumn(), new ColumnWeightData(10, 70)); + + tree.addSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + updateContentDescription(); + } + }); + tree.addDoubleClickListener(new IDoubleClickListener() { + @Override + public void doubleClick(DoubleClickEvent event) { + openAttributeDialog(); + } + }); + + contextActivation = ((IContextService) getSite() + .getService(IContextService.class)) + .activateContext("org.simantics.scenegraph.viewer"); + + ICommandService commandService = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class); + Command command = commandService.getCommand(LinkToActiveWorkbenchPartHandler.COMMAND); + State state = command.getState(LinkToActiveWorkbenchPartHandler.STATE); + this.linkToPart = Boolean.TRUE.equals(state.getValue()); + + // No need to remove this listener, the part service is local to this site. + IPartService partService = (IPartService) getSite().getService(IPartService.class); + partService.addPartListener(partListener); + } + + @Override + public void dispose() { + closeAttributeDialog(); + } + + protected void openAttributeDialog() { + if (attributeDialog != null) { + Shell shell = attributeDialog.getShell(); + if (shell == null || shell.isDisposed()) + attributeDialog = null; + } + if (attributeDialog == null) { + attributeDialog = new AttributeDialog(getSite().getShell(), tree); + attributeDialog.setBlockOnOpen(false); + attributeDialog.open(); + } + } + + protected void closeAttributeDialog() { + if (attributeDialog != null) { + attributeDialog.close(); + attributeDialog = null; + } + } + + IPartListener2 partListener = new IPartListener2() { + @Override + public void partVisible(IWorkbenchPartReference partRef) { + } + @Override + public void partOpened(IWorkbenchPartReference partRef) { + } + @Override + public void partInputChanged(IWorkbenchPartReference partRef) { + } + @Override + public void partHidden(IWorkbenchPartReference partRef) { + } + @Override + public void partDeactivated(IWorkbenchPartReference partRef) { + } + @Override + public void partClosed(IWorkbenchPartReference partRef) { + if (linkToPart) { + IWorkbenchPart part = partRef.getPart(false); + if (part != null) + refresh(null); + } + } + @Override + public void partBroughtToTop(IWorkbenchPartReference partRef) { + } + @Override + public void partActivated(IWorkbenchPartReference partRef) { + if (linkToPart) { + IWorkbenchPart part = partRef.getPart(false); + if (part != null) { + if (part != lastPart) { + refresh(part); + } + } + } + } + }; + + @Override + public void setFocus() { + tree.getTree().setFocus(); + if (!bootstrapped) { + bootstrapped = true; + refresh(); + } + } + + protected void refresh() { + IWorkbenchPart part = null; + try { + IWorkbenchWindow window = getSite().getWorkbenchWindow(); + if (window == null) + return; + IWorkbenchPage page = window.getActivePage(); + if (page == null) + return; + part = page.getActiveEditor(); + if (part == null) + return; + } finally { + if (part == null) { + setContentDescription("No scene graph nodes available."); + // TODO: Show info page instead of tree view. + } + } + + refresh(part); + } + + /** + * @param part null to reset the view to a blank state. + * @return + */ + protected boolean refresh(IWorkbenchPart part) { + boolean foundInput = true; + try { + Object obj = null; + if (part != null) { + obj = part.getAdapter(INode[].class); + if (obj == null) + obj = part.getAdapter(INode.class); + } + + if (obj != null) { + TreePath[] expanded = tree.getExpandedTreePaths(); + tree.setInput(obj); + tree.setExpandedTreePaths(expanded); + this.currentNodeCount = countNodes(obj); + updateContentDescription(); + foundInput = true; + } + lastPart = part; + return foundInput; + } finally { + if (!foundInput) { + setContentDescription("No scene graph nodes available."); + // TODO: Show info page instead of tree view. + } + } + } + + private void updateContentDescription() { + StringBuilder desc = new StringBuilder(); + desc.append(currentNodeCount + " nodes in total."); + + IStructuredSelection ss = (IStructuredSelection) tree.getSelection(); + Object obj = ss.getFirstElement(); + if (obj instanceof NodeProxy) { + NodeProxy np = (NodeProxy) obj; + INode n = np.getNode(); + if (n != null) { + int depth = NodeUtil.getDepth(n); + desc.append(" Selection "); + desc.append("at depth "); + desc.append(depth); + desc.append("."); + } + } + + setContentDescription(desc.toString()); + } + + private int countNodes(Object obj) { + if (obj instanceof INode) { + INode n = (INode) obj; + return NodeUtil.countTreeNodes(n); + } else if (obj instanceof INode[]) { + INode[] ns = (INode[]) obj; + int result = 0; + for (INode n : ns) + result += NodeUtil.countTreeNodes(n); + return result; + } + return 0; + } + + void copySelectionToClipboard() { + IStructuredSelection selection = (IStructuredSelection) tree.getSelection(); + Object obj = selection.getFirstElement(); + if (!(obj instanceof NodeProxy)) + return; + + NodeProxy np = (NodeProxy) obj; + INode n = np.getNode(); + if (n == null) + return; + + ByteArrayOutputStream bytes = new ByteArrayOutputStream(100000); + PrintStream stream = new PrintStream(bytes); + NodeUtil.printSceneGraph(stream, 0, n); + String textData = new String(bytes.toByteArray()); + if (textData.isEmpty()) + return; + + Clipboard clipboard = new Clipboard(tree.getControl().getDisplay()); + TextTransfer textTransfer = TextTransfer.getInstance(); + Transfer[] transfers = new Transfer[]{textTransfer}; + Object[] data = new Object[]{textData}; + clipboard.setContents(data, transfers); + clipboard.dispose(); + } + + void collapseAll() { + for (Object obj : tree.getExpandedElements()) { + tree.setExpandedState(obj, false); + } + } + + void expandSelectedNode() { + IStructuredSelection ss = (IStructuredSelection) tree.getSelection(); + for (Object obj : ss.toList()) { + tree.expandToLevel(obj, TreeViewer.ALL_LEVELS); + } + } + + public void linkToActiveWorkbenchPart(boolean value) { + this.linkToPart = value; + } + +}