workcraft/workcraft

View on GitHub
workcraft/CpogPlugin/src/org/workcraft/plugins/cpog/tools/CpogSelectionTool.java

Summary

Maintainability
C
1 day
Test Coverage
package org.workcraft.plugins.cpog.tools;

import org.workcraft.dom.Container;
import org.workcraft.dom.Node;
import org.workcraft.dom.math.PageNode;
import org.workcraft.dom.visual.*;
import org.workcraft.dom.visual.connections.VisualConnection;
import org.workcraft.exceptions.InvalidConnectionException;
import org.workcraft.formula.BooleanFormula;
import org.workcraft.formula.visitors.StringGenerator;
import org.workcraft.gui.events.GraphEditorMouseEvent;
import org.workcraft.gui.tools.GraphEditor;
import org.workcraft.gui.tools.SelectionTool;
import org.workcraft.gui.tools.editors.AbstractInplaceEditor;
import org.workcraft.gui.tools.editors.LabelInplaceEditor;
import org.workcraft.observation.*;
import org.workcraft.plugins.cpog.*;
import org.workcraft.plugins.cpog.formula.CpogConnector;
import org.workcraft.plugins.cpog.formula.CpogFormula;
import org.workcraft.plugins.cpog.formula.CpogFormulaToString;
import org.workcraft.plugins.cpog.formula.GraphFunc;
import org.workcraft.plugins.cpog.formula.jj.CpogFormulaParser;
import org.workcraft.plugins.cpog.formula.jj.ParseException;
import org.workcraft.plugins.cpog.formula.jj.TokenMgrError;
import org.workcraft.plugins.cpog.observers.CpogHangingConnectionRemover;
import org.workcraft.utils.DialogUtils;
import org.workcraft.utils.GuiUtils;
import org.workcraft.utils.WorkspaceUtils;
import org.workcraft.workspace.WorkspaceEntry;

import javax.swing.*;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;

public class CpogSelectionTool extends SelectionTool {

    private static final String GROUP_ICON = "images/selection-page.svg";
    private static final String GROUP_HINT = "Combine selection as a scenario (Alt-G)";

    private static final double minRadius = 2.0;
    private static final double expandRadius = 2.0;

    private static final double maxX = 0;
    private static final double maxY = 0;
    private static final int xpos = 0;

    private Point2D coordinate = new Point2D.Double(0, 0);
    private final HashMap<String, CpogFormula> graphMap = new HashMap<>();
    private final HashMap<String, Variable> variableMap = new HashMap<>();
    private final HashMap<String, GraphReference> referenceMap = new HashMap<>();
    private final HashMap<String, Point2D> prevPoints = new HashMap<>();
    private double highestY = 0; // Sets first graph at y co-ordinate of 0
    private JTextArea expressionText;
    private Checkbox insertTransitives;

    private final CpogParsingTool parsingTool = new CpogParsingTool(variableMap, xpos, referenceMap);
    private final ArrayList<VisualPage> refPages = new ArrayList<>();
    private GraphEditor editor;
    private int scenarioNo = 0;
    private JPanel panel;

    private final class CpogGraphFunc implements GraphFunc<String, CpogFormula> {
        private final VisualCpog visualCpog;
        private final HashSet<ArcCondition> arcConditionList;
        private final HashMap<String, VisualVertex> localVertices;
        private final LinkedHashMap<String, VisualVertex> vertexMap;

        private CpogGraphFunc(VisualCpog visualCpog, HashSet<ArcCondition> arcConditionList,
                HashMap<String, VisualVertex> localVertices, LinkedHashMap<String, VisualVertex> vertexMap) {
            this.visualCpog = visualCpog;
            this.arcConditionList = arcConditionList;
            this.localVertices = localVertices;
            this.vertexMap = vertexMap;
        }

        @Override
        public CpogFormula eval(String label) {
            VisualVertex vertex = null;

            if (vertexMap.containsKey(label)) {
                vertex = vertexMap.get(label);
                localVertices.put(label, vertex);
                return vertex;
            }

            vertex = null;

            if (vertex == null) {
                vertex = visualCpog.createVisualVertex(visualCpog.getCurrentLevel());
                vertex.setLabel(label);
                vertexMap.put(label, vertex);
                localVertices.put(label, vertex);
            }
            return vertex;
        }

        @Override
        public GraphFunc<String, CpogFormula> removeGraphName(String name) {
            if (vertexMap.containsKey(name)) {
                vertexMap.remove(name);
            }
            return this;
        }

