-/*******************************************************************************\r
- * Copyright (c) 2012, 2013 Association for Decentralized Information Management in\r
- * Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.g3d.csg.actions;\r
-\r
-import java.util.Collection;\r
-import java.util.HashMap;\r
-import java.util.Iterator;\r
-import java.util.Map;\r
-\r
-import javax.vecmath.Quat4d;\r
-import javax.vecmath.Vector3d;\r
-\r
-import org.eclipse.jface.action.Action;\r
-import org.simantics.g3d.csg.scenegraph2.CSGparentNode;\r
-import org.simantics.g3d.csg.scenegraph2.CSGrootNode;\r
-import org.simantics.g3d.csg.scenegraph2.ICSGnode;\r
-import org.simantics.utils.ui.ExceptionUtils;\r
-\r
-public class AddBooleanOpAction2 extends Action {\r
- CSGrootNode root;\r
- Class<? extends CSGparentNode> booleanClass;\r
- Collection<ICSGnode> nodes;\r
- \r
- public AddBooleanOpAction2(CSGrootNode root, Class<? extends CSGparentNode> booleanClass, Collection<ICSGnode> nodes) {\r
- super();\r
- String name = booleanClass.getSimpleName();\r
- if (name.endsWith("Node"))\r
- name = name.substring(0,name.length()-4);\r
- setText(name);\r
- this.booleanClass = booleanClass;\r
- this.nodes = nodes;\r
- this.root = root;\r
- if (nodes.size() != 2)\r
- setEnabled(false);\r
- for (ICSGnode node : nodes) {\r
- if (!node.getParent().equals(root))\r
- setEnabled(false);\r
- }\r
- }\r
- \r
- @Override\r
- public void run() {\r
- try {\r
- CSGparentNode booleanNode = booleanClass.newInstance();\r
- Map<ICSGnode,Vector3d> positions = new HashMap<ICSGnode, Vector3d>();\r
- Map<ICSGnode,Quat4d> orientations = new HashMap<ICSGnode, Quat4d>();\r
- for (ICSGnode node : nodes) {\r
- positions.put(node, node.getWorldPosition());\r
- orientations.put(node, node.getWorldOrientation());\r
- //root.remChild(node);\r
- node.deattach();\r
- }\r
- Iterator<ICSGnode> iter = nodes.iterator();\r
- booleanNode.addPrimaryChild(iter.next());\r
- booleanNode.addSecondaryChild(iter.next());\r
- \r
- String name = root.getUniqueName(booleanNode.getClass().getSimpleName());\r
- booleanNode.setName(name);\r
- \r
- root.addChild(booleanNode);\r
- for (ICSGnode node : nodes) {\r
- node.setWorldPosition(positions.get(node));\r
- node.setWorldOrientation(orientations.get(node));\r
- }\r
- root.getNodeMap().commit();\r
- } catch (Exception e) {\r
- ExceptionUtils.logAndShowError("Cannot create boolean operation.", e);\r
- }\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * 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.csg.actions;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.vecmath.Quat4d;
+import javax.vecmath.Vector3d;
+
+import org.eclipse.jface.action.Action;
+import org.simantics.g3d.csg.scenegraph2.CSGparentNode;
+import org.simantics.g3d.csg.scenegraph2.CSGrootNode;
+import org.simantics.g3d.csg.scenegraph2.ICSGnode;
+import org.simantics.utils.ui.ExceptionUtils;
+
+public class AddBooleanOpAction2 extends Action {
+ CSGrootNode root;
+ Class<? extends CSGparentNode> booleanClass;
+ Collection<ICSGnode> nodes;
+
+ public AddBooleanOpAction2(CSGrootNode root, Class<? extends CSGparentNode> booleanClass, Collection<ICSGnode> nodes) {
+ super();
+ String name = booleanClass.getSimpleName();
+ if (name.endsWith("Node"))
+ name = name.substring(0,name.length()-4);
+ setText(name);
+ this.booleanClass = booleanClass;
+ this.nodes = nodes;
+ this.root = root;
+ if (nodes.size() != 2)
+ setEnabled(false);
+ for (ICSGnode node : nodes) {
+ if (!node.getParent().equals(root))
+ setEnabled(false);
+ }
+ }
+
+ @Override
+ public void run() {
+ try {
+ CSGparentNode booleanNode = booleanClass.newInstance();
+ Map<ICSGnode,Vector3d> positions = new HashMap<ICSGnode, Vector3d>();
+ Map<ICSGnode,Quat4d> orientations = new HashMap<ICSGnode, Quat4d>();
+ for (ICSGnode node : nodes) {
+ positions.put(node, node.getWorldPosition());
+ orientations.put(node, node.getWorldOrientation());
+ //root.remChild(node);
+ node.deattach();
+ }
+ Iterator<ICSGnode> iter = nodes.iterator();
+ booleanNode.addPrimaryChild(iter.next());
+ booleanNode.addSecondaryChild(iter.next());
+
+ String name = root.getUniqueName(booleanNode.getClass().getSimpleName());
+ booleanNode.setName(name);
+
+ root.addChild(booleanNode);
+ for (ICSGnode node : nodes) {
+ node.setWorldPosition(positions.get(node));
+ node.setWorldOrientation(orientations.get(node));
+ }
+ root.getNodeMap().commit("Add Boolean Op");
+ } catch (Exception e) {
+ ExceptionUtils.logAndShowError("Cannot create boolean operation.", e);
+ }
+ }
+
+}
-/*******************************************************************************\r
- * Copyright (c) 2012, 2013 Association for Decentralized Information Management in\r
- * Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.g3d.csg.actions;\r
-\r
-import org.eclipse.jface.action.Action;\r
-import org.simantics.g3d.csg.scenegraph2.CSGnode;\r
-import org.simantics.g3d.csg.scenegraph2.CSGrootNode;\r
-import org.simantics.utils.ui.ExceptionUtils;\r
-\r
-public class AddPrimitiveAction2 extends Action {\r
- \r
- CSGrootNode root;\r
- Class<? extends CSGnode> primitiveClass;\r
- public AddPrimitiveAction2(CSGrootNode root, Class<? extends CSGnode> primitiveClass) {\r
- super();\r
- String name = primitiveClass.getSimpleName();\r
- if (name.endsWith("Node"))\r
- name = name.substring(0,name.length()-4);\r
- setText(name);\r
- this.primitiveClass = primitiveClass;\r
- this.root = root;\r
- }\r
- \r
- @Override\r
- public void run() {\r
- try {\r
- CSGnode node = primitiveClass.newInstance();\r
- String name = root.getUniqueName(node.getClass().getSimpleName());\r
- node.setName(name);\r
- root.addChild(node);\r
- root.getNodeMap().commit();\r
- } catch (Exception e) {\r
- ExceptionUtils.logAndShowError("Cannot create primitive.", e);\r
- }\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * 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.csg.actions;
+
+import org.eclipse.jface.action.Action;
+import org.simantics.g3d.csg.scenegraph2.CSGnode;
+import org.simantics.g3d.csg.scenegraph2.CSGrootNode;
+import org.simantics.utils.ui.ExceptionUtils;
+
+public class AddPrimitiveAction2 extends Action {
+
+ CSGrootNode root;
+ Class<? extends CSGnode> primitiveClass;
+ public AddPrimitiveAction2(CSGrootNode root, Class<? extends CSGnode> primitiveClass) {
+ super();
+ String name = primitiveClass.getSimpleName();
+ if (name.endsWith("Node"))
+ name = name.substring(0,name.length()-4);
+ setText(name);
+ this.primitiveClass = primitiveClass;
+ this.root = root;
+ }
+
+ @Override
+ public void run() {
+ try {
+ CSGnode node = primitiveClass.newInstance();
+ String name = root.getUniqueName(node.getClass().getSimpleName());
+ node.setName(name);
+ root.addChild(node);
+ root.getNodeMap().commit("Add primitive");
+ } catch (Exception e) {
+ ExceptionUtils.logAndShowError("Cannot create primitive.", e);
+ }
+ }
+
+}
-/*******************************************************************************\r
- * Copyright (c) 2012, 2013 Association for Decentralized Information Management in\r
- * Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.g3d.csg.actions;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.HashMap;\r
-import java.util.Map;\r
-\r
-import javax.vecmath.Quat4d;\r
-import javax.vecmath.Vector3d;\r
-\r
-import org.eclipse.jface.action.Action;\r
-import org.simantics.g3d.csg.scenegraph2.CSGparentNode;\r
-import org.simantics.g3d.csg.scenegraph2.CSGrootNode;\r
-import org.simantics.g3d.csg.scenegraph2.ICSGnode;\r
-\r
-public class SplitBooleanOpAction2 extends Action {\r
- private CSGrootNode root;\r
- private CSGparentNode booleanOp;\r
- \r
- public SplitBooleanOpAction2(CSGrootNode root, CSGparentNode booleanOp) {\r
- super();\r
- setText("Split");\r
- this.booleanOp = booleanOp;\r
- this.root = root;\r
- }\r
- \r
- @Override\r
- public void run() {\r
- Collection<ICSGnode> nodes = new ArrayList<ICSGnode>();\r
- nodes.addAll(booleanOp.getPrimaryChild());\r
- nodes.addAll(booleanOp.getSecondaryChild());\r
- Map<ICSGnode,Vector3d> positions = new HashMap<ICSGnode, Vector3d>();\r
- Map<ICSGnode,Quat4d> orientations = new HashMap<ICSGnode, Quat4d>();\r
- for (ICSGnode node : nodes) {\r
- positions.put(node, node.getWorldPosition());\r
- orientations.put(node, node.getWorldOrientation());\r
- node.deattach();\r
- }\r
- for (ICSGnode node : nodes) {\r
- root.addChild(node);\r
- node.setWorldPosition(positions.get(node));\r
- node.setWorldOrientation(orientations.get(node));\r
- }\r
- root.remChild(booleanOp);\r
- root.getNodeMap().commit();\r
-\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * 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.csg.actions;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.vecmath.Quat4d;
+import javax.vecmath.Vector3d;
+
+import org.eclipse.jface.action.Action;
+import org.simantics.g3d.csg.scenegraph2.CSGparentNode;
+import org.simantics.g3d.csg.scenegraph2.CSGrootNode;
+import org.simantics.g3d.csg.scenegraph2.ICSGnode;
+
+public class SplitBooleanOpAction2 extends Action {
+ private CSGrootNode root;
+ private CSGparentNode booleanOp;
+
+ public SplitBooleanOpAction2(CSGrootNode root, CSGparentNode booleanOp) {
+ super();
+ setText("Split");
+ this.booleanOp = booleanOp;
+ this.root = root;
+ }
+
+ @Override
+ public void run() {
+ Collection<ICSGnode> nodes = new ArrayList<ICSGnode>();
+ nodes.addAll(booleanOp.getPrimaryChild());
+ nodes.addAll(booleanOp.getSecondaryChild());
+ Map<ICSGnode,Vector3d> positions = new HashMap<ICSGnode, Vector3d>();
+ Map<ICSGnode,Quat4d> orientations = new HashMap<ICSGnode, Quat4d>();
+ for (ICSGnode node : nodes) {
+ positions.put(node, node.getWorldPosition());
+ orientations.put(node, node.getWorldOrientation());
+ node.deattach();
+ }
+ for (ICSGnode node : nodes) {
+ root.addChild(node);
+ node.setWorldPosition(positions.get(node));
+ node.setWorldOrientation(orientations.get(node));
+ }
+ root.remChild(booleanOp);
+ root.getNodeMap().commit("Split");
+
+ }
+
+}
-/*******************************************************************************\r
- * Copyright (c) 2012, 2013 Association for Decentralized Information Management in\r
- * Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.g3d.vtk.action;\r
-\r
-import org.eclipse.jface.action.Action;\r
-import org.simantics.g3d.scenegraph.IG3DNode;\r
-import org.simantics.g3d.scenegraph.structural.IStructuralNode;\r
-import org.simantics.g3d.vtk.Activator;\r
-import org.simantics.g3d.vtk.common.VTKNodeMap;\r
-\r
-public class RemoveAction extends Action {\r
-\r
- private VTKNodeMap nodeMap;\r
- protected IG3DNode node;\r
- \r
- public RemoveAction(VTKNodeMap nodeMap) {\r
- setText("Remove");\r
- setImageDescriptor(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/delete.png"));\r
- this.nodeMap = nodeMap;\r
- }\r
- \r
- public void setNode(IG3DNode node) {\r
- this.node = node;\r
- setEnabled(isRemovable(node));\r
- }\r
- \r
- public boolean isRemovable(IG3DNode node) {\r
- if ((node instanceof IStructuralNode) && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot())\r
- return false;\r
- return true;\r
- }\r
- \r
- @Override\r
- public void run() {\r
- \r
- doRemove(node);\r
- nodeMap.commit();\r
- node = null;\r
- }\r
- \r
- protected void doRemove(IG3DNode node) {\r
- node.remove();\r
- }\r
-}\r
+/*******************************************************************************
+ * 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.vtk.action;
+
+import org.eclipse.jface.action.Action;
+import org.simantics.g3d.scenegraph.IG3DNode;
+import org.simantics.g3d.scenegraph.structural.IStructuralNode;
+import org.simantics.g3d.vtk.Activator;
+import org.simantics.g3d.vtk.common.VTKNodeMap;
+
+public class RemoveAction extends Action {
+
+ private VTKNodeMap nodeMap;
+ protected IG3DNode node;
+
+ public RemoveAction(VTKNodeMap nodeMap) {
+ setText("Remove");
+ setImageDescriptor(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/delete.png"));
+ this.nodeMap = nodeMap;
+ }
+
+ public void setNode(IG3DNode node) {
+ this.node = node;
+ setEnabled(isRemovable(node));
+ }
+
+ public boolean isRemovable(IG3DNode node) {
+ if ((node instanceof IStructuralNode) && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot())
+ return false;
+ return true;
+ }
+
+ @Override
+ public void run() {
+
+ doRemove(node);
+ nodeMap.commit("Remove");
+ node = null;
+ }
+
+ protected void doRemove(IG3DNode node) {
+ node.remove();
+ }
+}
public void deattach() {
node = null;
- nodeMap.commit();
+ nodeMap.commit("Rotate");
deattachUI();
super.deattach();
panel.repaint();
public void deattach() {
node = null;
- nodeMap.commit();
+ nodeMap.commit("Translate");
deattachUI();
super.deattach();
panel.repaint();
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import org.simantics.db.common.request.ReadRequest;
import org.simantics.db.common.request.WriteRequest;
import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.util.Layer0Utils;
+import org.simantics.db.service.UndoRedoSupport;
import org.simantics.g3d.ontology.G3D;
import org.simantics.g3d.scenegraph.RenderListener;
import org.simantics.g3d.scenegraph.base.INode;
import org.simantics.g3d.scenegraph.base.NodeListener;
import org.simantics.g3d.scenegraph.base.ParentNode;
+import org.simantics.objmap.exceptions.MappingException;
import org.simantics.objmap.graph.IMapping;
import org.simantics.objmap.graph.IMappingListener;
import org.simantics.utils.datastructures.Callback;
import vtk.vtkProp;
-public abstract class AbstractVTKNodeMap<E extends INode> implements VTKNodeMap<E>, IMappingListener, RenderListener, NodeListener{
+public abstract class AbstractVTKNodeMap<E extends INode> implements VTKNodeMap<E>, IMappingListener, RenderListener, NodeListener, UndoRedoSupport.ChangeListener{
private static final boolean DEBUG = false;
protected ParentNode<E> rootNode;
+ protected UndoRedoSupport undoRedoSupport;
+ protected int undoOpCount = 0;
+ protected boolean runUndo = false;
public AbstractVTKNodeMap(Session session, IMapping<Object,E> mapping, VtkView view, ParentNode<E> rootNode) {
this.session = session;
this.mapping = mapping;
view.addListener(this);
mapping.addMappingListener(this);
rootNode.addListener(this);
+
+ undoRedoSupport = session.getService(UndoRedoSupport.class);
+ undoRedoSupport.subscribe(this);
+ try {
+ undoOpCount = undoRedoSupport.getUndoContext(session).getAll().size();
+ } catch(DatabaseException e) {
+ e.printStackTrace();
+ }
}
+
protected abstract void addActor(E node);
protected abstract void removeActor(E node);
protected abstract void updateActor(E node,Set<String> ids);
private boolean rangeModified = false;
+ @Override
+ public void onChanged() {
+ try {
+ int count = undoRedoSupport.getUndoContext(session).getAll().size();
+ if (count < undoOpCount) {
+ runUndo = true;
+ } else {
+ runUndo = false;
+ }
+ undoOpCount = count;
+ if (DEBUG) System.out.println("Undo " + runUndo);
+ } catch (DatabaseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+
+ }
+
@SuppressWarnings("unchecked")
@Override
public void updateRenderObjectsFor(INode node) {
@SuppressWarnings("unchecked")
private void receiveAdd(E node, String id, boolean db) {
- if (DEBUG) System.out.println("receiveAdd " + node + " " + id + " " + db);
+ if (DEBUG) System.out.println("receiveAdd " + debugString(node) + " " + id + " " + db);
synchronized (syncMutex) {
for (Pair<E, String> n : added) {
if (n.first.equals(node))
@SuppressWarnings("unchecked")
private void receiveRemove(E node, String id, boolean db) {
- if (DEBUG) System.out.println("receiveRemove " + node + " " + id + " " + db);
+ if (DEBUG) System.out.println("receiveRemove " + debugString(node) + " " + id + " " + db);
synchronized (syncMutex) {
for (Pair<E, String> n : removed) {
if (n.first.equals(node))
@SuppressWarnings("unchecked")
private void receiveUpdate(E node, String id, boolean db) {
- if (DEBUG) System.out.println("receiveUpdate " + node + " " + id + " " + db);
+ if (DEBUG) System.out.println("receiveUpdate " + debugString(node) + " " + id + " " + db);
synchronized (syncMutex) {
// for (Pair<E, String> n : updated) {
// if (n.first.equals(node))
private Set<E> graphModified = new HashSet<E>();
private boolean requestCommit = false;
+ private String commitMessage = null;
@Override
- public void commit() {
+ public void commit(String message) {
requestCommit = true;
+ commitMessage = message;
}
protected void doCommit() {
@Override
public void perform(WriteGraph graph) throws DatabaseException {
- commit(graph);
+ if (DEBUG) System.out.println("Commit " + commitMessage);
+ if (commitMessage != null) {
+ Layer0Utils.addCommentMetadata(graph, commitMessage);
+ graph.markUndoPoint();
+ commitMessage = null;
+ }
+ commit(graph);
}
}, new Callback<DatabaseException>() {
graphUpdates = true;
mapping.updateDomain(graph);
graphUpdates = false;
+ clearDeletes();
+ if (DEBUG) System.out.println("Commit done");
}
}
+
+
@Override
public void domainModified() {
if (graphUpdates)
}
+ protected void reset(ReadGraph graph) throws MappingException {
+ if (DEBUG) System.out.println("Reset");
+ synchronized (syncMutex) {
+ graphUpdates = true;
+ mapping.getRangeModified().clear();
+ for (Object o : mapping.getDomain())
+ mapping.domainModified(o);
+ mapping.updateRange(graph);
+ graphModified.clear();
+ graphUpdates = false;
+ }
+ }
+
+ private boolean useFullSyncWithUndo = false;
+
protected void update(ReadGraph graph) throws DatabaseException {
- synchronized (syncMutex) {
- graphUpdates = true;
- for (Object domainObject : mapping.getDomainModified()) {
- E rangeObject = mapping.get(domainObject);
- if (rangeObject != null)
- graphModified.add(rangeObject);
- }
- mapping.updateRange(graph);
- graphModified.clear();
- graphUpdates = false;
- }
+ if (DEBUG) System.out.println("Graph update start");
+ if (runUndo && useFullSyncWithUndo) {
+ reset(graph);
+ } else {
+ synchronized (syncMutex) {
+ graphUpdates = true;
+ for (Object domainObject : mapping.getDomainModified()) {
+ E rangeObject = mapping.get(domainObject);
+ if (rangeObject != null)
+ graphModified.add(rangeObject);
+ }
+ mapping.updateRange(graph);
+ graphModified.clear();
+ syncDeletes();
+ clearDeletes();
+ graphUpdates = false;
+ }
+ }
- if (mapping.isRangeModified())
- commit();
+ //if (mapping.isRangeModified() && !runUndo) // FIXME : redo?
+ if (mapping.isRangeModified())
+ commit((String)null);
+ if (DEBUG) System.out.println("Graph update done");
}
@Override
}
}
- List<Pair<E, String>> rem = new ArrayList<Pair<E,String>>();
- List<Pair<E, String>> add = new ArrayList<Pair<E,String>>();
- MapSet<E, String> mod = new MapSet.Hash<E, String>();
- Set<E> propagation = new HashSet<E>();
- Stack<E> stack = new Stack<E>();
-
+ // Reusable containers for data synchronisation
+ List<Pair<E, String>> rem = new ArrayList<Pair<E,String>>(); // Removed objects
+ List<Pair<E, String>> add = new ArrayList<Pair<E,String>>(); // Added objects
+ MapSet<E, String> mod = new MapSet.Hash<E, String>(); // Modified objects
+ Set<E> propagation = new HashSet<E>(); // Objects with propagated changes
+ Stack<E> stack = new Stack<E>(); // Stack for handling propagation
+ Set<E> delete = Collections.synchronizedSet(new HashSet<E>()); // Objects to be completely deleted
+ Set<E> deleteUC = new HashSet<E>();
@Override
public synchronized void preRender() {
updateCycle();
}
+
+ /**
+ * When objects are removed (either from Java or Graph), after remove processing the Java objects remain in mapping cache.
+ * This causes problems with Undo and Redo, whcih the end up re-using the removed objects from mapping cache.
+ *
+ * This code here synchronizes removed and added objects to collect deletable objects. (a deletable object is one which is removed but not added).
+ *
+ */
+ protected void syncDeletes() {
+ deleteUC.clear();
+ for (Pair<E, String> n : removed) {
+ deleteUC.add(n.first);
+ }
+ for (Pair<E, String> n : added) {
+ deleteUC.remove(n.first);
+ }
+ if (DEBUG && deleteUC.size() > 0) {
+ System.out.println("Delete sync");
+ for (E n : delete) {
+ System.out.println(debugString(n));
+ }
+ }
+ delete.addAll(deleteUC);
+ deleteUC.clear();
+ }
+
+ /**
+ * Clears deletable objects from mapping cache.
+ */
+ protected void clearDeletes() {
+ if (DEBUG && delete.size() > 0) System.out.println("Delete");
+ for (E n : delete) {
+ if (DEBUG) System.out.println(debugString(n));
+ mapping.getRange().remove(n);
+ }
+ delete.clear();
+ }
+
+ protected String debugString(E n) {
+ return n + "@" + Integer.toHexString(n.hashCode());
+ }
+
@SuppressWarnings("unchecked")
protected void updateCycle() {
rem.clear();
mod.clear();
propagation.clear();
+
synchronized (syncMutex) {
rem.addAll(removed);
add.addAll(added);
mod.add(e, s);
}
}
-
+ syncDeletes();
removed.clear();
added.clear();
updated.clear();
for (Pair<E, String> n : rem) {
stopListening(n.first);
removeActor(n.first);
-
}
for (Pair<E, String> n : add) {
for (String s : mod.getValues(e))
l.propertyChanged(e, s);
}
+
synchronized (syncMutex) {
- if (added.isEmpty() && removed.isEmpty() && updated.getKeys().size() == 0)
+ if (added.isEmpty() && removed.isEmpty() && updated.getKeys().size() == 0)
rangeModified = false;
}
}
@Override
public void delete() {
+ if (undoRedoSupport != null)
+ undoRedoSupport.cancel(this);
+
changeTracking = false;
view.removeListener(this);
mapping.removeMappingListener(this);
public void deattach() {
node = null;
- nodeMap.commit();
+ nodeMap.commit("Rotate");
deattachUI();
super.deattach();
panel.refresh();
public void deattach() {
node = null;
- nodeMap.commit();
+ nodeMap.commit("Translate");
deattachUI();
super.deattach();
panel.refresh();
if (DEBUG)System.err.println("CELL SET VALUE: " + element + " " + value);
manipulator.setValue((String)value,index);
viewer.refresh(item);
- nodeMap.commit();
+ nodeMap.commit("Set " + item.id + " value to " + value);
}
/**
* Commit changes to the database.
*/
- public void commit();
+ public void commit(String message);
/**
public void deattach() {
// deactivate();
component = null;
- nodeMap.commit();
+ nodeMap.commit("Add component");
deattachUI();
super.deattach();
panel.refresh();
String n = root.getUniqueName(item.getName());
equipment.setName(n);
root.addChild(equipment);
- root.getNodeMap().commit();
+ root.getNodeMap().commit("Add equipment " + n);
} catch (Exception e) {
ExceptionUtils.logAndShowError("Cannot create equipment",e);
}
equipment.addChild(nozzle);
//root.addChild(nozzle);
root.addChild(pipeRun);
- root.getNodeMap().commit();
+ root.getNodeMap().commit("Add nozzle " + n);
} catch (Exception e) {
ExceptionUtils.logAndShowError("Cannot create equipment",e);
}
public void deattach() {
deactivate();
startComponent = null;
- nodeMap.commit();
+ nodeMap.commit("Route pipe");
deattachUI();
super.deattach();
panel.refresh();
setEnabled(false);
return;
}
- if (prev.getControlPoint().isInline() && !prev.getControlPoint().isFixed())
+ if (prev.getControlPoint().isInline() && !prev.getControlPoint().isFixed() && prev.getPrevious() != null)
prev = prev.getPrevious();
- if (next.getControlPoint().isInline() && !next.getControlPoint().isFixed()) {
+ if (next.getControlPoint().isInline() && !next.getControlPoint().isFixed() && next.getNext() != null) {
next = next.getNext();
}
Point3d ns = new Point3d();
dir.normalize();
// We may have offsets in the path leg, hence we have to project the coordinates.
Vector3d wp = node.getWorldPosition();
- s = MathTools.closestPointOnStraight(pe, wp, dir);
- e = MathTools.closestPointOnStraight(ns, wp, dir);
+ if (prev.getControlPoint().isVariableLength())
+ s = MathTools.closestPointOnStraight(ps, wp, dir);
+ else
+ s = MathTools.closestPointOnStraight(pe, wp, dir);
+ if (next.getControlPoint().isVariableLength())
+ e = MathTools.closestPointOnStraight(ne, wp, dir);
+ else
+ e = MathTools.closestPointOnStraight(ns, wp, dir);
// Remove component's own space from end points to get actual movement range
double l = comp.getControlPoint().getInlineLength();
Vector3d ld = new Vector3d(dir);
}
@Override
- public void commit() {
+ public void commit(String commitMessage) {
validate();
// System.out.println("Graph commit");
- super.commit();
+ super.commit(commitMessage);
}
@Override
public void setNext(PipelineComponent comp) {
if (next == comp)
return;
+ if (comp == null)
+ this.next._removeRef(this);
this.next = comp;
+ this.syncnext = false;
syncNext();
firePropertyChanged(Plant3D.URIs.HasNext);
if (comp != null)
public void setPrevious(PipelineComponent comp) {
if (previous == comp)
return;
+ if (comp == null)
+ this.previous._removeRef(this);
this.previous = comp;
-
+ this.syncprev = false;
+ syncPrevious();
firePropertyChanged(Plant3D.URIs.HasPrevious);
if (comp != null)
comp.sync();
public void setBranch0(PipelineComponent comp) {
if (branch0 == comp)
return;
+ if (comp == null)
+ this.branch0._removeRef(this);
this.branch0 = comp;
+ this.syncbr0 = false;
syncBranch0();
firePropertyChanged(Plant3D.URIs.HasBranch0);
if (comp != null)
// System.out.println(this + " next " + comp);
}
+ @GetPropertyValue(name="Previous",tabId="Debug",value=Plant3D.URIs.HasPrevious)
+ public String getPreviousDebug() {
+ if (previous == null)
+ return null;
+ return previous.getName();
+ }
+
+ @GetPropertyValue(name="Next",tabId="Debug",value=Plant3D.URIs.HasNext)
+ public String getNextDebug() {
+ if (next == null)
+ return null;
+ return next.getName();
+ }
+
+ @GetPropertyValue(name="Branch0",tabId="Debug",value=Plant3D.URIs.HasBranch0)
+ public String getBR0Debug() {
+ if (branch0 == null)
+ return null;
+ return branch0.getName();
+ }
+
private PipeControlPoint getBranchPoint() {
PipeControlPoint branchPoint;
if (getControlPoint().getSubPoint().size() > 0) {
return true;
}
+ // When link to a component is removed, also link to the other direction must be removed at the same time, or
+ // Control point structure is left into illegal state.
+ private void _removeRef(PipelineComponent comp) {
+ if (next == comp) {
+ next = null;
+ syncnext = false;
+ syncNext();
+ } else if (previous == comp) {
+ previous = null;
+ syncprev = false;
+ syncPrevious();
+ } else if (branch0 == comp) {
+ branch0 = null;
+ syncbr0 = false;
+ syncBranch0();
+ }
+ }
+
+ boolean syncnext = false;
+ private void syncNext() {
+ if (syncnext)
+ return;
+ syncnext = _syncNext();
+ }
- private boolean syncNext() {
-
- if (getControlPoint() != null) {
+ private boolean _syncNext() {
+ PipeControlPoint pcp = getControlPoint();
+ if (pcp != null) {
+
if (next != null ) {
- if (next.getControlPoint() != null && next.getPipeRun() != null) {
+ if (next.getControlPoint() != null) {
// TODO, relying that the other direction is connected.
boolean nxt = next.getPrevious() == this;
boolean br0 = next.getBranch0() == this;
if (nxt){
- return _connectNext(getControlPoint(), next.getControlPoint());
+ return _connectNext(pcp, next.getControlPoint());
} else if (br0) {
- return _connectNext(getControlPoint(), next.getBranchPoint());
+ return _connectNext(pcp, next.getBranchPoint());
+ } else {
+ return false;
}
} else {
return false;
}
- } else if (getControlPoint().getPrevious() != null) {
- getControlPoint().setNext(null);
+ } else if (pcp.getNext() != null) {
+ pcp.setNext(null);
+ return true;
}
} else {
return false;
return true;
}
- private boolean syncPrevious() {
-
- if (getControlPoint() != null) {
+ boolean syncprev = false;
+ private void syncPrevious() {
+ if (syncprev)
+ return;
+ syncprev = _syncPrevious();
+ }
+
+ private boolean _syncPrevious() {
+ PipeControlPoint pcp = getControlPoint();
+ if (pcp != null) {
if (previous != null ) {
- if (previous.getControlPoint() != null && previous.getPipeRun() != null) {
+ if (previous.getControlPoint() != null) {
// TODO, relying that the other direction is connected.
boolean prev = previous.getNext() == this;
boolean br0 = previous.getBranch0() == this;
if (prev){
- return _connectPrev(getControlPoint(), previous.getControlPoint());
+ return _connectPrev(pcp, previous.getControlPoint());
} else if (br0) {
- return _connectPrev(getControlPoint(), previous.getBranchPoint());
+ return _connectPrev(pcp, previous.getBranchPoint());
+ } else {
+ return false;
}
} else {
return false;
}
- } else if (getControlPoint().getPrevious() != null) {
- getControlPoint().setPrevious(null);
+ } else if (pcp.getPrevious() != null) {
+ pcp.setPrevious(null);
+ return true;
}
} else {
return false;
return true;
}
- private boolean syncBranch0() {
+ boolean syncbr0 = false;
+ private void syncBranch0() {
+ if (syncbr0)
+ return;
+ syncbr0 = _syncBranch0();
+ }
+
+ private boolean _syncBranch0() {
if (getControlPoint() != null) {
if (getControlPoint().isDualInline()) {
branch0 = null;
return false;
}
if (branch0 != null) {
- if (branch0.getControlPoint() != null && branch0.getPipeRun() != null) {
+ if (branch0.getControlPoint() != null) {
PipeControlPoint branchPoint = getBranchPoint();
PipeControlPoint pcp = branch0.getControlPoint();
// TODO, relying that the other direction is connected.
_connectNext(branchPoint, pcp);
} else if (prev){
_connectPrev(branchPoint, pcp);
+ } else {
+ return false;
}
+
} else {
return false;
}
} else if (getControlPoint().getSubPoint().size() > 0) { // TODO : this may cause problems? (Removes branch point, before branch has been set?)
getControlPoint().getSubPoint().get(0).remove();
getControlPoint().children.clear();
+ return true;
}
} else {
return false;
public class PipeControlPoint extends G3DNode implements IP3DNode {
+
+ private static boolean DEBUG = false;
public enum Type{INLINE,TURN,END};
public enum Direction{NEXT,PREVIOUS};
public void setNext(PipeControlPoint next) {
if (isEnd() && previous != null && next != null)
throw new RuntimeException("End control points are allowed to have only one connection");
-// if (next != null && getPipeRun() == null)
-// throw new RuntimeException("Cannot connect control point befor piperun has been set");
+ if (this.next == next)
+ return;
+ if (DEBUG) System.out.println(this + " next " + next);
this.next = next;
if (component != null) {
if (parent == null || sub)
public void setPrevious(PipeControlPoint previous) {
if (isEnd() && next != null && previous != null)
throw new RuntimeException("End control points are allowed to have only one connection");
-// if (previous != null && getPipeRun() == null)
-// throw new RuntimeException("Cannot connect control point befor piperun has been set");
+ if (this.previous == previous)
+ return;
+ if (DEBUG) System.out.println(this + " previous " + previous);
this.previous = previous;
if (component != null) {
if (parent == null || sub)
public PipeControlPoint getParentPoint() {
return parent;
}
-
-
-
-
-
-
private double length;
private Double turnAngle;
private Vector3d turnAxis;
}
public void setTurnAxis(Vector3d turnAxis) {
- this.turnAxis = turnAxis;
+ if (this.turnAxis != null && MathTools.equals(turnAxis, this.turnAxis))
+ return;
+ this.turnAxis = turnAxis;
firePropertyChanged("turnAxis");
}
dir.sub(pcp.getWorldPosition(),previous.getWorldPosition());
if (dir.lengthSquared() > MathTools.NEAR_ZERO)
dir.normalize();
+ else
+ return null;
Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0);
AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle());
Quat4d q2 = MathTools.getQuat(aa);
dir.sub(next.getWorldPosition(),pcp.getWorldPosition());
if (dir.lengthSquared() > MathTools.NEAR_ZERO)
dir.normalize();
+ else
+ return null;
Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0);
AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle());
Quat4d q2 = MathTools.getQuat(aa);
if (component == null)
return;
PipelineComponent next = component.getNext();
- PipelineComponent prev = component.getNext();
+ PipelineComponent prev = component.getPrevious();
+ PipelineComponent br0 = component.getBranch0();
+ component.setNext(null);
+ component.setPrevious(null);
+ component.setBranch0(null);
if (next != null) {
if (next.getNext() == component)
next.setNext(null);
else if (next.getPrevious() == component)
next.setPrevious(null);
+ else if (next.getBranch0() == component)
+ next.setBranch0(null);
}
if (prev != null) {
if (prev.getNext() == component)
prev.setNext(null);
else if (prev.getPrevious() == component)
prev.setPrevious(null);
+ else if (prev.getBranch0() == component)
+ prev.setBranch0(null);
+ }
+ if (br0 != null) {
+ if (br0.getNext() == component)
+ prev.setNext(null);
+ else if (br0.getPrevious() == component)
+ prev.setPrevious(null);
+ else if (br0.getBranch0() == component)
+ br0.setBranch0(null);
}
PipelineComponent comp = component;
component = null;
turnAngle = 0.0;
tcp.setTurnAngle(0.0);
tcp.setLength(0.0);
- tcp.setTurnAxis(MathTools.Y_AXIS);
+ tcp.setTurnAxis(new Vector3d(MathTools.Y_AXIS));
}
updateControlPointOrientation(tcp);
if (DEBUG)
}
List<PipeControlPoint> runPcps = getControlPoints(pipeRun);
if (runPcps.size() != count) {
- System.out.println("Run is not connected");
+ System.out.println("Run " + pipeRun.getName() + " contains unconnected control points");
}
for (PipeControlPoint pcp : pcps) {
if (!pcp.isDirected() && pcp.getNext() == null && pcp.getPrevious() == null)