/******************************************************************************* * Copyright (c) 2006-2012 * Software Technology Group, Dresden University of Technology * DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026 * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Software Technology Group - TU Dresden, Germany; * DevBoost GmbH - Berlin, Germany * - initial API and implementation ******************************************************************************/ /* * @(#)AbstractTool.java 5.0 2007-11-05 * * Copyright (c) 1996-2007 by the original authors of JHotDraw * and all its contributors. * All rights reserved. * * The copyright of this software is owned by the authors and * contributors of the JHotDraw project ("the copyright holders"). * You may not use, copy or modify this software, except in * accordance with the license agreement you entered into with * the copyright holders. For details see accompanying license terms. */ package org.jhotdraw.draw; import javax.swing.*; import org.jhotdraw.app.action.*; import org.jhotdraw.beans.AbstractBean; import org.jhotdraw.draw.action.*; import java.awt.*; import java.awt.geom.*; import java.awt.event.*; import javax.swing.event.*; /** * AbstractTool. * * @author Werner Randelshofer * @version 5.0 2007-11-05 Changed superclass from Object to AbstractBean. * <br>4.0 2007-04-29 Replaced code in method keyPressed by an InputMap * and a ActionMap. * <br>3.0 2006-02-15 Updated to handle multiple views. * <br>2.0 2006-01-14 Changed to support double precision coordinates. * <br>1.0 2003-12-01 Derived from JHotDraw 5.4b1. */ public abstract class AbstractTool extends AbstractBean implements Tool { /** * This is set to true, if this is the active tool of the editor. */ private boolean isActive; /** * This is set to true, while the tool is doing some work. * This prevents the currentView from being changed when a mouseEnter * event is received. */ protected boolean isWorking; protected DrawingEditor editor; protected Point anchor = new Point(); protected EventListenerList listenerList = new EventListenerList(); private DrawingEditorProxy editorProxy; /* private PropertyChangeListener editorHandler; private PropertyChangeListener viewHandler; */ /** * The input map of the tool. */ private InputMap inputMap; /** * The action map of the tool. */ private ActionMap actionMap; /** Creates a new instance. */ public AbstractTool() { editorProxy = new DrawingEditorProxy(); setInputMap(createInputMap()); setActionMap(createActionMap()); } public void addUndoableEditListener(UndoableEditListener l) { listenerList.add(UndoableEditListener.class, l); } public void removeUndoableEditListener(UndoableEditListener l) { listenerList.remove(UndoableEditListener.class, l); } public void activate(DrawingEditor editor) { this.editor = editor; editorProxy.setTarget(editor); isActive = true; // Repaint all handles for (DrawingView v : editor.getDrawingViews()) { v.repaintHandles(); } } public void deactivate(DrawingEditor editor) { this.editor = editor; isActive = false; } public boolean isActive() { return isActive; } protected DrawingView getView() { return editor.getActiveView(); } protected DrawingEditor getEditor() { return editor; } protected Drawing getDrawing() { return getView().getDrawing(); } protected Point2D.Double viewToDrawing(Point p) { return constrainPoint(getView().viewToDrawing(p)); } protected Point2D.Double constrainPoint(Point p) { return constrainPoint(getView().viewToDrawing(p)); } protected Point2D.Double constrainPoint(Point2D.Double p) { return getView().getConstrainer().constrainPoint(p); } /** * Sets the InputMap for the Tool. * * @see #keyPressed * @see #setActionMap */ public void setInputMap(InputMap newValue) { inputMap = newValue; } /** * Gets the input map of the Tool */ public InputMap getInputMap() { return inputMap; } /** * Sets the ActionMap for the Tool. * @see #keyPressed */ public void setActionMap(ActionMap newValue) { actionMap = newValue; } /** * Gets the action map of the Tool */ public ActionMap getActionMap() { return actionMap; } /** * Deletes the selection. * Depending on the tool, this could be selected figures, selected points * or selected text. */ public void editDelete() { getView().getDrawing().removeAll(getView().getSelectedFigures()); } /** * Cuts the selection into the clipboard. * Depending on the tool, this could be selected figures, selected points * or selected text. */ public void editCut() { } /** * Copies the selection into the clipboard. * Depending on the tool, this could be selected figures, selected points * or selected text. */ public void editCopy() { } /** * Duplicates the selection. * Depending on the tool, this could be selected figures, selected points * or selected text. */ public void editDuplicate() { } /** * Pastes the contents of the clipboard. * Depending on the tool, this could be selected figures, selected points * or selected text. */ public void editPaste() { } public void keyReleased(KeyEvent evt) { fireToolDone(); } public void keyTyped(KeyEvent evt) { } /** * The Tool uses the InputMap to determine what to do, when a key is pressed. * If the corresponding value of the InputMap is a String, the ActionMap * of the tool is used, to find the action to be performed. * If the corresponding value of the InputMap is a ActionListener, the * actionPerformed method of the ActionListener is performed. */ public void keyPressed(KeyEvent evt) { if (! evt.isConsumed()) { if (evt.getSource() instanceof Container) { editor.setActiveView(editor.findView((Container) evt.getSource())); } if (inputMap != null) { Object obj = inputMap.get(KeyStroke.getKeyStroke(evt.getKeyCode(),evt.getModifiers(), false)); ActionListener al = null; if (obj instanceof ActionListener) { al = (ActionListener) obj; } else if (obj != null && actionMap != null) { al = actionMap.get(obj); } if (al != null) { evt.consume(); al.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "tool", evt.getWhen(), evt.getModifiers())); fireToolDone(); } } } } protected InputMap createInputMap() { InputMap m = new InputMap(); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), DeleteAction.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), DeleteAction.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), SelectAllAction.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK), SelectAllAction.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.META_DOWN_MASK), SelectAllAction.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), IncreaseHandleDetailLevelAction.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), MoveConstrainedAction.West.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), MoveConstrainedAction.East.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), MoveConstrainedAction.North.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), MoveConstrainedAction.South.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, InputEvent.ALT_DOWN_MASK), MoveAction.West.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.ALT_DOWN_MASK), MoveAction.East.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.ALT_DOWN_MASK), MoveAction.North.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK), MoveAction.South.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, InputEvent.SHIFT_DOWN_MASK), MoveAction.West.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.SHIFT_DOWN_MASK), MoveAction.East.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.SHIFT_DOWN_MASK), MoveAction.North.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.SHIFT_DOWN_MASK), MoveAction.South.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, InputEvent.CTRL_DOWN_MASK), MoveAction.West.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.CTRL_DOWN_MASK), MoveAction.East.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.CTRL_DOWN_MASK), MoveAction.North.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.CTRL_DOWN_MASK), MoveAction.South.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK), CopyAction.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.META_DOWN_MASK), CopyAction.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK), PasteAction.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.META_DOWN_MASK), PasteAction.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_DOWN_MASK), CutAction.ID); m.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.META_DOWN_MASK), CutAction.ID); return m; } protected ActionMap createActionMap() { ActionMap m = new ActionMap(); m.put(DeleteAction.ID, new DeleteAction()); m.put(SelectAllAction.ID, new SelectAllAction()); m.put(IncreaseHandleDetailLevelAction.ID, new IncreaseHandleDetailLevelAction(editorProxy)); m.put(MoveAction.East.ID, new MoveAction.East(editorProxy)); m.put(MoveAction.West.ID, new MoveAction.West(editorProxy)); m.put(MoveAction.North.ID, new MoveAction.North(editorProxy)); m.put(MoveAction.South.ID, new MoveAction.South(editorProxy)); m.put(MoveConstrainedAction.East.ID, new MoveConstrainedAction.East(editorProxy)); m.put(MoveConstrainedAction.West.ID, new MoveConstrainedAction.West(editorProxy)); m.put(MoveConstrainedAction.North.ID, new MoveConstrainedAction.North(editorProxy)); m.put(MoveConstrainedAction.South.ID, new MoveConstrainedAction.South(editorProxy)); m.put(CutAction.ID, new CutAction()); m.put(CopyAction.ID, new CopyAction()); m.put(PasteAction.ID, new PasteAction()); return m; } public void mouseClicked(MouseEvent evt) { } public void mouseEntered(MouseEvent evt) { /*if (! isWorking) { editor.setActiveView(editor.findView((Container) evt.getSource())); }*/ } public void mouseExited(MouseEvent evt) { } public void mouseMoved(MouseEvent evt) { } public void mousePressed(MouseEvent evt) { DrawingView view = editor.findView((Container) evt.getSource()); view.requestFocus(); anchor = new Point(evt.getX(), evt.getY()); isWorking = true; fireToolStarted(view); } public void mouseReleased(MouseEvent evt) { isWorking = false; } public void addToolListener(ToolListener l) { listenerList.add(ToolListener.class, l); } public void removeToolListener(ToolListener l) { listenerList.remove(ToolListener.class, l); } /** * Notify all listenerList that have registered interest for * notification on this event type. */ protected void fireToolStarted(DrawingView view) { ToolEvent event = null; // Notify all listeners that have registered interest for // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i] == ToolListener.class) { // Lazily create the event: if (event == null) event = new ToolEvent(this, view, new Rectangle(0,0,-1,-1)); ((ToolListener)listeners[i+1]).toolStarted(event); } } } /** * Notify all listenerList that have registered interest for * notification on this event type. */ protected void fireToolDone() { ToolEvent event = null; // Notify all listeners that have registered interest for // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i] == ToolListener.class) { // Lazily create the event: if (event == null) event = new ToolEvent(this, getView(), new Rectangle(0,0,-1,-1)); ((ToolListener)listeners[i+1]).toolDone(event); } } } /** * Notify all listenerList that have registered interest for * notification on this event type. */ protected void fireAreaInvalidated(Rectangle2D.Double r) { Point p1 = getView().drawingToView(new Point2D.Double(r.x, r.y)); Point p2 = getView().drawingToView(new Point2D.Double(r.x+r.width, r.y+r.height)); fireAreaInvalidated( new Rectangle(p1.x,p1.y,p2.x-p1.x,p2.y-p1.y) ); } /** * Notify all listenerList that have registered interest for * notification on this event type. */ protected void fireAreaInvalidated(Rectangle invalidatedArea) { ToolEvent event = null; // Notify all listeners that have registered interest for // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i] == ToolListener.class) { // Lazily create the event: if (event == null) event = new ToolEvent(this, getView(), invalidatedArea); ((ToolListener)listeners[i+1]).areaInvalidated(event); } } } public void draw(Graphics2D g) { } public void updateCursor(DrawingView view, Point p) { if (view.isEnabled()) { Handle handle = view.findHandle(p); if (handle != null) { view.setCursor(handle.getCursor()); } else { Figure figure = view.findFigure(p); Point2D.Double point = view.viewToDrawing(p); Drawing drawing = view.getDrawing(); while (figure != null && ! figure.isSelectable()) { figure = drawing.findFigureBehind(point, figure); } if (figure != null) { view.setCursor(figure.getCursor(view.viewToDrawing(p))); } else { view.setCursor(Cursor.getDefaultCursor()); } } } else { view.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); } } public String getToolTipText(DrawingView view, MouseEvent evt) { return null; } /** * Returns true, if this tool lets the user interact with handles. * <p> * Handles may draw differently, if interaction is not possible. * * @return True, if this tool supports interaction with the handles. */ public boolean supportsHandleInteraction() { return false; } }