        @Override
        public CpogFormula eval(String label, String boolExpression) throws ParseException {
            VisualVertex vertex = null;
            if (vertexMap.containsKey(label)) {
                vertex = vertexMap.get(label);
                String s = StringGenerator.toString(vertex.getCondition());
                if (!boolExpression.isEmpty()) {
                    if (s.isEmpty()) {
                        try {
                            vertex.setCondition(parsingTool.parseBool(boolExpression, visualCpog));
                        } catch (org.workcraft.formula.jj.ParseException e) {
                            throw new ParseException("Boolean error in: " + boolExpression);
                        }
                    } else {
                        try {
                            BooleanFormula bool = parsingTool.parseBool(s + "|" + boolExpression, visualCpog);
                            vertex.setCondition(bool);
                        } catch (org.workcraft.formula.jj.ParseException e) {
                            throw new ParseException("Boolean error in: " + boolExpression);
                        }
                    }
                }
                return vertex;
            }

            if (vertex == null) {
                vertex = visualCpog.createVisualVertex(visualCpog.getCurrentLevel());
                vertex.setLabel(label);
                vertexMap.put(label, vertex);
                localVertices.put(label, vertex);
            }

            if (!boolExpression.isEmpty()) {
                String s = StringGenerator.toString(vertex.getCondition());
                if (s.isEmpty()) {
                    try {
                        BooleanFormula bf = parsingTool.parseBool(boolExpression, visualCpog);
                        vertex.setCondition(bf);
                    } catch (org.workcraft.formula.jj.ParseException e) {
                        throw new ParseException("Boolean error in: " + boolExpression);
                    }
                } else {
                    try {
                        BooleanFormula bf = parsingTool.parseBool(boolExpression, visualCpog);
                        vertex.setCondition(bf);
                    } catch (org.workcraft.formula.jj.ParseException e) {
                        throw new ParseException("Boolean error in: " + boolExpression);
                    }
                }
            }
            return vertex;
        }

        @Override
        public void setSequenceCondition(CpogFormula formula, String boolForm) {
            ArcCondition a = new ArcCondition(formula, boolForm);
            arcConditionList.add(a);
        }
    }

    private class RenderTypeChangedHandler extends StateSupervisor {
        private final VisualCpog visualCpog;

        RenderTypeChangedHandler(VisualCpog visualCpog) {
            this.visualCpog = visualCpog;
        }

        @Override
        public void handleEvent(StateEvent e) {
            if (e instanceof PropertyChangedEvent) {
                PropertyChangedEvent pce = (PropertyChangedEvent) e;
                if (VisualVertex.PROPERTY_RENDER_TYPE.equals(pce.getPropertyName())) {
                    correctConnectionLengths((VisualVertex) pce.getSender());
                }
            }
        }
    }

    @Override
    public JPanel getControlsPanel(final GraphEditor editor) {
        if (panel != null) {
            return panel;
        }
        this.editor = editor;

        expressionText = new JTextArea();
        expressionText.setMargin(SizeHelper.getTextMargin());
        expressionText.setLineWrap(false);
        expressionText.setEditable(true);
        expressionText.setFont(new Font(Font.MONOSPACED, Font.PLAIN, SizeHelper.getMonospacedFontSize()));
        JScrollPane expressionScroll = new JScrollPane(expressionText);

        JPanel buttonPanel = new JPanel();

        JButton btnInsert = new JButton("Insert");
        btnInsert.addActionListener(event -> insertAction());
        buttonPanel.add(btnInsert);

        insertTransitives = new Checkbox("Insert transitives", false);
        buttonPanel.add(insertTransitives);

        panel = new JPanel();
        panel.setLayout(new BorderLayout());
        panel.add(expressionScroll, BorderLayout.CENTER);
        panel.add(buttonPanel, BorderLayout.SOUTH);

        JButton groupPageButton = GuiUtils.createIconButton(GROUP_ICON, GROUP_HINT, event -> groupPageAction(editor));

        JPanel groupPanel = getGroupPanel();
        if (groupPanel != null) {
            groupPanel.add(groupPageButton, 1);
        }

        final VisualCpog visualCpog = (VisualCpog) editor.getWorkspaceEntry().getModelEntry().getVisualModel();
        new RenderTypeChangedHandler(visualCpog).attach(visualCpog.getRoot());
        return panel;
    }

