/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo 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. * * OpenFlexo 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 OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.wkf.controller; import java.awt.geom.Point2D; import java.io.File; import java.util.Enumeration; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JComponent; import javax.swing.JMenuItem; import org.openflexo.fge.geom.FGEDimension; import org.openflexo.fge.geom.FGEGeometricObject.Filling; import org.openflexo.fge.geom.FGEPoint; import org.openflexo.fge.geom.FGERectangle; import org.openflexo.foundation.FlexoModelObject; import org.openflexo.foundation.RepresentableFlexoModelObject; import org.openflexo.foundation.rm.FlexoProject; import org.openflexo.foundation.wkf.DuplicateRoleException; import org.openflexo.foundation.wkf.FlexoLevel; import org.openflexo.foundation.wkf.FlexoPetriGraph; import org.openflexo.foundation.wkf.FlexoProcess; import org.openflexo.foundation.wkf.Role; import org.openflexo.foundation.wkf.RoleCompound; import org.openflexo.foundation.wkf.RoleList; import org.openflexo.foundation.wkf.WKFArtefact; import org.openflexo.foundation.wkf.WKFGroup; import org.openflexo.foundation.wkf.WKFObject; import org.openflexo.foundation.wkf.action.AddPort; import org.openflexo.foundation.wkf.action.DropWKFElement; import org.openflexo.foundation.wkf.edge.WKFEdge; import org.openflexo.foundation.wkf.node.AbstractActivityNode; import org.openflexo.foundation.wkf.node.LOOPOperator; import org.openflexo.foundation.wkf.node.NodeCompound; import org.openflexo.foundation.wkf.node.OperationNode; import org.openflexo.foundation.wkf.node.PetriGraphNode; import org.openflexo.foundation.wkf.node.SelfExecutableNode; import org.openflexo.foundation.wkf.ws.DeletePort; import org.openflexo.foundation.wkf.ws.FlexoPort; import org.openflexo.foundation.wkf.ws.InOutPort; import org.openflexo.foundation.wkf.ws.InPort; import org.openflexo.foundation.wkf.ws.NewPort; import org.openflexo.foundation.wkf.ws.OutPort; import org.openflexo.foundation.wkf.ws.PortRegistery; import org.openflexo.localization.FlexoLocalization; import org.openflexo.selection.FlexoClipboard; import org.openflexo.selection.PastingGraphicalContext; import org.openflexo.toolbox.FileUtils; import org.openflexo.view.controller.FlexoController; import org.openflexo.wkf.processeditor.ProcessEditorConstants; import org.openflexo.xmlcode.XMLSerializable; /** * WKFClipboard is intented to be the object working with the WKFSelectionManager and storing copied, cutted and pasted objects. Handled * objects are instances implementing {@link org.openflexo.selection.SelectableView}. * * @author sguerin */ public class WKFClipboard extends FlexoClipboard { private static final Logger logger = Logger.getLogger(WKFClipboard.class.getPackage().getName()); protected WKFSelectionManager _wkfSelectionManager; private FlexoModelObject _clipboardData; private FlexoLevel currentCopyLevel = null; public WKFClipboard(WKFSelectionManager aSelectionManager, JMenuItem copyMenuItem, JMenuItem pasteMenuItem, JMenuItem cutMenuItem) { super(aSelectionManager, copyMenuItem, pasteMenuItem, cutMenuItem); _wkfSelectionManager = aSelectionManager; resetClipboard(); } public WKFSelectionManager getSelectionManager() { return _wkfSelectionManager; } public WKFController getWKFController() { return getSelectionManager().getWKFController(); } @Override public boolean performSelectionPaste() { if (_isPasteEnabled) { /* * if (getWKFController().getFlexoPaletteWindow().hasFocus()) { * //JTabbedPane tabs = * getWKFController().getFlexoPaletteWindow().currentTabbedPane; * //String selectedTabName = * tabs.getComponent(tabs.getSelectedIndex()).getName(); String * selectedTabName = * getWKFController().getFlexoPaletteWindow().getPalette * ().getCurrentPalettePanel().getName(); File dir = new * File(((WKFPalette * )getWKFController().getFlexoPaletteWindow().getPalette * ()).paletteDirectory(), selectedTabName); String exportedName = * WKFController * .askForString("Please enter a name for the exported element."); * exportClipboardToPalette(dir, exportedName); * getWKFController().recreatePalette(); return true; } else { */ return super.performSelectionPaste(); // } } else { if (logger.isLoggable(Level.FINE)) { logger.fine("Sorry, PASTE disabled"); } return false; } } @Override protected void performSelectionPaste(FlexoModelObject pastingContext, PastingGraphicalContext graphicalContext) { logger.info("performSelectionPaste() with context " + pastingContext); JComponent targetContainer = null; Point2D location = null; if (graphicalContext != null) { targetContainer = graphicalContext.targetContainer; location = graphicalContext.precisePastingLocation; if (location == null) { location = graphicalContext.pastingLocation; } } if (location == null) { location = new Point2D.Double(); } if (pastingContext instanceof PetriGraphNode) { pastingContext = ((PetriGraphNode) pastingContext).getParentPetriGraph(); } else if (pastingContext instanceof WKFArtefact) { pastingContext = ((WKFArtefact) pastingContext).getParentPetriGraph(); } if (isTargetValidForPasting(pastingContext)) { if (logger.isLoggable(Level.FINE)) { logger.fine("Paste is legal"); } getSelectionManager().resetSelection(); XMLSerializable pasted = null; try { pasted = _clipboardData.cloneUsingXMLMapping(); } catch (Exception ex) { if (logger.isLoggable(Level.WARNING)) { logger.warning("Unexpected exception raised during pasting: " + ex.getMessage()); } ex.printStackTrace(); return; } if (pasted instanceof NodeCompound && pastingContext instanceof WKFObject) { Vector<WKFObject> newSelection = pasteNodeCompound((WKFObject) pastingContext, (NodeCompound) pasted, location); getWKFController().getSelectionManager().setSelectedObjects(newSelection); } else if (pasted instanceof RoleCompound && pastingContext instanceof RoleList) { Vector<Role> newSelection = pasteRoleCompound((RoleList) pastingContext, (RoleCompound) pasted, location); getWKFController().getSelectionManager().setSelectedObjects(newSelection); } } else { FlexoController.notify(FlexoLocalization.localizedForKey("cannot_paste_at_this_place_wrong_level")); if (logger.isLoggable(Level.INFO)) { logger.info("Paste is NOT legal"); logger.info("pastingContext=" + pastingContext + " of " + pastingContext.getClass().getSimpleName()); logger.info("_clipboardData=" + _clipboardData); logger.info("xml=" + (_clipboardData != null ? _clipboardData.getXMLRepresentation() : null)); } } } protected Vector<WKFObject> pasteNodeCompound(WKFObject pastingContext, NodeCompound pastedCompound, Point2D location) { WKFObject container = pastingContext; FlexoProcess process = container.getProcess(); // We paste as a selection of nodes inside a NodeCompound NodeCompound compound = pastedCompound; String context = ProcessEditorConstants.BASIC_PROCESS_EDITOR; compound.setLocation(location, context); Vector<WKFObject> newSelection = new Vector<WKFObject>(); FGERectangle bounds = new FGERectangle(new FGEPoint(location), new FGEDimension(0, 0), Filling.FILLED); for (Enumeration<WKFObject> e = compound.getAllEmbeddedWKFObjects().elements(); e.hasMoreElements();) { WKFObject node = e.nextElement(); if (node == compound) { continue; } bounds.width = Math.max(bounds.width, node.getX(context) + node.getWidth(context) - bounds.x); bounds.height = Math.max(bounds.height, node.getY(context) + node.getHeight(context) - bounds.y); } // GPO: Not sure it is required, so I leave it but commented /*bounds.width+=20; // We add this for the borders of the GR bounds.height+=10;*/ FGERectangle processBounds = new FGERectangle(0, 0, process.getWidth(context), process.getHeight(context), Filling.FILLED); processBounds = processBounds.rectangleUnion(bounds); process.setWidth(processBounds.width, context); process.setHeight(processBounds.height, context); for (Enumeration<WKFObject> e = compound.getAllEmbeddedWKFObjects().elements(); e.hasMoreElements();) { WKFObject node = e.nextElement(); if (node == compound) { continue; } insertWKFObject(node, container); newSelection.add(node); } return newSelection; } protected Vector<Role> pasteRoleCompound(RoleList pastingContext, RoleCompound pastedCompound, Point2D location) { pastedCompound.setLocation(location, RepresentableFlexoModelObject.DEFAULT); Vector<Role> newSelection = new Vector<Role>(); FGERectangle bounds = new FGERectangle(new FGEPoint(location), new FGEDimension(0, 0), Filling.FILLED); for (Enumeration<Role> e = pastedCompound.getRoles().elements(); e.hasMoreElements();) { Role role = e.nextElement(); bounds.width = Math.max(bounds.width, role.getX(RepresentableFlexoModelObject.DEFAULT) + role.getWidth(RepresentableFlexoModelObject.DEFAULT) - bounds.x); bounds.height = Math.max(bounds.height, role.getY(RepresentableFlexoModelObject.DEFAULT) + role.getHeight(RepresentableFlexoModelObject.DEFAULT) - bounds.y); } FGERectangle roleListBounds = new FGERectangle(0, 0, pastingContext.getWidth(RepresentableFlexoModelObject.DEFAULT), pastingContext.getHeight(RepresentableFlexoModelObject.DEFAULT), Filling.FILLED); roleListBounds = roleListBounds.rectangleUnion(bounds); pastingContext.setWidth(roleListBounds.width, RepresentableFlexoModelObject.DEFAULT); pastingContext.setHeight(roleListBounds.height, RepresentableFlexoModelObject.DEFAULT); for (Enumeration<Role> e = pastedCompound.getRoles().elements(); e.hasMoreElements();) { Role role = e.nextElement(); insertRole(role, pastingContext); newSelection.add(role); } return newSelection; } private void insertRole(Role toInsert, RoleList roleList) { logger.info("Insert role " + toInsert); try { roleList.addToRoles(toInsert); } catch (DuplicateRoleException e) { int i = 1; String baseName = toInsert.getName(); boolean ok = false; while (!ok) { try { toInsert.setName(baseName + "-" + i); roleList.addToRoles(toInsert); ok = true; } catch (DuplicateRoleException e1) { i++; } } } } public void insertWKFObject(WKFObject toInsert, WKFObject container) { if (toInsert instanceof FlexoPort) { FlexoPort port = (FlexoPort) toInsert; if (container instanceof PortRegistery) { AddPort action = null; if (port instanceof NewPort) { action = AddPort.createNewPort.makeNewAction(container, null, getWKFController().getEditor()); } else if (port instanceof DeletePort) { action = AddPort.createDeletePort.makeNewAction(container, null, getWKFController().getEditor()); } else if (port instanceof InPort) { action = AddPort.createInPort.makeNewAction(container, null, getWKFController().getEditor()); } else if (port instanceof OutPort) { action = AddPort.createOutPort.makeNewAction(container, null, getWKFController().getEditor()); } else if (port instanceof InOutPort) { action = AddPort.createInOutPort.makeNewAction(container, null, getWKFController().getEditor()); } if (action != null) { action.setNewPortName(port.getDefaultName()); action.setEditNodeLabel(false); action.doAction(); } } } else { FlexoPetriGraph pg = null; if (container instanceof SelfExecutableNode) { pg = ((SelfExecutableNode) container).getExecutionPetriGraph(); } if (container instanceof FlexoProcess) { pg = ((FlexoProcess) container).getActivityPetriGraph(); } if (container instanceof AbstractActivityNode) { pg = ((AbstractActivityNode) container).getOperationPetriGraph(); } if (container instanceof OperationNode) { pg = ((OperationNode) container).getActionPetriGraph(); } if (container instanceof LOOPOperator) { pg = ((LOOPOperator) container).getExecutionPetriGraph(); } if (container instanceof FlexoPetriGraph) { pg = (FlexoPetriGraph) container; } if (container instanceof WKFGroup) { pg = ((WKFGroup) container).getParentPetriGraph(); } if (pg != null) { DropWKFElement action = DropWKFElement.actionType.makeNewAction(pg, null, getWKFController().getEditor()); action.setObject(toInsert); action.setResetNodeName(false); action.setEditNodeLabel(false); action.setLeaveSubProcessNodeUnchanged(true); if (container instanceof WKFGroup) { action.setGroup((WKFGroup) container); } action.doAction(); } } } @Override protected boolean isCurrentSelectionValidForCopy(Vector<? extends FlexoModelObject> currentlySelectedObjects) { return getSelectionManager().getSelectionSize() > 0; } protected void resetClipboard() { currentCopyLevel = null; _clipboardData = null; } public FlexoModelObject getClipboardData() { return _clipboardData; } /** * Selection procedure for copy */ @Override protected boolean performCopyOfSelection(Vector<? extends FlexoModelObject> currentlySelectedObjects) { logger.info("performCopyOfSelection() for " + currentlySelectedObjects); // TODO reimplement all of this resetClipboard(); if (currentlySelectedObjects.size() > 0) { if (currentlySelectedObjects.firstElement() instanceof PetriGraphNode || currentlySelectedObjects.firstElement() instanceof WKFArtefact || currentlySelectedObjects.firstElement() instanceof WKFEdge<?, ?>) { Vector<PetriGraphNode> selectedNodes = new Vector<PetriGraphNode>(); Vector<WKFArtefact> selectedAnnotations = new Vector<WKFArtefact>(); FlexoProcess process = null; for (Enumeration<? extends FlexoModelObject> e = currentlySelectedObjects.elements(); e.hasMoreElements();) { FlexoModelObject next = e.nextElement(); if (logger.isLoggable(Level.FINE)) { logger.fine("Selected: " + next); } if (next instanceof PetriGraphNode) { PetriGraphNode node = (PetriGraphNode) next; process = node.getProcess(); selectedNodes.add(node); } else if (next instanceof WKFArtefact) { WKFArtefact annotation = (WKFArtefact) next; process = annotation.getProcess(); selectedAnnotations.add(annotation); } } currentCopyLevel = getSelectionManager().getSelectionLevel(); if (selectedNodes.size() + selectedAnnotations.size() > 0) { // We make // a // NodeCompound _clipboardData = new NodeCompound(process, selectedNodes, selectedAnnotations); } } else if (currentlySelectedObjects.firstElement() instanceof Role) { FlexoProject project = ((Role) currentlySelectedObjects.firstElement()).getProject(); Vector<Role> rolesToBeCopied = new Vector<Role>(); for (FlexoModelObject o : currentlySelectedObjects) { if (o instanceof Role) { rolesToBeCopied.add((Role) o); } } _clipboardData = new RoleCompound(project.getFlexoWorkflow(), rolesToBeCopied); currentCopyLevel = FlexoLevel.WORKFLOW; } } if (_clipboardData != null) { // Call XMLRepresentation can be tricky because it trigger XML encoding and later some issues with FlexoID's // logger.fine("Storing in clipboard: " + _clipboardData.getXMLRepresentation()); } else { logger.warning("null value in clipboard ! "); } return true; } protected boolean isTargetValidForPasting(FlexoModelObject pastingContext) { if (pastingContext == null) { return false; } if (_clipboardData instanceof NodeCompound) { if (pastingContext instanceof PortRegistery) { return ((NodeCompound) _clipboardData).getLevel() == FlexoLevel.PORT; } else { FlexoPetriGraph targetPetriGraph = null; if (pastingContext instanceof FlexoProcess) { targetPetriGraph = ((FlexoProcess) pastingContext).getActivityPetriGraph(); } else if (pastingContext instanceof FlexoPetriGraph) { targetPetriGraph = (FlexoPetriGraph) pastingContext; } else if (pastingContext instanceof WKFGroup) { targetPetriGraph = ((WKFGroup) pastingContext).getParentPetriGraph(); } else { if (logger.isLoggable(Level.INFO)) { logger.info("Cannot paste into " + pastingContext.getClass().getName()); } } if (targetPetriGraph != null) { return targetPetriGraph.acceptsObject((NodeCompound) _clipboardData); } } } else if (_clipboardData instanceof RoleCompound) { if (pastingContext instanceof RoleList) { return true; } else if (pastingContext instanceof Role) { return true; } } return false; } protected void exportClipboardToPalette(File paletteDirectory, String newPaletteElementName) { if (_clipboardData instanceof NodeCompound) { NodeCompound compound = (NodeCompound) _clipboardData; if (compound.isSingleNode()) { if (!newPaletteElementName.endsWith(".xml")) { newPaletteElementName = newPaletteElementName + ".xml"; try { FileUtils.saveToFile(newPaletteElementName, compound.getFirstNode().getXMLRepresentation(), paletteDirectory); } catch (Exception e) { if (logger.isLoggable(Level.WARNING)) { logger.warning("Error occurs while saving node in the palette\n" + e.getMessage()); } } } } else { if (logger.isLoggable(Level.WARNING)) { logger.warning("Sorry, but you can't export more than one top level node in the palette"); } } } } }