com.mxgraph.swing.handler.mxCellMarker Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jgraphx Show documentation
Show all versions of jgraphx Show documentation
JGraphX Swing Component - Java Graph Visualization Library
This is a binary & source redistribution of the original, unmodified JGraphX library originating from:
"https://github.com/jgraph/jgraphx/archive/v3.4.1.3.zip".
The purpose of this redistribution is to make the library available to other Maven projects.
/**
* $Id: mxCellMarker.java,v 1.22 2012/01/13 13:14:42 david Exp $
* Copyright (c) 2008-2012, JGraph Ltd
*/
package com.mxgraph.swing.handler;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseEvent;
import javax.swing.JComponent;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.swing.util.mxSwingConstants;
import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxEvent;
import com.mxgraph.util.mxEventObject;
import com.mxgraph.util.mxEventSource;
import com.mxgraph.util.mxEventSource.mxIEventListener;
import com.mxgraph.util.mxUtils;
import com.mxgraph.view.mxCellState;
import com.mxgraph.view.mxGraphView;
/**
* Implements a mouse tracker that marks cells under the mouse.
*
* This class fires the following event:
*
* mxEvent.MARK fires in mark and unmark to notify the listener of a new cell
* under the mouse. The state
property contains the mxCellState
* of the respective cell or null if no cell is under the mouse.
*
* To create a cell marker which highlights cells "in-place", the following
* code can be used:
*
* mxCellMarker highlighter = new mxCellMarker(graphComponent) {
*
* protected Map lastStyle;
*
* public mxCellState process(MouseEvent e)
* {
* mxCellState state = null;
*
* if (isEnabled())
* {
* state = getState(e);
* boolean isValid = (state != null) ? isValidState(state) : false;
*
* if (!isValid)
* {
* state = null;
* }
*
* highlight(state);
* }
*
* return state;
* }
*
* public void highlight(mxCellState state)
* {
* if (validState != state)
* {
* Rectangle dirty = null;
*
* if (validState != null)
* {
* validState.setStyle(lastStyle);
* dirty = validState.getBoundingBox().getRectangle();
* dirty.grow(4, 4);
* }
*
* if (state != null)
* {
* lastStyle = state.getStyle();
* state.setStyle(new Hashtable(state.getStyle()));
* state.getStyle().put("strokeColor", "#00ff00");
* state.getStyle().put("fontColor", "#00ff00");
* state.getStyle().put("strokeWidth", "3");
*
* Rectangle tmp = state.getBoundingBox().getRectangle();
*
* if (dirty != null)
* {
* dirty.add(tmp);
* }
* else
* {
* dirty = tmp;
* }
*
* dirty.grow(4, 4);
* }
*
* validState = state;
* graphComponent.repaint(dirty);
* }
* }
*
* public void reset()
* {
* highlight(null);
* }
*
* public void paint(Graphics g)
* {
* // do nothing
* }
* };
*
* graphComponent.getConnectionHandler().setMarker(highlighter);
*
*/
public class mxCellMarker extends JComponent
{
/**
*
*/
private static final long serialVersionUID = 614473367053597572L;
/**
* Specifies if the highlights should appear on top of everything
* else in the overlay pane. Default is false.
*/
public static boolean KEEP_ON_TOP = false;
/**
* Specifies the default stroke for the marker.
*/
public static Stroke DEFAULT_STROKE = new BasicStroke(3);
/**
* Holds the event source.
*/
protected mxEventSource eventSource = new mxEventSource(this);
/**
* Holds the enclosing graph component.
*/
protected mxGraphComponent graphComponent;
/**
* Specifies if the marker is enabled. Default is true.
*/
protected boolean enabled = true;
/**
* Specifies the portion of the width and height that should trigger
* a highlight. The area around the center of the cell to be marked is used
* as the hotspot. Possible values are between 0 and 1. Default is
* mxConstants.DEFAULT_HOTSPOT.
*/
protected double hotspot;
/**
* Specifies if the hotspot is enabled. Default is false.
*/
protected boolean hotspotEnabled = false;
/**
* Specifies if the the content area of swimlane should be non-transparent
* to mouse events. Default is false.
*/
protected boolean swimlaneContentEnabled = false;
/**
* Specifies the valid- and invalidColor for the marker.
*/
protected Color validColor, invalidColor;
/**
* Holds the current marker color.
*/
protected transient Color currentColor;
/**
* Holds the marked state if it is valid.
*/
protected transient mxCellState validState;
/**
* Holds the marked state.
*/
protected transient mxCellState markedState;
/**
* Constructs a new marker for the given graph component.
*
* @param graphComponent
*/
public mxCellMarker(mxGraphComponent graphComponent)
{
this(graphComponent, mxSwingConstants.DEFAULT_VALID_COLOR);
}
/**
* Constructs a new marker for the given graph component.
*/
public mxCellMarker(mxGraphComponent graphComponent, Color validColor)
{
this(graphComponent, validColor, mxSwingConstants.DEFAULT_INVALID_COLOR);
}
/**
* Constructs a new marker for the given graph component.
*/
public mxCellMarker(mxGraphComponent graphComponent, Color validColor,
Color invalidColor)
{
this(graphComponent, validColor, invalidColor,
mxConstants.DEFAULT_HOTSPOT);
}
/**
* Constructs a new marker for the given graph component.
*/
public mxCellMarker(mxGraphComponent graphComponent, Color validColor,
Color invalidColor, double hotspot)
{
this.graphComponent = graphComponent;
this.validColor = validColor;
this.invalidColor = invalidColor;
this.hotspot = hotspot;
}
/**
* Sets the enabled state of the marker.
*/
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
/**
* Returns true if the marker is enabled, that is, if it processes events
* in process.
*/
public boolean isEnabled()
{
return enabled;
}
/**
* Sets the hotspot.
*/
public void setHotspot(double hotspot)
{
this.hotspot = hotspot;
}
/**
* Returns the hotspot.
*/
public double getHotspot()
{
return hotspot;
}
/**
* Specifies whether the hotspot should be used in intersects.
*/
public void setHotspotEnabled(boolean enabled)
{
this.hotspotEnabled = enabled;
}
/**
* Returns true if hotspot is used in intersects.
*/
public boolean isHotspotEnabled()
{
return hotspotEnabled;
}
/**
* Sets if the content area of swimlanes should not be transparent to
* events.
*/
public void setSwimlaneContentEnabled(boolean swimlaneContentEnabled)
{
this.swimlaneContentEnabled = swimlaneContentEnabled;
}
/**
* Returns true if the content area of swimlanes is non-transparent to
* events.
*/
public boolean isSwimlaneContentEnabled()
{
return swimlaneContentEnabled;
}
/**
* Sets the color used for valid highlights.
*/
public void setValidColor(Color value)
{
validColor = value;
}
/**
* Returns the color used for valid highlights.
*/
public Color getValidColor()
{
return validColor;
}
/**
* Sets the color used for invalid highlights.
*/
public void setInvalidColor(Color value)
{
invalidColor = value;
}
/**
* Returns the color used for invalid highlights.
*/
public Color getInvalidColor()
{
return invalidColor;
}
/**
* Returns true if validState is not null.
*/
public boolean hasValidState()
{
return (validState != null);
}
/**
* Returns the valid state.
*/
public mxCellState getValidState()
{
return validState;
}
/**
* Sets the current color.
*/
public void setCurrentColor(Color value)
{
currentColor = value;
}
/**
* Returns the current color.
*/
public Color getCurrentColor()
{
return currentColor;
}
/**
* Sets the marked state.
*/
public void setMarkedState(mxCellState value)
{
markedState = value;
}
/**
* Returns the marked state.
*/
public mxCellState getMarkedState()
{
return markedState;
}
/**
* Resets the state of the cell marker.
*/
public void reset()
{
validState = null;
if (markedState != null)
{
markedState = null;
unmark();
}
}
/**
* Processes the given event and marks the state returned by getStateAt
* with the color returned by getMarkerColor. If the markerColor is not
* null, then the state is stored in markedState. If isValidState returns
* true, then the state is stored in validState regardless of the marker
* color. The state is returned regardless of the marker color and
* valid state.
*/
public mxCellState process(MouseEvent e)
{
mxCellState state = null;
if (isEnabled())
{
state = getState(e);
boolean valid = (state != null) ? isValidState(state) : false;
Color color = getMarkerColor(e, state, valid);
highlight(state, color, valid);
}
return state;
}
/**
*
*/
public void highlight(mxCellState state, Color color)
{
highlight(state, color, true);
}
/**
*
*/
public void highlight(mxCellState state, Color color, boolean valid)
{
if (valid)
{
validState = state;
}
else
{
validState = null;
}
if (state != markedState || color != currentColor)
{
currentColor = color;
if (state != null && currentColor != null)
{
markedState = state;
mark();
}
else if (markedState != null)
{
markedState = null;
unmark();
}
}
}
/**
* Marks the markedState and fires a mxEvent.MARK event.
*/
public void mark()
{
if (markedState != null)
{
Rectangle bounds = markedState.getRectangle();
bounds.grow(3, 3);
bounds.width += 1;
bounds.height += 1;
setBounds(bounds);
if (getParent() == null)
{
setVisible(true);
if (KEEP_ON_TOP)
{
graphComponent.getGraphControl().add(this, 0);
}
else
{
graphComponent.getGraphControl().add(this);
}
}
repaint();
eventSource.fireEvent(new mxEventObject(mxEvent.MARK, "state",
markedState));
}
}
/**
* Hides the marker and fires a mxEvent.MARK event.
*/
public void unmark()
{
if (getParent() != null)
{
setVisible(false);
getParent().remove(this);
eventSource.fireEvent(new mxEventObject(mxEvent.MARK));
}
}
/**
* Returns true if the given state is a valid state. If this returns true,
* then the state is stored in validState. The return value of this method
* is used as the argument for getMarkerColor.
*/
protected boolean isValidState(mxCellState state)
{
return true;
}
/**
* Returns the valid- or invalidColor depending on the value of isValid.
* The given state is ignored by this implementation.
*/
protected Color getMarkerColor(MouseEvent e, mxCellState state,
boolean isValid)
{
return (isValid) ? validColor : invalidColor;
}
/**
* Uses getCell, getMarkedState and intersects to return the state for
* the given event.
*/
protected mxCellState getState(MouseEvent e)
{
Object cell = getCell(e);
mxGraphView view = graphComponent.getGraph().getView();
mxCellState state = getStateToMark(view.getState(cell));
return (state != null && intersects(state, e)) ? state : null;
}
/**
* Returns the state at the given location. This uses mxGraph.getCellAt.
*/
protected Object getCell(MouseEvent e)
{
return graphComponent.getCellAt(e.getX(), e.getY(),
swimlaneContentEnabled);
}
/**
* Returns the state to be marked for the given state under the mouse. This
* returns the given state.
*/
protected mxCellState getStateToMark(mxCellState state)
{
return state;
}
/**
* Returns true if the given mouse event intersects the given state. This
* returns true if the hotspot is 0 or the event is inside the hotspot for
* the given cell state.
*/
protected boolean intersects(mxCellState state, MouseEvent e)
{
if (isHotspotEnabled())
{
return mxUtils.intersectsHotspot(state, e.getX(), e.getY(),
hotspot, mxConstants.MIN_HOTSPOT_SIZE,
mxConstants.MAX_HOTSPOT_SIZE);
}
return true;
}
/**
* Adds the given event listener.
*/
public void addListener(String eventName, mxIEventListener listener)
{
eventSource.addListener(eventName, listener);
}
/**
* Removes the given event listener.
*/
public void removeListener(mxIEventListener listener)
{
eventSource.removeListener(listener);
}
/**
* Removes the given event listener for the specified event name.
*/
public void removeListener(mxIEventListener listener, String eventName)
{
eventSource.removeListener(listener, eventName);
}
/**
* Paints the outline of the markedState with the currentColor.
*/
public void paint(Graphics g)
{
if (markedState != null && currentColor != null)
{
((Graphics2D) g).setStroke(DEFAULT_STROKE);
g.setColor(currentColor);
if (markedState.getAbsolutePointCount() > 0)
{
Point last = markedState.getAbsolutePoint(0).getPoint();
for (int i = 1; i < markedState.getAbsolutePointCount(); i++)
{
Point current = markedState.getAbsolutePoint(i).getPoint();
g.drawLine(last.x - getX(), last.y - getY(), current.x
- getX(), current.y - getY());
last = current;
}
}
else
{
g.drawRect(1, 1, getWidth() - 3, getHeight() - 3);
}
}
}
}