/******************************************************************************* * 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")); NodeProcedurenull
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;
}
}