/*
* AbstractTool.java
* Eisenkraut
*
* Copyright (c) 2004-2016 Hanns Holger Rutz. All rights reserved.
*
* This software is published under the GNU General Public License v3+
*
*
* For further information, please contact Hanns Holger Rutz at
* contact@sciss.de
*/
package de.sciss.eisenkraut.gui;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import de.sciss.gui.MenuAction;
import de.sciss.gui.TopPainter;
/**
* This class describes a generic GUI tool
* that can be aquired and dismissed by
* a <code>Component</code>.
*/
public abstract class AbstractTool
implements MouseListener, MouseMotionListener, TopPainter {
private Component comp;
private MenuAction actionCancel = null;
protected AbstractTool() {
/* empty */
}
/**
* Makes this tool a component's active
* tool. Subclasses should override this
* method to perform additional initializations
* but are obliged to call the super method,
* which will store the component for the
* <code>getComponent</code> method and will
* activate Mouse and MouseMotion listening.
*
* @param c the <code>Component</code> on which
* this tool will operate.
* @throws IllegalArgumentException if the passed <code>Component</code>
* is <code>null</code>
* @throws IllegalStateException if the tool was aquired before.
*/
public void toolAcquired(Component c) {
if( comp != null ) throw new IllegalStateException();
if( c == null ) throw new IllegalArgumentException();
comp = c;
c.addMouseListener( this );
c.addMouseMotionListener( this );
// c.addKeyListener( this );
if( comp instanceof JComponent ) {
if( actionCancel == null ) actionCancel = new ActionCancel();
actionCancel.installOn( (JComponent) comp, JComponent.WHEN_IN_FOCUSED_WINDOW );
}
}
/**
* Makes this tool inactive. This usually
* happens when the user switches to
* a different tool. Any ongoing drag- and
* drop actions or the like are to be
* cancelled upon invocation of this method.
* Subclasses should override this
* method to perform additional cleanup operations
* but are obliged to call the super method,
* which will forget the component so
* <code>getComponent</code> will return
* <code>null</code> afterwards, also it will
* deactivate Mouse and MouseMotion listening
*
* @param c the <code>Component</code> from
* which the tool is removed.
* @throws IllegalArgumentException if the passed <code>Component</code>
* is <code>null</code> or if the
* tool was attached to a different
* component.
* @throws IllegalStateException if the tool was not aquired before.
*/
public void toolDismissed( Component c )
{
if( comp == null ) throw new IllegalStateException();
if( c == null || c != comp ) throw new IllegalArgumentException();
c.removeMouseMotionListener( this );
c.removeMouseListener( this );
// c.removeKeyListener( this );
if( (actionCancel != null) && (comp instanceof JComponent) ) {
actionCancel.deinstallFrom( (JComponent) comp, JComponent.WHEN_IN_FOCUSED_WINDOW );
}
cancelGesture();
comp = null;
}
protected abstract void cancelGesture();
/**
* Paint the current (possibly volatile) state
* of the tool performance. The should be called
* at the end of the component's <code>paintComponent</code>
* method. The tool is allowed to modify the <code>Stroke</code>
* and the <code>Paint</code> of the <code>Graphics2D</code>
* object without needing to restore it. The tool is responsible
* for undoing any changes to the <code>AffineTransform</code>
* of the <code>Graphics2D</code> object however.
*
* @param g a <code>Graphics2D</code> object to paint on.
* Initial <code>Stroke</code> and <code>Paint</code>
* are undefined. Initial transform should
* be negotiated between the component
* and the tool, e.g. the <code>Surface</code> object
* may guarantee to scale the graphics
* to the virtual space (0, 0 ... 1, 1)
*/
public abstract void paintOnTop( Graphics2D g );
/**
* Returns the component on which the
* tool operates.
*
* @return the tool's <code>Component</code> or
* <code>null</code> if the tool was dismissed.
*/
protected Component getComponent()
{
return comp;
}
public void mousePressed( MouseEvent e )
{
// final Component c = getComponent(); // needn't be the one from e.getComponent() !
//
// if( c != null ) c.requestFocus();
//System.err.println( "requesting focus on "+e.getComponent().getClass().getName() );
}
public void mouseReleased( MouseEvent e ) { /* empty */ }
public void mouseClicked( MouseEvent e ) { /* empty */ }
public void mouseDragged( MouseEvent e ) { /* empty */ }
public void mouseEntered( MouseEvent e ) { /* empty */ }
public void mouseExited( MouseEvent e ) { /* empty */ }
public void mouseMoved( MouseEvent e ) { /* empty */ }
// public void keyPressed( KeyEvent e )
// {
// boolean consume = true;
//
// switch( e.getKeyCode() ) {
// case KeyEvent.VK_ESCAPE: // abort
// cancelGesture();
// break;
//
// default:
// consume = false;
// break;
// }
//
// if( consume ) e.consume();
// }
//
// public void keyReleased( KeyEvent e ) {}
// public void keyTyped( KeyEvent e ) {}
@SuppressWarnings("serial")
private class ActionCancel
extends MenuAction {
protected ActionCancel() {
super("tool-cancel", KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0));
}
public void actionPerformed(ActionEvent e) {
cancelGesture();
}
}
}