    private void insertAction() {
        int prevLineEnd = 0;
        ArrayList<String> expressions = new ArrayList<>();
        editor.getWorkspaceEntry().captureMemento();
        try {
            for (int i = 0; i < expressionText.getLineCount(); i++) {
                String exp1 = expressionText.getText().substring(prevLineEnd, expressionText.getLineEndOffset(i));

                exp1 = exp1.replace("\n", "");
                exp1 = exp1.replace("\t", " ");

                if (!exp1.isEmpty()) {
                    expressions.add(exp1);
                }

                prevLineEnd = expressionText.getLineEndOffset(i);
            }
            WorkspaceEntry we = editor.getWorkspaceEntry();
            VisualCpog visualCpog = WorkspaceUtils.getAs(we, VisualCpog.class);
            String exp2 = "";
            coordinate = getLowestVertex(visualCpog);
            coordinate.setLocation(coordinate.getX(), coordinate.getY() + 2);
            for (String s : expressions) {
                if (!s.contains("=")) {
                    exp2 += ' ' + s;
                } else {
                    if (!exp2.isEmpty()) {
                        insertExpression(exp2, visualCpog, false, true, false);
                        exp2 = "";
                    }
                    exp2 = s;
                }
            }
            if (!exp2.isEmpty()) {
                insertExpression(exp2, visualCpog, false, true, false);
            }
            editor.getWorkspaceEntry().saveMemento();
        } catch (BadLocationException e1) {
            editor.getWorkspaceEntry().cancelMemento();
            e1.printStackTrace();
        }
    }

    private void groupPageAction(final GraphEditor editor) {
        VisualCpog visualCpog = (VisualCpog) editor.getWorkspaceEntry().getModelEntry().getVisualModel();
        visualCpog.groupScenarioPageSelection("scenario" + scenarioNo);
        scenarioNo++;
        editor.requestFocus();
    }

    private JPanel getGroupPanel() {
        Component[] comps = panel.getComponents();
        JPanel groupPanel = null;
        for (int i = 0; i < comps.length; i++) {
            if (!(comps[i] instanceof JPanel)) continue;
            JPanel panel = (JPanel) comps[i];
            Component[] cmp = panel.getComponents();
            for (int j = 0; j < cmp.length; j++) {
                if (!(cmp[j] instanceof JPanel)) continue;
                JPanel pan = (JPanel) cmp[j];
                Component[] c = pan.getComponents();
                for (int k = 0; k < c.length; k++) {
                    if (!(c[k] instanceof JButton)) continue;
                    JButton b = (JButton) c[k];
                    if ((b.getToolTipText() != null) && b.getToolTipText().startsWith("Group selection (")) {
                        groupPanel = pan;
                    }
                }
            }
        }
        return groupPanel;
    }

    public HashMap<String, VisualVertex> insertExpression(String text, final VisualCpog visualCpog,
            boolean getVertList, boolean zoomFit, boolean blockTransitiveRemoval) {

        WorkspaceEntry we = editor.getWorkspaceEntry();
        String name = "";
        visualCpog.setCurrentLevel(visualCpog.getRoot());

        final LinkedHashMap<String, VisualVertex> vertexMap = new LinkedHashMap<>();
        final HashSet<ArcCondition> arcConditionList = new HashSet<>();
        text = text.replace("\n", "");
        text = parsingTool.replaceReferences(text);

        if (text.contains("=")) {
            name = text.substring(0, text.indexOf("="));
            name = name.trim();
            text = text.substring(text.indexOf("=") + 1);
            text = text.trim();
        }

        CpogFormula f = null;
        final HashMap<String, VisualVertex> localVertices = new HashMap<>();
        try {
            f = CpogFormulaParser.parse(text, new CpogGraphFunc(visualCpog, arcConditionList, localVertices, vertexMap));
        } catch (ParseException e) {
            we.cancelMemento();
            DialogUtils.showError(e.getMessage(), "Parse error");
            return null;
        } catch (TokenMgrError e) {
            we.cancelMemento();
            DialogUtils.showError(e.getMessage(), "Lexical error");
            return null;
        }

        if (getVertList) {
            for (VisualVertex v : vertexMap.values()) {
                visualCpog.removeWithoutNotify(v);
            }
            return localVertices;
        } else {

            visualCpog.selectNone();
            int n = vertexMap.size();
            int i = 0;

            for (VisualVertex v : vertexMap.values()) {
                visualCpog.addToSelection(v);
            }

            CpogConnector cc = new CpogConnector(visualCpog);
            f.accept(cc);
            VisualPage inserted = null;

            graphMap.put(name, f);

            parsingTool.setArcConditions(arcConditionList, visualCpog, vertexMap);

            LinkedHashSet<VisualNode> roots = getRootNodes(visualCpog, vertexMap.values());

            if (!(insertTransitives.getState()) && (!blockTransitiveRemoval)) {
                boolean[][] c = parsingTool.convertToArrayForm(vertexMap.values(), visualCpog);
                parsingTool.computeTransitiveClosure(c);
                if (!parsingTool.hasSelfLoops(c)) {
                    boolean[][] t = parsingTool.findTransitives(c);
                    parsingTool.convertFromArrayForm(t, vertexMap.values(), visualCpog);
                }
            }

            ArrayList<VisualNode> prevSelection = new ArrayList<>();
            for (VisualNode n1 : vertexMap.values()) {
                prevSelection.add(n1);
            }

            ArrayList<String> usedReferences = parsingTool.getUsedReferences();

            addUsedReferences(visualCpog, editor, usedReferences, localVertices, prevSelection);

            if (roots.isEmpty()) {
                noRootLayout(vertexMap, n, i);
            } else {
                bfsLayout(visualCpog, roots);
            }

            editor.requestFocus();

            if (!name.isEmpty()) {
                inserted = insertAsPage(visualCpog, name, coordinate, editor);
                coordinate = new Point2D.Double(coordinate.getX(), coordinate.getY() + 2);
            } else {
                insertLoose(visualCpog, coordinate);
            }
            if (inserted != null) {
                String normalForm = getNormalForm(arcConditionList, localVertices);
                String graphName = name;
                graphName = graphName.replace("{", "");
                graphName = graphName.replace("}", "");
                roots = getRootNodes(visualCpog, localVertices.values());
                bfsLayout(visualCpog, roots);
                if (referenceMap.containsKey(graphName)) {
                    referenceMap.remove(graphName);
                }
                GraphReference g = new GraphReference(normalForm, (HashMap<String, VisualVertex>) localVertices.clone());
                g.addRefPage(inserted);
                referenceMap.put(graphName, g);
            }
            Collection<VisualNode> oldSelection = visualCpog.getSelection();
            visualCpog.selectNone();
            //editor.requestFocus();
            //editor.forceRedraw();
            //Doesn't allow zoomFit when creating a new CPOG model
            //Such as when extracting concurrency
            if (zoomFit) {
                editor.zoomFit();
            }
            visualCpog.select(oldSelection);
            return null;
        }
    }

