/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info: http://jsynoptic.sourceforge.net/index.html
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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.
*
* (C) Copyright 2001-2003, by :
* Corporate:
* Astrium SAS
* EADS CRC
* Individual:
* Nicolas Brodu
* Jean-Baptiste Lièvremont
*
* $Id: Abstract1DShape.java,v 1.40 2009/01/08 15:07:58 ogor Exp $
*
* Changes
* -------
* 23-Oct-2003 : Initial version (NB);
*
*/
package jsynoptic.builtin;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Vector;
import javax.swing.undo.CompoundEdit;
import jsynoptic.base.ContextualActionProvider;
import jsynoptic.base.Linkable;
import jsynoptic.base.SelectionContextualActionProvider;
import jsynoptic.builtin.ui.PropertiesPanel1D;
import jsynoptic.ui.JSynoptic;
import jsynoptic.ui.LongAction;
import simtools.data.DataInfo;
import simtools.data.DataSource;
import simtools.data.DataSourceListener;
import simtools.data.DataSourcePool;
import simtools.data.EndNotificationListener;
import simtools.data.UnsupportedOperation;
import simtools.diagram.DiagramSelection;
import simtools.shapes.AbstractShape;
import simtools.shapes.StrokeParameters;
import simtools.shapes.ui.AbstractShapePropertiesDialogBox;
import simtools.shapes.undo.PropertyChangeEdit;
import simtools.ui.ColorMapper;
import simtools.ui.JPropertiesPanel;
import simtools.ui.ResourceFinder;
import simtools.ui.SourceTree;
import simtools.ui.MenuResourceBundle;
/**
* Base class for Lines and the 2D shapes (Polygons and Ellipses)
*/
public abstract class Abstract1DShape extends AbstractShape implements simtools.diagram.Resizable, DataSourceListener,
EndNotificationListener, Linkable, AffineTransformData.Listener, ContextualActionProvider, SelectionContextualActionProvider {
static final long serialVersionUID = 1292256994785217201L;
public static MenuResourceBundle resources = ResourceFinder.getMenu(Abstract1DShape.class);
protected Color drawColor = Color.black;
protected transient Color drawDynamicColor = null;
protected ColorMapper drawMapper;
protected transient DataSource drawMapperSource;
protected transient long drawMapperIndex;
protected boolean allowResize;
protected boolean fixedRatio;
protected double ratio;
// Linkable shape
protected String link;
protected transient boolean dirtyDrawColor = false; // state of the draw
// color
protected transient boolean dirty = false; // children may want repaint
// even if draw color in clean
protected transient Rectangle dirtyRectangle = null;
protected transient Stroke stroke = null;
// stroke
protected StrokeParameters strokeParams;
protected AffineTransformData transform = null;
protected transient Rectangle2D.Double bounds2D = new Rectangle2D.Double();
// See comments in set/get methods
protected transient EndNotificationListener delegateEndNotificationListener;
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
protected void setDrawColor(Color drawColor){
this.drawColor = drawColor;
}
protected void setDrawMapperSource(DataSource ds){
if(drawMapperSource != null) {
drawMapperSource.removeListener(this);
drawMapperSource.removeEndNotificationListener(delegateEndNotificationListener);
}
if ( (drawColor!=null)) {
drawMapperSource = ds;
if (drawMapperSource != null){
try {
drawMapperIndex = drawMapperSource.getLastIndex();
} catch (UnsupportedOperation e) {
drawMapperIndex = 0;
}
drawMapperSource.addListener(this);
drawMapperSource.addEndNotificationListener(delegateEndNotificationListener);
}
} else{
drawMapperSource = null;
}
if (drawMapperSource!=null && drawMapper!=null) {
drawDynamicColor = (Color)drawMapper.getPaint(drawMapperSource, drawMapperIndex);
} else {
drawDynamicColor = null;
}
}
public Abstract1DShape(int ox, int oy, int width, int height) {
super(ox, oy);
delegateEndNotificationListener = this; // by default
_w = width;
_h = height;
strokeParams = new StrokeParameters();
stroke = strokeParams.createStroke();
allowResize = true;
updateBounds();
ratio = (double)_w / (double)_h;
}
public void setAnchor(int ox, int oy) {
super.setAnchor(ox, oy);
updateBounds();
}
public void translate(int dx, int dy) {
super.translate(dx, dy);
if (transform != null) {
updateTransform();
} else {
updateBounds();
}
}
/*
* (non-Javadoc)
*
* @see jsynoptic.builtin.AffineTransformData.Listener#updateTransform()
*/
public void updateTransform() {
transform.updateTransform(_ox + _x + _w / 2, _oy + _y - _h / 2);
if (dirtyRectangle == null) {
dirtyRectangle = getBounds();
}
updateBounds();
dirty = true;
notificationEnd(transform);
}
protected void updateBounds() {
if (transform == null) {
bounds2D.x = _ox + _x - ((drawColor != null) ? strokeParams.thickness / 2 : 0);
bounds2D.y = _oy + _y - _h - ((drawColor != null) ? strokeParams.thickness / 2 : 0);
bounds2D.width = _w + ((drawColor != null) ? strokeParams.thickness : 0);
bounds2D.height = _h + ((drawColor != null) ? strokeParams.thickness : 0);
} else {
transform.updateBounds(_ox + _x - (int) ((drawColor != null) ? strokeParams.thickness / 2 : 0), _oy + _y
- _h - (int) ((drawColor != null) ? strokeParams.thickness / 2 : 0), _ox + _x + _w
+ (int) ((drawColor != null) ? strokeParams.thickness / 2 : 0), _oy + _y
+ (int) ((drawColor != null) ? strokeParams.thickness / 2 : 0), bounds2D);
}
}
/**
* Performs a copy of the shape This method has to be overriden to deal with
* concrete shapes
*
* @return a copy of the shape
*/
protected AbstractShape cloneShape() {
Abstract1DShape clone = (Abstract1DShape) super.cloneShape();
clone.delegateEndNotificationListener = clone;
if (clone != null) {
if (clone.drawMapperSource != null) {
clone.drawMapperSource.addListener(clone);
clone.drawMapperSource.addEndNotificationListener(clone.delegateEndNotificationListener);
}
clone.strokeParams = new StrokeParameters(strokeParams);
clone.stroke = clone.strokeParams.createStroke();
if (clone.transform != null) {
clone.transform = transform.cloneTransform();
clone.transform.setListener(clone);
}
clone.bounds2D = new Rectangle2D.Double();
clone.updateBounds();
return clone;
}
return null;
}
protected abstract Shape getDelegateShape();
public boolean contains(double x, double y) {
return bounds2D.contains(x, y);
}
public boolean contains(double x, double y, double w, double h) {
return bounds2D.contains(x, y, w, h);
}
public boolean contains(Point2D p) {
return bounds2D.contains(p);
}
public boolean contains(Rectangle2D r) {
return bounds2D.contains(r);
}
public boolean intersects(double x, double y, double w, double h) {
return bounds2D.intersects(x, y, w, h);
}
public boolean intersects(Rectangle2D r) {
return bounds2D.intersects(r);
}
public Rectangle getBounds() {
return bounds2D.getBounds();
}
public Rectangle2D getBounds2D() {
return bounds2D.getBounds2D();
}
public PathIterator getPathIterator(AffineTransform at) {
return getDelegateShape().getPathIterator(at);
}
public PathIterator getPathIterator(AffineTransform at, double flatness) {
return getDelegateShape().getPathIterator(at, flatness);
}
/**
* For subclasses, called before restoring original graphics properties,
* after the delegate shape is drawn if shapeDrawn is true, or after saving
* the current context, before the delegate shape is drawn if shapeDrawn is
* false
*/
protected void drawHook(Graphics2D g, boolean shapeDrawn) {
}
/*
* (non-Javadoc)
*
* @see simtools.shapes.AbstractShape#draw(java.awt.Graphics2D)
*/
public void draw(Graphics2D g) {
Color oldColor = g.getColor();
Color oldBackground = g.getBackground();
Stroke oldStroke = g.getStroke();
Object antialiasHint = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
AbstractShape.ANTI_ALIASING ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
AffineTransform oldTransform = null;
if (transform != null) {
oldTransform = g.getTransform();
g.transform(getTransform());
}
drawHook(g, false);
// stroke
g.setStroke(stroke);
Color c = getDrawColor();
if (c != null) {
g.setColor(c);
Shape s = getDelegateShape();
if (s != null) {
g.draw(s);
}
}
drawHook(g, true);
if (oldTransform != null) {
g.setTransform(oldTransform);
}
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antialiasHint);
g.setBackground(oldBackground);
g.setColor(oldColor);
g.setStroke(oldStroke);
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#getTransform()
*/
public AffineTransform getTransform(){
AffineTransform res = null;
if (transform != null){
res = transform.getTransform();
} else {
res = super.getTransform();
}
return res;
}
/* (non-Javadoc)
* @see jsynoptic.base.ContextualActionProvider#getActions(double, double, java.lang.Object, int)
*/
public String[] getActions(double x, double y, Object o, int context) {
if (context == MOUSE_OVER_CONTEXT) {
return null;
}
if (context == MOUSE_OUT_CONTEXT) {
return null;
}
if (context == MOUSE_PRESSED_CONTEXT) {
return null;
}
if (context == EDITOR_CONTEXT) {
}
Vector v = new Vector();
return (String[]) v.toArray(new String[v.size()]);
}
public LinkedHashMap getCollectiveActions(DiagramSelection sel, double x, double y, Object o, int context) {
LinkedHashMap res = new LinkedHashMap();
res.put(resources.getString("properties"), null);
res.put(resources.getString("rotation") + ";" + resources.getString("leftRotation"), resources
.getIcon("leftRotationImage"));
res.put(resources.getString("rotation") + ";" + resources.getString("rightRotation"), resources
.getIcon("rightRotationImage"));
return res;
}
/* (non-Javadoc)
* @see jsynoptic.base.SelectionContextualActionProvider#doAction(simtools.diagram.DiagramSelection, double, double, java.lang.Object, java.lang.String, javax.swing.undo.CompoundEdit)
*/
public boolean doCollectiveAction(DiagramSelection sel, double x, double y, Object o, String action, CompoundEdit undoableEdit){
boolean res = false;
Vector v = sel.getSelectedElements();
if (!v.isEmpty()) {
res = true;
if (action.equals(resources.getString("properties"))) {
doPropertiesAction(sel.getShapes());
} else {
// do action for all selected shapes
for(int i=0; i < v.size(); i++) {
Object element = v.get(i);
if (element instanceof Abstract1DShape){
res &= ((Abstract1DShape)element).doAction(x, y, o, action, undoableEdit);
}
}
}
}
return res;
}
/*
* (non-Javadoc)
*
* @see jsynoptic.base.ContextualActionProvider#doAction(double, double,
* java.lang.Object, java.lang.String)
*/
public boolean doAction(double x, double y, Object o, String action, CompoundEdit undoableEdit) {
if (action.equals(resources.getString("properties"))) {
List shapes = new ArrayList();
shapes.add(this);
doPropertiesAction(shapes);
} else if (action.equals(resources.getString("rotation") + ";" + resources.getString("rightRotation"))) {
// Save old params
CompoundEdit ce = new CompoundEdit();
HashMap oldValues = new HashMap();
oldValues.put("TRANSFORM", getPropertyValue("TRANSFORM"));
// Make changes
if (transform == null) {
transform = new AffineTransformData(this);
}
transform.rotEnabled = true;
transform.rotValue = ((transform.rotValue * transform.angleUnitScale) + Math.PI / 2)
/ transform.angleUnitScale;
setPropertyValue("TRANSFORM", transform);
// Notify changes
Iterator it = oldValues.keySet().iterator();
while (it.hasNext()) {
String n = (String) it.next();
ce.addEdit(new PropertyChangeEdit(this, n, oldValues.get(n), getPropertyValue(n)));
}
ce.end();
if (undoableEdit != null) {
undoableEdit.addEdit(ce);
}
} else if (action.equals(resources.getString("rotation") + ";" + resources.getString("leftRotation"))) {
// Save old params
CompoundEdit ce = new CompoundEdit();
HashMap oldValues = new HashMap();
oldValues.put("TRANSFORM", getPropertyValue("TRANSFORM"));
// Make changes
if (transform == null) {
transform = new AffineTransformData(this);
}
transform.rotEnabled = true;
transform.rotValue = ((transform.rotValue * transform.angleUnitScale) - Math.PI / 2)
/ transform.angleUnitScale;
setPropertyValue("TRANSFORM", transform);
// Notify changes
Iterator it = oldValues.keySet().iterator();
while (it.hasNext()) {
String n = (String) it.next();
ce.addEdit(new PropertyChangeEdit(this, n, oldValues.get(n), getPropertyValue(n)));
}
ce.end();
if (undoableEdit != null) {
undoableEdit.addEdit(ce);
}
}
return false;
}
/*
* (non-Javadoc)
*
* @see jsynoptic.base.ContextualActionProvider#canDoAction(double, double,
* java.lang.Object, java.lang.String, int)
*/
public boolean canDoAction(double x, double y, Object o, String action, int context) {
return true;
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#getPanel(java.util.List)
*/
public JPropertiesPanel getPanel(List properties) {
if (properties == null){
return null;
}
if (properties.containsAll(Arrays.asList(new Abstract1DShapePropertiesNames().getPropertyNames()))){
return new PropertiesPanel1D(Builtin.resources.getString("1DShape"));
} else {
return super.getPanel(properties);
}
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#getShapeName()
*/
public String getShapeName(){
return Builtin.resources.getString("1DShape");
}
/**
* Set the properties related to a list of shapes.
*
* @param shapes
*/
protected void doPropertiesAction(List shapes){
new LongAction(LongAction.LONG_ACTION_SHAPE, shapes, this) {
protected void doAction() {
List shapes = (List)param;
// Get the set of properties which can be applied to the selection
List properties = AbstractShape.getCommonProperties(shapes);
SourceTree.getFromPool("PropertiesPanel0").removeAllTreeSelectionListeners();
// Get the panel related to this set of properties
JPropertiesPanel panel = getPanel(properties);
if (panel != null){
/*
* Only one shape properties dialog box can be displayed at
* once When user opens a dialog box properties while
* another one is still displayed: this last dislaog box is
* closed
*/
Point oldLocation = null;
if (currentDialogBox != null) {
oldLocation = currentDialogBox.getBounds().getLocation();
currentDialogBox.dispose();
}
// Create properties dialog
AbstractShapePropertiesDialogBox optionDialog = new AbstractShapePropertiesDialogBox(
JSynoptic.gui.getOwner(),
panel,
panel.getShapeName() + resources.getString("propertiesTitle"),
shapes,
JSynoptic.gui.getActiveComponent()
);
if (oldLocation != null) {
optionDialog.setLocation(oldLocation);
}
currentDialogBox = optionDialog;
// Show dialog box
optionDialog.setVisible(true);
} else {
JSynoptic.gui.setStatus(resources.getString("noProperties"));
}
}
}.start();
}
public Color getDrawColor(){
return (drawDynamicColor!=null) ? drawDynamicColor : drawColor;
}
/**
* This is useful if this shape belongs to an array of multiple text shapes,
* in which cas it is better to register the delegate si is is notified only
* once at each notification end Note1 : take care of read Objects too Note2 :
* don't forget to use this shape default handler if necessary
*
* @return Returns the delegateEndNotificationListener.
*/
public EndNotificationListener getDelegateEndNotificationListener() {
return delegateEndNotificationListener;
}
/**
* This is useful if this shape belongs to an array of multiple text shapes,
* in which cas it is better to register the delegate if is is notified only
* once at each notification end Note1 : take care of read Objects too Note2 :
* don't forget to use this shape default handler if necessary
*
* @param delegateEndNotificationListener
* The delegateEndNotificationListener to set.
*/
public void setDelegateEndNotificationListener(EndNotificationListener denl) {
if (drawMapperSource != null) {
drawMapperSource.removeEndNotificationListener(this.delegateEndNotificationListener);
drawMapperSource.addEndNotificationListener(denl);
}
delegateEndNotificationListener = denl;
}
/*
* (non-Javadoc)
*
* @see simtools.data.EndNotificationListener#notificationEnd(java.lang.Object)
*/
public void notificationEnd(Object referer) {
if (dirtyDrawColor) {
dirtyDrawColor = false; // for the check below
// Get the new color
Color c = null;
if (drawMapper != null) {
c = (Color) drawMapper.getPaint(drawMapperSource, drawMapperIndex);
}
// repaint only if necessary
if (c == null) {
dirtyDrawColor = (drawDynamicColor != null);
} else {
dirtyDrawColor = !c.equals(drawDynamicColor);
}
drawDynamicColor = c;
dirty |= dirtyDrawColor; // force repaint if color is dirty
dirtyDrawColor = false; // for next time
}
// Repaint our area if something changed, do a redraw only when
// necessary
if (dirty) {
notifyChange(dirtyRectangle); // may have been set by children
dirtyRectangle = null; // take all bounds next time
dirty = false;
}
}
/*
* (non-Javadoc)
*
* @see simtools.data.DataSourceListener#DataSourceIndexRangeChanged(simtools.data.DataSource,
* long, long)
*/
public void DataSourceIndexRangeChanged(DataSource ds, long startIndex, long lastIndex) {
// Only care for our source, defer notification of the change to our own
// listeners when all
// listener events are done (see EndNotificationListener interface)
if (ds.equals(this.drawMapperSource)) {
drawMapperIndex = lastIndex;
// Wait till all sources have changed before reading the new value
// => the mapper source
// may not be refreshed yet
dirtyDrawColor = true;
}
}
/*
* (non-Javadoc)
*
* @see simtools.data.DataSourceListener#DataSourceInfoChanged(simtools.data.DataSource,
* simtools.data.DataInfo)
*/
public void DataSourceInfoChanged(DataSource ds, DataInfo newInfo) {
// don't care about this one
}
/*
* (non-Javadoc)
*
* @see simtools.data.DataSourceListener#DataSourceOrderChanged(simtools.data.DataSource,
* int)
*/
public void DataSourceOrderChanged(DataSource ds, int newOrder) {
// don't care about this one
}
/*
* (non-Javadoc)
*
* @see simtools.data.DataSourceListener#DataSourceValueChanged(simtools.data.DataSource,
* long, long)
*/
public void DataSourceValueChanged(DataSource ds, long minIndex, long maxIndex) {
// Only care for our source, defer notification of the change to our own
// listeners when all
// listener events are done (see EndNotificationListener interface)
if (ds.equals(this.drawMapperSource)) {
// We care only about our index value change
if ((drawMapperIndex < minIndex) || (drawMapperIndex > maxIndex)) {
return;
}
// Wait till all sources have changed before reading the new value
// => the mapper source
// may not be refreshed yet
dirtyDrawColor = true;
}
}
/*
* (non-Javadoc)
*
* @see simtools.data.DataSourceListener#DataSourceReplaced(simtools.data.DataSource,
* simtools.data.DataSource)
*/
public void DataSourceReplaced(DataSource oldData, DataSource newData) {
if (oldData == drawMapperSource) {
drawMapperSource = newData;
if (drawMapperSource != null) {
drawMapperSource.addListener(this);
drawMapperSource.addEndNotificationListener(delegateEndNotificationListener);
try {
drawMapperIndex = drawMapperSource.getLastIndex();
} catch (UnsupportedOperation uo1) {
drawMapperIndex = 0;
}
}
oldData.removeListener(this);
oldData.removeEndNotificationListener(delegateEndNotificationListener);
dirtyDrawColor = true;
}
}
/*
* (non-Javadoc)
*
* @see simtools.data.DataSourceListener#DataSourceValueRangeChanged(simtools.data.DataSource)
*/
public void DataSourceValueRangeChanged(DataSource ds) {
// don't care about this one
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#subscribeToDataNotifications()
*/
public void processShapeRestoring(){
if (drawMapperSource != null) {
drawMapperSource.addListener(this);
drawMapperSource.addEndNotificationListener(delegateEndNotificationListener);
try {
drawMapperIndex = drawMapperSource.getLastIndex();
} catch (UnsupportedOperation uo1) {
drawMapperIndex = 0;
}
}
if (transform != null) {
transform.subscribeToDataNotifications();
}
super.processShapeRestoring();
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#unsubscribeToDataNotifications()
*/
public void processShapeRemoving(){
if (drawMapperSource != null) {
drawMapperSource.removeListener(this);
drawMapperSource.removeEndNotificationListener(delegateEndNotificationListener);
}
if (transform != null) {
transform.unsubscribeToDataNotifications();
}
super.processShapeRemoving();
}
/**
* Allow resize: it is possible to forbid shape resizing even the allow resize property has been set to true by user.
* For instance, resizing is not allowed when a rotation has been applied to the shape
* Overload canResize method in sub classes if needed.
*
* @return true if shape can be resized.
*/
protected boolean canResize() {
if (transform != null) {
return (allowResize && !transform.rotEnabled);
}
return allowResize;
}
/*
* (non-Javadoc)
*
* @see simtools.diagram.Resizable#resize(int, int)
*/
public void resize(int dx, int dy) {
if (canResize()) {
if (!fixedRatio) {
_w += dx;
_h += dy;
if (_w < MIN_SIZE) {
_w = MIN_SIZE;
}
if (_h < MIN_SIZE) {
_h = MIN_SIZE;
}
if (transform != null) {
updateTransform();
} else {
updateBounds();
}
} else {
_w += dx;
_h += dy;
double dw;
if (dy > 0) {
dw = Math.max(_w, _h * ratio);
} else if (dy < 0) {
dw = Math.min(_w, _h * ratio);
} else {
dw = _w;
}
_w = (int) dw;
_h = (int) (dw / ratio);
if (_w < MIN_SIZE) {
_w = MIN_SIZE;
}
if (_h < MIN_SIZE) {
_h = MIN_SIZE;
}
if (transform != null) {
updateTransform();
} else {
updateBounds();
}
}
}
}
public int getDx(int dx) {
if (_w + dx < MIN_SIZE) {
return (_w - MIN_SIZE);
}
return dx;
}
public int getDy(int dy) {
if (_h + dy < MIN_SIZE) {
return (_h - MIN_SIZE);
}
return dy;
}
// Take care of serialisation. Special handling for datasources
private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
out.defaultWriteObject();
DataSourcePool.global.writeDataSource(out, drawMapperSource);
}
private void readObject(java.io.ObjectInputStream in) throws java.lang.ClassNotFoundException, java.io.IOException {
in.defaultReadObject();
delegateEndNotificationListener = this;
drawMapperSource = DataSourcePool.global.readDataSource(in);
if (drawMapperSource != null) {
try {
drawMapperSource.addListener(this);
drawMapperSource.addEndNotificationListener(delegateEndNotificationListener);
drawMapperIndex = drawMapperSource.getLastIndex();
} catch (UnsupportedOperation uo1) {
drawMapperIndex = 0;
}
}
if (drawMapper != null) {
drawMapper = ColorMapper.updateColorMapper(drawMapper);
}
if ((drawMapper != null) && (drawMapperSource != null)) {
drawDynamicColor = (Color) drawMapper.getPaint(drawMapperSource, drawMapperIndex);
} else {
drawDynamicColor = null;
}
if (strokeParams == null) {
strokeParams = new StrokeParameters();
}
stroke = strokeParams.createStroke();
bounds2D = new Rectangle2D.Double();
// Update geometric transformation and bounding box
if (transform != null) {
updateTransform();
} else {
updateBounds();
}
// Update ratio
ratio = (double)_w / (double)_h;
}
public void setPropertyValue(String name, Object value) {
super.setPropertyValue(name, value);
if (name.equalsIgnoreCase("STROKE_COLOR")) {
setDrawColor( (value instanceof Color)? (Color) value : null);
} else if (name.equalsIgnoreCase("ALLOW_RESIZE")) {
if (value instanceof Boolean) {
allowResize = ((Boolean) value).booleanValue();
}
} else if (name.equalsIgnoreCase("FIXED_RATIO")) {
if (value instanceof Boolean) {
fixedRatio = ((Boolean) value).booleanValue();
}
} else if (name.equalsIgnoreCase("WIDTH")) {
if (value instanceof Integer) {
_w = ((Integer) value).intValue();
// Update ratio
ratio = (double)_w / (double)_h;
}
} else if (name.equalsIgnoreCase("HEIGHT")) {
if (value instanceof Integer) {
_h = ((Integer) value).intValue();
// Update ratio
ratio = (double)_w / (double)_h;
}
} else if (name.equalsIgnoreCase("DRAW_MAPPER")) {
// If drawColor is null, draw mapper shall be disabled
if ((drawColor != null) && (value instanceof ColorMapper)) {
drawMapper = (ColorMapper) value;
} else {
drawMapper = null;
}
} else if (name.equalsIgnoreCase("DRAW_MAPPER_SOURCE")) {
setDrawMapperSource((DataSource)value);
} else if (name.equalsIgnoreCase("STROKE_PARAMS")) {
if (value instanceof StrokeParameters) {
strokeParams = ((StrokeParameters) value);
stroke = StrokeParameters
.createStroke(strokeParams.param1, strokeParams.param2, strokeParams.thickness);
}
} else if (name.equalsIgnoreCase("TRANSFORM")) {
if (transform != null) {
transform.unsubscribeToDataNotifications();
transform = null;
}
if (value instanceof AffineTransformData) {
transform = ((AffineTransformData) value).cloneTransform(); // add data listeners
transform.setListener(this); // shape listen to the change
// release the cloned transform
((AffineTransformData) value).unsubscribeToDataNotifications();
updateTransform();
} else {
updateBounds();
}
}
// Update the shape's appearance
notifyChange(null);
}
public String[] getPropertyNames() {
if (_propertyNames == null) {
_propertyNames = new Abstract1DShapePropertiesNames().getPropertyNames();
}
return _propertyNames;
}
public Object getPropertyValue(String name) {
Object res = super.getPropertyValue(name);
if (name.equalsIgnoreCase("STROKE_COLOR")) {
res = drawColor;
} else if (name.equalsIgnoreCase("ALLOW_RESIZE")) {
res = new Boolean(allowResize);
} else if (name.equalsIgnoreCase("FIXED_RATIO")) {
res = new Boolean(fixedRatio);
} else if (name.equalsIgnoreCase("WIDTH")) {
res = new Integer(_w);
} else if (name.equalsIgnoreCase("HEIGHT")) {
res = new Integer(_h);
} else if (name.equalsIgnoreCase("DRAW_MAPPER")) {
res = drawMapper;
} else if (name.equalsIgnoreCase("DRAW_MAPPER_SOURCE")) {
res = drawMapperSource;
} else if (name.equalsIgnoreCase("STROKE_PARAMS")) {
res = strokeParams;
} else if (name.equalsIgnoreCase("TRANSFORM")) {
if (transform != null) {
res = transform.cloneTransform(false); // don't add data
// listeners
} else {
res = null;
}
}
return res;
}
public static class Abstract1DShapePropertiesNames extends AbstractShapePropertiesNames {
private static transient String[] props = new String[] {
"STROKE_COLOR",
"ALLOW_RESIZE",
"FIXED_RATIO",
"WIDTH",
"HEIGHT",
"DRAW_MAPPER",
"DRAW_MAPPER_SOURCE",
"STROKE_PARAMS",
"TRANSFORM" };
public Abstract1DShapePropertiesNames() {
super();
for (int i = 0; i < props.length; i++) {
propertyNames.add(props[i]);
}
}
}
}