/*
* $Id$
* This file is a part of the Arakhne Foundation Classes, http://www.arakhne.org/afc
*
* Copyright (c) 2000-2012 Stephane GALLAND.
* Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
* Universite de Technologie de Belfort-Montbeliard.
* Copyright (c) 2013-2016 The original authors, and other authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.arakhne.afc.ui.actionmode ;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import org.arakhne.afc.math.continous.object2d.Rectangle2f;
import org.arakhne.afc.ui.MouseCursor;
import org.arakhne.afc.ui.ZoomableContext;
import org.arakhne.afc.ui.event.KeyEvent;
import org.arakhne.afc.ui.selection.Selectable;
import org.arakhne.afc.vmutil.locale.Locale;
/** This is the abstract superclass of all editor modes. A Mode is
* responsible for handling most of the events that come to the
* Editor. A Mode defines a context for interperting those events.
* For example, a mouse drag in BaseMode
* will define a selection rectangle, while a mouse drag in
* EdgeCreationMode will drag out a
* rubberband line. Placing the logic for most event handing in
* Modes is key to keeping the Editor source code small and
* managable, and also key for allowing addition of new kinds of user
* interactions without modifying Editor and having to
* integrate these modifications with other contributors
* modifications.
*
* @param <DRAW> is the type of the graphical object supported by this container.
* @param <CANVAS> is the type of the drawing canvas.
* @param <COLOR> is the type that is representing a color.
* @author $Author: sgalland$
* @author $Author: hannoun$
* @author $Author: baumgartner$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @deprecated see JavaFX API
*/
@Deprecated
public abstract class ActionMode<DRAW extends Selectable, CANVAS, COLOR> {
private WeakReference<ActionModeManager<DRAW,CANVAS,COLOR>> modeManager ;
/** Say if the cursor has changed.
*/
protected boolean cursorChanged = false;
private boolean isPersistent;
/** Construct a new Mode.
*
* @param modeManager a reference to the ModeManager that
* contains this Mode.
*/
public ActionMode(ActionModeManager<DRAW,CANVAS,COLOR> modeManager) {
this.modeManager = new WeakReference<>(modeManager) ;
}
/** Construct a new Mode.
*/
public ActionMode() {
this.modeManager = null ;
}
/** Replies if this mode stay active after it has
* created an edge.
*
* @return <code>true</code> if the mode stay active;
* <code>false</code> if it is stopping is execution.
*/
public boolean isPersistent() {
return this.isPersistent;
}
/** Set if this mode stay active after it has
* created an edge.
*
* @param persistent is <code>true</code> if the mode stay active;
* <code>false</code> if it is stopping is execution.
*/
public void setPersistent(boolean persistent) {
this.isPersistent = persistent;
}
/** Invoked when the mode is activated, ie put in the mode stack.
*/
protected void onModeActivated() {
//
}
/** Invoked when the mode is desactivated, ie removed in the mode stack.
*/
protected void onModeDesactivated() {
//
}
/** Repaint the mode container.
*
* @param bounds is the area to repaint.
*/
public void repaint(Rectangle2f bounds) {
getModeManagerOwner().repaint(bounds);
}
/** Repaint the mode container.
*/
public void repaint() {
getModeManagerOwner().repaint();
}
/** Set the parent ModeManager of this Mode.
* @param modeManager a reference to the ModeManager that
* contains this Mode.
*/
public void setModeManager(ActionModeManager<DRAW,CANVAS,COLOR> modeManager) {
this.modeManager = modeManager==null ? null : new WeakReference<>(modeManager);
setCursor(getInitialCursor());
}
/** Reply the parent ModeManager of this Mode.
* @return a reference to the ModeManager that
* contains this Mode.
*/
public ActionModeManager<DRAW,CANVAS,COLOR> getModeManager() {
return this.modeManager==null ? null : this.modeManager.get();
}
/** Reply the root mode container.
* @return a reference to the ModeContainer.
*/
public ActionModeManagerOwner<DRAW,CANVAS,COLOR> getModeManagerOwner() {
ActionModeManager<DRAW,CANVAS,COLOR> manager = getModeManager();
if (manager==null) return null;
return manager.getModeManagerOwner();
}
/** Request the key focus for the Workspace parent.
* <p>
* This method add to the focus manager to give
* keyboard events to the container of the mode manager.
*/
public void requestFocus() {
ActionModeManager<DRAW,CANVAS,COLOR> mm = getModeManager();
if (mm!=null) mm.getModeManagerOwner().requestFocus();
}
/** Returns the cursor that should be shown when this Mode starts.
*
* @return a reference to a cursor.
*/
@SuppressWarnings("static-method")
public MouseCursor getInitialCursor() {
return MouseCursor.DEFAULT;
}
/** Set the mouse cursor to some appropriate for this mode.
*
* @param c a reference to the new mouse cursor.
*/
public void setCursor(MouseCursor c) {
this.cursorChanged = true;
ActionModeManager<DRAW,CANVAS,COLOR> mm = getModeManager();
if (mm!=null) mm.getModeManagerOwner().setCursor(
c==null ? MouseCursor.DEFAULT : c);
}
/** Set the mouse cursor to the default.
*/
protected void restoreCursor() {
if ( this.cursorChanged ) {
setCursor( getInitialCursor() );
this.cursorChanged = false;
}
}
/** Clean and pop this mode from the
* {@link ActionModeManager ModeManager} stack.
*
* @see #setExclusive(boolean)
* @see ActionModeManager#endMode()
* @see #cleanMode()
*/
public void done() {
setCursor(MouseCursor.DEFAULT);
setExclusive( false );
cleanMode();
ActionModeManager<DRAW,CANVAS,COLOR> mm = getModeManager();
if (mm!=null) mm.endMode();
}
/** Reply is this mode is exclusive.
*
* @return <code>true</code> if this Mode is the exclusive
* mode of the enclosing {@link ActionModeManager ModeManager},
* otherwise <code>false</code>.
* @see ActionModeManager#isExclusiveMode(ActionMode)
*/
public boolean isExclusive() {
ActionModeManager<DRAW,CANVAS,COLOR> mm = getModeManager();
if (mm==null) return false;
return mm.isExclusiveMode( this );
}
/** Set this mode to exclusive state or not.
*
* @param exclu <code>true</code> if this Mode must be the exclusive
* mode of the enclosing {@link ActionModeManager ModeManager},
* otherwise <code>false</code>.
* @see ActionModeManager#setExclusiveMode(ActionMode,boolean)
*/
public void setExclusive( boolean exclu ) {
ActionModeManager<DRAW,CANVAS,COLOR> mm = getModeManager();
if (mm!=null) {
mm.setExclusiveMode( this, exclu );
}
}
/** Ask to this mode to return to a stable state.
* This method was called each time this Mode
* need to be in a stable state e.g., initial
* mode state.
*/
public void cleanMode() {
//
}
/** Some Mode's should never be exited, but by default any Mode can
* exit. Mode's which return <code>false</code> for canExit()
* will not be popped from a {@link ActionModeManager}.
*
* @return <code>true</code> if this mode can be stopped and popped
* from the ModeManager's stack.
*/
@SuppressWarnings("static-method")
public boolean canExit() {
return true;
}
/** Modes can paint themselves to give to the user some feedback.
*
* @param g the graphic context.
*/
public void paint(CANVAS g) {
//
}
/** Replies the figure under the mouse cursor.
* To know is the mouse cursor is inside the
* shape of the figure pluease invoke
* {@link #isPointerInFigureShape()}.
*
* @return the figure under the mosue cursor;
* or <code>null</code> if none.
* @see #isPointerInFigureShape()
*/
public DRAW getPointedFigure() {
return getModeManager().getPointedFigure();
}
/** Replies if the mouse pointer is inside the shape
* of the pointer figure.
* To determine the pointed figure, please invoke
* {@link #getPointedFigure()}.
*
* @return <code>true</code> if the mouse pointer is
* inside the shape; otherwise <code>false</code>.
* @see #getPointedFigure()
*/
public boolean isPointerInFigureShape() {
return getModeManager().isPointerInFigureShape();
}
/** Replies the precision of a click in the logical coordinate space.
* <p>
* This function is an helper to access to the click precision
* of the action mode owner, and to translate it to the logical
* coordinate space.
* @return the click precision.
*/
protected float getClickPrecision() {
float prec = getModeManagerOwner().getClickPrecision();
ZoomableContext zc = getModeManagerOwner().getZoomableContext();
if (zc!=null) {
prec = zc.pixel2logical_size(prec);
}
return prec;
}
/** Delegate the execution to the specified mode.
*
* @param delegation is the type of the mode to create and delegate to.
* @return the delegated mode.
*/
protected <M extends ActionMode<DRAW,CANVAS,COLOR>> M createDelegation(Class<M> delegation) {
M mode = null;
try {
Constructor<M> cons = delegation.getConstructor(ActionModeManager.class);
mode = cons.newInstance(getModeManager());
}
catch (Throwable e) {
//
}
if (mode==null) {
try {
mode = delegation.newInstance();
}
catch (Throwable e) {
throw new ActionModeException(Locale.getString("NOT_MODE_TRIGGER"), e); //$NON-NLS-1$
}
mode.setModeManager(getModeManager());
}
assert(mode!=null);
getModeManager().beginMode(mode);
return mode;
}
/** Delegate the execution to the specified mode.
*
* @param mode is the mode to delegate to.
*/
protected <M extends ActionMode<DRAW,CANVAS,COLOR>> void createDelegation(M mode) {
assert(mode!=null);
mode.setModeManager(getModeManager());
getModeManager().beginMode(mode);
repaint();
}
/** Force the mode manager to consider the specified event.
*
* @param event
*/
protected void forcePointerEvent(ActionPointerEvent event) {
getModeManager().updatePointerInfo(event, true);
}
/**
* Invoked when a key has been typed.
* See the class description for {@link KeyEvent} for a definition of
* a key typed event.
* <p>
* The KEY_TYPED event may be unavailable on several components.
* You must read the document of the component on which the action management
* is applied to be sure that the KEY_TYPED event is handled.
*
* @param e
*/
public void keyTyped(KeyEvent e) {
//
}
/**
* Invoked when a key has been pressed.
* See the class description for {@link KeyEvent} for a definition of
* a key pressed event.
* <p>
* The KEY_PRESSED event may be unavailable on several components.
* You must read the document of the component on which the action management
* is applied to be sure that the KEY_PRESSED event is handled.
*
* @param e
*/
public void keyPressed(KeyEvent e) {
//
}
/**
* Invoked when a key has been released.
* See the class description for {@link KeyEvent} for a definition of
* a key released event.
* <p>
* The KEY_RELEASED event may be unavailable on several components.
* You must read the document of the component on which the action management
* is applied to be sure that the KEY_RELEASED event is handled.
*
* @param e
*/
public void keyReleased(KeyEvent e) {
//
}
/**
* Invoked when the pointer button has been clicked (pressed
* and released) on a component.
* <p>
* The POINTER_CLICKED event may be unavailable on several components.
* You must read the document of the component on which the action management
* is applied to be sure that the POINTER_CLICKED event is handled.
*
* @param e
* @see #pointerLongClicked(ActionPointerEvent)
*/
public void pointerClicked(ActionPointerEvent e) {
//
}
/**
* Invoked when the pointer button has been long clicked (pressed
* and released) on a component.
* <p>
* The POINTER_LONG_CLICKED event may be unavailable on several components.
* You must read the document of the component on which the action management
* is applied to be sure that the POINTER_LONG_CLICKED event is handled.
*
* @param e
* @see #pointerClicked(ActionPointerEvent)
*/
public void pointerLongClicked(ActionPointerEvent e) {
//
}
/**
* Invoked when a pointer button has been pressed on a component.
* <p>
* The POINTER_PRESSED event may be unavailable on several components.
* You must read the document of the component on which the action management
* is applied to be sure that the POINTER_PRESSED event is handled.
*
* @param e
*/
public void pointerPressed(ActionPointerEvent e) {
//
}
/**
* Invoked when a pointer button has been released on a component.
* <p>
* The POINTER_RELEASED event may be unavailable on several components.
* You must read the document of the component on which the action management
* is applied to be sure that the POINTER_RELEASED event is handled.
*
* @param e
*/
public void pointerReleased(ActionPointerEvent e) {
//
}
/**
* Invoked when the mouse is moved with a button down.
* <p>
* The POINTER_DRAGGED event may be unavailable on several components.
* You must read the document of the component on which the action management
* is applied to be sure that the POINTER_DRAGGED event is handled.
*
* @param e
*/
public void pointerDragged(ActionPointerEvent e) {
//
}
/**
* Invoked when the mouse is moved with no button down.
* <p>
* The POINTER_MOVED event may be unavailable on several components.
* You must read the document of the component on which the action management
* is applied to be sure that the POINTER_MOVED event is handled.
*
* @param e
*/
public void pointerMoved(ActionPointerEvent e) {
//
}
}