package net.sourceforge.fidocadj.circuit;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import net.sourceforge.fidocadj.dialogs.*;
import net.sourceforge.fidocadj.globals.*;
import net.sourceforge.fidocadj.primitives.*;
import net.sourceforge.fidocadj.circuit.controllers.*;
import net.sourceforge.fidocadj.clipboard.*;
/** Pop up menu for the main editing panel.
<pre>
cp file is part of FidoCadJ.
FidoCadJ 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.
FidoCadJ 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 FidoCadJ. If not,
@see <a href=http://www.gnu.org/licenses/>http://www.gnu.org/licenses/</a>.
Copyright 2007-2015 by Davide Bucci
</pre>
@author Davide Bucci
*/
public class PopUpMenu implements ActionListener
{
// Elements to be included in the popup menu.
private JMenuItem editProperties;
private JMenuItem editCut;
private JMenuItem editCopy;
private JMenuItem editPaste;
private JMenuItem editDuplicate;
private JMenuItem editSelectAll;
private JMenuItem editRotate;
private JMenuItem editMirror;
private JMenuItem editSymbolize; // phylum
private JMenuItem editUSymbolize; // phylum
private JMenuItem editAddNode;
private JMenuItem editRemoveNode;
private final CircuitPanel cp;
private final SelectionActions sa;
private final EditorActions edt;
private final ContinuosMoveActions eea;
private final UndoActions ua;
private final ParserActions pa;
private final CopyPasteActions cpa;
private final JPopupMenu pp;
// We need to save the position where the popup menu appears.
private int menux;
private int menuy;
/** Constructor. Create a PopUpMenu and associates it to the provided
handler.
@param p the CircuitPanel.
*/
public PopUpMenu(CircuitPanel p)
{
cp=p;
sa=cp.getSelectionActions();
edt=cp.getEditorActions();
eea=cp.getContinuosMoveActions();
ua=cp.getUndoActions();
pa=cp.getParserActions();
cpa=cp.getCopyPasteActions();
pp = new JPopupMenu();
definePopupMenu();
}
/** Get the x coordinate of the place where the user clicked for the
popup menu.
@return the x coordinate.
*/
public int getMenuX()
{
return menux;
}
/** Get the y coordinate of the place where the user clicked for the
popup menu.
@return the y coordinate.
*/
public int getMenuY()
{
return menuy;
}
/** Create the popup menu.
*/
private void definePopupMenu()
{
editProperties = new
JMenuItem(Globals.messages.getString("Param_opt"));
editCut = new JMenuItem(Globals.messages.getString("Cut"));
editCopy = new JMenuItem(Globals.messages.getString("Copy"));
editSelectAll = new JMenuItem(Globals.messages.getString("SelectAll"));
editPaste = new JMenuItem(Globals.messages.getString("Paste"));
editDuplicate = new JMenuItem(Globals.messages.getString("Duplicate"));
editRotate = new JMenuItem(Globals.messages.getString("Rotate"));
editMirror = new JMenuItem(Globals.messages.getString("Mirror_E"));
editSymbolize = new JMenuItem(Globals.messages.getString("Symbolize"));
editUSymbolize =
new JMenuItem(Globals.messages.getString("Unsymbolize"));
editAddNode = new JMenuItem(Globals.messages.getString("Add_node"));
editRemoveNode =
new JMenuItem(Globals.messages.getString("Remove_node"));
pp.add(editProperties);
pp.addSeparator();
pp.add(editCut);
pp.add(editCopy);
pp.add(editPaste);
pp.add(editDuplicate);
pp.addSeparator();
pp.add(editSelectAll);
pp.addSeparator();
pp.add(editRotate);
pp.add(editMirror);
pp.add(editAddNode);
pp.add(editRemoveNode);
pp.addSeparator();
pp.add(editSymbolize); // by phylum
pp.add(editUSymbolize); // phylum
// Adding the action listener
editProperties.addActionListener(this);
editCut.addActionListener(this);
editCopy.addActionListener(this);
editSelectAll.addActionListener(this);
editPaste.addActionListener(this);
editDuplicate.addActionListener(this);
editRotate.addActionListener(this);
editMirror.addActionListener(this);
editAddNode.addActionListener(this);
editRemoveNode.addActionListener(this);
editSymbolize.addActionListener(this); // phylum
editUSymbolize.addActionListener(this); // phylum
}
/** Show a popup menu representing the actions that can be done on the
selected context.
@param j the panel to which this menu should be associated.
@param x the x coordinate where the popup menu should be put.
@param y the y coordinate where the popup menu should be put.
*/
public void showPopUpMenu(JPanel j, int x, int y)
{
menux=x; menuy=y;
boolean s=false;
GraphicPrimitive g=sa.getFirstSelectedPrimitive();
boolean somethingSelected=g!=null;
// A certain number of menu options are applied to selected
// primitives. We therefore check wether are there some
// of them available and in cp case we activate what should
// be activated in the pop up menu.
s=somethingSelected;
editProperties.setEnabled(s);
editCut.setEnabled(s);
editCopy.setEnabled(s);
editRotate.setEnabled(s);
editMirror.setEnabled(s);
editDuplicate.setEnabled(s);
editSelectAll.setEnabled(true);
if(g instanceof PrimitiveComplexCurve ||
g instanceof PrimitivePolygon)
{
s=true;
} else
s=false;
if (!sa.isUniquePrimitiveSelected())
s=false;
editAddNode.setEnabled(s);
editRemoveNode.setEnabled(s);
editAddNode.setVisible(s);
editRemoveNode.setVisible(s);
// We just check if the clipboard is empty. It would be better
// to see if there is some FidoCadJ code wich might be pasted
TextTransfer textTransfer = new TextTransfer();
if(textTransfer.getClipboardContents().equals(""))
editPaste.setEnabled(false);
else
editPaste.setEnabled(true);
editSymbolize.setEnabled(somethingSelected);
editUSymbolize.setEnabled(sa.selectionCanBeSplitted()); // phylum
pp.show(j, x, y);
}
/** Register an action involving the editing
@param actionString the action name to be associated to this action
@param key the key to be used. It will be associated either in
lower case as well as in upper case.
@param state the wanted state to be used (see definitions INTERFACE).
*/
private void registerAction(String actionString, char key, final int state)
{
// We need to make this indipendent to the case. So we start by
// registering the action for the upper case
cp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke(Character.toUpperCase(key)),
actionString);
// And then we repeat the operation for the lower case
cp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke(Character.toLowerCase(key)),
actionString);
cp.getActionMap().put(actionString, new AbstractAction() {
public void actionPerformed(ActionEvent ignored)
{
// We now set the new editing state
cp.setSelectionState(state,"");
// If we are entering or modifying a primitive or a macro,
// we should be sure it disappears when the state changes
eea.primEdit = null;
cp.repaint();
}
});
}
/** Register a certain number of keyboard actions with an associated
meaning:
<pre>
[A] or [space] Selection
[L] Line
[T] Text
[B] Bézier
[P] Polygon
[O] Complex curve
[E] Ellipse
[G] Rectangle
[C] Connection
[I] PCB track
[Z] PCB pad
[ESC] Exit from current editing action
[DEL] or [BACKSPC] Delete the selected objects
</pre>
*/
public final void registerActiveKeys()
{
registerAction("selection", 'a', ElementsEdtActions.SELECTION);
cp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0,false),
"selection");
registerAction("line", 'l', ElementsEdtActions.LINE);
registerAction("text", 't', ElementsEdtActions.TEXT);
registerAction("bezier", 'b', ElementsEdtActions.BEZIER);
registerAction("polygon", 'p', ElementsEdtActions.POLYGON);
registerAction("complexcurve", 'o', ElementsEdtActions.COMPLEXCURVE);
registerAction("ellipse", 'e', ElementsEdtActions.ELLIPSE);
registerAction("rectangle", 'g', ElementsEdtActions.RECTANGLE);
registerAction("connection", 'c', ElementsEdtActions.CONNECTION);
registerAction("pcbline", 'i', ElementsEdtActions.PCB_LINE);
registerAction("pcbpad", 'z', ElementsEdtActions.PCB_PAD);
final String delete = "delete";
// Delete key
cp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke("DELETE"), delete);
cp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke("BACK_SPACE"), delete);
cp.getActionMap().put(delete, new AbstractAction() {
public void actionPerformed(ActionEvent ignored)
{
edt.deleteAllSelected(true);
cp.repaint();
}
});
final String escape = "escape";
// Escape: clear everything
cp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke("ESCAPE"), escape);
cp.getActionMap().put(escape, new AbstractAction() {
public void actionPerformed(ActionEvent ignored)
{
if(eea.clickNumber>0){
// Here we need to clear the variables which are used
// during the primitive introduction and editing.
// see mouseMoved method for details.
eea.successiveMove = false;
eea.clickNumber = 0;
eea.primEdit = null;
cp.repaint();
}
}
});
final String left = "lleft";
// left key
cp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,
java.awt.event.InputEvent.ALT_MASK,false), left);
cp.getActionMap().put(left, new AbstractAction() {
public void actionPerformed(ActionEvent ignored)
{
edt.moveAllSelected(-1,0);
cp.repaint();
}
});
final String right = "lright";
// right key
cp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,
java.awt.event.InputEvent.ALT_MASK,false), right);
cp.getActionMap().put(right, new AbstractAction() {
public void actionPerformed(ActionEvent ignored)
{
edt.moveAllSelected(1,0);
cp.repaint();
}
});
final String up = "lup";
// up key
cp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP,
java.awt.event.InputEvent.ALT_MASK,false), up);
cp.getActionMap().put(up, new AbstractAction() {
public void actionPerformed(ActionEvent ignored)
{
edt.moveAllSelected(0,-1);
cp.repaint();
}
});
final String down = "ldown";
// down key
cp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,
java.awt.event.InputEvent.ALT_MASK,false), down);
cp.getActionMap().put(down, new AbstractAction() {
public void actionPerformed(ActionEvent ignored)
{
edt.moveAllSelected(0,1);
cp.repaint();
}
});
}
/** The action listener. Recognize menu events and behaves consequently.
@param evt the MouseEvent to handle
*/
public void actionPerformed(ActionEvent evt)
{
// TODO: Avoid some copy/paste of code
// Recognize and handle popup menu events
if(evt.getSource() instanceof JMenuItem) {
String arg=evt.getActionCommand();
if (arg.equals(Globals.messages.getString("Param_opt"))) {
cp.setPropertiesForPrimitive();
} else if (arg.equals(Globals.messages.getString("Copy"))) {
// Copy all selected elements in the clipboard
cpa.copySelected(!cp.getStrictCompatibility(), false);
} else if (arg.equals(Globals.messages.getString("Cut"))) {
// Cut elements
cpa.copySelected(!cp.getStrictCompatibility(), false);
edt.deleteAllSelected(true);
cp.repaint();
} else if (arg.equals(Globals.messages.getString("Paste"))) {
// Paste elements from the clipboard
cpa.paste(cp.getMapCoordinates().getXGridStep(),
cp.getMapCoordinates().getYGridStep());
cp.repaint();
} else if (arg.equals(Globals.messages.getString("Duplicate"))) {
// Copy all selected elements in the clipboard
cpa.copySelected(!cp.getStrictCompatibility(), false);
// Paste elements from the clipboard
cpa.paste(cp.getMapCoordinates().getXGridStep(),
cp.getMapCoordinates().getYGridStep());
cp.repaint();
} else if (arg.equals(Globals.messages.getString("SelectAll"))) {
// Select all in the drawing.
sa.setSelectionAll(true);
// Even if the drawing is not changed, a repaint operation is
// needed since all selected elements are rendered in green.
cp.repaint();
}else if (arg.equals(Globals.messages.getString("Rotate"))) {
// Rotate the selected element
if(eea.isEnteringMacro())
eea.rotateMacro();
else
edt.rotateAllSelected();
cp.repaint();
} else if(arg.equals(Globals.messages.getString("Mirror_E"))) {
// Mirror the selected element
if(eea.isEnteringMacro())
eea.mirrorMacro();
else
edt.mirrorAllSelected();
cp.repaint();
} else if (arg.equals(Globals.messages.getString("Symbolize"))) {
if (sa.getFirstSelectedPrimitive() == null) return;
DialogSymbolize s = new DialogSymbolize(cp,
cp.getDrawingModel());
s.setModal(true);
s.setVisible(true);
try {
LibUtils.saveLibraryState(ua);
} catch (IOException e) {
System.out.println("Exception: "+e);
}
cp.repaint();
} else if (arg.equals(Globals.messages.getString("Unsymbolize"))) {
StringBuffer s=sa.getSelectedString(true, pa);
edt.deleteAllSelected(false);
pa.addString(pa.splitMacros(s, true),true);
ua.saveUndoState();
cp.repaint();
} else if(arg.equals(Globals.messages.getString("Remove_node"))) {
if(sa.getFirstSelectedPrimitive()
instanceof PrimitivePolygon)
{
PrimitivePolygon poly=
(PrimitivePolygon)sa.getFirstSelectedPrimitive();
poly.removePoint(
cp.getMapCoordinates().unmapXnosnap(getMenuX()),
cp.getMapCoordinates().unmapYnosnap(getMenuY()),
1);
ua.saveUndoState();
cp.repaint();
} else if(sa.getFirstSelectedPrimitive()
instanceof PrimitiveComplexCurve)
{
PrimitiveComplexCurve curve=
(PrimitiveComplexCurve)sa.getFirstSelectedPrimitive();
curve.removePoint(
cp.getMapCoordinates().unmapXnosnap(getMenuX()),
cp.getMapCoordinates().unmapYnosnap(getMenuY()),
1);
ua.saveUndoState();
cp.repaint();
}
} else if(arg.equals(Globals.messages.getString("Add_node"))) {
if(sa.getFirstSelectedPrimitive()
instanceof PrimitivePolygon)
{
PrimitivePolygon poly=
(PrimitivePolygon)sa.getFirstSelectedPrimitive();
poly.addPointClosest(
cp.getMapCoordinates().unmapXsnap(getMenuX()),
cp.getMapCoordinates().unmapYsnap(getMenuY()));
ua.saveUndoState();
cp.repaint();
} else if(sa.getFirstSelectedPrimitive() instanceof
PrimitiveComplexCurve)
{
PrimitiveComplexCurve poly=
(PrimitiveComplexCurve)sa.getFirstSelectedPrimitive();
poly.addPointClosest(
cp.getMapCoordinates().unmapXsnap(getMenuX()),
cp.getMapCoordinates().unmapYsnap(getMenuY()));
ua.saveUndoState();
cp.repaint();
}
}
}
}
}