/* ========================
* 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
*
* $Id: Abstract2DShape.java,v 1.28 2008/10/23 15:36:36 ogor Exp $
*
* Changes
* -------
* 21-Oct-2003 : Initial version (NB);
*
*/
package jsynoptic.builtin;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import jsynoptic.builtin.ui.PropertiesPanel2D;
import simtools.data.DataSource;
import simtools.data.DataSourcePool;
import simtools.data.EndNotificationListener;
import simtools.data.UnsupportedOperation;
import simtools.shapes.AbstractShape;
import simtools.ui.ColorMapper;
import simtools.ui.JPropertiesPanel;
import simtools.ui.ResourceFinder;
/**
* Base class for Polygons and Ellipses
*/
public abstract class Abstract2DShape extends Abstract1DShape{
static final long serialVersionUID = -251037943033567016L;
public static ResourceBundle resources = ResourceFinder.get(Abstract2DShape.class);
protected Color fillColor = null;
protected transient Color fillDynamicColor = null;
protected ColorMapper fillMapper;
protected transient DataSource fillMapperSource;
protected transient long fillMapperIndex;
protected transient boolean dirtyFillColor = false;
public Abstract2DShape(int ox, int oy, int width, int height) {
super(ox, oy, width, height);
fillColor = null;
}
/**
* 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(){
Abstract2DShape clone = (Abstract2DShape)super.cloneShape();
if(clone!=null){
if(clone.fillMapperSource!=null){
clone.fillMapperSource.addListener(clone);
clone.fillMapperSource.addEndNotificationListener(clone.delegateEndNotificationListener);
}
return clone;
}
return null;
}
/* (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(transform.getTransform());
}
fillHook(g);
drawHook(g, false);
//stroke
g.setStroke(stroke);
Color c = getDrawColor();
if (c!=null) {
g.setColor(c);
Shape delegateShape = getDelegateShape();
if(delegateShape!=null){
g.draw(delegateShape);
}
}
drawHook(g, true);
if(oldTransform!=null){
g.setTransform(oldTransform);
}
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antialiasHint);
g.setBackground(oldBackground);
g.setColor(oldColor);
g.setStroke(oldStroke);
}
/**
* A hook to fill this Abstract2D shape
* @param g the graphics
*/
protected void fillHook(Graphics2D g) {
Color c = getFillColor();
if (c!=null) {
g.setColor(c);
Shape delegateShape = getDelegateShape();
if (delegateShape != null){
g.fill(delegateShape);
}
}
}
/* (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 Abstract2DShapePropertiesNames().getPropertyNames()))){
return new PropertiesPanel2D(Builtin.resources.getString("2DShape"));
} else {
return super.getPanel(properties);
}
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#getShapeName()
*/
public String getShapeName(){
return Builtin.resources.getString("2DShape");
}
/* (non-Javadoc)
* @see jsynoptic.builtin.Abstract1DShape#setDelegateEndNotificationListener(simtools.data.EndNotificationListener)
*/
public void setDelegateEndNotificationListener(EndNotificationListener denl) {
if (fillMapperSource != null) {
fillMapperSource.removeEndNotificationListener(delegateEndNotificationListener);
fillMapperSource.addEndNotificationListener(denl);
}
super.setDelegateEndNotificationListener(denl);
}
/* (non-Javadoc)
* @see simtools.data.EndNotificationListener#notificationEnd(java.lang.Object)
*/
public void notificationEnd(Object referer) {
// care about the fill color
if (dirtyFillColor) {
dirtyFillColor = false; // for the check below
// Get the new color
Color c = null;
if (fillMapper!=null) {
c = (Color)fillMapper.getPaint(fillMapperSource, fillMapperIndex);
}
// repaint only if necessary
if (c==null) {
dirtyFillColor = (fillDynamicColor!=null);
} else {
dirtyFillColor = !c.equals(fillDynamicColor);
}
fillDynamicColor = c;
// Repaint our area if the color changed, do a redraw only when necessary => see parent
dirty |= dirtyFillColor;
dirtyFillColor = false; // for next time
}
// parent tasks, including notification of our own change
super.notificationEnd(referer);
}
public Color getFillColor(){
return (fillDynamicColor!=null) ? fillDynamicColor : fillColor;
}
protected void setFillColor(Color fillColor){
this.fillColor = fillColor;
}
protected void setFillMapperSource(DataSource ds){
if(fillMapperSource != null) {
fillMapperSource.removeListener(this);
fillMapperSource.removeEndNotificationListener(delegateEndNotificationListener);
}
if ( (fillColor!=null)) {
fillMapperSource = ds;
if (fillMapperSource != null){
try {
fillMapperIndex = fillMapperSource.getLastIndex();
} catch (UnsupportedOperation e) {
fillMapperIndex = 0;
}
fillMapperSource.addListener(this);
fillMapperSource.addEndNotificationListener(delegateEndNotificationListener);
}
} else{
fillMapperSource = null;
}
if (fillMapper!=null && fillMapperSource!=null) {
fillDynamicColor = (Color)fillMapper.getPaint(fillMapperSource, fillMapperIndex);
} else {
fillDynamicColor = null;
}
}
/* (non-Javadoc)
* @see simtools.data.DataSourceListener#DataSourceIndexRangeChanged(simtools.data.DataSource, long, long)
*/
public void DataSourceIndexRangeChanged(DataSource ds, long startIndex, long lastIndex) {
if (ds.equals(this.fillMapperSource)) {
fillMapperIndex = lastIndex;
dirtyFillColor = true;
}
super.DataSourceIndexRangeChanged(ds, startIndex, lastIndex);
}
/* (non-Javadoc)
* @see simtools.data.DataSourceListener#DataSourceValueChanged(simtools.data.DataSource, long, long)
*/
public void DataSourceValueChanged(DataSource ds, long minIndex, long maxIndex) {
if (ds.equals(this.fillMapperSource)) {
// We care only about our index value change
if ((fillMapperIndex >= minIndex) && (fillMapperIndex <= maxIndex)) dirtyFillColor = true;
}
super.DataSourceValueChanged(ds, minIndex, maxIndex);
}
/* (non-Javadoc)
* @see simtools.data.DataSourceListener#DataSourceReplaced(simtools.data.DataSource, simtools.data.DataSource)
*/
public void DataSourceReplaced(DataSource oldData, DataSource newData) {
if(oldData==fillMapperSource){
fillMapperSource=newData;
if (fillMapperSource!=null) try {
fillMapperSource.addListener(this);
fillMapperSource.addEndNotificationListener(delegateEndNotificationListener);
fillMapperIndex = fillMapperSource.getLastIndex();
}
catch (UnsupportedOperation uo1) {
fillMapperIndex = 0;
}
oldData.removeListener(this);
oldData.removeEndNotificationListener(delegateEndNotificationListener);
dirtyFillColor = true;
}
super.DataSourceReplaced(oldData,newData);
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#subscribeToDataNotifications()
*/
public void processShapeRestoring(){
if (fillMapperSource != null) {
fillMapperSource.addListener(this);
fillMapperSource.addEndNotificationListener(delegateEndNotificationListener);
try {
fillMapperIndex = fillMapperSource.getLastIndex();
} catch (UnsupportedOperation uo1) {
fillMapperIndex = 0;
}
}
super.processShapeRestoring();
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#unsubscribeToDataNotifications()
*/
public void processShapeRemoving(){
if (fillMapperSource != null) {
fillMapperSource.removeListener(this);
fillMapperSource.removeEndNotificationListener(delegateEndNotificationListener);
}
super.processShapeRemoving();
}
// 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, fillMapperSource);
}
private void readObject(java.io.ObjectInputStream in) throws java.lang.ClassNotFoundException, java.io.IOException {
in.defaultReadObject();
fillMapperSource = DataSourcePool.global.readDataSource(in);
if (fillMapperSource!=null) try {
fillMapperSource.addListener(this);
fillMapperSource.addEndNotificationListener(delegateEndNotificationListener);
fillMapperIndex = fillMapperSource.getLastIndex();
}
catch (UnsupportedOperation uo1) {
fillMapperIndex = 0;
}
if (fillMapper != null) {
fillMapper = ColorMapper.updateColorMapper(fillMapper);
}
if (fillMapper!=null && fillMapperSource!=null) {
fillDynamicColor = (Color)fillMapper.getPaint(fillMapperSource, fillMapperIndex);
}
else fillDynamicColor = null;
}
public void setPropertyValue(String name, Object value) {
super.setPropertyValue(name, value);
if(name.equalsIgnoreCase("FILL_COLOR")) {
setFillColor( (value instanceof Color)? (Color)value : null);
} else if(name.equalsIgnoreCase("FILL_MAPPER")) {
if ( (fillColor!=null) && (value instanceof ColorMapper)) {
fillMapper = (ColorMapper)value;
}
else{
fillMapper = null;
}
} else if(name.equalsIgnoreCase("FILL_MAPPER_SOURCE")) {
setFillMapperSource( (DataSource)value);
}
}
public String[] getPropertyNames(){
if (_propertyNames==null)
_propertyNames = new Abstract2DShapePropertiesNames().getPropertyNames();
return _propertyNames;
}
public Object getPropertyValue(String name) {
Object res = super.getPropertyValue(name); // NULL if not supported by above class
if(name.equalsIgnoreCase("FILL_COLOR")) {
res = fillColor;
} else if(name.equalsIgnoreCase("FILL_MAPPER")) {
res = fillMapper;
} else if(name.equalsIgnoreCase("FILL_MAPPER_SOURCE")) {
res = fillMapperSource;
}
return res;
}
public static class Abstract2DShapePropertiesNames extends Abstract1DShapePropertiesNames{
private static transient String[] props = new String[] { "FILL_COLOR", "FILL_MAPPER", "FILL_MAPPER_SOURCE" };
public Abstract2DShapePropertiesNames(){
super();
for (int i=0;i<props.length;i++){
propertyNames.add(props[i]);
}
}
}
}