    public String getNormalForm(HashSet<ArcCondition> arcConditionList, HashMap<String, VisualVertex> localVertices) {
        String normalForm = "";
        Collection<VisualVertex> verts = localVertices.values();
        Iterator<VisualVertex> it = verts.iterator();
        VisualVertex v;
        while (it.hasNext()) {
            v = it.next();
            if ("1".equals(StringGenerator.toString(v.getCondition()))) {
                normalForm += v.getLabel();
            } else {
                normalForm += "[" + StringGenerator.toString(v.getCondition()) + "]" + v.getLabel();
            }
            if (it.hasNext()) {
                normalForm += " + ";
            }
        }

        Iterator<ArcCondition> it1 = arcConditionList.iterator();
        ArcCondition ac;
        if (!arcConditionList.isEmpty()) {
            normalForm += " + ";
        }
        while (it1.hasNext()) {
            ac = it1.next();
            if (ac.getBoolForm().isEmpty()) {
                normalForm += ' ' + CpogFormulaToString.toString(ac.getFormula());
            } else {
                normalForm += '[' + ac.getBoolForm() + "](" + CpogFormulaToString.toString(ac.getFormula()) + ')';
            }
            if (it1.hasNext()) {
                normalForm += " + ";
            }
        }
        return normalForm;
    }

    public void insertLoose(VisualCpog visualCpog, Point2D coordinate) {
        for (VisualNode node : visualCpog.getSelection()) {
            if (node instanceof VisualVertex) {
                VisualVertex v = (VisualVertex) node;
                v.setPosition(new Point2D.Double(v.getX(), v.getY() + coordinate.getY()));
            }
        }
    }

    public VisualPage insertAsPage(VisualCpog visualCpog, String graphName, Point2D coordinate, GraphEditor editor) {
        HashSet<VisualScenarioPage> pageList = new HashSet<>();
        for (VisualNode n0 : visualCpog.getSelection()) {
            if (n0 instanceof VisualScenarioPage) {
                pageList.add((VisualScenarioPage) n0);
            }
        }

        PageNode pageNode = new PageNode();
        visualCpog.getMathModel().add(pageNode);
        VisualScenarioPage page = new VisualScenarioPage(pageNode);
        visualCpog.getCurrentLevel().add(page);
        includeArcsInPage(visualCpog);

        Container container = visualCpog.getCurrentLevel();
        HashSet<VisualNode> nodes = new HashSet<>();
        for (VisualNode n : visualCpog.getSelection()) {
            if (!(n.getParent().equals(container))) {
                visualCpog.reparent(page, visualCpog, container, nodes);
                container = (Container) n.getParent();
                nodes.clear();
            }
            nodes.add(n);
        }

        visualCpog.reparent(page, visualCpog, container, nodes);
        for (VisualComponent c : page.getComponents()) {
            if (c instanceof VisualPage) {
                if (c.getComponents().isEmpty()) {
                    visualCpog.remove(c);
                }
            }
        }
        visualCpog.select(page);

        page.setLabel(graphName);
        Point2D.Double pageLocation = new Point2D.Double(coordinate.getX(), coordinate.getY() + (page.getBoundingBox().getHeight() / 2));
        coordinate.setLocation(coordinate.getX(), coordinate.getY() + page.getBoundingBox().getHeight() + 1);
        page.setPosition(pageLocation);

        attatchRefEventHandler(visualCpog, page, editor);

        return page;

    }

