X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Futils%2FTopologicalSelectionExpander.java;h=f9b121ad4ed187346432e2c0177534830eb3127d;hb=78d831a19c254d829e45d04c5ec6a3057680b7d7;hp=55f2ce1fb09bf9d55b18539ef8b6f42af15c5afe;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/utils/TopologicalSelectionExpander.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/utils/TopologicalSelectionExpander.java index 55f2ce1fb..f9b121ad4 100644 --- a/bundles/org.simantics.g2d/src/org/simantics/g2d/utils/TopologicalSelectionExpander.java +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/utils/TopologicalSelectionExpander.java @@ -1,252 +1,252 @@ -/******************************************************************************* - * 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.g2d.utils; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Deque; -import java.util.HashSet; -import java.util.Queue; -import java.util.Set; - -import org.simantics.g2d.connection.ConnectionEntity; -import org.simantics.g2d.diagram.IDiagram; -import org.simantics.g2d.diagram.handler.DataElementMap; -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.element.ElementHints; -import org.simantics.g2d.element.IElement; -import org.simantics.g2d.element.handler.TerminalTopology; -import org.simantics.g2d.elementclass.FlagHandler; - -/** - * This class tries to expand the selection provided by the specified elements - * by a single expansion step. Its purpose is to provide a way for the user to - * easily select a larger range of elements based on the diagram connectivity. - * This can be useful e.g. when preparing for a copy-paste operation or simply - * for visualizing the connectivity of a diagram.

- * - *

- * The expansion logic is as follows: - *

- *
    - *
  1. If connections are included in the current selection, make sure that no - * connection entity is only partly selected. If only partly selected connection - * entities are found, complete those and stop there. Otherwise continue to the - * next step.
  2. - *
  3. Expand the current selection by one step. For connections this means - * selecting all nodes that are attached by the connection but not yet in the - * current selection. For nodes this means expanding the selection to all the - * connections reachable from that particular node.
  4. - *
- * - * @author Tuukka Lehtonen - */ -public class TopologicalSelectionExpander { - - public static final boolean DEBUG = false; - - IDiagram diagram; - Set startSelection; - Set resultSelection; - Set processedConnections = new HashSet(); - - Topology topology; - DataElementMap dem; - - public static Set expandSelection(IDiagram diagram, Set elements) { - return new TopologicalSelectionExpander(diagram, elements).expanded(); - } - - public TopologicalSelectionExpander(IDiagram diagram, Set startSelection) { - assert diagram != null; - - this.diagram = diagram; - this.startSelection = startSelection; - this.resultSelection = new HashSet(startSelection); - - this.topology = diagram.getDiagramClass().getAtMostOneItemOfClass(Topology.class); - this.dem = diagram.getDiagramClass().getAtMostOneItemOfClass(DataElementMap.class); - } - - /** - * @return null if the selection did not change in the - * expansion, another set of elements otherwise - */ - public Set expandedIfChanged() { - Set result = expanded(); - if (DEBUG) - System.out.println("result selection: " + result); - if (result.equals(startSelection)) - return null; - if (DEBUG) - System.out.println("setting new selection"); - return result; - } - - /** - * @return - */ - public Set expanded() { - if (topology == null || dem == null || startSelection.isEmpty()) - return startSelection; - - if (DEBUG) - System.out.println("expand start selection: " + startSelection); - - Deque work = new ArrayDeque(startSelection.size() + 4); - work.addAll(startSelection); - - // 1. Iterate the start selection to see if there are any partly - // selected connection entities. If so, then only complete the - // selection of those entities before expanding the selection in - // any other way. - boolean connectionPartsSelected = false; - for (IElement e : work) { - IElement connection = getConnectionOfConnectionPart(e); - if (connection != null) { - // There was a mere connection part selection among the selection. - Set connectionParts = getAllConnectionEntityParts(e); - if (!connectionParts.isEmpty()) { - if (DEBUG) - System.out.println("\tconnection part selected: " + e + ", replacing with connection " + connection); - resultSelection.add(connection); - resultSelection.removeAll(connectionParts); - connectionPartsSelected = true; - } - } - } - - if (!connectionPartsSelected) { - // No connection entities were partly selected. Go ahead with - // the normal selection expansion procedure. - while (!work.isEmpty()) { - IElement e = work.poll(); - if (DEBUG) - System.out.println("\texpanding at element: " + e); - @SuppressWarnings("unused") - boolean expanded = expandConnection(e, work) || expandNode(e, work); - } - } - - if (DEBUG) - System.out.println("expanded selection: " + resultSelection); - return resultSelection; - } - - boolean expandConnection(IElement connection, Queue workQueue) { - ConnectionEntity ce = connection.getHint(ElementHints.KEY_CONNECTION_ENTITY); - if (ce == null) - return false; - - if (!processedConnections.add(ce)) - return true; - - // Expand the selection to all the nodes attached to this connection. - if (DEBUG) - System.out.println("\texpanding at connection " + ce); - Collection terminals = new ArrayList(); - ce.getTerminalConnections(terminals); - if (DEBUG) - System.out.println("\t\tfound " + terminals.size() + " terminal connections: " + terminals); - for (Connection terminal : terminals) { - if (resultSelection.add(terminal.node)) { - if (DEBUG) - System.out.println("\t\t\tadding node '" + terminal.node + "' at terminal '" + terminal.terminal + "'"); - } - } - return true; - } - - boolean expandNode(IElement e, Queue workQueue) { - // This is a node. - TerminalTopology tt = e.getElementClass().getAtMostOneItemOfClass(TerminalTopology.class); - if (tt == null) - return false; - if (DEBUG) - System.out.println("\texpanding selection to node terminal connections: " + e); - - Collection terminals = new ArrayList(); - tt.getTerminals(e, terminals); - Collection connections = new ArrayList(); - for (Terminal terminal : terminals) { - topology.getConnections(e, terminal, connections); - } - if (DEBUG) - System.out.println("\t\tfound " + connections.size() + " connected terminals: " + connections); - for (Connection connection : connections) { - IElement conn = getConnectionEntityConnection(connection.edge); - if (conn != null) { - if (DEBUG) - System.out.println("\t\t\tadding connection: " + conn); - resultSelection.add(conn); - } - } - - boolean expanded = !connections.isEmpty(); - - // We want to: - // * expand selection to monitors and other related "sub-elements" of the selection - // We don't want to: - // * expand selection through flags - FlagHandler fh = e.getElementClass().getAtMostOneItemOfClass(FlagHandler.class); - if (fh == null) { - RelationshipHandler rh = diagram.getDiagramClass().getAtMostOneItemOfClass(RelationshipHandler.class); - if (rh != null) { - for(Relation rel : rh.getRelations(diagram, e, new ArrayList())) { - if(rel.getSubject() instanceof IElement) { - expanded |= resultSelection.add((IElement)rel.getSubject()); - } - if(rel.getObject() instanceof IElement) { - expanded |= resultSelection.add((IElement)rel.getObject()); - } - } - } - } - - return expanded; - } - - static IElement getConnectionOfConnectionPart(IElement e) { - ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY); - if (ce == null) - return null; - IElement c = ce.getConnection(); - if (c == e) - return null; - return c; - } - - static IElement getConnectionEntityConnection(IElement e) { - ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY); - if (ce == null) - return null; - return ce.getConnection(); - } - - static Set getAllConnectionEntityParts(IElement e) { - ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY); - if (ce == null) - return Collections.emptySet(); - Set result = new HashSet(); - result.add(e); - ce.getBranchPoints(result); - ce.getSegments(result); - return result; - } - -} +/******************************************************************************* + * 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.g2d.utils; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Deque; +import java.util.HashSet; +import java.util.Queue; +import java.util.Set; + +import org.simantics.g2d.connection.ConnectionEntity; +import org.simantics.g2d.diagram.IDiagram; +import org.simantics.g2d.diagram.handler.DataElementMap; +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.element.ElementHints; +import org.simantics.g2d.element.IElement; +import org.simantics.g2d.element.handler.TerminalTopology; +import org.simantics.g2d.elementclass.FlagHandler; + +/** + * This class tries to expand the selection provided by the specified elements + * by a single expansion step. Its purpose is to provide a way for the user to + * easily select a larger range of elements based on the diagram connectivity. + * This can be useful e.g. when preparing for a copy-paste operation or simply + * for visualizing the connectivity of a diagram.

+ * + *

+ * The expansion logic is as follows: + *

+ *
    + *
  1. If connections are included in the current selection, make sure that no + * connection entity is only partly selected. If only partly selected connection + * entities are found, complete those and stop there. Otherwise continue to the + * next step.
  2. + *
  3. Expand the current selection by one step. For connections this means + * selecting all nodes that are attached by the connection but not yet in the + * current selection. For nodes this means expanding the selection to all the + * connections reachable from that particular node.
  4. + *
+ * + * @author Tuukka Lehtonen + */ +public class TopologicalSelectionExpander { + + public static final boolean DEBUG = false; + + IDiagram diagram; + Set startSelection; + Set resultSelection; + Set processedConnections = new HashSet(); + + Topology topology; + DataElementMap dem; + + public static Set expandSelection(IDiagram diagram, Set elements) { + return new TopologicalSelectionExpander(diagram, elements).expanded(); + } + + public TopologicalSelectionExpander(IDiagram diagram, Set startSelection) { + assert diagram != null; + + this.diagram = diagram; + this.startSelection = startSelection; + this.resultSelection = new HashSet(startSelection); + + this.topology = diagram.getDiagramClass().getAtMostOneItemOfClass(Topology.class); + this.dem = diagram.getDiagramClass().getAtMostOneItemOfClass(DataElementMap.class); + } + + /** + * @return null if the selection did not change in the + * expansion, another set of elements otherwise + */ + public Set expandedIfChanged() { + Set result = expanded(); + if (DEBUG) + System.out.println("result selection: " + result); + if (result.equals(startSelection)) + return null; + if (DEBUG) + System.out.println("setting new selection"); + return result; + } + + /** + * @return + */ + public Set expanded() { + if (topology == null || dem == null || startSelection.isEmpty()) + return startSelection; + + if (DEBUG) + System.out.println("expand start selection: " + startSelection); + + Deque work = new ArrayDeque(startSelection.size() + 4); + work.addAll(startSelection); + + // 1. Iterate the start selection to see if there are any partly + // selected connection entities. If so, then only complete the + // selection of those entities before expanding the selection in + // any other way. + boolean connectionPartsSelected = false; + for (IElement e : work) { + IElement connection = getConnectionOfConnectionPart(e); + if (connection != null) { + // There was a mere connection part selection among the selection. + Set connectionParts = getAllConnectionEntityParts(e); + if (!connectionParts.isEmpty()) { + if (DEBUG) + System.out.println("\tconnection part selected: " + e + ", replacing with connection " + connection); + resultSelection.add(connection); + resultSelection.removeAll(connectionParts); + connectionPartsSelected = true; + } + } + } + + if (!connectionPartsSelected) { + // No connection entities were partly selected. Go ahead with + // the normal selection expansion procedure. + while (!work.isEmpty()) { + IElement e = work.poll(); + if (DEBUG) + System.out.println("\texpanding at element: " + e); + @SuppressWarnings("unused") + boolean expanded = expandConnection(e, work) || expandNode(e, work); + } + } + + if (DEBUG) + System.out.println("expanded selection: " + resultSelection); + return resultSelection; + } + + boolean expandConnection(IElement connection, Queue workQueue) { + ConnectionEntity ce = connection.getHint(ElementHints.KEY_CONNECTION_ENTITY); + if (ce == null) + return false; + + if (!processedConnections.add(ce)) + return true; + + // Expand the selection to all the nodes attached to this connection. + if (DEBUG) + System.out.println("\texpanding at connection " + ce); + Collection terminals = new ArrayList(); + ce.getTerminalConnections(terminals); + if (DEBUG) + System.out.println("\t\tfound " + terminals.size() + " terminal connections: " + terminals); + for (Connection terminal : terminals) { + if (resultSelection.add(terminal.node)) { + if (DEBUG) + System.out.println("\t\t\tadding node '" + terminal.node + "' at terminal '" + terminal.terminal + "'"); + } + } + return true; + } + + boolean expandNode(IElement e, Queue workQueue) { + // This is a node. + TerminalTopology tt = e.getElementClass().getAtMostOneItemOfClass(TerminalTopology.class); + if (tt == null) + return false; + if (DEBUG) + System.out.println("\texpanding selection to node terminal connections: " + e); + + Collection terminals = new ArrayList(); + tt.getTerminals(e, terminals); + Collection connections = new ArrayList(); + for (Terminal terminal : terminals) { + topology.getConnections(e, terminal, connections); + } + if (DEBUG) + System.out.println("\t\tfound " + connections.size() + " connected terminals: " + connections); + for (Connection connection : connections) { + IElement conn = getConnectionEntityConnection(connection.edge); + if (conn != null) { + if (DEBUG) + System.out.println("\t\t\tadding connection: " + conn); + resultSelection.add(conn); + } + } + + boolean expanded = !connections.isEmpty(); + + // We want to: + // * expand selection to monitors and other related "sub-elements" of the selection + // We don't want to: + // * expand selection through flags + FlagHandler fh = e.getElementClass().getAtMostOneItemOfClass(FlagHandler.class); + if (fh == null) { + RelationshipHandler rh = diagram.getDiagramClass().getAtMostOneItemOfClass(RelationshipHandler.class); + if (rh != null) { + for(Relation rel : rh.getRelations(diagram, e, new ArrayList())) { + if(rel.getSubject() instanceof IElement) { + expanded |= resultSelection.add((IElement)rel.getSubject()); + } + if(rel.getObject() instanceof IElement) { + expanded |= resultSelection.add((IElement)rel.getObject()); + } + } + } + } + + return expanded; + } + + static IElement getConnectionOfConnectionPart(IElement e) { + ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY); + if (ce == null) + return null; + IElement c = ce.getConnection(); + if (c == e) + return null; + return c; + } + + static IElement getConnectionEntityConnection(IElement e) { + ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY); + if (ce == null) + return null; + return ce.getConnection(); + } + + static Set getAllConnectionEntityParts(IElement e) { + ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY); + if (ce == null) + return Collections.emptySet(); + Set result = new HashSet(); + result.add(e); + ce.getBranchPoints(result); + ce.getSegments(result); + return result; + } + +}