CustomSelectionTool.java
/*
* @(#)CustomSelectionTool.java
*
* Project: JHotdraw - a GUI framework for technical drawings
* http://www.jhotdraw.org
* http://jhotdraw.sourceforge.net
* Copyright: © by the original author(s) and all contributors
* License: Lesser GNU Public License (LGPL)
* http://www.opensource.org/licenses/lgpl-license.html
*/
package CH.ifa.draw.contrib;
import CH.ifa.draw.framework.*;
import CH.ifa.draw.standard.*;
import CH.ifa.draw.figures.*;
import CH.ifa.draw.util.*;
import javax.swing.JPopupMenu;
import java.awt.*;
import java.awt.event.*;
/**
* A SelectionTool, which recognizes double clicks and popup menu triggers.
* If a double click or popup trigger is encountered a hook method is called,
* which handles the event. This methods can be overriden in subclasse to
* provide customized behaviour.
* Popup menus must be registered with a Figure using the setAttribute() method.
* The key which associates a popup menu as an attribute is Figure.POPUP_MENU.
*
* @author Wolfram Kaiser
* @version <$CURRENT_VERSION$>
*/
public class CustomSelectionTool extends SelectionTool {
/**
* Create an instance of this SelectionTool for the given view
*
* @param editor DrawingEditor for which the SelectionTool gets the active view
*/
public CustomSelectionTool(DrawingEditor editor) {
super( editor );
}
/**
* MouseListener method for mouseDown events. If the popup trigger has been
* activated, then the appropriate hook method is called.
*
* @param e MouseEvent which should be interpreted
* @param x x coordinate of the MouseEvent
* @param y y coordinate of the MouseEvent
*/
public void mouseDown(MouseEvent e, int x, int y) {
// isPopupTrigger() at mouseDown() is only notified at UNIX systems
if (e.isPopupTrigger()) {
handlePopupMenu(e, x, y);
}
else {
super.mouseDown(e, x, y);
handleMouseDown(e, x, y);
}
}
/**
* MouseListener method for mouseDrag events. Usually, mouse drags are
* ignored for popup menus or double clicks.
*
* @param e MouseEvent which should be interpreted
* @param x x coordinate of the MouseEvent
* @param y y coordinate of the MouseEvent
*/
public void mouseDrag(MouseEvent e, int x, int y) {
if (!e.isPopupTrigger()) {
super.mouseDrag(e, x, y);
}
}
/**
* MouseListener method for mouseUp events. Depending on the kind of event
* the appropriate hook method is called (popupMenuUp for popup trigger,
* doubleMouseClick for a double click, and mouseUp() and mouseClick() for
* normal mouse clicks).
*
* @param e MouseEvent which should be interpreted
* @param x x coordinate of the MouseEvent
* @param y y coordinate of the MouseEvent
*/
public void mouseUp(MouseEvent e, int x, int y) {
if (e.isPopupTrigger()) {
handlePopupMenu(e, x, y);
}
else if (e.getClickCount() == 2) {
handleMouseDoubleClick(e, x, y);
}
else {
super.mouseUp(e, x, y);
handleMouseUp(e, x, y);
handleMouseClick(e, x, y);
}
}
/**
* Hook method which can be overriden by subclasses to provide
* specialised behaviour in the event of a mouse down.
*/
protected void handleMouseDown(MouseEvent e, int x, int y) {
}
/**
* Hook method which can be overriden by subclasses to provide
* specialised behaviour in the event of a mouse up.
*/
protected void handleMouseUp(MouseEvent e, int x, int y) {
}
/**
* Hook method which can be overriden by subclasses to provide
* specialised behaviour in the event of a mouse click.
*/
protected void handleMouseClick(MouseEvent e, int x, int y) {
}
/**
* Hook method which can be overriden by subclasses to provide
* specialised behaviour in the event of a mouse double click.
*/
protected void handleMouseDoubleClick(MouseEvent e, int x, int y) {
}
/**
* Hook method which can be overriden by subclasses to provide
* specialised behaviour in the event of a popup trigger.
*/
protected void handlePopupMenu(MouseEvent e, int x, int y) {
Figure figure = drawing().findFigure(e.getX(), e.getY());
if (figure != null) {
Object attribute = figure.getAttribute(Figure.POPUP_MENU);
if (attribute == null) {
figure = drawing().findFigureInside(e.getX(), e.getY());
}
if (figure != null) {
showPopupMenu(figure, e.getX(), e.getY(), e.getComponent());
}
}
}
/**
* This method displays a popup menu, if there is one registered with the
* Figure (the Figure's attributes are queried for Figure.POPUP_MENU which
* is used to indicate an association of a popup menu with the Figure).
*
* @param figure Figure for which a popup menu should be displayed
* @param x x coordinate where the popup menu should be displayed
* @param y y coordinate where the popup menu should be displayed
* @param component Component which invoked the popup menu
*/
protected void showPopupMenu(Figure figure, int x, int y, Component comp) {
Object attribute = figure.getAttribute(Figure.POPUP_MENU);
if ((attribute != null) && (attribute instanceof JPopupMenu)) {
JPopupMenu popup = (JPopupMenu)attribute;
if (popup instanceof PopupMenuFigureSelection) {
((PopupMenuFigureSelection)popup).setSelectedFigure(figure);
}
// calculate offsets for internal MDI frames
Point newLocation = new Point(x, y);
adjustOffsets(comp.getParent(), newLocation);
popup.setLocation(newLocation);
popup.setInvoker(comp);
popup.setVisible(true);
}
}
/**
* Internal MDI frames have offsets where a popup menu should be
* shown (in JDK 1.2).
* This method sums up iteratively all x and y offsets of all
* parent compontents until the top parent component is reached.
*/
private void adjustOffsets(Component comp, Point offsetPoint) {
if (comp != null) {
Point compLocation = comp.getLocation();
offsetPoint.translate(compLocation.x, compLocation.y);
adjustOffsets(comp.getParent(), offsetPoint);
}
}
}