X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fhandler%2FDeleteHandler.java;h=5fa94ebc7a2787d1c9b3a51db9fe508ef04106dc;hb=3e877b48594c98cff85f4db64964f86fe14c0f03;hp=d26e0cdcdaf27788286c16bb255119df70c33503;hpb=593a8f75d9dbc363234002dc500c346afbeba040;p=simantics%2Fplatform.git
diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/DeleteHandler.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/DeleteHandler.java
index d26e0cdcd..5fa94ebc7 100644
--- a/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/DeleteHandler.java
+++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/DeleteHandler.java
@@ -1,440 +1,452 @@
-/*******************************************************************************
- * 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.diagram.handler;
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.jface.action.IStatusLineManager;
-import org.eclipse.swt.widgets.Display;
-import org.simantics.DatabaseJob;
-import org.simantics.Simantics;
-import org.simantics.db.ReadGraph;
-import org.simantics.db.Resource;
-import org.simantics.db.WriteGraph;
-import org.simantics.db.common.request.WriteRequest;
-import org.simantics.db.exception.DatabaseException;
-import org.simantics.db.layer0.adapter.Remover;
-import org.simantics.db.layer0.exception.CannotRemoveException;
-import org.simantics.db.layer0.util.RemoverUtil;
-import org.simantics.diagram.adapter.ElementFactoryUtil;
-import org.simantics.diagram.content.ConnectionUtil;
-import org.simantics.diagram.content.EdgeResource;
-import org.simantics.diagram.internal.Activator;
-import org.simantics.diagram.synchronization.ISynchronizationContext;
-import org.simantics.diagram.synchronization.graph.RemoveBranchpoint;
-import org.simantics.diagram.synchronization.graph.RemoveElement;
-import org.simantics.diagram.ui.DiagramModelHints;
-import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
-import org.simantics.g2d.connection.ConnectionEntity;
-import org.simantics.g2d.connection.handler.ConnectionHandler;
-import org.simantics.g2d.diagram.IDiagram;
-import org.simantics.g2d.diagram.handler.PickRequest.PickFilter;
-import org.simantics.g2d.diagram.handler.Relationship;
-import org.simantics.g2d.diagram.handler.RelationshipHandler;
-import org.simantics.g2d.diagram.handler.RelationshipHandler.Relation;
-import org.simantics.g2d.diagram.handler.Topology;
-import org.simantics.g2d.diagram.handler.Topology.Connection;
-import org.simantics.g2d.diagram.handler.Topology.Terminal;
-import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant;
-import org.simantics.g2d.diagram.participant.Selection;
-import org.simantics.g2d.element.ElementClass;
-import org.simantics.g2d.element.ElementHints;
-import org.simantics.g2d.element.ElementUtils;
-import org.simantics.g2d.element.IElement;
-import org.simantics.g2d.element.handler.BendsHandler;
-import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;
-import org.simantics.g2d.element.handler.TerminalTopology;
-import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;
-import org.simantics.scenegraph.g2d.events.command.CommandEvent;
-import org.simantics.scenegraph.g2d.events.command.Commands;
-import org.simantics.utils.logging.TimeLogger;
-import org.simantics.utils.strings.EString;
-import org.simantics.utils.threads.SWTThread;
-import org.simantics.utils.threads.ThreadUtils;
-import org.simantics.utils.ui.dialogs.ShowMessage;
-
-/**
- * DeleteHandler is a canvas handler for Commands.DELETE commands for an
- * IDiagram.
- *
- *
- * The handler attempts to delete the current selection for pointer 0, meaning
- * {@link Selection#SELECTION0}.
- *
- *
- *
- * The handler logic goes as follows:
- *
- *
- * - Separate nodes and edges form the the removed selection
- * - Find all edges attached to the removed nodes and remove them too
- * - Delete connections that contain less than 2 terminal connections
- *
- *
- * @see Selection for the current diagram selection source
- *
- * @author Tuukka Lehtonen
- *
- * TODO: start using WorkbenchStatusLine participant
- */
-public class DeleteHandler extends AbstractDiagramParticipant {
-
- public static final boolean DEBUG_DELETE = false;
-
- @Dependency Selection sel;
-
- private final IStatusLineManager statusLine;
-
- public DeleteHandler(IStatusLineManager statusLine) {
- this.statusLine = statusLine;
- }
-
- @EventHandler(priority = 0)
- public boolean handleCommand(CommandEvent e) {
- if (Commands.DELETE.equals( e.command )) {
- IDiagram d = diagram;
- if (d == null)
- return true;
-
- Set ss = sel.getSelection(0);
- if (ss.isEmpty())
- return true;
-
- if (delete(d, ss)) {
- sel.clear(0);
- }
-
- return true;
- }
- return false;
- }
-
- public boolean delete(final IDiagram d, Collection ss) {
- TimeLogger.resetTimeAndLog(getClass(), "delete");
-
- Topology topology = d.getDiagramClass().getAtMostOneItemOfClass(Topology.class);
- RelationshipHandler erh = d.getDiagramClass().getAtMostOneItemOfClass(RelationshipHandler.class);
-
- if (DEBUG_DELETE) {
- System.out.println("diagram: " + d);
- for (IElement e : d.getSnapshot()) {
- ElementClass ec = e.getElementClass();
- System.out.println("\t-element " + e);
- System.out.println("\t -class " + e.getElementClass());
- if (ec.containsClass(ConnectionHandler.class)) {
- ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);
- for (IElement child : ce.getBranchPoints(null)) {
- System.out.println("\t\t-branch " + child);
- System.out.println("\t\t -class " + child.getElementClass());
- }
- for (IElement child : ce.getSegments(null)) {
- System.out.println("\t\t-segment " + child);
- System.out.println("\t\t -class " + child.getElementClass());
- }
- }
- }
- System.out.println("delete requested for elements:");
- for (IElement e : ss)
- System.out.println("\t-element " + e);
- }
-
- // Analyze removals:
- // - separate elements and connections
- // - find all connections attached to the elements and remove them too
- Deque elementsToProcess = new ArrayDeque(ss);
- Set processedElements = new HashSet();
- Set relationshipsProcessedForElement = new HashSet();
-
- final Collection elements = new ArrayList();
- final Set edges = new HashSet();
- Collection connections = new ArrayList();
- Collection terminals = new ArrayList();
- Collection relations = new ArrayList();
- while (!elementsToProcess.isEmpty()) {
- IElement el = elementsToProcess.pollFirst();
-
- if (relationshipsProcessedForElement.add(el)) {
- // Check for relationships to other elements and mark child
- // elements to be removed before the parent element.
- relations.clear();
- erh.getRelations(d, el, relations);
- if (!relations.isEmpty()) {
- boolean restart = false;
- for (Relation r : relations) {
- //System.out.println("FOUND RELATION: " + r);
- if (r.getRelationship() == Relationship.PARENT_OF) {
- if ((r.getObject() instanceof IElement)) {
- IElement ee = (IElement) r.getObject();
- if (d.containsElement(ee)) {
- //System.out.println("DIAGRAM CONTAINS OBJECT: " + r.getObject());
-
- // Mark the object also to be processed for removal.
- elementsToProcess.addFirst(ee);
- restart = true;
- }
- }
- }
- }
- if (restart) {
- // Only process this element after we're sure that
- // all its children have been processed.
- elementsToProcess.addLast(el);
- continue;
- }
- }
- }
-
- if (!processedElements.add(el))
- continue;
-
- TerminalTopology tt = el.getElementClass().getAtMostOneItemOfClass(TerminalTopology.class);
- BendsHandler bh = el.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
-
- if (bh != null) {
- // Verify that the edge is NOT between two branch points.
- // If it is, do not allow deletion because it is the only case
- // which can break a connection tree into a connection forest.
- // We do not want that to happen.
- Connection begin = topology.getConnection(el, EdgeEnd.Begin);
- Connection end = topology.getConnection(el, EdgeEnd.End);
-
- // Try to work with cases where the model is somewhat corrupt.
- if (begin != null && end != null) {
- if (PickFilter.FILTER_BRANCH_POINT.accept(begin.node) && PickFilter.FILTER_BRANCH_POINT.accept(end.node)) {
- error("Deletion of branch point connecting edges is not allowed. Must be connected to a node terminal.");
- return false;
- }
- }
-
- if (DEBUG_DELETE)
- System.out.println("ADDED EDGE FOR REMOVAL: " + el);
- edges.add(el);
- } else {
- if (DEBUG_DELETE)
- System.out.println("ADDED ELEMENT FOR REMOVAL: " + el);
- elements.add(el);
-
- if (tt != null) {
- terminals.clear();
- tt.getTerminals(el, terminals);
- connections.clear();
- for (Terminal terminal : terminals)
- topology.getConnections(el, terminal, connections);
- for (Connection c : connections) {
- if (c.edge != null) {
- if (c.edge.getElementClass().containsClass(BendsHandler.class))
- edges.add(c.edge);
- if (DEBUG_DELETE)
- System.out.println("TERMINAL CONNECTION WILL BE DISCONNECTED: " + c);
- }
- }
- }
- }
- }
-
- if (elements.isEmpty() && edges.isEmpty())
- return false;
-
- if (DEBUG_DELETE) {
- System.out.println("gathered elements to delete:");
- System.out.println("\telements:");
- if (!elements.isEmpty())
- for (IElement e : elements)
- System.out.println("\t\t" + e);
- System.out.println("\tedges:");
- if (!edges.isEmpty())
- for (IElement e : edges)
- System.out.println("\t\t" + e);
- }
-
- final IDiagram diagram = this.diagram;
- final ISynchronizationContext syncContext = ElementFactoryUtil.getContextChecked(diagram);
-
- new DatabaseJob("Delete selection") {
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- try {
- delete(monitor);
- return Status.OK_STATUS;
- } catch (CannotRemoveException e) {
- ShowMessage.showInformation("Delete Selection Was Denied", e.getLocalizedMessage());
- return new Status(IStatus.CANCEL, Activator.PLUGIN_ID, e.getLocalizedMessage(), e);
- } catch (DatabaseException e) {
- return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Unexpected error in delete.", e);
- } finally {
- error(null);
- monitor.done();
- }
- }
-
- private void delete(IProgressMonitor monitor) throws DatabaseException {
- Simantics.getSession().syncRequest(new WriteRequest() {
- Set connectionsToRemove = new HashSet();
- Set touchedConnections = new HashSet();
-
- @Override
- public void perform(WriteGraph graph) throws DatabaseException {
- validateRemoval(graph);
- graph.markUndoPoint();
-
- ConnectionUtil cu = new ConnectionUtil(graph);
-
- // Remove edges
- for (IElement edge : edges) {
- ConnectionEntity ce = edge.getHint(ElementHints.KEY_CONNECTION_ENTITY);
- touchConnection( ce.getConnection() );
-
- if (DEBUG_DELETE)
- System.out.println("REMOVING EDGE: " + edge);
- Object obj = ElementUtils.getObject(edge);
- if (obj instanceof EdgeResource) {
- cu.remove((EdgeResource) obj);
- }
- }
-
- // Remove elements
- for (IElement element : elements) {
- ConnectionHandler ch = element.getElementClass().getAtMostOneItemOfClass(ConnectionHandler.class);
- if (ch != null) {
- if (DEBUG_DELETE)
- System.out.println("MARKING CONNECTION TO BE REMOVED: " + element);
- connectionsToRemove.add( (Resource) ElementUtils.getObject(element) );
- } else {
- ConnectionEntity ce = element.getHint(ElementHints.KEY_CONNECTION_ENTITY);
- if(ce != null) {
- if (DEBUG_DELETE)
- System.out.println("REMOVING BRANCH POINT: " + element);
- new RemoveBranchpoint(element).perform(graph);
- touchConnection( ce.getConnection() );
- } else {
- if (DEBUG_DELETE)
- System.out.println("REMOVING ELEMENT: " + element);
-
- Object obj = ElementUtils.getObject(element);
- if (obj instanceof Resource) {
- // Get terminal connections for element
- Collection connectors = cu.getTerminalConnectors((Resource) obj, null);
- for (Resource connector : connectors) {
- Resource connection = ConnectionUtil.tryGetConnection(graph, connector);
- if (connection != null)
- touchConnection( connection );
- cu.disconnectFromAllRouteNodes(connector);
- }
-
- new RemoveElement((Resource)d.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE), (Resource)element.getHint(ElementHints.KEY_OBJECT)).perform(graph);
- }
- }
- }
- }
-
- // Check all touched connections to see if they are empty.
- for (Resource connection : touchedConnections) {
- int removedConnectors = cu.removeUnusedConnectors(connection);
- if (DEBUG_DELETE)
- System.out.println("PRUNED " + removedConnectors + " CONNECTORS FROM TOUCHED CONNECTION " + connection);
- while (true) {
- int removedInteriorRouteNodes = cu.removeExtraInteriorRouteNodes(connection);
- if (DEBUG_DELETE)
- System.out.println("PRUNED " + removedInteriorRouteNodes + " INTERIOR ROUTE NODES FROM TOUCHED CONNECTION " + connection);
- if (removedInteriorRouteNodes == 0)
- break;
- }
- int connectors = cu.getConnectedConnectors(connection, null).size();
- if (DEBUG_DELETE)
- System.out.println("\t" + connectors + " CONNECTORS LEFT");
- if (connectors < 2) {
- connectionsToRemove.add(connection);
- }
- }
-
- // Remove selected/left-over empty connections
- for (Resource connection : connectionsToRemove) {
- if (DEBUG_DELETE)
- System.out.println("REMOVING CONNECTION: " + connection);
- RemoveElement.removeElement(graph, (Resource)d.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE), connection);
- }
- }
-
- private void validateRemoval(ReadGraph graph) throws DatabaseException, CannotRemoveException {
- ArrayList problems = new ArrayList(elements.size());
- for (IElement element : elements) {
- Object obj = ElementUtils.getObject(element);
- if (obj instanceof Resource) {
- Remover remover = RemoverUtil.getPossibleRemover(graph, (Resource) obj);
- if (remover != null) {
- String problem = remover.canRemove(graph, new HashMap