Java tutorial
//======================================================================== // //File: $RCSfile: CanvasPasteAction.java,v $ //Version: $Revision: 1.11 $ //Modified: $Date: 2013/05/10 05:37:56 $ // //(c) Copyright 2007-2014 by Mentor Graphics Corp. All rights reserved. // //======================================================================== // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy // of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //======================================================================== // package com.mentor.nucleus.bp.ui.graphics.actions; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.UUID; import org.eclipse.draw2d.geometry.Point; import org.eclipse.gef.EditPart; import org.eclipse.gef.GraphicalViewer; import org.eclipse.gef.editparts.AbstractGraphicalEditPart; import org.eclipse.gef.requests.ChangeBoundsRequest; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.widgets.Event; import com.mentor.nucleus.bp.core.CorePlugin; import com.mentor.nucleus.bp.core.Ooaofooa; import com.mentor.nucleus.bp.core.common.InstanceList; import com.mentor.nucleus.bp.core.common.ModelRoot; import com.mentor.nucleus.bp.core.common.ModelStreamProcessor; import com.mentor.nucleus.bp.core.common.NonRootModelElement; import com.mentor.nucleus.bp.core.common.TransactionManager; import com.mentor.nucleus.bp.core.ui.PasteAction; import com.mentor.nucleus.bp.core.ui.Selection; import com.mentor.nucleus.bp.ui.canvas.Cl_c; import com.mentor.nucleus.bp.ui.canvas.Connector_c; import com.mentor.nucleus.bp.ui.canvas.ContainingShape_c; import com.mentor.nucleus.bp.ui.canvas.Diagram_c; import com.mentor.nucleus.bp.ui.canvas.Diagramelement_c; import com.mentor.nucleus.bp.ui.canvas.Graphconnector_c; import com.mentor.nucleus.bp.ui.canvas.Graphedge_c; import com.mentor.nucleus.bp.ui.canvas.Graphelement_c; import com.mentor.nucleus.bp.ui.canvas.GraphicalElement_c; import com.mentor.nucleus.bp.ui.canvas.Graphnode_c; import com.mentor.nucleus.bp.ui.canvas.Model_c; import com.mentor.nucleus.bp.ui.canvas.Ooaofgraphics; import com.mentor.nucleus.bp.ui.canvas.Shape_c; import com.mentor.nucleus.bp.ui.graphics.editor.GraphicalEditor; import com.mentor.nucleus.bp.ui.graphics.tools.GraphicalPanningSelectionTool; import com.mentor.nucleus.bp.ui.graphics.utilities.GraphicsUtil; public class CanvasPasteAction extends PasteAction { private GraphicalEditor m_editor; private int offsetX; private int offsetY; private GraphicalElement_c[] graphicElements; private ChangeBoundsRequest fRequest; public CanvasPasteAction(GraphicalEditor editor) { super(); m_editor = editor; } @Override public void runWithEvent(Event event) { // if the paste was initiated via // the keyboard, then clear the last // context press and use 0,0 for the // location (until a better layout is // provided) if (event.keyCode != 0) { GraphicalViewer viewer = (GraphicalViewer) m_editor.getAdapter(GraphicalViewer.class); GraphicalPanningSelectionTool tool = (GraphicalPanningSelectionTool) viewer.getEditDomain() .getActiveTool(); tool.clearLastLeftClickLocation(); } super.runWithEvent(event); } public void runSubtypeProcessing(NonRootModelElement destination) { // we only want to do graphical processing // if the destination is the diagram if (getDestinations().size() == 1 && getDestinations().get(0) == m_editor.getModel().getRepresents()) { NonRootModelElement[] elements = getLoadedGraphicalInstances( (NonRootModelElement) m_editor.getModel().getRepresents()); graphicElements = getPastedGraphicalElements((NonRootModelElement) m_editor.getModel().getRepresents(), processorMap); if (graphicElements.length == 0) { // this is likely a copy from ME to diagram where // no graphics exist, one case and maybe the only // is copy a domain and paste to SYS diagram return; } boolean newParent = areGraphicalElementsExternal(); updateGraphicalElementRoots(elements, m_editor.getModel().getModelRoot()); for (int i = 0; i < graphicElements.length; i++) { graphicElements[i].relateAcrossR1To(m_editor.getModel()); updateContainement(m_editor.getModel(), graphicElements[i]); } updateLocation(graphicElements, newParent); if (m_editor.getModel().Hascontainersymbol()) { Shape_c container = Shape_c .getOneGD_SHPOnR2(GraphicalElement_c.getOneGD_GEOnR1(m_editor.getModel())); ContainingShape_c cs = ContainingShape_c.getOneGD_CTROnR28(container); if (cs != null) { cs.Autoresize(); } } offsetX = 0; offsetY = 0; } else { handleNonDiagramElementAsDestination(destination, processorMap); } } public static void handleNonDiagramElementAsDestination(NonRootModelElement destination, HashMap<NonRootModelElement, ModelStreamProcessor> processorMap) { // we are pasting into a shape, we need to move the // graphical elements to the new Model_c instance Model_c model = getModelForDestination(destination); // skip if no diagram if (model == null) { return; } GraphicalElement_c[] pastedGraphicalElements = getPastedGraphicalElements(destination, processorMap); NonRootModelElement[] loadedGraphicalElements = processorMap.get(destination).getImporter() .getLoadedGraphicalInstances(); updateGraphicalElementRoots(loadedGraphicalElements, model.getModelRoot()); for (GraphicalElement_c element : pastedGraphicalElements) { element.relateAcrossR1To(model); updateContainement(model, element); } // move the elements so they do not overlap any existing elements moveGraphicalElementsToPreventOverlapping(pastedGraphicalElements, model); if (model.Hascontainersymbol()) { Shape_c container = Shape_c.getOneGD_SHPOnR2(GraphicalElement_c.getOneGD_GEOnR1(model)); ContainingShape_c cs = ContainingShape_c.getOneGD_CTROnR28(container); if (cs != null) { cs.Autoresize(); } } } private static void moveGraphicalElementsToPreventOverlapping(GraphicalElement_c[] elements, Model_c model) { // store current selection ISelection selection = Selection.getInstance().getSelection(); // clear the current selection and add all elements // to it, this allows connectors to move properly Selection.getInstance().clear(); Point northWestSelectionPoint = getNorthWestSelectionPoint(elements); Point nextAvailableEastLocation = getNextAvailableEastLocation(model); for (int i = 0; i < elements.length; i++) { Cl_c.Addtoselection(elements[i]); } for (int i = 0; i < elements.length; i++) { Connector_c connector = Connector_c.getOneGD_CONOnR2(elements[i]); if (connector == null) { elements[i].Move(nextAvailableEastLocation.x - northWestSelectionPoint.x, nextAvailableEastLocation.y - northWestSelectionPoint.y); } } // restore the selection Selection.getInstance().setSelection(selection); } private static Point getNextAvailableEastLocation(Model_c model) { GraphicalElement_c[] existing = GraphicalElement_c.getManyGD_GEsOnR1(model); Point east = new Point(-1, Integer.MAX_VALUE); for (int i = 0; i < existing.length; i++) { Graphelement_c graphEle = Graphelement_c.getOneDIM_GEOnR23(existing[i]); Graphnode_c node = Graphnode_c.getOneDIM_NDOnR301(graphEle); Connector_c connector = Connector_c.getOneGD_CONOnR2(GraphicalElement_c.getOneGD_GEOnR23(graphEle)); if (connector == null) { if (east.x < graphEle.getPositionx() + node.getWidth()) { east.x = (int) (graphEle.getPositionx() + node.getWidth() + 50); } if (east.y > graphEle.getPositiony()) { east.y = (int) graphEle.getPositiony(); } } } return east; } private static Model_c getModelForDestination(NonRootModelElement destination) { Ooaofgraphics graphicsRoot = Ooaofgraphics.getInstance(destination.getModelRoot().getId()); Model_c[] models = Model_c.ModelInstances(graphicsRoot); for (Model_c model : models) { if (model.getRepresents() == destination) { return model; } } return null; } private boolean areGraphicalElementsExternal() { // right now all graphical elements come from // the same location, so just check the first // in the list UUID copiedFromDiagramId = graphicElements[0].getDiagramidCachedValue(); Diagram_c destinationDiagram = Diagram_c.getOneDIM_DIAOnR18(m_editor.getModel()); if (!copiedFromDiagramId.equals(destinationDiagram.getDiagramid())) { return true; } return false; } private static void updateContainement(Model_c ptCanvas, GraphicalElement_c element_c) { Diagramelement_c diaElem = Diagramelement_c .getOneDIM_ELEOnR302(Graphelement_c.getOneDIM_GEOnR23(element_c)); if (ptCanvas.Hascontainersymbol()) { // if this shape is pasted into // a shape, make sure the necessary // containment associations are setup Graphelement_c container = Graphelement_c.getOneDIM_GEOnR307(diaElem); if (container == null) { container = Graphelement_c.getOneDIM_GEOnR23(GraphicalElement_c .getOneGD_GEOnR2(Shape_c.getOneGD_SHPOnR28(ContainingShape_c.getOneGD_CTROnR28( Shape_c.getOneGD_SHPOnR2(GraphicalElement_c.getOneGD_GEOnR1(ptCanvas)))))); diaElem.relateAcrossR307To(container); } } else { // if not pasted into a shape // make sure no containment // association is setup Graphelement_c container = Graphelement_c.getOneDIM_GEOnR307(diaElem); if (container != null) { diaElem.unrelateAcrossR307From(container); } } } private static void updateGraphicalElementRoots(NonRootModelElement[] elements, ModelRoot modelRoot) { for (int i = 0; i < elements.length; i++) { InstanceList list = elements[i].getModelRoot().getInstanceList(elements[i].getClass()); synchronized (list) { list.remove(elements[i]); } InstanceList parentList = modelRoot.getInstanceList(elements[i].getClass()); synchronized (list) { parentList.add(elements[i]); } parentList.put(elements[i].getInstanceKey(), elements[i]); elements[i].setModelRoot(modelRoot); } } private static GraphicalElement_c[] getPastedGraphicalElements(NonRootModelElement destination, HashMap<NonRootModelElement, ModelStreamProcessor> processorMap) { // do not process unless the destination is the diagram ArrayList<GraphicalElement_c> list = new ArrayList<GraphicalElement_c>(); GraphicalElement_c[] pastedElems = GraphicalElement_c .GraphicalElementInstances(Ooaofgraphics.getInstance(Ooaofooa.CLIPBOARD_MODEL_ROOT_NAME)); for (int i = 0; i < pastedElems.length; i++) { // skip containing shapes ContainingShape_c cs = ContainingShape_c.getOneGD_CTROnR28(Shape_c.getOneGD_SHPOnR2(pastedElems[i])); if (cs != null) { continue; } // skip connectors that start on a container shape // as they are never part of the copy, if we later // enable copy of a container then we will likely // need to remove these checks cs = ContainingShape_c.getOneGD_CTROnR28(Shape_c.getOneGD_SHPOnR2(GraphicalElement_c .getOneGD_GEOnR23(Graphelement_c.getOneDIM_GEOnR311(Graphconnector_c.getOneDIM_CONOnR320( Graphedge_c.getOneDIM_EDOnR20(Connector_c.getOneGD_CONOnR2(pastedElems[i]))))))); if (cs != null) { continue; } cs = ContainingShape_c.getOneGD_CTROnR28(Shape_c.getOneGD_SHPOnR2(GraphicalElement_c .getOneGD_GEOnR23(Graphelement_c.getOneDIM_GEOnR311(Graphconnector_c.getOneDIM_CONOnR321( Graphedge_c.getOneDIM_EDOnR20(Connector_c.getOneGD_CONOnR2(pastedElems[i]))))))); if (cs != null) { continue; } if (pastedElems[i].getRepresents() != null) { if (processorMap.get(destination) .isTypePartOfExport((NonRootModelElement) pastedElems[i].getRepresents())) { list.add(pastedElems[i]); } } } return list.toArray(new GraphicalElement_c[list.size()]); } /** * Determines the position for the pasted elements, then makes a call * to update their positional values. * * @param elements */ private void updateLocation(GraphicalElement_c[] elements, boolean newParent) { if (offsetX == 0 && offsetY == 0) { if (fRequest != null) { offsetX = fRequest.getMoveDelta().x; offsetY = fRequest.getMoveDelta().y; // clear the request cache fRequest = null; } else { // determine the offset based on the northwest corner // point of the selection and the mouse point where // the user decided to paste the selection Point nw = getNorthWestSelectionPoint(elements); Point location = getMouseLocation(); offsetX = (int) (location.x - nw.x); offsetY = (int) (location.y - nw.y); GraphicalViewer viewer = (GraphicalViewer) m_editor.getAdapter(GraphicalViewer.class); GraphicalPanningSelectionTool tool = (GraphicalPanningSelectionTool) viewer.getEditDomain() .getActiveTool(); if (tool.getLastLeftClickLocation().x == 0 && tool.getLastLeftClickLocation().y == 0) { // there is no location hint, so we // just give a slight offset to the right // and down a bit, unless the elements are // being pasted from a different diagram if (newParent) { // then we simply use the top left corner Point topLeft = new Point(15, 15); ((AbstractGraphicalEditPart) viewer.getContents()).getFigure().translateToRelative(topLeft); offsetX = topLeft.x - nw.x; offsetY = topLeft.y - nw.y; } else { offsetX = 15; offsetY = 15; } } } } updateLocations(offsetX, offsetY, elements); } private Point getMouseLocation() { GraphicalViewer viewer = (GraphicalViewer) m_editor.getAdapter(GraphicalViewer.class); GraphicalPanningSelectionTool tool = (GraphicalPanningSelectionTool) viewer.getEditDomain().getActiveTool(); Point lastLeftClickLocation = tool.getLastLeftClickLocation().getCopy(); ((AbstractGraphicalEditPart) viewer.getContents()).getFigure().translateToRelative(lastLeftClickLocation); return lastLeftClickLocation; } /** * Updates the positional values of the elements on the clipboard, using * the given offset. Note the elements are added to the selection just in * case the selection was cleared before a paste, this allows for connectors * to move appropriately. * * @param offsetX2 * @param offsetY2 * @param elements */ private void updateLocations(int offsetX2, int offsetY2, GraphicalElement_c[] elements) { // set the selection before moving and after refreshing // the diagram contents (the refresh will create // the new edit parts) m_editor.refresh(); GraphicalViewer viewer = (GraphicalViewer) m_editor.getAdapter(GraphicalViewer.class); viewer.deselectAll(); for (int i = 0; i < elements.length; i++) { Object newModel = null; Shape_c shape = Shape_c.getOneGD_SHPOnR2(elements[i]); if (shape != null) { newModel = shape; } Connector_c connector = Connector_c.getOneGD_CONOnR2(elements[i]); if (connector != null) { newModel = connector; } List<?> children = viewer.getContents().getChildren(); for (Object child : children) { EditPart editPart = (EditPart) child; if (editPart.getModel() == newModel) { viewer.appendSelection(editPart); } } } for (int i = 0; i < elements.length; i++) { Connector_c connector = Connector_c.getOneGD_CONOnR2(elements[i]); if (connector == null) { elements[i].Move(offsetX2, offsetY2); } } } /** * Looks through the elements on the clipboard to determine * a reference point for location placement * * @param elements * @return */ private static Point getNorthWestSelectionPoint(GraphicalElement_c[] elements) { Point nw = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE); for (int i = 0; i < elements.length; i++) { Graphelement_c graphEle = Graphelement_c.getOneDIM_GEOnR23(elements[i]); Connector_c connector = Connector_c.getOneGD_CONOnR2(GraphicalElement_c.getOneGD_GEOnR23(graphEle)); if (connector == null) { if (nw.x > graphEle.getPositionx()) { nw.x = (int) graphEle.getPositionx(); } if (nw.y > graphEle.getPositiony()) { nw.y = (int) graphEle.getPositiony(); } } } return nw; } /** * Determines whether or not the clipboard contains any model elements * that may be pasted into the current editor. */ public boolean clipboardContainsPastableModelElements() { Clipboard cb = CorePlugin.getSystemClipboard(); if (m_editor == null) return false; if (cb == null || cb.isDisposed()) return false; boolean result = true; Object contents = cb.getContents(TextTransfer.getInstance()); for (NonRootModelElement destination : getDestinations()) { if (contents instanceof String) { String types[] = getClipboardTypes((String) contents, destination); for (int i = 0; i < types.length; i++) { result = Cl_c.supportsPaste(destination, types[i]); if (!result) break; } if (types.length == 0) { result = false; } } else { result = false; } } return result; } public TransactionManager getTransactionManager() { return ((NonRootModelElement) m_editor.getModel().getRepresents()).getTransactionManager(); } @Override public List<NonRootModelElement> getDestinations() { if (fRequest != null) { // this is for the clone command, which always needs // the diagram host as the destination List<NonRootModelElement> destinations = new ArrayList<NonRootModelElement>(); destinations.add((NonRootModelElement) m_editor.getModel().getRepresents()); return destinations; } IStructuredSelection selection = (IStructuredSelection) m_editor.getSite().getSelectionProvider() .getSelection(); return getDestinationsFromSelection(selection); } private List<NonRootModelElement> getDestinationsFromSelection(IStructuredSelection selection) { List<NonRootModelElement> destinations = new ArrayList<NonRootModelElement>(); for (Iterator<?> iterator = selection.iterator(); iterator.hasNext();) { Object selected = iterator.next(); if (selected instanceof EditPart) { EditPart part = (EditPart) selected; NonRootModelElement element = (NonRootModelElement) GraphicsUtil.getRepresentsFromEditPart(part); destinations.add(element); } } return destinations; } public void setRequest(ChangeBoundsRequest request) { fRequest = request; } @Override public boolean isEnabled() { if (!super.isEnabled()) { return false; } return clipboardContainsPastableModelElements(); } }