    public void bfsLayout(VisualCpog visualCpog, LinkedHashSet<VisualNode> roots) {
        Iterator<VisualNode> root = roots.iterator();
        ConcurrentLinkedQueue<VisualNode> q = new ConcurrentLinkedQueue<>();
        double originalX = 0;
        double originalY = 0;
        while (root.hasNext()) {
            q.add(root.next());
            parsingTool.bfsLayout(q, visualCpog, originalX, originalY);
            originalY += 2.5;
        }
    }

    public void noRootLayout(LinkedHashMap<String, VisualVertex> vertexMap, int n, int i) {
        double y = maxY + 2.5;
        for (VisualVertex v : vertexMap.values()) {
            double radius = Math.max(minRadius, expandRadius * n / Math.PI
                    / 2.0);
            Point2D pos = new Point2D.Double(maxX + radius
                    * Math.cos(2.0 * Math.PI * i / n), y + radius * Math.sin(2.0 * Math.PI * i / n));
            v.setPosition(pos);
            if (pos.getY() > highestY) {
                highestY = pos.getY();
            }
            i++;
        }
    }

    @Override
    public void mouseClicked(GraphEditorMouseEvent e) {
        boolean processed = false;

        if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() > 1) {
            VisualModel model = e.getEditor().getModel();
            VisualNode node = HitMan.hitFirstInCurrentLevel(e.getPosition(), model);
            if (node != null) {
                if (node instanceof VisualVariable) {
                    VisualVariable var = (VisualVariable) node;
                    var.toggle();
                    processed = true;
                } else if (node instanceof VisualVertex) {
                    final VisualVertex vertex = (VisualVertex) node;
                    AbstractInplaceEditor textEditor = new LabelInplaceEditor(editor, vertex) {
                        @Override
                        public void processResult(String text) {
                            super.processResult(text);
                            correctConnectionLengths(vertex);
                        }
                    };
                    textEditor.edit(vertex.getLabel(), vertex.getLabelFont(),
                            vertex.getLabelOffset(), vertex.getLabelAlignment(), false);
                    processed = true;
                }
            }
        }
        if (!processed) {
            super.mouseClicked(e);

        }
    }

    @Override
    public void mouseReleased(GraphEditorMouseEvent e) {
        super.mouseReleased(e);

        WorkspaceEntry we = e.getEditor().getWorkspaceEntry();
        final VisualCpog visualCpog = WorkspaceUtils.getAs(we, VisualCpog.class);

        for (VisualNode n : visualCpog.getSelection()) {
            if (n instanceof VisualVertex) {
                n.sendNotification(new PropertyChangedEvent(n, "position"));
            }
        }
    }

    @Override
    public void startDrag(GraphEditorMouseEvent e) {
        super.startDrag(e);
        WorkspaceEntry we = e.getEditor().getWorkspaceEntry();
        final VisualCpog visualCpog = WorkspaceUtils.getAs(we, VisualCpog.class);

        prevPoints.clear();
        for (VisualNode n : visualCpog.getSelection()) {
            if (n instanceof VisualVertex) {
                VisualVertex v = (VisualVertex) n;
                prevPoints.put(v.getLabel(), new Point2D.Double(v.getPosition().getX(), v.getPosition().getY()));
            }
        }
    }

    public LinkedHashSet<VisualNode> getRootNodes(VisualCpog visualCpog, Collection<VisualVertex> vertexMap) {
        LinkedHashSet<VisualNode> roots = new LinkedHashSet<>();
        Set<VisualConnection> arcs;
        Iterator<VisualConnection> it;
        VisualConnection connection;
        boolean second = false;
        for (VisualNode node : vertexMap) {
            arcs = visualCpog.getConnections(node);
            it = arcs.iterator();
            //The following covers root nodes, and nodes with no connections
            while (it.hasNext()) {
                connection = it.next();
                if (!connection.getFirst().equals(node)) {
                    second = true;
                    break;
                }
            }
            if (!second) {
                roots.add(node);
            }
            second = false;
        }
        return roots;
    }

    public void addUsedReferences(VisualCpog visualCpog, GraphEditor editor, ArrayList<String> usedReferences,
            HashMap<String, VisualVertex> localVertices, ArrayList<VisualNode> prevSelection) {

        for (String k : usedReferences) {
            visualCpog.selectNone();
            ArrayList<VisualVertex> pageVerts = new ArrayList<>();
            if (referenceMap.containsKey(k)) {
                GraphReference g = referenceMap.get(k);
                HashMap<String, VisualVertex> vMap = g.getVertMap();
                for (String k1 : vMap.keySet()) {
                    localVertices.get(k1).setPosition(new Point2D.Double(vMap.get(k1).getX(), vMap.get(k1).getY()));
                    pageVerts.add(localVertices.get(k1));
                    if (visualCpog.getVertices(visualCpog.getCurrentLevel()).contains(localVertices.get(k1))) {
                        visualCpog.add(localVertices.get(k1));
                    }
                    visualCpog.addToSelection(localVertices.get(k1));
                }
                prevSelection.removeAll(pageVerts);
                includeArcsInPage(visualCpog);
                pageSelection(editor);
                if (visualCpog.getSelection().size() == 1) {
                    for (VisualNode n1 : visualCpog.getSelection()) {
                        if (n1 instanceof VisualPage) {
                            VisualPage vp = (VisualPage) n1;
                            vp.setLabel(k);
                            vp.setIsCollapsed(false);
                            vp.setParent(visualCpog.getCurrentLevel());
                            prevSelection.add(vp);
                            referenceMap.get(k).addRefPage(vp);
                            refPages.add(vp);
                        }
                    }
                }
            }
            visualCpog.addToSelection(prevSelection);
        }
    }

    public void attatchRefEventHandler(final VisualCpog visualCpog, final Container page, final GraphEditor editor) {
        new HierarchySupervisor() {

            ArrayList<VisualNode> toBeRemoved = new ArrayList<>();
            String refKey = "";
            @Override
            public void handleEvent(HierarchyEvent e) {
                ArrayList<VisualPage> relaventPages = new ArrayList<>();
                if (e instanceof NodesDeletingEvent) {
                    for (Node node : e.getAffectedNodes()) {
                        if (node instanceof VisualVertex) {
                            final VisualVertex vert = (VisualVertex) node;
                            if (!(vert.getParent() instanceof VisualScenarioPage)) {
                                if (vert.getParent() instanceof VisualPage) {
                                    VisualPage page = (VisualPage) vert.getParent();
                                    refKey = page.getLabel();
                                    relaventPages.addAll(referenceMap.get(page.getLabel()).getRefPages());
                                    relaventPages.remove(page);
                                    for (VisualPage p : relaventPages) {
                                        for (Node n : p.getChildren()) {
                                            if (n instanceof VisualVertex) {
                                                VisualVertex v = (VisualVertex) n;
                                                if (v.getLabel().compareTo(vert.getLabel()) == 0) {
                                                    if (!(e.getAffectedNodes().contains(v))) {
                                                        toBeRemoved.add(v);
                                                    }
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            CpogHangingConnectionRemover arcRemover = new CpogHangingConnectionRemover(visualCpog);
                            for (VisualNode n : toBeRemoved) {
                                arcRemover.handleEvent(new NodesDeletingEvent(n.getParent(), n));
                                visualCpog.removeWithoutNotify(n);
                            }

                        } else if (node instanceof VisualArc) {
                            VisualArc a = (VisualArc) node;
                            if (a.getFirst().getParent().equals(a.getSecond().getParent())) {
                                if ((a.getFirst().getParent() instanceof VisualPage) || (a.getFirst().getParent() instanceof VisualScenarioPage)) {
                                    VisualPage vp = (VisualPage) a.getFirst().getParent();
                                    String first = ((VisualVertex) a.getFirst()).getLabel();
                                    String second = ((VisualVertex) a.getSecond()).getLabel();
                                    refKey = vp.getLabel();
                                    relaventPages.addAll(referenceMap.get(refKey).getRefPages());
                                    relaventPages.remove(vp);
                                    for (VisualPage p : relaventPages) {
                                        for (Node n : p.getChildren()) {
                                            if (n instanceof VisualVertex) {
                                                VisualVertex f = (VisualVertex) n;
                                                if (f.getLabel().equals(first)) {
                                                    for (Node n1 : p.getChildren()) {
                                                        if (n1 instanceof VisualVertex) {
                                                            VisualVertex s = (VisualVertex) n1;
                                                            if (s.getLabel().equals(second)) {
                                                                VisualConnection c = visualCpog.getConnection(f, s);
                                                                if (!(e.getAffectedNodes().contains(c))) {
                                                                    toBeRemoved.add(c);
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            for (VisualNode n : toBeRemoved) {
                                visualCpog.removeFromSelection(n);
                                visualCpog.removeWithoutNotify(n);
                                while (n.getParent() != null) {
                                    try {
                                        this.wait(5);
                                    } catch (InterruptedException e1) {
                                        e1.printStackTrace();
                                    }
                                }
                            }
                        }

                    }
                }

                toBeRemoved.clear();
                //updateReferenceNormalForm(relaventPages, visualCpog, editor);
            }

        }.attach(page);

        final class StateSupervisorExtension extends StateSupervisor {
            @Override
            public void handleEvent(StateEvent e) {
                if (e instanceof PropertyChangedEvent) {
                    PropertyChangedEvent pce = (PropertyChangedEvent) e;
                    if ("position".equals(pce.getPropertyName())) {
                        if ((pce.getSender() instanceof VisualVertex) && !(pce.getSender().getParent() instanceof VisualScenarioPage)) {
                            VisualVertex v = (VisualVertex) pce.getSender();
                            double xDiff = 0;
                            double yDiff = 0;
                            if (prevPoints.get(v.getLabel()) != null) {
                                xDiff = v.getPosition().getX() - prevPoints.get(v.getLabel()).getX();
                                yDiff = v.getPosition().getY() - prevPoints.get(v.getLabel()).getY();
                                prevPoints.remove(v.getLabel());
                            }

                            if (v.getParent() instanceof VisualPage) {
                                VisualPage page = (VisualPage) v.getParent();

                                String refKey = page.getLabel();

                                GraphReference g = referenceMap.get(page.getLabel());
                                if (g != null) {
                                    g.updateVertexPosition(v.getLabel(), xDiff, yDiff);

                                    ArrayList<VisualPage> refPages = getRefPages(visualCpog, refKey, v);
                                    refPages.remove(page);

                                    for (VisualPage p : refPages) {
                                        for (Node n : p.getChildren()) {
                                            if ((n instanceof VisualVertex) && (((VisualVertex) n).getLabel().compareTo(v.getLabel()) == 0)) {
                                                VisualVertex vert = (VisualVertex) n;
                                                vert.setPosition(new Point2D.Double(vert.getPosition().getX() + xDiff, vert.getPosition().getY() + yDiff));
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        new StateSupervisorExtension().attach(page);
    }

    public ArrayList<VisualPage> getRefPages(VisualCpog visualCpog, String refKey, VisualVertex v) {
        ArrayList<VisualPage> result = new ArrayList<>();

        for (VisualPage p : refPages) {
            if (p.getLabel().compareTo(refKey) == 0) {
                result.add(p);

            }
        }
        return result;
    }

    public void updateReferenceNormalForm(ArrayList<VisualPage> relaventPages, VisualCpog visualCpog, GraphEditor editor) {
        if (!relaventPages.isEmpty()) {
            Container previousLevel = visualCpog.getCurrentLevel();
            Collection<VisualNode> selection = visualCpog.getSelection();

            VisualPage page = relaventPages.get(0);
            visualCpog.setCurrentLevel((Container) page.getParent());
            visualCpog.select(page);

            String newExpression = parsingTool.getExpressionFromGraph(visualCpog);
            newExpression = newExpression.replace("\n", "");
            newExpression = newExpression.trim();
            GraphReference g = referenceMap.get(page.getLabel());

            int eqLocation;
            eqLocation = newExpression.indexOf('=');
            g.updateNormalForm(newExpression.substring(eqLocation + 1));

            HashMap<String, VisualVertex> vertMap = (HashMap<String, VisualVertex>) insertExpression(
                    newExpression, visualCpog, true, true, false).clone();

            for (VisualVertex v : vertMap.values()) {
                Point2D.Double newPosition = new Point2D.Double(g.getVertMap().get(v.getLabel()).getX(), g.getVertMap().get(v.getLabel()).getY());
                v.setPosition(newPosition);
            }

            g.updateVertMap(vertMap);

            visualCpog.setCurrentLevel(previousLevel);
            visualCpog.select(selection);
        }
    }

    public void includeArcsInPage(VisualCpog visualCpog) {
        HashSet<VisualNode> arcs = new HashSet<>();
        for (VisualNode n : visualCpog.getSelection()) {
            for (VisualConnection c : visualCpog.getConnections(n)) {
                arcs.add(c);
            }
        }
        visualCpog.addToSelection(arcs);
    }

    public void insertEventLog(VisualCpog visualCpog, int i, String[] events, double yPos) {
        final LinkedHashMap<String, VisualVertex> vertexMap = new LinkedHashMap<>();
        VisualVertex vertex1;
        VisualVertex vertex2;
        for (int c = 0; c < events.length - 1; c++) {
            String first = "";
            String second = "";

            first = events[c];
            second = events[c + 1];

            if (vertexMap.containsKey(first)) {
                vertex1 = vertexMap.get(first);
            } else {
                vertex1 = visualCpog.createVisualVertex(visualCpog.getCurrentLevel());
                vertex1.setLabel(first);
                vertexMap.put(first, vertex1);
            }

            if (vertexMap.containsKey(second)) {
                int d = 1;
                while (vertexMap.containsKey(second + "_" + d)) {
                    d++;
                }
                vertex2 = visualCpog.createVisualVertex(visualCpog.getCurrentLevel());
                vertex2.setLabel(second + "_" + d);
                vertexMap.put(second + "_" + d, vertex2);

                events[c + 1] = second + "_" + d;
            } else {
                vertex2 = visualCpog.createVisualVertex(visualCpog.getCurrentLevel());
                vertex2.setLabel(second);
                vertexMap.put(second, vertex2);
            }

            visualCpog.connect(vertex1, vertex2);

        }

        double xPos = vertexMap.values().size();
        xPos *= 2.5;
        xPos = 0 - xPos / 2;

        PageNode pageNode = new PageNode();
        visualCpog.getMathModel().add(pageNode);
        VisualScenarioPage page = new VisualScenarioPage(pageNode);
        visualCpog.getCurrentLevel().add(page);
        page.setLabel("t" + i);

        Container container = visualCpog.getCurrentLevel();
        HashSet<VisualNode> nodes = new HashSet<>();

        visualCpog.selectNone();
        for (VisualVertex v : vertexMap.values()) {
            v.setPosition(new Point2D.Double(xPos, yPos));
            xPos += 2.5;
            nodes.add(v);
        }

        visualCpog.reparent(page, visualCpog, container, nodes);
        includeArcsInPage(visualCpog);

    }

    public Point2D getLowestVertex(VisualCpog visualCpog) {
        return parsingTool.getLowestVertex(visualCpog);
    }

    private void correctConnectionLengths(VisualVertex vertex) {
        WorkspaceEntry we = editor.getWorkspaceEntry();
        VisualCpog visualCpog = WorkspaceUtils.getAs(we, VisualCpog.class);
        ArrayList<VisualNode> cons = parsingTool.getChildren(visualCpog, vertex);
        cons.addAll(parsingTool.getParents(visualCpog, vertex));
        for (VisualNode n : cons) {
            VisualNode f;
            VisualNode s;
            if (visualCpog.getConnection(n, vertex) != null) {
                f = n;
                s = vertex;
            } else {
                f = vertex;
                s = n;
            }
            VisualConnection c = visualCpog.getConnection(f, s);
            VisualArc a = (VisualArc) c;
            BooleanFormula b = a.getCondition();
            visualCpog.remove(c);
            try {
                a = (VisualArc) visualCpog.connect(f, s);
            } catch (InvalidConnectionException e) {
                e.printStackTrace();
            }
            a.setCondition(b);
        }
    }

    public boolean insertCpogFromFile(File f) {
        Scanner fileIn;
        try {
            fileIn = new Scanner(f);
        } catch (FileNotFoundException e1) {
            DialogUtils.showError(e1.getMessage());
            return false;
        }

        WorkspaceEntry we = editor.getWorkspaceEntry();
        VisualCpog visualCpog = WorkspaceUtils.getAs(we, VisualCpog.class);

        coordinate = getLowestVertex(visualCpog);
        coordinate.setLocation(coordinate.getX(), coordinate.getY() + 2);

        String expression = "";

        while (fileIn.hasNextLine()) {
            expression += fileIn.nextLine() + '\n';
        }
        fileIn.close();


        String exp = "";
        coordinate = getLowestVertex(visualCpog);
        coordinate.setLocation(coordinate.getX(), coordinate.getY() + 2);
        String[] expressions = expression.split("\n");
        for (String s : expressions) {
            if (!s.contains("=")) {
                exp += ' ' + s;
            } else {
                if (!exp.isEmpty()) {
                    insertExpression(exp, visualCpog, false, true, false);
                    exp = "";
                }
                exp = s;
            }
        }
        if (!exp.isEmpty()) {
            insertExpression(exp, visualCpog, false, true, false);
        }

        return true;
    }

    public void setExpressionText(String exp) {
        expressionText.setText(exp);
    }

    public CpogParsingTool getParsingTool() {
        return parsingTool;
    }
}