Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sun.electric.tool.user.Clipboard Maven / Gradle / Ivy
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Clipboard.java
*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) 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.
*
* Electric(tm) 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 Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool.user;
import com.sun.electric.database.EditingPreferences;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.geometry.Poly;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Export;
import com.sun.electric.database.hierarchy.View;
import com.sun.electric.database.id.CellId;
import com.sun.electric.database.id.IdManager;
import com.sun.electric.database.prototype.NodeProto;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.Geometric;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.NodeInst.ExpansionState;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.database.variable.DisplayedText;
import com.sun.electric.database.variable.EditWindow_;
import com.sun.electric.database.variable.ElectricObject;
import com.sun.electric.database.variable.UserInterface;
import com.sun.electric.database.variable.VarContext;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.technology.Technology;
import com.sun.electric.technology.technologies.Generic;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.JobException;
import com.sun.electric.tool.user.ui.ClickZoomWireListener;
import com.sun.electric.tool.user.ui.EditWindow;
import com.sun.electric.tool.user.ui.MessagesWindow;
import com.sun.electric.tool.user.ui.TextWindow;
import com.sun.electric.tool.user.ui.WindowFrame;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.math.DBMath;
import com.sun.electric.util.math.EDimension;
import com.sun.electric.util.math.FixpTransform;
import com.sun.electric.util.math.GenMath;
import com.sun.electric.util.math.Orientation;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;
/**
* Class for managing the circuitry clipboard (for copy and paste).
*/
public class Clipboard //implements ClipboardOwner
{
/** The Clipboard CellId. */
public static final String CLIPBOARD_LIBRAY_NAME = "Clipboard!!";
public static final String CLIPBOARD_CELL_NAME = "Clipboard!!;1{}";
public static final int CLIPBOARD_CELL_INDEX = 0;
/** the amount that the last node moved */ private static double lastDupX = 10, lastDupY = 10;
/**
* There is only one instance of this object (just one clipboard).
*/
private Clipboard() {}
/**
* Returns a printable version of this Clipboard.
* @return a printable version of this Clipboard.
*/
public String toString() { return "Clipboard"; }
// this is really only for debugging
public static void editClipboard()
{
EditWindow wnd = EditWindow.getCurrent();
wnd.setCell(getClipCell(), VarContext.globalContext, null);
}
/**
* Method to copy the selected objects to the clipboard.
*/
public static void copy()
{
// Clear text buffer
TextUtils.setTextOnClipboard(null);
// is this the messages window?
MessagesWindow mw = MessagesWindow.getFocusOwner();
if (mw != null)
{
mw.copyText(false, false);
return;
}
// if current window is text window, copy from it
WindowFrame wf = WindowFrame.getCurrentWindowFrame();
if (wf != null && wf.getContent() instanceof TextWindow)
{
TextWindow tw = (TextWindow)wf.getContent();
tw.copy();
return;
}
// get the edit window
EditWindow wnd = EditWindow.needCurrent();
if (wnd == null) return;
Highlighter highlighter = wnd.getHighlighter();
List highlightedGeoms = highlighter.getHighlightedEObjs(true, true);
List highlightedText = highlighter.getHighlightedText(true);
if (highlightedGeoms.size() == 0 && highlightedText.size() == 0)
{
System.out.println("First select objects to copy");
return;
}
// special case: if one text object is selected, copy its text to the system clipboard
copySelectedText(highlightedText);
// create the transformation for "down in place" copying
FixpTransform inPlace = new FixpTransform();
Orientation inPlaceOrient = Orientation.IDENT;
if (wnd.isInPlaceEdit())
{
List nodes = wnd.getInPlaceEditNodePath();
for(NodeInst n : nodes)
{
Orientation o = n.getOrient().inverse();
inPlaceOrient = o.concatenate(inPlaceOrient);
}
FixpTransform justRotation = inPlaceOrient.pureRotate();
Rectangle2D pasteBounds = getPasteBounds(highlightedGeoms, highlightedText, wnd);
FixpTransform untranslate = FixpTransform.getTranslateInstance(-pasteBounds.getCenterX(), -pasteBounds.getCenterY());
FixpTransform retranslate = FixpTransform.getTranslateInstance(pasteBounds.getCenterX(), pasteBounds.getCenterY());
inPlace.preConcatenate(untranslate);
inPlace.preConcatenate(justRotation);
inPlace.preConcatenate(retranslate);
}
// copy to Electric clipboard cell
new CopyObjects(wnd.getCell(), highlightedGeoms, highlightedText, User.getAlignmentToGrid(),
inPlace, inPlaceOrient);
}
/**
* Method to copy the selected objects to the clipboard and then delete them.
*/
public static void cut()
{
// is this the messages window?
MessagesWindow mw = MessagesWindow.getFocusOwner();
if (mw != null)
{
mw.copyText(false, true);
return;
}
// if current window is text window, cut from it
WindowFrame wf = WindowFrame.getCurrentWindowFrame();
if (wf != null && wf.getContent() instanceof TextWindow)
{
TextWindow tw = (TextWindow)wf.getContent();
tw.cut();
return;
}
// get the edit window
EditWindow wnd = EditWindow.needCurrent();
if (wnd == null) return;
Highlighter highlighter = wnd.getHighlighter();
List highlightedGeoms = highlighter.getHighlightedEObjs(true, true);
List highlightedText = highlighter.getHighlightedText(true);
if (highlightedGeoms.size() == 0 && highlightedText.size() == 0)
{
System.out.println("First select objects to cut");
return;
}
highlighter.clear();
highlighter.finished();
// special case: if one text object is selected, copy its text to the system clipboard
copySelectedText(highlightedText);
// create the transformation for "down in place" copying
FixpTransform inPlace = new FixpTransform();
Orientation inPlaceOrient = Orientation.IDENT;
if (wnd.isInPlaceEdit())
{
List nodes = wnd.getInPlaceEditNodePath();
for(NodeInst n : nodes)
{
Orientation o = n.getOrient().inverse();
inPlaceOrient = o.concatenate(inPlaceOrient);
}
FixpTransform justRotation = inPlaceOrient.pureRotate();
Rectangle2D pasteBounds = getPasteBounds(highlightedGeoms, highlightedText, wnd);
FixpTransform untranslate = FixpTransform.getTranslateInstance(-pasteBounds.getCenterX(), -pasteBounds.getCenterY());
FixpTransform retranslate = FixpTransform.getTranslateInstance(pasteBounds.getCenterX(), pasteBounds.getCenterY());
inPlace.preConcatenate(untranslate);
inPlace.preConcatenate(justRotation);
inPlace.preConcatenate(retranslate);
}
// cut from Electric, copy to clipboard cell
new CutObjects(wnd.getCell(), highlightedGeoms, highlightedText, User.getAlignmentToGrid(),
User.isReconstructArcsAndExportsToDeletedCells(), inPlace, inPlaceOrient);
}
/**
* Method to paste the clipboard back into the current cell.
*/
public static void paste()
{
// is this the messages window?
MessagesWindow mw = MessagesWindow.getFocusOwner();
if (mw != null)
{
mw.pasteText();
return;
}
// if current window is text window, paste to it
WindowFrame wf = WindowFrame.getCurrentWindowFrame();
if (wf != null && wf.getContent() instanceof TextWindow)
{
TextWindow tw = (TextWindow)wf.getContent();
tw.paste();
return;
}
// Get text put in the clipboard but using variables.
String extraText = TextUtils.getTextOnClipboard();
// get objects to paste
int nTotal = 0, aTotal = 0, vTotal = 0;
Cell clipCell = getClipCell();
if (clipCell != null)
{
nTotal = clipCell.getNumNodes();
aTotal = clipCell.getNumArcs();
vTotal = clipCell.getNumVariables();
if (clipCell.getVar(User.FRAME_LAST_CHANGED_BY) != null) vTotal--; // discount this variable since it should not be copied.
}
// find out where the paste is going
EditWindow wnd = EditWindow.needCurrent();
if (wnd == null)
{
System.out.println("No place to paste");
return;
}
Highlighter highlighter = wnd.getHighlighter();
Cell parent = wnd.getCell();
int total = nTotal + aTotal + vTotal;
if (total == 0)
{
if (extraText != null)
{
List highlightedText = highlighter.getHighlightedText(true);
new PasteSpecialText(highlightedText, extraText, parent);
}
else
System.out.println("Nothing in the clipboard to paste");
return;
}
// special case of pasting on top of selected objects
List geoms = highlighter.getHighlightedEObjs(true, true);
if (geoms.size() > 0)
{
// can only paste a single object onto selection
if (nTotal == 2 && aTotal == 1)
{
ArcInst ai = clipCell.getArcs().next();
NodeInst niHead = ai.getHeadPortInst().getNodeInst();
NodeInst niTail = ai.getTailPortInst().getNodeInst();
Iterator nIt = clipCell.getNodes();
NodeInst ni1 = nIt.next();
NodeInst ni2 = nIt.next();
if ((ni1 == niHead && ni2 == niTail) ||
(ni1 == niTail && ni2 == niHead)) nTotal = 0;
total = nTotal + aTotal;
}
if (total > 1)
{
System.out.println("Can only paste a single object on top of selected objects");
return;
}
for(Geometric geom : geoms)
{
if (geom instanceof NodeInst && nTotal == 1)
{
NodeInst ni = (NodeInst)geom;
new PasteNodeToNode(ni, clipCell.getNodes().next());
} else if (geom instanceof ArcInst)
{
ArcInst ai = (ArcInst)geom;
if (aTotal == 1)
new PasteArcToArc(ai, clipCell.getArcs().next());
else
new PasteSpecialText(Arrays.asList(new DisplayedText(ai, ArcInst.ARC_NAME)), extraText, parent);
// new ai.setName(extraText);
}
}
return;
}
// make list of things to paste
List geomList = new ArrayList();
for(Iterator it = clipCell.getNodes(); it.hasNext(); )
geomList.add(it.next());
for(Iterator it = clipCell.getArcs(); it.hasNext(); )
geomList.add(it.next());
List textList = new ArrayList();
for (Iterator it = clipCell.getVariables(); it.hasNext(); )
{
Variable var = it.next();
if (!var.isDisplay()) continue;
textList.add(new DisplayedText(clipCell, var.getKey()));
}
if (geomList.size() == 0 && textList.size() == 0) return;
// create the transformation for "down in place" pasting
FixpTransform inPlace = new FixpTransform();
Orientation inPlaceOrient = Orientation.IDENT;
if (wnd.isInPlaceEdit())
{
List nodes = wnd.getInPlaceEditNodePath();
for(NodeInst n : nodes)
{
Orientation o = n.getOrient();
inPlaceOrient = inPlaceOrient.concatenate(o);
}
FixpTransform justRotation = inPlaceOrient.pureRotate();
Rectangle2D pasteBounds = getPasteBounds(geomList, textList, wnd);
FixpTransform untranslate = FixpTransform.getTranslateInstance(-pasteBounds.getCenterX(), -pasteBounds.getCenterY());
FixpTransform retranslate = FixpTransform.getTranslateInstance(pasteBounds.getCenterX(), pasteBounds.getCenterY());
inPlace.preConcatenate(untranslate);
inPlace.preConcatenate(justRotation);
inPlace.preConcatenate(retranslate);
}
boolean convertSchLay = false;
if (aTotal == 0 && User.isConvertSchematicLayoutWhenPasting()) convertSchLay = true;
if (User.isMoveAfterDuplicate())
{
EventListener currentListener = WindowFrame.getListener();
WindowFrame.setListener(new PasteListener(clipCell, wnd, geomList, textList, currentListener,
inPlace, inPlaceOrient, false, convertSchLay));
} else if (User.isDuplicateInPlace()) {
new PasteObjects(clipCell, parent, geomList, textList, 0, 0,
User.getAlignmentToGrid(), User.isDupCopiesExports(), User.isIncrementRightmostIndex(),
User.isArcsAutoIncremented(), convertSchLay, inPlace, inPlaceOrient);
} else
{
new PasteObjects(clipCell, parent, geomList, textList, lastDupX, lastDupY,
User.getAlignmentToGrid(), User.isDupCopiesExports(), User.isIncrementRightmostIndex(),
User.isArcsAutoIncremented(), convertSchLay, inPlace, inPlaceOrient);
}
}
/**
* Method to duplicate the selected objects.
*/
public static void duplicate()
{
// see what is highlighted
EditWindow wnd = EditWindow.needCurrent();
if (wnd == null) return;
Highlighter highlighter = wnd.getHighlighter();
List geomList = highlighter.getHighlightedEObjs(true, true);
List textList = highlighter.getHighlightedText(true);
if (geomList.size() == 0 && textList.size() == 0)
{
System.out.println("First select objects to duplicate");
return;
}
// do duplication
if (User.isMoveAfterDuplicate())
{
EventListener currentListener = WindowFrame.getListener();
WindowFrame.setListener(new PasteListener(wnd.getCell(), wnd, geomList, textList, currentListener, null, null, true, false));
} else if (User.isDuplicateInPlace()) {
lastDupX = 0;
lastDupY = 0;
new DuplicateObjects(wnd.getCell(), geomList, textList, User.getAlignmentToGrid());
} else
{
new DuplicateObjects(wnd.getCell(), geomList, textList, User.getAlignmentToGrid());
}
}
/**
* Helper method to copy any selected text to the system-wide clipboard.
*/
private static void copySelectedText(List highlightedText)
{
// must be one text selected
if (highlightedText.size() != 1) return;
// get the text
DisplayedText dt = highlightedText.get(0);
ElectricObject eObj = dt.getElectricObject();
Variable.Key varKey = dt.getVariableKey();
String selected = null;
if (varKey == ArcInst.ARC_NAME)
{
selected = ((ArcInst)eObj).getName();
}
else if (varKey == NodeInst.NODE_NAME || varKey == NodeInst.NODE_PROTO)
{
selected = ((NodeInst)eObj).getName();
}
else if (varKey == Export.EXPORT_NAME)
{
selected = ((Export)eObj).getName();
}
else
{
Variable var = eObj.getParameterOrVariable(varKey);
if (var == null) return;
selected = var.describe(-1);
}
if (selected == null) return;
// put the text in the clipboard
TextUtils.setTextOnClipboard(selected);
}
/****************************** CHANGE JOBS ******************************/
private static class CopyObjects extends Job
{
private List highlightedGeoms;
private List highlightedText;
private EDimension alignment;
private FixpTransform inPlace;
private Orientation inPlaceOrient;
private boolean isDupCopiesExports = User.isDupCopiesExports();
private boolean isIncrementRightmostIndex = User.isIncrementRightmostIndex();
private boolean isArcsAutoIncremented = User.isArcsAutoIncremented();
private ExpansionState expansionState;
private List nodesToExpand;
protected CopyObjects(Cell cell, List highlightedGeoms, List highlightedText,
EDimension alignment, FixpTransform inPlace, Orientation inPlaceOrient)
{
super("Copy", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.highlightedGeoms = highlightedGeoms;
this.highlightedText = highlightedText;
this.alignment = alignment;
this.inPlace = inPlace;
this.inPlaceOrient = inPlaceOrient;
this.nodesToExpand = new ArrayList();
this.expansionState = new ExpansionState(cell, ExpansionState.JUSTTHISCELL);
startJob();
}
@Override
public boolean doIt() throws JobException
{
// remove contents of clipboard
clear();
// copy objects to clipboard
copyListToCell(getClipCell(), highlightedGeoms, highlightedText, null, null, new Point2D.Double(),
isDupCopiesExports, isIncrementRightmostIndex, isArcsAutoIncremented, false,
alignment, inPlace, inPlaceOrient, expansionState, nodesToExpand, getEditingPreferences());
fieldVariableChanged("nodesToExpand");
return true;
}
@Override
public void terminateOK()
{
for(NodeInst ni : nodesToExpand)
ni.setExpanded(true);
}
}
private static class CutObjects extends Job
{
private Cell cell;
private List geomList;
private List textList;
private EDimension alignment;
private boolean reconstructArcsAndExports;
private FixpTransform inPlace;
private Orientation inPlaceOrient;
private List thingsToHighlight;
private boolean isDupCopiesExports = User.isDupCopiesExports();
private boolean isIncrementRightmostIndex = User.isIncrementRightmostIndex();
private boolean isArcsAutoIncremented = User.isArcsAutoIncremented();
private ExpansionState expansionState;
private List nodesToExpand;
protected CutObjects(Cell cell, List geomList, List textList, EDimension alignment,
boolean reconstructArcsAndExports, FixpTransform inPlace, Orientation inPlaceOrient)
{
super("Cut", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.cell = cell;
this.geomList = geomList;
this.textList = textList;
this.alignment = alignment;
this.reconstructArcsAndExports = reconstructArcsAndExports;
this.inPlace = inPlace;
this.inPlaceOrient = inPlaceOrient;
this.expansionState = new ExpansionState(cell, ExpansionState.JUSTTHISCELL);
this.nodesToExpand = new ArrayList();
startJob();
}
@Override
public boolean doIt() throws JobException
{
EditingPreferences ep = getEditingPreferences();
// remove contents of clipboard
clear();
// make sure deletion is allowed
if (CircuitChangeJobs.cantEdit(cell, null, true, false, true) != 0) return false;
for(Geometric geom : geomList)
{
if (geom instanceof NodeInst)
{
int errorCode = CircuitChangeJobs.cantEdit(cell, (NodeInst)geom, true, false, true);
if (errorCode < 0) return false;
if (errorCode > 0) continue;
}
}
// copy objects to clipboard
copyListToCell(getClipCell(), geomList, textList, null, null, new Point2D.Double(),
isDupCopiesExports, isIncrementRightmostIndex, isArcsAutoIncremented, false,
alignment, inPlace, inPlaceOrient, expansionState, nodesToExpand, ep);
fieldVariableChanged("nodesToExpand");
// and delete the original objects
Set stuffToHighlight = new HashSet();
CircuitChangeJobs.eraseObjectsInList(cell, geomList, reconstructArcsAndExports, stuffToHighlight, ep);
thingsToHighlight = new ArrayList();
for(ElectricObject eObj : stuffToHighlight)
{
if (eObj instanceof ArcInst)
{
ArcInst ai = (ArcInst)eObj;
thingsToHighlight.add(ai);
} else if (eObj instanceof Export)
{
Export e = (Export)eObj;
thingsToHighlight.add(e.getOriginalPort().getNodeInst());
}
}
fieldVariableChanged("thingsToHighlight");
// kill exports and variables on cells
for(DisplayedText dt : textList)
{
// deleting variable on object
Variable.Key key = dt.getVariableKey();
ElectricObject eobj = dt.getElectricObject();
if (key == NodeInst.NODE_NAME)
{
// deleting the name of a node
NodeInst ni = (NodeInst)eobj;
ni.setName(null);
ni.move(0, 0);
} else if (key == ArcInst.ARC_NAME)
{
// deleting the name of an arc
ArcInst ai = (ArcInst)eobj;
ai.setName(null, ep);
ai.modify(0, 0, 0, 0);
} else if (key == Export.EXPORT_NAME)
{
// deleting the name of an export
Export pp = (Export)eobj;
pp.kill();
} else
{
// deleting a variable
if (eobj.isParam(key)) {
if (eobj instanceof Cell)
((Cell)eobj).getCellGroup().delParam((Variable.AttrKey)key);
else if (eobj instanceof NodeInst)
((NodeInst)eobj).delParameter(key);
} else {
eobj.delVar(key);
}
}
}
return true;
}
@Override
public void terminateOK()
{
// expand requested nodes
for(NodeInst ni : nodesToExpand)
ni.setExpanded(true);
// remove highlighting, show only reconstructed objects
UserInterface ui = Job.getUserInterface();
EditWindow_ wnd = ui.getCurrentEditWindow_();
if (wnd != null)
{
wnd.clearHighlighting();
if (thingsToHighlight != null)
{
for(Geometric geom: thingsToHighlight)
wnd.addElectricObject(geom, cell);
}
wnd.finishedHighlighting();
}
}
}
private static class DuplicateObjects extends Job
{
private Cell cell;
private List geomList, newGeomList;
private List textList, newTextList;
private boolean dupCopiesExports, fromRight, autoIncrementArcs;
private EDimension alignment;
private ExpansionState expansionState;
private List nodesToExpand;
protected DuplicateObjects(Cell cell, List geomList, List textList, EDimension alignment)
{
super("Duplicate", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.cell = cell;
this.geomList = geomList;
this.textList = textList;
this.alignment = alignment;
dupCopiesExports = User.isDupCopiesExports();
fromRight = User.isIncrementRightmostIndex();
autoIncrementArcs = User.isArcsAutoIncremented();
this.expansionState = new ExpansionState(cell, ExpansionState.JUSTTHISCELL);
this.nodesToExpand = new ArrayList();
startJob();
}
@Override
public boolean doIt() throws JobException
{
EditingPreferences ep = getEditingPreferences();
// copy objects to clipboard
newGeomList = new ArrayList();
newTextList = new ArrayList();
copyListToCell(cell, geomList, textList, newGeomList, newTextList, new Point2D.Double(lastDupX, lastDupY),
dupCopiesExports, fromRight, autoIncrementArcs, false, alignment, null, null, expansionState, nodesToExpand, ep);
fieldVariableChanged("newGeomList");
fieldVariableChanged("newTextList");
fieldVariableChanged("nodesToExpand");
return true;
}
@Override
public void terminateOK()
{
// highlight the copy
showCopiedObjects(newGeomList, newTextList);
// expand requested nodes
for(NodeInst ni : nodesToExpand)
ni.setExpanded(true);
}
}
private static class PasteArcToArc extends Job
{
private ArcInst src, dst, newArc;
protected PasteArcToArc(ArcInst dst, ArcInst src)
{
super("Paste Arc to Arc", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.src = src;
this.dst = dst;
startJob();
}
@Override
public boolean doIt() throws JobException
{
// make sure pasting is allowed
if (CircuitChangeJobs.cantEdit(dst.getParent(), null, true, false, true) != 0) return false;
newArc = pasteArcToArc(dst, src, getEditingPreferences());
if (newArc == null) System.out.println("Nothing was pasted"); else
fieldVariableChanged("newArc");
return true;
}
@Override
public void terminateOK()
{
if (newArc != null)
{
EditWindow wnd = EditWindow.getCurrent();
if (wnd != null)
{
Highlighter highlighter = wnd.getHighlighter();
if (highlighter != null)
{
highlighter.clear();
highlighter.addElectricObject(newArc, newArc.getParent());
highlighter.finished();
}
}
}
}
}
private static class PasteNodeToNode extends Job
{
private NodeInst src, dst, newNode;
protected PasteNodeToNode(NodeInst dst, NodeInst src)
{
super("Paste Node to Node", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.src = src;
this.dst = dst;
startJob();
}
@Override
public boolean doIt() throws JobException
{
// make sure pasting is allowed
if (CircuitChangeJobs.cantEdit(dst.getParent(), null, true, false, true) != 0) return false;
newNode = pasteNodeToNode(dst, src, getEditingPreferences());
if (newNode == null) System.out.println("Nothing was pasted"); else
fieldVariableChanged("newNode");
return true;
}
@Override
public void terminateOK()
{
if (newNode != null)
{
newNode.setExpanded(src.isExpanded());
EditWindow wnd = EditWindow.getCurrent();
if (wnd != null)
{
Highlighter highlighter = wnd.getHighlighter();
if (highlighter != null)
{
highlighter.clear();
highlighter.addElectricObject(newNode, newNode.getParent());
highlighter.finished();
}
}
}
}
}
private static class PasteObjects extends Job
{
private Cell toCell;
private List geomList, newGeomList;
private List textList, newTextList;
private double dX, dY;
private EDimension alignment;
private boolean copyExports, fromRight, uniqueArcs, convertSchLay;
private FixpTransform inPlace;
private Orientation inPlaceOrient;
private ExpansionState expansionState;
private List nodesToExpand;
protected PasteObjects(Cell fromCell, Cell toCell, List geomList, List textList, double dX, double dY,
EDimension alignment, boolean copyExports, boolean fromRight, boolean uniqueArcs,
boolean convertSchLay, FixpTransform inPlace, Orientation inPlaceOrient)
{
super("Paste", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.toCell = toCell;
this.geomList = geomList;
this.textList = textList;
this.dX = dX;
this.dY = dY;
this.alignment = alignment;
this.copyExports = copyExports;
this.fromRight = fromRight;
this.uniqueArcs = uniqueArcs;
this.convertSchLay = convertSchLay;
this.inPlace = inPlace;
this.inPlaceOrient = inPlaceOrient;
this.expansionState = new ExpansionState(fromCell, ExpansionState.JUSTTHISCELL);
this.nodesToExpand = new ArrayList();
startJob();
}
@Override
public boolean doIt() throws JobException
{
// make sure pasting is allowed
if (CircuitChangeJobs.cantEdit(toCell, null, true, false, true) != 0) return false;
// paste them into the current cell
newGeomList = new ArrayList();
newTextList = new ArrayList();
copyListToCell(toCell, geomList, textList, newGeomList, newTextList, new Point2D.Double(dX, dY),
copyExports, fromRight, uniqueArcs, convertSchLay, alignment, inPlace, inPlaceOrient,
expansionState, nodesToExpand, getEditingPreferences());
fieldVariableChanged("newGeomList");
fieldVariableChanged("newTextList");
fieldVariableChanged("nodesToExpand");
return true;
}
@Override
public void terminateOK()
{
// highlight the copy
showCopiedObjects(newGeomList, newTextList);
// expand requested nodes
for(NodeInst ni : nodesToExpand)
ni.setExpanded(true);
if (nodesToExpand.size() > 0)
EditWindow.repaintAllContents();
}
}
private static class PasteSpecialText extends Job
{
private List textList;
private String newText;
private Cell cell;
protected PasteSpecialText(List tList, String newT, Cell c)
{
super("Paste Text", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.textList = tList;
this.newText = newT;
this.cell = c;
startJob();
}
@Override
public boolean doIt() throws JobException
{
EditingPreferences ep = getEditingPreferences();
// make sure pasting is allowed
if (CircuitChangeJobs.cantEdit(cell, null, true, false, true) != 0) return false;
// paste them into the current cell
for (DisplayedText obj : textList)
{
Variable.Key key = obj.getVariableKey();
ElectricObject eObj = obj.getElectricObject();
if (key == ArcInst.ARC_NAME)
{
((ArcInst)eObj).setName(newText, ep);
}
else if (key == NodeInst.NODE_NAME || key == NodeInst.NODE_PROTO)
{
((NodeInst)eObj).setName(newText);
}
else if (key == Export.EXPORT_NAME)
{
Export ex = (Export)eObj;
ex.rename(newText);
}
}
return true;
}
}
/****************************** CHANGE JOB SUPPORT ******************************/
public static CellId getClipCellId() {
return IdManager.stdIdManager.getCellId(CLIPBOARD_CELL_INDEX);
}
/**
* Method to clear the clipboard.
*/
private static Cell getClipCell()
{
return Job.getUserInterface().getDatabase().getCell(getClipCellId());
}
/**
* Method to clear the contents of the clipboard.
*/
public static void clear()
{
Cell clipCell = getClipCell();
// delete all arcs in the clipboard
List arcsToDelete = new ArrayList();
for(Iterator it = clipCell.getArcs(); it.hasNext(); )
arcsToDelete.add(it.next());
for(ArcInst ai : arcsToDelete)
{
ai.kill();
}
// delete all exports in the clipboard
Set exportsToDelete = new HashSet();
for(Iterator it = clipCell.getExports(); it.hasNext(); )
exportsToDelete.add(it.next());
clipCell.killExports(exportsToDelete);
// delete all nodes in the clipboard
Set nodesToDelete = new HashSet();
for(Iterator it = clipCell.getNodes(); it.hasNext(); )
nodesToDelete.add(it.next());
clipCell.killNodes(nodesToDelete);
// Delete all variables
for(Iterator it = clipCell.getParameters(); it.hasNext(); ) {
Variable var = it.next();
clipCell.getCellGroup().delParam((Variable.AttrKey)var.getKey());
}
for(Iterator it = clipCell.getVariables(); it.hasNext(); )
{
Variable var = it.next();
clipCell.delVar(var.getKey());
}
}
/**
* Method to copy the list of Geometrics to a new Cell.
* @param toCell the destination cell of the Geometrics.
* @param geomList the list of Geometrics to copy.
* @param textList the list of text to copy.
* @param newGeomList the list of Geometrics that were created.
* @param newTextList the list of text objects that were created.
* @param delta an offset for all of the copied Geometrics.
* @param copyExports true to copy exports.
* @param fromRight true to increment the rightmost index of multidimensional arrays.
* @param uniqueArcs true to generate unique arc names.
* @param convertSchLay true to convert between schematic and layout cells as needed by the current cell.
* @param alignment the grid alignment to use (0 for none).
* @param inPlace the transformation to use which accounts for "down in place" editing.
* @param inPlaceOrient the orientation to use which accounts for "down in place" editing.
* @param ep EditingPreferneces
* @return the last NodeInst that was created.
*/
public static NodeInst copyListToCell(Cell toCell, List geomList, List textList,
List newGeomList, List newTextList, Point2D delta,
boolean copyExports, boolean fromRight, boolean uniqueArcs, boolean convertSchLay,
EDimension alignment, FixpTransform inPlace, Orientation inPlaceOrient,
ExpansionState expansionState, List nodesToExpand, EditingPreferences ep)
{
// make a list of all objects to be copied (includes end points of arcs)
List theNodes = new ArrayList();
List theArcs = new ArrayList();
if (copyExports)
{
// copy the geometry list since it might be augmented
List internalGeomList = new ArrayList();
for(Geometric geom : geomList) internalGeomList.add(geom);
geomList = internalGeomList;
for(DisplayedText dt : textList)
{
ElectricObject eObj = dt.getElectricObject();
if (eObj instanceof Export)
{
// add the object exported to the list
Export e = (Export)eObj;
NodeInst ni = e.getOriginalPort().getNodeInst();
if (!geomList.contains(ni))
geomList.add(ni);
}
}
}
for (Geometric geom : geomList)
{
if (geom instanceof NodeInst)
{
if (!theNodes.contains(geom)) theNodes.add((NodeInst)geom);
}
if (geom instanceof ArcInst)
{
ArcInst ai = (ArcInst)geom;
theArcs.add(ai);
NodeInst head = ai.getHeadPortInst().getNodeInst();
NodeInst tail = ai.getTailPortInst().getNodeInst();
if (!theNodes.contains(head)) theNodes.add(head);
if (!theNodes.contains(tail)) theNodes.add(tail);
}
}
if (theNodes.isEmpty() && textList.isEmpty()) return null;
// check for recursion
for(NodeInst ni : theNodes)
{
if (!ni.isCellInstance()) continue;
Cell niCell = (Cell)ni.getProto();
if (Cell.isInstantiationRecursive(niCell, toCell))
{
System.out.println("Cannot: that would be recursive (" +
toCell.describe(false) + " is beneath " + niCell.describe(false) + ")");
return null;
}
}
DBMath.gridAlign(delta, alignment);
double dX = delta.getX();
double dY = delta.getY();
// sort the nodes by name
Collections.sort(theNodes);
// create the new nodes
NodeInst lastCreatedNode = null;
Map newNodes = new HashMap();
List reExports = new ArrayList();
for(NodeInst ni : theNodes)
{
double width = ni.getXSize();
double height = ni.getYSize();
NodeProto makeProto = ni.getProto();
if (makeProto == Generic.tech().cellCenterNode && toCell.alreadyCellCenter()) continue;
// convert cell instances to the proper view if requested
if (ni.isCellInstance() && convertSchLay)
{
Cell otherCell = findAlternate((Cell)makeProto, toCell);
if (otherCell != makeProto)
{
makeProto = otherCell;
width = otherCell.getDefWidth();
height = otherCell.getDefHeight();
}
}
String name = null;
if (ni.isUsernamed())
name = ElectricObject.uniqueObjectName(ni.getName(), toCell, NodeInst.class, false, fromRight);
EPoint point = new EPoint(ni.getAnchorCenterX()+dX, ni.getAnchorCenterY()+dY);
Orientation orient = ni.getOrient();
if (inPlace != null)
{
Point2D dst = new Point2D.Double(0, 0);
inPlace.transform(new Point2D.Double(ni.getAnchorCenterX(), ni.getAnchorCenterY()), dst);
point = new EPoint(dst.getX()+dX, dst.getY()+dY);
orient = orient.concatenate(inPlaceOrient);
}
NodeInst newNi = NodeInst.newInstance(makeProto, ep, point, width, height,
toCell, orient, name, ni.getTechSpecific());
if (newNi == null)
{
System.out.println("Cannot create node");
return lastCreatedNode;
}
if (expansionState.isExpanded(ni))
nodesToExpand.add(newNi);
newNi.copyStateBits(ni);
newNi.copyTextDescriptorFrom(ni, NodeInst.NODE_PROTO);
newNi.copyTextDescriptorFrom(ni, NodeInst.NODE_NAME);
newNi.copyVarsFrom(ni);
newNodes.put(ni, newNi);
if (newGeomList != null) newGeomList.add(newNi);
lastCreatedNode = newNi;
// copy the ports, too
if (copyExports)
{
for(Iterator eit = ni.getExports(); eit.hasNext(); )
{
Export e = eit.next();
if (makeProto != ni.getProto())
e = e.findEquivalent((Cell)makeProto);
if (e != null) reExports.add(e);
}
}
}
if (copyExports)
{
// sort list of original Exports and make list of PortInsts on new nodes
Map originalExports = new HashMap();
Collections.sort(reExports, new ExportChanges.ExportSortedByBusIndex());
List reExpThese = new ArrayList();
for(Export e : reExports)
{
PortInst pi = e.getOriginalPort();
NodeInst newNi = newNodes.get(pi.getNodeInst());
PortInst newPi = newNi.findPortInstFromProto(pi.getPortProto());
reExpThese.add(newPi);
originalExports.put(newPi, e);
}
ExportChanges.reExportPorts(toCell, reExpThese, false, true, true, false, fromRight, originalExports, ep);
}
Map newArcs = new HashMap();
if (theArcs.size() > 0)
{
// sort the arcs by name
Collections.sort(theArcs);
// for associating old names with new names
Map newArcNames = new HashMap();
FixpTransform fixOffset = null;
if (inPlaceOrient != null) fixOffset = inPlaceOrient.pureRotate();
// create the new arcs
for(ArcInst ai : theArcs)
{
PortInst oldHeadPi = ai.getHeadPortInst();
NodeInst headNi = newNodes.get(oldHeadPi.getNodeInst());
PortInst headPi = headNi.findPortInstFromProto(oldHeadPi.getPortProto());
EPoint headP = oldHeadPi.getCenter();
double headDX = ai.getHeadLocation().getX() - headP.getX();
double headDY = ai.getHeadLocation().getY() - headP.getY();
PortInst oldTailPi = ai.getTailPortInst();
NodeInst tailNi = newNodes.get(oldTailPi.getNodeInst());
PortInst tailPi = tailNi.findPortInstFromProto(oldTailPi.getPortProto());
EPoint tailP = oldTailPi.getCenter();
double tailDX = ai.getTailLocation().getX() - tailP.getX();
double tailDY = ai.getTailLocation().getY() - tailP.getY();
// adjust offset if down-in-place
if (fixOffset != null)
{
Point2D result = new Point2D.Double(0, 0);
fixOffset.transform(new Point2D.Double(headDX, headDY), result);
headDX = result.getX();
headDY = result.getY();
fixOffset.transform(new Point2D.Double(tailDX, tailDY), result);
tailDX = result.getX();
tailDY = result.getY();
}
String name = null;
if (ai.isUsernamed())
{
name = ai.getName();
if (uniqueArcs)
{
String newName = newArcNames.get(name);
if (newName == null)
{
newName = ElectricObject.uniqueObjectName(name, toCell, ArcInst.class, false, fromRight);
newArcNames.put(name, newName);
}
name = newName;
}
}
headP = new EPoint(headPi.getCenter().getX() + headDX, headPi.getCenter().getY() + headDY);
tailP = new EPoint(tailPi.getCenter().getX() + tailDX, tailPi.getCenter().getY() + tailDY);
ArcInst newAr = ArcInst.newInstanceBase(ai.getProto(), ep, ai.getLambdaBaseWidth(),
headPi, tailPi, headP, tailP, name, ai.getAngle());
if (newAr == null)
{
System.out.println("Cannot create arc");
return lastCreatedNode;
}
newAr.copyPropertiesFrom(ai);
newArcs.put(ai, newAr);
if (newGeomList != null) newGeomList.add(newAr);
}
}
// copy variables on cells
for(DisplayedText dt : textList)
{
ElectricObject eObj = dt.getElectricObject();
if (!(eObj instanceof Cell)) continue;
Variable.Key varKey = dt.getVariableKey();
Variable var = eObj.getParameterOrVariable(varKey);
double xP = var.getTextDescriptor().getXOff();
double yP = var.getTextDescriptor().getYOff();
Variable newVar = Variable.newInstance(varKey, var.getObject(), var.getTextDescriptor().withOff(xP+dX, yP+dY));
if (var.getTextDescriptor().isParam())
toCell.getCellGroup().addParam(newVar);
else
toCell.addVar(newVar);
if (newTextList != null) newTextList.add(new DisplayedText(toCell, varKey));
}
return lastCreatedNode;
}
private static Cell findAlternate(Cell cell, Cell destination)
{
View desiredView = destination.getView();
if (desiredView == View.SCHEMATIC) desiredView = View.ICON;
if (cell.getView() != desiredView)
{
for(Iterator it = cell.getCellGroup().getCells(); it.hasNext(); )
{
Cell otherCell = it.next();
if (otherCell.getView() == desiredView) return otherCell;
}
}
return cell;
}
private static void showCopiedObjects(List newGeomList, List newTextList)
{
EditWindow wnd = EditWindow.needCurrent();
if (wnd != null)
{
Cell cell = wnd.getCell();
Highlighter highlighter = wnd.getHighlighter();
highlighter.clear();
for(Geometric geom : newGeomList)
{
if (geom instanceof NodeInst)
{
NodeInst ni = (NodeInst)geom;
// special case for displayable text on invisible pins
if (ni.isInvisiblePinWithText())
{
for(Iterator vIt = ni.getVariables(); vIt.hasNext(); )
{
Variable var = vIt.next();
if (!var.isDisplay()) continue;
highlighter.addText(ni, cell, var.getKey());
}
continue;
}
}
highlighter.addElectricObject(geom, cell);
}
for(DisplayedText dt : newTextList)
{
highlighter.addText(dt.getElectricObject(), cell, dt.getVariableKey());
}
highlighter.finished();
}
}
/**
* Method to "paste" node onto another node, making them the same.
* @param destNode the destination node (which will be deleted and replaced).
* @param srcNode the source node.
* @param ep EditingPreferences
* Returns the address of the new destination node (null on error).
*/
private static NodeInst pasteNodeToNode(NodeInst destNode, NodeInst srcNode, EditingPreferences ep)
{
destNode = CircuitChangeJobs.replaceNodeInst(destNode, srcNode.getProto(), true, false, ep);
if (destNode == null) return null;
// destNode.setExpanded(srcNode.isExpanded());
if (!destNode.isCellInstance() && !srcNode.isCellInstance()) {
if (srcNode.getProto().getTechnology() == destNode.getProto().getTechnology()) {
Technology tech = srcNode.getProto().getTechnology();
destNode.setPrimitiveFunction(srcNode.getFunction());
}
}
// make the sizes the same if they are primitives
if (!destNode.isCellInstance())
{
double dX = srcNode.getXSize() - destNode.getXSize();
double dY = srcNode.getYSize() - destNode.getYSize();
if (dX != 0 || dY != 0)
{
destNode.resize(dX, dY);
}
}
// remove parameters that are not on the pasted object
for(Iterator it = destNode.getDefinedParameters(); it.hasNext(); )
{
Variable destParam = it.next();
Variable.Key key = destParam.getKey();
if (!srcNode.isDefinedParameter(key))
destNode.delParameter(key);
}
// remove variables that are not on the pasted object
boolean checkAgain = true;
while (checkAgain)
{
checkAgain = false;
for(Iterator it = destNode.getVariables(); it.hasNext(); )
{
Variable destVar = it.next();
Variable.Key key = destVar.getKey();
Variable srcVar = srcNode.getVar(key);
if (srcVar != null) continue;
destNode.delVar(key);
checkAgain = true;
break;
}
}
// make sure all variables are on the node
destNode.copyVarsFrom(srcNode);
// copy any special user bits
destNode.copyStateBits(srcNode);
destNode.setExpanded(false);
destNode.clearLocked();
return(destNode);
}
/**
* Method to paste one arc onto another.
* @param destArc the destination arc that will be replaced.
* @param srcArc the source arc that will replace it.
* @param ep EditingPreferences
* @return the replaced arc (null on error).
*/
private static ArcInst pasteArcToArc(ArcInst destArc, ArcInst srcArc, EditingPreferences ep)
{
// make sure they have the same type
if (destArc.getProto() != srcArc.getProto())
{
destArc = destArc.replace(srcArc.getProto(), ep);
if (destArc == null) return null;
}
// make the widths the same
destArc.setLambdaBaseWidth(srcArc.getLambdaBaseWidth());
// remove variables that are not on the pasted object
boolean checkAgain = true;
while (checkAgain)
{
checkAgain = false;
for(Iterator it = destArc.getVariables(); it.hasNext(); )
{
Variable destVar = it.next();
Variable.Key key = destVar.getKey();
Variable srcVar = srcArc.getVar(key);
if (srcVar != null) continue;
destArc.delVar(key);
checkAgain = true;
break;
}
}
// make sure all variables are on the arc
for(Iterator it = srcArc.getVariables(); it.hasNext(); )
{
Variable srcVar = it.next();
Variable.Key key = srcVar.getKey();
destArc.newVar(key, srcVar.getObject(), srcVar.getTextDescriptor());
}
// make sure the constraints and other userbits are the same
destArc.copyPropertiesFrom(srcArc);
return destArc;
}
/**
* Gets a boundary representing the paste bounds of the list of objects.
* The corners and center point of the bounds can be used as anchors
* when pasting the objects interactively. This is all done in database units.
* Note: you will likely want to grid align any points before using them.
* @param pasteList a list of Geometrics to paste
* @return a Rectangle2D that is the paste bounds.
*/
private static Rectangle2D getPasteBounds(List geomList, List textList, EditWindow wnd) {
Point2D llcorner = null;
Point2D urcorner = null;
// figure out lower-left corner and upper-right corner of this collection of objects
for(DisplayedText dt : textList)
{
Poly poly = dt.getElectricObject().computeTextPoly(wnd, dt.getVariableKey());
Rectangle2D bounds = poly.getBounds2D();
if (llcorner == null) {
llcorner = new Point2D.Double(bounds.getMinX(), bounds.getMinY());
urcorner = new Point2D.Double(bounds.getMaxX(), bounds.getMaxY());
continue;
}
if (bounds.getMinX() < llcorner.getX()) llcorner.setLocation(bounds.getMinX(), llcorner.getY());
if (bounds.getMinY() < llcorner.getY()) llcorner.setLocation(llcorner.getX(), bounds.getMinY());
if (bounds.getMaxX() > urcorner.getX()) urcorner.setLocation(bounds.getMaxX(), urcorner.getY());
if (bounds.getMaxY() > urcorner.getY()) urcorner.setLocation(urcorner.getX(), bounds.getMaxY());
}
for(Geometric geom : geomList)
{
if (geom instanceof NodeInst)
{
NodeInst ni = (NodeInst)geom;
Point2D pt = ni.getAnchorCenter();
if (llcorner == null) {
llcorner = new Point2D.Double(pt.getX(), pt.getY());
urcorner = new Point2D.Double(pt.getX(), pt.getY());
continue;
}
if (pt.getX() < llcorner.getX()) llcorner.setLocation(pt.getX(), llcorner.getY());
if (pt.getY() < llcorner.getY()) llcorner.setLocation(llcorner.getX(), pt.getY());
if (pt.getX() > urcorner.getX()) urcorner.setLocation(pt.getX(), urcorner.getY());
if (pt.getY() > urcorner.getY()) urcorner.setLocation(urcorner.getX(), pt.getY());
} else
{
ArcInst ai = (ArcInst)geom;
Poly poly = ai.makeLambdaPoly(ai.getGridBaseWidth(), Poly.Type.FILLED);
Rectangle2D bounds = poly.getBounds2D();
if (llcorner == null) {
llcorner = new Point2D.Double(bounds.getMinX(), bounds.getMinY());
urcorner = new Point2D.Double(bounds.getMaxX(), bounds.getMaxY());
continue;
}
if (bounds.getMinX() < llcorner.getX()) llcorner.setLocation(bounds.getMinX(), llcorner.getY());
if (bounds.getMinY() < llcorner.getY()) llcorner.setLocation(llcorner.getX(), bounds.getMinY());
if (bounds.getMaxX() > urcorner.getX()) urcorner.setLocation(bounds.getMaxX(), urcorner.getY());
if (bounds.getMaxY() > urcorner.getY()) urcorner.setLocation(urcorner.getX(), bounds.getMaxY());
}
}
// figure bounds
double width = urcorner.getX() - llcorner.getX();
double height = urcorner.getY() - llcorner.getY();
Rectangle2D bounds = new Rectangle2D.Double(llcorner.getX(), llcorner.getY(), width, height);
return bounds;
}
/****************************** PASTE LISTENER ******************************/
/**
* Class to handle the interactive drag after a paste.
*/
private static class PasteListener
implements MouseMotionListener, MouseListener, MouseWheelListener, KeyListener
{
private Cell fromCell;
private EditWindow wnd;
private List geomList;
private List textList;
private EventListener currentListener;
private Rectangle2D pasteBounds;
private double translateX;
private double translateY;
private Point2D lastMouseDB; // last point where mouse was (in database units)
private JPopupMenu popup;
private FixpTransform inPlace;
private Orientation inPlaceOrient;
private boolean convertSchLay;
/**
* Create a new paste listener
* @param wnd Controlling window
* @param pasteList list of objects to paste
* @param currentListener listener to restore when done
*/
private PasteListener(Cell fromCell, EditWindow wnd, List geomList, List textList,
EventListener currentListener, FixpTransform inPlace, Orientation inPlaceOrient, boolean dup, boolean convertSchLay)
{
this.fromCell = fromCell;
this.wnd = wnd;
this.geomList = geomList;
this.textList = textList;
this.currentListener = currentListener;
this.inPlace = inPlace;
this.inPlaceOrient = inPlaceOrient;
this.pasteBounds = getPasteBounds(geomList, textList, wnd);
this.convertSchLay = convertSchLay;
translateX = translateY = 0;
initPopup();
// get starting point from current mouse location
Point2D mouse = ClickZoomWireListener.theOne.getLastMouse();
Point2D mouseDB = wnd.screenToDatabase((int)mouse.getX(), (int)mouse.getY());
if (dup)
{
pasteBounds.setRect(pasteBounds.getMinX()+mouseDB.getX()-pasteBounds.getCenterX(),
pasteBounds.getMinY()+mouseDB.getY()-pasteBounds.getCenterY(),
pasteBounds.getWidth(), pasteBounds.getHeight());
}
Point2D delta = getDelta(mouseDB, false);
wnd.getHighlighter().pushHighlight();
showList(delta);
}
/**
* Gets grid-aligned delta translation for nodes based on mouse location
* @param mouseDB the location of the mouse
* @param orthogonal if the translation is orthogonal only
* @return a grid-aligned delta
*/
private Point2D getDelta(Point2D mouseDB, boolean orthogonal)
{
// mouseDB == null if you press arrow keys before placing the new copy
if (mouseDB == null) return null;
EDimension alignment = User.getAlignmentToGrid();
DBMath.gridAlign(mouseDB, alignment);
// this is the point on the clipboard cell that will be pasted at the mouse location
Point2D refPastePoint = new Point2D.Double(pasteBounds.getCenterX() + translateX,
pasteBounds.getCenterY() + translateY);
double deltaX = mouseDB.getX() - refPastePoint.getX();
double deltaY = mouseDB.getY() - refPastePoint.getY();
// if orthogonal is true, convert to orthogonal
if (orthogonal)
{
// Attempt to fix bug #1748
// double distanceX = deltaX;
// double distanceY = deltaY;
//
// // deciding direction for the move
// if (lastMouseDB != null)
// {
// distanceX = mouseDB.getX() - lastMouseDB.getX();
// distanceY = mouseDB.getY() - lastMouseDB.getY();
// }
// If the mouse is within the X and Y extent of the object use X and Y only
// If the mouse is not confined to either extent then use the 45 degree rule
// Arguably we can change it to x degree rule where x is defined by the ratio of the widths
if (mouseDB.getX() > pasteBounds.getMinX() && mouseDB.getX() < pasteBounds.getMaxX()) {
deltaX = 0;
} else if (mouseDB.getY() > pasteBounds.getMinY() && mouseDB.getY() < pasteBounds.getMaxY()) {
deltaY = 0;
} else {
// only use delta in direction that has larger delta
if (Math.abs(deltaX) > Math.abs(deltaY))
deltaY = 0;
else
deltaX = 0;
}
}
// this is now a delta, not a point
refPastePoint.setLocation(deltaX, deltaY);
DBMath.gridAlign(refPastePoint, alignment);
return refPastePoint;
}
/**
* Show the objects to paste with the anchor point at 'mouseDB'
* @param delta the translation for the highlights
*/
private void showList(Point2D delta)
{
// if delta==null, problems to get mouseDB pointer
if (delta == null) return;
// find offset of highlights
double oX = delta.getX();
double oY = delta.getY();
Cell cell = wnd.getCell();
EditingPreferences ep = wnd.getEditingPreferences();
Highlighter highlighter = wnd.getHighlighter();
highlighter.clear();
for(Geometric geom : geomList)
{
if (geom instanceof ArcInst)
{
ArcInst ai = (ArcInst)geom;
Poly poly = ai.makeLambdaPoly(ai.getGridBaseWidth(), Poly.Type.CLOSED);
if (inPlace != null) poly.transform(inPlace);
Point2D [] points = poly.getPoints();
showPoints(points, oX, oY, cell, highlighter);
continue;
}
NodeInst ni = (NodeInst)geom;
if (ni.isInvisiblePinWithText())
{
// find text on the invisible pin
boolean found = false;
for(Iterator vIt = ni.getVariables(); vIt.hasNext(); )
{
Variable var = vIt.next();
if (var.isDisplay())
{
Point2D [] points = Highlighter.describeHighlightText(wnd, geom, var.getKey());
if (inPlace != null) inPlace.transform(points, 0, points, 0, points.length);
showPoints(points, oX, oY, cell, highlighter);
found = true;
break;
}
}
if (found) continue;
}
// convert cell instances to the proper view if requested
if (ni.isCellInstance() && convertSchLay)
{
Cell otherCell = findAlternate((Cell)ni.getProto(), cell);
if (otherCell != ni.getProto())
{
ni = NodeInst.makeDummyInstance(otherCell, ep, ni.getAnchorCenter(),
otherCell.getDefWidth(), otherCell.getDefHeight(), ni.getOrient());
}
}
Poly poly = ni.getBaseShape();
if (inPlace != null) poly.transform(inPlace);
showPoints(poly.getPoints(), oX, oY, cell, highlighter);
}
// show delta from original
Rectangle2D bounds = wnd.getDisplayedBounds();
highlighter.addMessage(cell, "("+(int)oX+","+(int)oY+")",
new Point2D.Double(bounds.getCenterX(),bounds.getCenterY()));
// also draw arrow if user has moved highlights off the screen
double halfWidth = 0.5*pasteBounds.getWidth();
double halfHeight = 0.5*pasteBounds.getHeight();
if (Math.abs(translateX) > halfWidth || Math.abs(translateY) > halfHeight)
{
Rectangle2D transBounds = new Rectangle2D.Double(pasteBounds.getX()+oX, pasteBounds.getY()+oY,
pasteBounds.getWidth(), pasteBounds.getHeight());
Poly p = new Poly(transBounds);
if (inPlace != null) p.transform(inPlace);
Point2D endPoint = p.closestPoint(lastMouseDB);
// draw arrow
highlighter.addLine(lastMouseDB, endPoint, cell);
int angle = GenMath.figureAngle(lastMouseDB, endPoint);
angle += 1800;
int angleOfArrow = 300; // 30 degrees
int backAngle1 = angle - angleOfArrow;
int backAngle2 = angle + angleOfArrow;
Point2D p1 = new Point2D.Double(endPoint.getX() + DBMath.cos(backAngle1), endPoint.getY() + DBMath.sin(backAngle1));
Point2D p2 = new Point2D.Double(endPoint.getX() + DBMath.cos(backAngle2), endPoint.getY() + DBMath.sin(backAngle2));
highlighter.addLine(endPoint, p1, cell);
highlighter.addLine(endPoint, p2, cell);
}
highlighter.finished();
}
private void showPoints(Point2D [] points, double oX, double oY, Cell cell, Highlighter highlighter)
{
for(int i=0; i |