/* ========================
* 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-2005, by :
* Corporate:
* EADS Astrium SAS
* EADS CRC
* Individual:
* Claude Cazenave
*
* $Id: RectangleShape.java,v 1.10 2008/09/05 12:23:22 ogor Exp $
*
* Changes
* -------
* 7 juil. 2005 : Initial public release (CC);
*
*/
package jsynoptic.builtin;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Rectangle2D;
import java.util.Arrays;
import java.util.List;
import jsynoptic.builtin.ui.RectanglePropertiesPanel;
import simtools.data.DataException;
import simtools.data.DataSource;
import simtools.data.DataSourcePool;
import simtools.data.UnsupportedOperation;
import simtools.shapes.AbstractShape;
import simtools.ui.JPropertiesPanel;
/**
* The Rectangle shape handles rectangle with an optional variable fill area (progress bar)
*/
public class RectangleShape extends Abstract2DShape {
protected transient Rectangle2D.Double rec;
protected transient Rectangle2D.Double fillrec;
protected double min;
protected double max;
protected transient DataSource progressSource;
protected transient long progressSourceIndex;
protected transient double progressValue;
protected transient boolean dirtyProgress = false;
static final long serialVersionUID = 967626544275691745L;
/**
* @param ox
* @param oy
* @param width
* @param height
*/
public RectangleShape(int ox, int oy, int width, int height) {
super(ox, oy, width, height);
allowResize = true;
fixedRatio = false;
rec = new Rectangle2D.Double(ox, oy-_h, width-1, height-1);
fillrec = new Rectangle2D.Double();
min = 0;
max = 1;
progressValue = 0;
}
/* (non-Javadoc)
* @see jsynoptic.builtin.SimpleShape#getDelegateShape()
*/
protected Shape getDelegateShape() {
return rec;
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#translate(int, int)
*/
public void translate(int dx, int dy) {
super.translate(dx, dy);
rec.x+=dx;
rec.y+=dy;
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#setAnchor(int, int)
*/
public void setAnchor(int ox, int oy) {
super.setAnchor(ox, oy);
rec.x=ox;
rec.y=oy-_h;
}
/* (non-Javadoc)
* @see simtools.diagram.Resizable#resize(int, int)
*/
public void resize(int dx, int dy) {
super.resize(dx, dy);
rec.x=_ox; rec.y=_oy-_h;
rec.height=_h-1; rec.width=_w-1;
}
/**
* A hook to fill this Rectangle shape
* @param g the graphics
*/
protected void fillHook(Graphics2D g) {
if(progressSource==null){
super.fillHook(g);
}
else{
Color c = (fillDynamicColor!=null) ? fillDynamicColor : fillColor;
if (c!=null) {
g.setColor(c);
// check if vertical or horizontal
if(_h<_w){ // horizontal
fillrec.y=rec.y;
fillrec.height=rec.height;
if(max>min){
fillrec.width=computeLength(rec.width);
fillrec.x=rec.x;
}
else{
fillrec.width=computeLength(rec.width);
fillrec.x=rec.x+rec.width-fillrec.width;
}
}
else{ // vertical
fillrec.x=rec.x;
fillrec.width=rec.width;
if(max>min){
fillrec.height=computeLength(rec.height);
fillrec.y=rec.y + rec.height - fillrec.height;
}
else{
fillrec.height =computeLength(rec.height);
fillrec.y = rec.y;
}
}
g.fill(fillrec);
}
}
}
protected double computeLength(double baseLength){
double res=baseLength;
if(max>min){
res=(progressValue-min)/(max-min)*res;
}
else if (max<min){
res=(progressValue-max)/(min-max)*res;
}
// saturate
if(res<0.){
res=0;
}
if(res>baseLength){
res=baseLength;
}
return res;
}
/* (non-Javadoc)
* @see jsynoptic.builtin.Abstract2DShape#getPanel(java.util.List)
*/
public JPropertiesPanel getPanel(List properties) {
if (properties == null){
return null;
}
if (properties.containsAll(Arrays.asList(new RectangleShapePropertiesNames().getPropertyNames()))){
return new RectanglePropertiesPanel(Builtin.resources.getString("Rectangle"));
} else {
return super.getPanel(properties);
}
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#getShapeName()
*/
public String getShapeName(){
return Builtin.resources.getString("Rectangle");
}
protected void setProgressMin(double min){
this.min = min;
}
protected void setProgressMax(double max){
this.max = max;
}
/**
* Update the value of the progressive bar
* @return - true if it was modified, false otherwise => repaint only when necessary
*/
protected boolean updateProgress() {
double s;
if(progressSource!=null){
try {
s = progressSource.getDoubleValue(progressSourceIndex);
} catch (DataException de) {
s = progressValue;
}
}else{
s = progressValue;
}
boolean res= (s!=progressValue);
progressValue=s;
return res;
}
/* (non-Javadoc)
* @see simtools.data.EndNotificationListener#notificationEnd(java.lang.Object)
*/
public void notificationEnd(Object referer) {
if (dirtyProgress) {
dirty |= updateProgress();
dirtyProgress = false;
}
// parent for colors & update
super.notificationEnd(referer);
}
/* (non-Javadoc)
* @see simtools.data.DataSourceListener#DataSourceIndexRangeChanged(simtools.data.DataSource, long, long)
*/
public void DataSourceValueChanged(DataSource ds, long minIndex, long maxIndex) {
if (ds.equals(progressSource)) {
if ((progressSourceIndex >= minIndex) && (progressSourceIndex <= maxIndex)){
dirtyProgress = true;
}
}
super.DataSourceValueChanged(ds, minIndex, maxIndex);
}
/* (non-Javadoc)
* @see simtools.data.DataSourceListener#DataSourceValueChanged(simtools.data.DataSource, long, long)
*/
public void DataSourceIndexRangeChanged(DataSource ds, long startIndex, long lastIndex) {
if (ds.equals(progressSource)) {
progressSourceIndex = lastIndex;
dirtyProgress = true;
}
super.DataSourceIndexRangeChanged(ds, startIndex, lastIndex);
}
/* (non-Javadoc)
* @see simtools.data.DataSourceListener#DataSourceReplaced(simtools.data.DataSource, simtools.data.DataSource)
*/
public void DataSourceReplaced(DataSource oldData, DataSource newData) {
if(oldData==progressSource){
progressSource=newData;
if (progressSource!=null){
progressSource.addListener(this);
progressSource.addEndNotificationListener(this);
try {
progressSourceIndex = progressSource.getLastIndex();
}
catch (UnsupportedOperation uo1) {
progressSourceIndex = 0;
}
}
oldData.removeListener(this);
oldData.removeEndNotificationListener(this);
dirtyProgress = true;
}
super.DataSourceReplaced(oldData,newData);
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#subscribeToDataNotifications()
*/
public void processShapeRestoring(){
if (progressSource!=null) {
progressSource.addListener(this);
progressSource.addEndNotificationListener(this);
try {
progressSourceIndex = progressSource.getLastIndex();
} catch (UnsupportedOperation uo1) {
progressSourceIndex = 0;
}
}
super.processShapeRestoring();
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#unsubscribeToDataNotifications()
*/
public void processShapeRemoving(){
if (progressSource != null) {
progressSource.removeListener(this);
progressSource.removeEndNotificationListener(this);
}
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, progressSource);
}
private void readObject(java.io.ObjectInputStream in) throws java.lang.ClassNotFoundException, java.io.IOException {
in.defaultReadObject();
rec = new Rectangle2D.Double(_ox, _oy-_h, _w-1, _h-1);
fillrec = new Rectangle2D.Double();
progressSource = DataSourcePool.global.readDataSource(in);
if (progressSource!=null) try {
progressSource.addListener(this);
progressSource.addEndNotificationListener(this);
progressSourceIndex = progressSource.getLastIndex();
}
catch (UnsupportedOperation uo1) {
progressSourceIndex = 0;
}
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#cloneShape()
*/
protected AbstractShape cloneShape() {
RectangleShape es = (RectangleShape)super.cloneShape();
es.rec = (Rectangle2D.Double)rec.clone();
es.fillrec = (Rectangle2D.Double)fillrec.clone();
if(es.progressSource!=null){
es.progressSource.addEndNotificationListener(es);
es.progressSource.addListener(es);
}
return es;
}
public String[] getPropertyNames(){
if (_propertyNames==null)
_propertyNames = new RectangleShapePropertiesNames().getPropertyNames();
return _propertyNames;
}
public void setSource(DataSource ds) {
if (progressSource != null) {
progressSource.removeListener(this);
progressSource.removeEndNotificationListener(this);
progressSource=null;
}
progressSource = ds;
if (progressSource == null) {
return;
}
try {
progressSourceIndex = progressSource.getLastIndex();
} catch (UnsupportedOperation e) {
progressSourceIndex = 0;
}
try {
progressValue = progressSource.getDoubleValue(progressSourceIndex);
} catch (DataException e) {
}
progressSource.addListener(this);
progressSource.addEndNotificationListener(this);
}
public void setPropertyValue(String name, Object value) {
super.setPropertyValue(name, value);
if(name.equalsIgnoreCase("PROGRESS_MIN")) {
if(value instanceof Double) {
setProgressMin( ((Double)value).doubleValue() );
}
} else if(name.equalsIgnoreCase("PROGRESS_MAX")) {
if(value instanceof Double) {
setProgressMax( ((Double)value).doubleValue() );
}
} else if(name.equalsIgnoreCase("PROGRESS_SOURCE")) {
setSource( (value instanceof DataSource)? (DataSource)value : null);
// Finally, update rectangle shape (on last property set)
rec.x=_ox;
rec.y=_oy-_h;
rec.height=_h-1;
rec.width=_w-1;
}
}
public Object getPropertyValue(String name) {
Object res = super.getPropertyValue(name);
if(name.equalsIgnoreCase("PROGRESS_MIN")) {
res=new Double(min);
} else if(name.equalsIgnoreCase("PROGRESS_MAX")) {
res=new Double(max);
} else if(name.equalsIgnoreCase("PROGRESS_SOURCE")) {
res=progressSource;
}
return res;
}
public static class RectangleShapePropertiesNames extends Abstract2DShapePropertiesNames{
private static transient String[] props = new String[] { "PROGRESS_MIN", "PROGRESS_MAX", "PROGRESS_SOURCE" };
public RectangleShapePropertiesNames(){
super();
for (int i=0;i<props.length;i++){
propertyNames.add(props[i]);
}
}
}
}