/* gvSIG. Sistema de Información Geográfica de la Generalitat Valenciana * * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana. * * This program 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 2 * of the License, or (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA. * * For more information, contact: * * Generalitat Valenciana * Conselleria d'Infraestructures i Transport * Av. Blasco Ibáñez, 50 * 46010 VALENCIA * SPAIN * * +34 963862235 * gvsig@gva.es * www.gvsig.gva.es * * or * * IVER T.I. S.A * Salamanca 50 * 46005 Valencia * Spain * * +34 963163400 * dac@iver.es */ package com.iver.cit.gvsig.fmap; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.Set; import javax.swing.JComponent; import javax.swing.Timer; import org.cresques.cts.IProjection; import com.iver.cit.gvsig.fmap.crs.CRSFactory; import com.iver.cit.gvsig.fmap.edition.commands.CommandListener; import com.iver.cit.gvsig.fmap.layers.FLayers; import com.iver.cit.gvsig.fmap.layers.GraphicLayer; import com.iver.cit.gvsig.fmap.layers.LayerCollectionEvent; import com.iver.cit.gvsig.fmap.layers.LayerEvent; import com.iver.cit.gvsig.fmap.tools.BehaviorException; import com.iver.cit.gvsig.fmap.tools.CompoundBehavior; import com.iver.cit.gvsig.fmap.tools.Behavior.Behavior; import com.iver.cit.gvsig.fmap.tools.Listeners.ToolListener; import com.iver.utiles.exceptionHandling.ExceptionHandlingSupport; import com.iver.utiles.exceptionHandling.ExceptionListener; import com.iver.utiles.swing.threads.Cancellable; /** *
A component that includes a {@link MapContext MapContext} with support for use it as a particular {@link Behavior Behavior}.
* *A developer can register a set of Behavior
, but only one (that can be a composition of several) of them can be active. The active one
* defines the way to work and access with its MapContext
's layers. The active behavior, in combination with the appropriate
* {@link ToolListener ToolListener} will allow user work with a particular tool.
All mouse events produced on this component will be delegated to the current active behavior, the currentMapTool.
* *Drawing process:
* *Uses a double buffer for the drawing process of MapContext
's information.
If the double buffer wasn't created, creates a new one.
* *Paints the component according the following algorithm:
*
*   If status is UPDATED:
*     If there is a double buffer:
*       If there is a behavior for managing the MapControl
instance, delegates
* the drawing process to that behavior, calling: behavior_instance.paintComponent(g)
.
*       Else, repaints the current graphical information quickly calling: g.drawImage(image,0,0,null)
.
*   Else, (status is OUTDATED, or ONLY_GRAPHICS): executes a quickly repaint of the previous information calling g.drawImage(image,0,0,null)
, and creates
* a painting request to delegate the heavy drawing process to the {@link Drawer2 Drawer2}'s worker thread, according the SingleWorketThread pattern, starting a timer to update
* (invoking repaint()
) the view every delay of 1000 / drawFrameRate
ms. during that heavy drawing process, and if its enabled drawAnimationEnabled
. The painting request once is being attended, invokes MapContext
to
* draw the layers: mapContext.draw(image, g, cancel,mapContext.getScaleView());
*
*
Some notes: *
MapControl
's MapContrext
* will be that one which will draw the graphical information, and, if supports, which could cancel its drawing subprocess.Tools:
* *A developer can: *
Exception listener:
* * Adding an ExceptionListener
, can get notification about any exception produced:
*
Other:
* *Other useful capabilities of MapControl
:
*
MapContext
instance and its layers): {@link #cancelDrawing() #cancelDrawing()}.ToolListener
): {@link #zoomIn() #zoomIn()}.ToolListener
): {@link #zoomOut() #zoomOut()}.One of the possible status of MapControl
. Determines that all visible information has been
* drawn and its updated.
One of the possible status of MapControl
. Determines that not all visible information has been
* drawn or isn't updated.
One of the possible status of MapControl
. Determines that only the graphical layer must
* be drawn / updated.
Determines the number of frames.
* *Number of updates per second that the timer will invoke repaint this component.
*/ private static int drawFrameRate = 3; /** *Determines if the drawer can update this MapControl
instance when the timer launches an event.
Inner model with the layers, event support for drawing them, and the ViewPort
* with information to adapt to the bounds available in image coordinates.
All registered Behavior
that can define a way to work with this MapControl
.
Only one of them can be active at a given moment.
* * @see #addMapTool(String, Behavior) * @see #addMapTool(String, Behavior[]) * @see #getMapTool(String) * @see #getMapToolsKeySet() * @see #getNamesMapTools() */ protected HashMap namesMapTools = new HashMap(); /** *Active {@link Behavior Behavior} that will generate events according a criterion, and then, with a {@link ToolListener ToolListener} * associated, will simulate to user that works with this component as a particular tool.
* * @see #getCurrentMapTool() * @see #getCurrentTool() * @see #setTool(String) */ protected Behavior currentMapTool = null; /** *Determines which's the current drawn status of this component: *
The MapControl
drawing process will consider the value of this parameter to decide which elements will
* be updated or drawn.
Image with a buffer to accelerate the draw the changes of the graphical items in this component.
* *Firstly, information will be drawn in the buffer, and, when is outright drawn, that information will be displayed. * Meanwhile, the previous image can be kept showed.
* * @see BufferedImage * * @see #getImage() */ private BufferedImage image = null; /** *Name of the tool used currently to interact with this component.
* * @see #getCurrentTool() * @see #setTool(String) */ protected String currentTool; /** *Object to store the flag that notifies a drawing thread task and MapContext
's layers,
* that must be canceled or can continue with the process.
Fires an action events after a specified delay.
* *MapControl
will use the timer to update its visible graphical information during
* a drawing process, or allowing to cancel that process.
This is very useful to pretend faster interactivity to user when MapControl
has
* lots of layers, and / or layers with heavy graphical elements, that need a long time to finish
* drawing all its data.
Reference to the {@link ViewPort ViewPort} of the {@link MapContext MapContext} of this component.
* *The view port once is created an instance of MapControl
,
* is obtained from the EPSG:23030 projection, that's the default projection for this component.
After, the view port will change adapting itself according the current projection and the extent.
* * @see #getViewPort() * * @see ViewPort */ protected ViewPort vp; //private Drawer drawer; /** *Manager of all MapControl
painting requests.
Listener of all kind of mouse events produced in this component.
* *Delegates each mouse event to the current map tool.
* * @see #addMapTool(String, Behavior) * @see #addMapTool(String, Behavior[]) * @see #getMapTool(String) * @see #getMapToolsKeySet() * @see #getNamesMapTools() * @see #setTool(String) */ protected MapToolListener mapToolListener = new MapToolListener(); /** *Listener of all events produced in a this component's MapContext
* object during an atomic period of time.
Group of ExceptionListener
that, in whatever moment could be notified a Throwable Java error or exception.
Name of the previous tool used.
*/ protected String prevTool; /** *Tool that will be used combined with the current tool of this MapControl
.
Creates a new MapControl
instance with the following characteristics:
*
JComponent
.OUTDATED
.MapContext
's layers if can continue processing the drawn or must cancel it.drawFrameRate
per second, when is running a drawing process, and its enabled
* drawAnimationEnabled
.Sets a MapContext
to this component.
The MapContext
has the model, and most of the view,
* and control logic of the layers of this component, including a {@link ViewPort ViewPort} to adapt the
* information to the projection, and to display it in the available area.
If model
hadn't a ViewPort
, assigns the current one to it, otherwise, use its ViewPort
.
After assigning the MapContext
and ViewPort
, sets the same {@link MapContextListener MapContextListener}
* that was using, and changes the status to OUTDATED
.
MapContext
, that includes the ViewPort
.
*
* @see MapContext
*
* @see #getMapContext()
*/
public void setMapContext(MapContext model) {
if (mapContext != null) {
mapContext.removeAtomicEventListener(mapContextListener);
}
mapContext = model;
if (mapContext.getViewPort() == null) {
mapContext.setViewPort(vp);
} else {
vp = mapContext.getViewPort();
// vp.setImageSize(new Dimension(getWidth(), getHeight()));
//System.err.println("Viewport en setMapContext:" + vp);
}
mapContext.addAtomicEventListener(mapContextListener);
status = DESACTUALIZADO;
}
/**
* Gets this component's {@link MapContext MapContext} projection.
* * @return this component's {@link MapContext MapContext} projection * * @see MapContext#getProjection() * @see MapControl#setProjection(IProjection) */ public IProjection getProjection() { return getMapContext().getProjection(); } /** *Sets the projection to this component's {@link MapContext MapContext}.
* * @param proj the kind of projection to this component's {@link MapContext MapContext} * * @see MapContext#setProjection(IProjection) * @see MapControl#getProjection() */ public void setProjection(IProjection proj) { getMapContext().setProjection(proj); } /** *Gets this component's MapContext
, with the model, and most of the view,
* and control logic of the layers of this component, including a {@link ViewPort ViewPort} to adapt the
* information to the projection, and display it in the available area.
MapContext
, that includes the ViewPort
used to project the
* graphical information, and display it in the available area
*
* @see MapContext
*
* @see MapControl#setMapContext(MapContext)
*/
public MapContext getMapContext() {
return mapContext;
}
/**
* Registers a new behavior to this component.
* *According the nature of the {@link Behavior Behavior}, different events will be generated. Those
* events can be caught by a particular {@link ToolListener ToolListener}, allowing user to interact with this
* MapControl
object as a tool.
Registers a new behavior to this component as a {@link CompoundBehavior CompoundBehavior} made up of tools
.
According the nature of the behaviors registered, different events will be generated. Those
* events can be caught by a particular {@link ToolListener ToolListener}, allowing user to interact with this
* MapControl
object as a tool.
Gets the Behavior
registered in this component, identified
* by name
.
name
, or null
if
* no one has that identifier
*
* @see #addMapTool(String, Behavior)
* @see #addMapTool(String, Behavior[])
* @see #hasTool(String)
*/
public Behavior getMapTool(String name) {
return (Behavior)namesMapTools.get(name);
}
/**
* Returns a set view of the keys that identified the tools * registered.
* * @return a set view of the keys that identified the tools registered * * @see HashMap#keySet() * * @see #getNamesMapTools() * @see #addMapTool(String, Behavior) * @see #addMapTool(String, Behavior[]) */ public Set getMapToolsKeySet() { return namesMapTools.keySet(); } /** *Returns true
if this component contains a tool identified by toolName
.
true
if this component contains a tool identified by toolName
; otherwise false
*
* @see #addMapTool(String, Behavior)
* @see #addMapTool(String, Behavior[])
*/
public boolean hasTool(String toolName) {
return namesMapTools.containsKey(toolName);
}
/**
* Sets as current active Behavior
associated to this component, that one which
* is registered and identified by toolName
.
Changing the current active behavior for this MapControl
, implies also updating the
* previous behavior tool, and the current cursor.
Gets as current active Behavior
associated to this component, that one which
* is registered and identified by toolName
.
Changing the current active behavior for this MapControl
, implies also updating the
* previous behavior tool, and the current cursor.
Returns the name of the current selected tool on this MapControl
* * @return the name of the current's behavior tool associated to this component * * @see #getCurrentMapTool() * @see #setTool(String) */ public String getCurrentTool() { return currentTool; } /** *Determines that current drawing process of MapControl
's MapContext
's data must be canceled.
It has no effects if now isn't drawing that graphical information.
* *At last resort, the particular implementation of each layer in this MapControl
's MapContrext
* will be that one which will draw the graphical information, and, if supports, which could cancel its drawing subprocess.
Creates a {@link BufferedImage BufferedImage} image if there was no buffered image, or if * its viewport's image height or width is different from this component's size. Once has created * a double-buffer, fills it with the vieport's background color, or with white if it had no background color.
* *If no double-buffered existed, creates a {@link BufferedImage BufferedImage} with the size of this component,
* and as an image with 8-bit RGBA color components packed into integer pixels. That image has a DirectColorModel
with alpha.
* The color data in that image is considered not to be premultiplied with alpha.
Once has created and filled the new inner MapControl
's double-buffer, changes the status to
* OUTDATED
.
true
if has created and filled a new double-buffer for this MapControl
instance; otherwise false
*/
private boolean adaptToImageSize()
{
if ((image == null) || (vp.getImageWidth() != this.getWidth()) || (vp.getImageHeight() != this.getHeight()))
{
image = new BufferedImage(this.getWidth(), this.getHeight(),
BufferedImage.TYPE_INT_ARGB);
// ESTILO MAC
// image = GraphicsEnvironment.getLocalGraphicsEnvironment()
// .getDefaultScreenDevice().getDefaultConfiguration()
// .createCompatibleImage(this.getWidth(), this.getHeight());
vp.setImageSize(new Dimension(getWidth(), getHeight()));
getMapContext().getViewPort().refreshExtent();
Graphics gTemp = image.createGraphics();
Color theBackColor = vp.getBackColor();
if (theBackColor == null)
gTemp.setColor(Color.WHITE);
else
gTemp.setColor(theBackColor);
gTemp.fillRect(0,0,getWidth(), getHeight());
gTemp.dispose();
status = DESACTUALIZADO;
// g.drawImage(image,0,0,null);
return true;
}
return false;
}
/**
* Paints the graphical information of this component using a double buffer.
* *If the double buffer wasn't created, creates a new one.
* *Paints the component according the following algorithm:
*
*   If status is UPDATED:
*     If there is no double buffer:
*       If there is a behavior for managing the MapControl
instance, delegates
* the drawing process to that behavior, calling: behavior_instance.paintComponent(g)
  .
*       Else, repaints the current graphical information quickly calling: g.drawImage(image,0,0,null)
  .
*   Else, (status is OUTDATED, or ONLY_GRAPHICS): executes a quickly repaint of the previous information calling g.drawImage(image,0,0,null)
, and creates
* a painting request to delegate the heavy drawing process to the {@link Drawer2 Drawer2}'s worker thread, according the SingleWorketThread pattern, starting a timer to update
* (invoking repaint()
that comprises invoke this method) the view every delay of 360 ms. during the the process drawing.
Gets the {@link BufferedImage BufferedImage} used to accelerate the draw of new ''frames'' with changes, * or new graphical items in this component.
* * @return double buffered image used by this component to accelerate the draw of its graphical information, or *null
if isn't already created
*
* @see BufferedImage
*/
public BufferedImage getImage() {
return image;
}
/**
* Forces repaint all visible graphical information in this component.
* *If doClear == true
, before repainting, clears the background color, with the
* inner viewport's background color.
true
if needs clearing the background color before drawing the map
*
* @see #cancelDrawing()
* @see FLayers#setDirty(boolean)
*/
public void drawMap(boolean doClear) {
cancelDrawing();
//System.out.println("drawMap con doClear=" + doClear);
status = DESACTUALIZADO;
// getMapContext().getLayers().setDirty(true);
if (doClear)
{
// image = null; // Se usa para el PAN
if (image != null)
{
Graphics2D g = image.createGraphics();
Color theBackColor = vp.getBackColor();
if (theBackColor == null)
g.setColor(Color.WHITE);
else
g.setColor(theBackColor);
g.fillRect(0, 0, vp.getImageWidth(), vp.getImageHeight());
g.dispose();
}
}
repaint();
}
/**
* Cancels any current drawing process, changing the status to OUTDATED
, and forcing
* repaint only the layers dirty.
Cancels any current drawing process, changing the status to ONLY_GRAPHICS
, and forcing
* repaint only the graphical layer of the MapContext
.
Represents each MapControl
's data painting request.
The request will be attended by a Drawer2
, which will hold it since the Drawer2
's worker
* takes it, or arrives a new painting request, which will replace it.
Creates a new PaintingRequest
MapControl
paint process:
*
MapControl
's drawing processes.mapContext.draw(double-buffer, double-buffer's buffer, shared cancel-draw object, mapContext.getScaleView());
.canceldraw.isCanceled()
* mapContext.drawGraphics(double-buffer, double-buffer's buffer, shared cancel-draw object, mapContext.getScaleView());
.repaint();
An instance of Drawer2
could manage all MapControl
painting requests.
Based on the WorkerThread software pattern, creates a worker thread that will attend sequentially * the current waiting painting request, after finishing the previous (that could be by a cancel action).
* *All new {@link PaintingRequest PaintingRequest} generated will be stored as waiting requests since the worker * attends it.
* *If a worker finished and there was no painting request, the worker would be set to wait until any * painting request would be put.
* * @author fjp */ public class Drawer2 { // Una mini cola de 2. No acumulamos peticiones de dibujado // dibujamos solo lo último que nos han pedido. /** *Painting request that's been attended by the Drawer2
's worker.
Painting request waiting to be attended by the Drawer2
's worker.
Determines that the Drawer2
's worker is busy attending a painting request.
Notifies the Drawer2
's worker to finish or continue with its process.
Sets this Drawer2
's worker to finish or continue with its process.
Creates a new drawer for managing all data painting requests in MapControl
.
Includes the following steps: *
Sets a PaintingRequest
to be attended by the worker thread of this object. If
* this one was waiting, wakes up.
All waiting threads will be notified synchronized.
* * @param newPaintRequest * * @see #take() */ public void put(PaintingRequest newPaintRequest) { waitingRequest = newPaintRequest; if (waiting) { synchronized (this) { notifyAll(); } } } /** *Used by this object's worker, returns the current waiting drawing request, causing current thread * to wait until another thread invokes {@link #put(com.iver.cit.gvsig.fmap.MapControl.PaintingRequest) #put(com.iver.cit.gvsig.fmap.MapControl.PaintingRequest)}, * if there was no waiting request.
* *All threads will access synchronized to the waiting request.
* * @returnPaintingRequest
that was waiting to be attended
*
* @see #put(com.iver.cit.gvsig.fmap.MapControl.PaintingRequest)
*/
public PaintingRequest take()
{
if (waitingRequest == null)
{
synchronized (this) {
waiting = true;
try {
wait();
}
catch (InterruptedException ie)
{
waiting = false;
}
}
}
paintingRequest = waitingRequest;
waitingRequest = null;
return paintingRequest;
}
/**
* Thread for attending painting requests.
* *If there was no double buffer, sets the status to OUTDATED
and finishes, otherwise
* takes the painting request (it's probably that would wait some time), cancel the previous drawing
* process, and starts processing the request.
Drawer
is implemented for drawing the layers of a MapControl
's MapContext instance
* as a thread of execution.
Draws MapControl
according its status:
*
ONLY_GRAPHICS
: refreshes only the graphical layer, changing the status to UPDATED
, via
* {@linkplain MapContext#drawGraphics(BufferedImage, Graphics2D, Cancellable, double) MapContext#drawGraphics(BufferedImage, Graphics2D, Cancellable, double)}.OUTDATED
: refreshes all layers, changing the status to UPDATED
, via
* {@linkplain MapContext#draw(BufferedImage, Graphics2D, Cancellable, double) MapContext#draw(BufferedImage, Graphics2D, Cancellable, double)}.This drawing process is accelerated by a BufferedImage
, and can be canceled.
Once the drawing process has finished, the timer stops and this component gets repainted.
* * @deprecated * @author Vicente Caballero Navarro */ public class Drawer extends Thread { //private Graphics g; /** *Image with a buffer to accelerate the draw the changes of the graphical items in this component.
* *Firstly, information will be drawn in the buffer, and, when is outright drawn, that information will be displayed. * Meanwhile, the previous image can be kept showed.
* * @see BufferedImage */ private BufferedImage image = null; /** *Object to store the flag that notifies the drawing must be canceled or can continue with the process.
* *At last resort, the particular implementation of each layer in a MapControl
's MapContrext
* will be which will draw the graphical information, and, if supports, which could cancel its drawing subprocess.
Creates a new Drawer
instance.
An instance of CancelDraw
will be shared by all this MapControl
's MapContext
layers,
* allowing receive a notification that, when they're been drawn, to be cancelled.
Determines if the drawing task must be canceled or not.
* * @see #isCanceled() * @see #setCanceled(boolean) */ private boolean cancel = false; /** * Creates a newCancelDraw
object.
*/
public CancelDraw() {
}
/*
* (non-Javadoc)
* @see com.iver.utiles.swing.threads.Cancellable#setCanceled(boolean)
*/
public void setCanceled(boolean b) {
cancel = b;
}
/*
* (non-Javadoc)
* @see com.iver.utiles.swing.threads.Cancellable#isCanceled()
*/
public boolean isCanceled() {
return cancel;
}
}
/**
* Listens all kind of mouse events produced in {@link MapControl MapControl}, and invokes its current * map tool ({@link MapControl#getCurrentMapTool() MapControl#getCurrentMapTool()} to simulate a behavior.
* *Mouse wheel moved events produce a zoom in operation if wheel rotation is negative, or a zoom out * if its positive. Both will be centered in the position of the mouse, but, meanwhile zoom in operation * applies a factor of 0.9, zoom out operation applies a factor of 1.2
* *Mouse wheel moved events can be produced as much frequently, that between each one, the drawing process could * hadn't finished. This is the reason that, in this situation, cancels always the previous drawing process before * applying a zoom operation, and ignores all new mouse positions that are produced before 1 second.
* * @author Fernando González Cortés */ public class MapToolListener implements MouseListener, MouseWheelListener, MouseMotionListener { /** *Used to avoid mouse wheel move events closed.
* *If a mouse wheel move event is produced */ long t1; /** *
Position of the mouse, in map coordinates.
* *This point coordinates will be used as center of the zoom operation.
*/ Point2D pReal; /** * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent) * @see Behavior#mouseClicked(MouseEvent) */ public void mouseClicked(MouseEvent e) { try { if (currentMapTool != null) currentMapTool.mouseClicked(e); } catch (BehaviorException t) { throwException(t); } } /** * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) * @see Behavior#mouseEntered(MouseEvent) */ public void mouseEntered(MouseEvent e) { try { if (currentMapTool != null) currentMapTool.mouseEntered(e); } catch (BehaviorException t) { throwException(t); } } /** * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) * @see Behavior#mouseExited(MouseEvent) */ public void mouseExited(MouseEvent e) { try { if (currentMapTool != null) currentMapTool.mouseExited(e); } catch (BehaviorException t) { throwException(t); } } /** * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent) * @see Behavior#mousePressed(MouseEvent) */ public void mousePressed(MouseEvent e) { try { if (currentMapTool != null) currentMapTool.mousePressed(e); } catch (BehaviorException t) { throwException(t); } } /** * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent) * @see Behavior#mouseReleased(MouseEvent) */ public void mouseReleased(MouseEvent e) { try { if (currentMapTool != null) currentMapTool.mouseReleased(e); } catch (BehaviorException t) { throwException(t); } } /** * @see java.awt.event.MouseWheelListener#mouseWheelMoved(java.awt.event.MouseWheelEvent) * @see Behavior#mouseWheelMoved(MouseWheelEvent) */ public void mouseWheelMoved(MouseWheelEvent e) { try { if (currentMapTool == null) return; currentMapTool.mouseWheelMoved(e); // Si el tool actual no ha consumido el evento // entendemos que quiere el comportamiento por defecto. if (!e.isConsumed()) { // Para usar el primer punto sobre el que queremos centrar // el mapa, dejamos pasar un segundo para considerar el siguiente // punto como válido. if (t1 == 0) { t1= System.currentTimeMillis(); pReal = vp.toMapPoint(e.getPoint()); } else { long t2 = System.currentTimeMillis(); if ((t2-t1) > 1000) t1=0; } cancelDrawing(); ViewPort vp = getViewPort(); /* Point2D pReal = new Point2D.Double(vp.getAdjustedExtent().getCenterX(), vp.getAdjustedExtent().getCenterY()); */ int amount = e.getWheelRotation(); double nuevoX; double nuevoY; double factor; if (amount < 0) // nos acercamos { factor = 0.9; } else // nos alejamos { factor = 1.2; } Rectangle2D.Double r = new Rectangle2D.Double(); if (vp.getExtent() != null) { nuevoX = pReal.getX() - ((vp.getExtent().getWidth() * factor) / 2.0); nuevoY = pReal.getY() - ((vp.getExtent().getHeight() * factor) / 2.0); r.x = nuevoX; r.y = nuevoY; r.width = vp.getExtent().getWidth() * factor; r.height = vp.getExtent().getHeight() * factor; vp.setExtent(r); } } } catch (BehaviorException t) { throwException(t); } } /** * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent) * @see Behavior#mouseDragged(MouseEvent) */ public void mouseDragged(MouseEvent e) { try { if (currentMapTool != null) currentMapTool.mouseDragged(e); } catch (BehaviorException t) { throwException(t); } } /** * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent) * @see Behavior#mouseMoved(MouseEvent) */ public void mouseMoved(MouseEvent e) { try { if (currentMapTool != null) currentMapTool.mouseMoved(e); } catch (BehaviorException t) { throwException(t); } } } /** *MapContextListener listens all events produced in a MapControl
's MapContext
* object during an atomic period of time, and sets it to dirty, executing drawMap(false)
, if any of the
* following conditions is accomplished:
*
LayerEvent
in the AtomicEvent
parameter notifies a visibility change.ColorEvent
in the AtomicEvent
parameter.ExtentEvent
in the AtomicEvent
parameter.LayerCollectionEvent
in the AtomicEvent
parameter notifies that a driver's layer has reloaded it successfully.LegendEvent
in the AtomicEvent
parameter.SelectionEvent
in the AtomicEvent
parameter.Gets the ViewPort
of this component's {@link MapContext MapContext} .
Returns all registered Behavior
that can define a way to work with this MapControl
.
Behavior
to this MapControl
*
* @see #addMapTool(String, Behavior)
* @see #addMapTool(String, Behavior[])
* @see #getMapToolsKeySet()
* @see #hasTool(String)
*/
public HashMap getNamesMapTools() {
return namesMapTools;
}
/*
* (non-Javadoc)
* @see com.iver.cit.gvsig.fmap.edition.commands.CommandListener#commandRepaint()
*/
public void commandRepaint() {
drawMap(false);
}
/*
* (non-Javadoc)
* @see com.iver.cit.gvsig.fmap.edition.commands.CommandListener#commandRefresh()
*/
public void commandRefresh() {
// TODO Auto-generated method stub
}
/**
* Equivalent operation to undo.
* *Exchanges the previous tool with the current one.
* * @see #addMapTool(String, Behavior) * @see #addMapTool(String, Behavior[]) * @see #setTool(String) */ public void setPrevTool() { setTool(prevTool); } /** *Executes a zoom in operation centered at the center of the extent.
* *This implementation is designed for being invoked outside a Behavior
, for example
* by an action of pressing a button; and simulates that the event has been produced by
* releasing the button 1 of the mouse using the registered Behavior
in this
* MapControl
object that's responsible for the zoom in operation.
Executes a zoom out operation centered at the center of the extent.
* *This implementation is thought for being invoked outside a Behavior
, for example
* by an action of pressing a button, and simulates that the event has been produced by
* releasing the button 1 of the mouse using the registered Behavior
in this
* MapControl
object that's responsible for the zoom out operation.
Returns the listener used to catch all mouse events produced in this MapControl
instance
* and that redirects the calls to the current map tool.
Sets mapTool
as this MapControl
's current map tool.
*
* @param mapTool a map tool, or null
to disable the interaction with the user
*
* @see #getCurrentMapTool()
* @see #getCurrentTool()
* @see #setTool(String)
* @see #setPrevTool()
* @see #addMapTool(String, Behavior)
* @see #addMapTool(String, Behavior[])
*/
public void setCurrentMapTool(Behavior mapTool ){
currentMapTool = mapTool;
}
/**
*
Sets the delay to the timer that refreshes this MapControl
instance.
Delay (in ms) = 1000 / getDrawFrameRate()
Returns the draw frame rate.
* *Draw frame rate is the number of repaints of this MapControl
instance that timer invokes per second.
MapControl
instance that timer invokes per second
*
* @see #applyFrameRate()
* @see #setDrawFrameRate(int)
*/
public static int getDrawFrameRate() {
return drawFrameRate;
}
/**
* Sets the draw frame rate.
* *Draw frame rate is the number of repaints of this MapControl
instance that timer invokes per second.
MapControl
instance that timer invokes per second
*
* @see #applyFrameRate()
* @see #getDrawFrameRate()
*/
public static void setDrawFrameRate(int drawFrameRate) {
MapControl.drawFrameRate = drawFrameRate;
}
/**
* Determines if its enabled the repaint that invokes the timer according to {@link #getDrawFrameRate() #getDrawFrameRate()}.
* * @returntrue
if its enabled; otherwise false
*/
public static boolean isDrawAnimationEnabled() {
return drawAnimationEnabled;
}
/**
* Sets if its enabled the repaint that invokes the timer according to {@link #getDrawFrameRate() #getDrawFrameRate()}.
* * @param drawAnimationEnabledtrue
to enable the mode; otherwise false
*/
public static void setDrawAnimationEnabled(boolean drawAnimationEnabled) {
MapControl.drawAnimationEnabled = drawAnimationEnabled;
}
/**
* Gets the shared object that determines if a drawing process must be cancelled or can continue.
* * @return the shared object that determines if a drawing process must be cancelled or can continue */ public CancelDraw getCanceldraw() { return canceldraw; } /** *Adds a new tool as combined tool.
*The new tool will be stored with the previous combined tools, and will be combined with * the current tool.
*If tool
was already stored as a combined tool, doesn't adds it.
Gets the tool used in combination with the current tool of this MapControl
.
currentMapTool
; null
if there is
* no combined tool
*/
public Behavior getCombinedTool() {
return combinedTool;
}
/**
* Sets a tool to be used in combination with the current tool of this MapControl
.
MapControl
*/
public void setCombinedTool(Behavior combinedTool) {
this.combinedTool = combinedTool;
if (currentMapTool == null)
return;
if (currentMapTool instanceof CompoundBehavior) {
((CompoundBehavior)currentMapTool).addMapBehavior(combinedTool, true);
}
else {
currentMapTool = new CompoundBehavior(new Behavior[] {currentMapTool});
((CompoundBehavior)currentMapTool).addMapBehavior(combinedTool, true);
}
}
/**
* Removes the tool used in combination with the current tool of this MapControl
.
Removes the tool tool
used in combination with the current tool of this MapControl
.