/* * Copyright (C) 2012 Jason Gedge <http://www.gedge.ca> * * This file is part of the OpGraph project. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.gedge.opgraph.nodes.menu.edits; import java.util.Set; import java.util.TreeSet; import java.util.logging.Logger; import javax.swing.undo.AbstractUndoableEdit; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; import ca.gedge.opgraph.OpLink; import ca.gedge.opgraph.OpGraph; import ca.gedge.opgraph.OpNode; import ca.gedge.opgraph.dag.CycleDetectedException; import ca.gedge.opgraph.dag.VertexNotFoundException; import ca.gedge.opgraph.exceptions.ItemMissingException; import ca.gedge.opgraph.extensions.Publishable.PublishedInput; import ca.gedge.opgraph.extensions.Publishable.PublishedOutput; import ca.gedge.opgraph.nodes.general.MacroNode; /** * An edit that creates a macro from a given collection of nodes in a graph. */ public class ExplodeMacroEdit extends AbstractUndoableEdit { /** Logger */ private static final Logger LOGGER = Logger.getLogger(ExplodeMacroEdit.class.getName()); /** The graph to which this edit was applied */ private OpGraph graph; /** The constructed macro node */ private MacroNode macro; /** Links within the macro, and for published fields */ private Set<OpLink> newLinks; /** Links attached to the macro */ private Set<OpLink> oldLinks; /** * Constructs a macro-explosion edit which acts upon a given macro node. * * @param graph the graph to which this edit will be applied * @param macro the macro node to explode */ public ExplodeMacroEdit(OpGraph graph, MacroNode macro) { this.graph = graph; this.macro = macro; this.oldLinks = new TreeSet<OpLink>(); this.oldLinks.addAll(graph.getIncomingEdges(macro)); this.oldLinks.addAll(graph.getOutgoingEdges(macro)); this.newLinks = new TreeSet<OpLink>(); this.newLinks.addAll(macro.getGraph().getEdges()); for(OpLink link : graph.getIncomingEdges(macro)) { // If an incoming link is linked to a node that isn't a published // input, we can't reliably explode this node if(!(link.getDestinationField() instanceof PublishedInput)) throw new IllegalArgumentException("Macro node contains an incoming link linked to a node that isn't a published input."); final PublishedInput input = (PublishedInput)link.getDestinationField(); try { this.newLinks.add(new OpLink(link.getSource(), link.getSourceField(), input.destinationNode, input.nodeInputField)); } catch(ItemMissingException exc) { throw new IllegalArgumentException("A link connected to this MacroNode is in an impossible state"); } } for(OpLink link : graph.getOutgoingEdges(macro)) { // If an outgoing link is linked to a node that isn't a published // output, we can't reliably explode this node if(!(link.getSourceField() instanceof PublishedOutput)) throw new IllegalArgumentException("Macro node contains an outgoing link linked to a node that isn't a published output. Cannot reliably explode."); final PublishedOutput output = (PublishedOutput)link.getSourceField(); try { this.newLinks.add(new OpLink(output.sourceNode, output.nodeOutputField, link.getDestination(), link.getDestinationField())); } catch(ItemMissingException exc) { throw new IllegalArgumentException("A link connected to this MacroNode is in an impossible state"); } } perform(); } /** * Performs this edit. */ private void perform() { // Remove macro node graph.remove(macro); // Add all nodes from macro for(OpNode nodes : macro.getGraph().getVertices()) graph.add(nodes); // Add new links for(OpLink link : newLinks) { try { graph.add(link); } catch(VertexNotFoundException exc) { LOGGER.severe("impossible exception"); } catch(CycleDetectedException exc) { LOGGER.severe("impossible exception"); } } } // // AbstractEdit overrides // @Override public String getPresentationName() { return "Create Macro"; } @Override public void redo() throws CannotRedoException { super.redo(); perform(); } @Override public void undo() throws CannotUndoException { super.undo(); // Add all nodes from macro for(OpNode node : macro.getGraph().getVertices()) graph.remove(node); // Add macro node graph.add(macro); for(OpLink link : oldLinks) { try { graph.add(link); } catch(VertexNotFoundException exc) { LOGGER.severe("impossible exception"); } catch(CycleDetectedException exc) { LOGGER.severe("impossible exception"); } } } }