/* ========================
* 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: BarShape.java,v 1.3 2009/01/09 10:01:42 ogor Exp $
*
* Changes
* -------
* 15 juil. 2008 : Initial public release (CC);
*
*/
package jsynoptic.builtin;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
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.ResourceBundle;
import javax.swing.undo.CompoundEdit;
import jsynoptic.base.DataSourceConsumer;
import jsynoptic.builtin.ui.BarPropertiesPanel;
import simtools.data.DataException;
import simtools.data.DataInfo;
import simtools.data.DataSource;
import simtools.data.DataSourcePool;
import simtools.data.EndNotificationListener;
import simtools.data.UnsupportedOperation;
import simtools.diagram.DiagramSelection;
import simtools.shapes.AbstractShape;
import simtools.shapes.AxisShape;
import simtools.shapes.AxisShape.AxePropertiesNames;
import simtools.shapes.undo.PropertyChangeEdit;
import simtools.ui.JPropertiesPanel;
import simtools.ui.ResourceFinder;
/**
*
* The Bar shape is a 2D shape composed of
* <ul>
* <li> A rectangle
* <li> A horizontal axis
* </ul>
* @author zxpletran007
*
*/
public class BarShape extends Abstract2DShape implements
DataSourceConsumer,
EndNotificationListener {
private static final long serialVersionUID = -7151431866068790164L;
public static ResourceBundle resources = ResourceFinder.get(BarShape.class);
public static final String barAxisId = "barAxis";
protected RectangleShape rectangle;
protected AxisShape axis;
/**
* Axis step.
*/
protected double step;
/**
* Axis min.
*/
protected double min;
/**
* Axis max.
*/
protected double max;
/**
* Axis validity
*/
protected boolean validity;
/**
* If true autoscale axis range
*/
protected boolean auto;
/**
* Axis label
*/
protected String label;
/**
* Bar data source
*/
protected transient DataSource progressSource;
public BarShape(int ox, int oy, int width, int height) {
super(ox, oy, width, height);
// Rectangle
rectangle = new RectangleShape(ox, oy, width, height);
// Axis
axis = new AxisShape(false,true,_ox,_oy ,width, height);
axis.setWithGridlines(true);
axis.setWithAxis(false); // do not display axis line
validity = false;
auto = true;
updateBarBounds();
}
/**
* When axis is auto-scaled, update axis range according
* to progress data source min and max values.
*/
protected void updateAxisRange() {
if ( (!validity) && (progressSource!=null) && auto) {
try {
double min = progressSource.getDoubleMin();
double max = progressSource.getDoubleMax();
if(min == max){
min--;
max++;
}
double step = Plot.computeStep(min, max,Plot.preferredXGraduation); // use of Plot static method for step computing...
validity = true;
setAxisRange(min, max, step);
} catch (UnsupportedOperation uo) {} catch (DataException e) {
}
}
}
protected void setAxisRange(double min, double max, double step){
this.min= min;
this.max= max;
this.step= step;
axis.set(min, max, step);
rectangle.setProgressMin(min);
rectangle.setProgressMax(max);
updateBarBounds();
}
protected void setAxisLabel(String label){
this.label = label;
axis.setLabel(label);
updateBarBounds();
}
/**
* Translates the shape
*/
public void translate(int dx, int dy) {
super.translate(dx, dy);
rectangle.translate(dx, dy);
axis.translate(dx, dy);
}
public void resize(int dx, int dy) {
rectangle.resize(dx, dy);
updateBarBounds();
}
protected void updateBarBounds(){
if (rectangle != null){
rectangle.updateBounds();
Rectangle r = rectangle.getBounds();
axis.setSize(r.width, r.height);
boolean isVertical = r.height > r.width;
if (isVertical != axis.isVertical()){
axis.setVertical(isVertical);
}
r.add(axis.getBounds());
_w = r.width;
_h = r.height;
_x = r.x - _ox;
_y = r.y + _h - _oy;
}
updateBounds();
}
public void draw(Graphics2D g) {
rectangle.draw(g);
axis.draw(g);
}
/*
* (non-Javadoc)
*
* @see jsynoptic.base.DataSourceConsumer#addDataSource(simtools.data.DataSource)
*/
public boolean addDataSource(DataSource d) {
if (rectangle.getFillColor() == null){
rectangle.setFillColor(Color.DARK_GRAY);
}
setSource(d);
return true;
}
/*
* (non-Javadoc)
*
* @see jsynoptic.base.DataSourceConsumer#canAddDataSource(simtools.data.DataSource)
*/
public boolean canAddDataSource(DataSource d) {
return true;
}
/**
* @param ds
*/
public void setSource(DataSource ds) {
rectangle.setSource(ds);
if (progressSource != null) {
progressSource.removeEndNotificationListener(this);
progressSource=null;
}
progressSource = ds;
if (progressSource != null){
progressSource.addEndNotificationListener(this);
}
// Set label
setAxisLabel(DataInfo.getLabel(progressSource));
// Set range
updateAxisRange();
notifyChange(null);
}
public void notificationEnd(Object referer) {
if (referer == progressSource){
dirty = true;
if (auto){
validity = false;
updateAxisRange();
}
}
notifyChange(null);
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#subscribeToDataNotifications()
*/
public void processShapeRestoring(){
axis.processShapeRestoring();
rectangle.processShapeRestoring();
if (progressSource!=null) {
progressSource.addEndNotificationListener(this);
}
super.processShapeRestoring();
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#unsubscribeToDataNotifications()
*/
public void processShapeRemoving(){
axis.processShapeRemoving();
rectangle.processShapeRemoving();
if (progressSource != null) {
progressSource.removeEndNotificationListener(this);
}
super.processShapeRemoving();
}
protected AbstractShape cloneShape() {
BarShape es = (BarShape)super.cloneShape();
es.rectangle = (RectangleShape)rectangle.cloneShape();
es.axis = (AxisShape)axis.cloneShape();
es.setSource(progressSource);
return es;
}
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();
progressSource = DataSourcePool.global.readDataSource(in);
if (progressSource!=null) {
progressSource.addEndNotificationListener(this);
}
}
/* (non-Javadoc)
* @see jsynoptic.builtin.RectangleShape#getPropertyNames()
*/
public String[] getPropertyNames(){
if (_propertyNames==null)
_propertyNames = new BarShapePropertiesNames().getPropertyNames();
return _propertyNames;
}
public void setPropertyValue(String name, Object value) {
rectangle.setPropertyValue(name, value);
if (name.equalsIgnoreCase("PROGRESS_SOURCE")) {
setSource( (value instanceof DataSource)? (DataSource)value : null);
} else if (name.endsWith("_OK") && (value instanceof Boolean)) {
validity = ((Boolean)value).booleanValue();
} else if (name.endsWith("_GRID") && (value instanceof Boolean)) {
axis.setWithGridlines( ((Boolean)value).booleanValue() );
} else if (name.endsWith("_DASHEDGRID") && (value instanceof Boolean)) {
axis.setWithDashedGrid( ((Boolean)value).booleanValue() );
} else if (name.endsWith("_AUTO")&& (value instanceof Boolean)) {
auto = ((Boolean)value).booleanValue();
} else if (name.endsWith("_LOG")&& (value instanceof Boolean)) {
// TODO
} else if (name.endsWith("_MIN")&& (value instanceof Double)) {
min = ((Double)value).doubleValue();
} else if (name.endsWith("_MAX")&& (value instanceof Double)) {
max = ((Double)value).doubleValue();
} else if (name.endsWith("_STEP")&& (value instanceof Double)) {
step = ((Double)value).doubleValue();
} else if ((name.endsWith("_LABEL"))) {
if (value instanceof String){
setAxisLabel((String)value);
}
// Last property: update bar size and notify changes
if (!auto){
setAxisRange(min, max, step);
}
updateBarBounds();
notifyChange(null);
}
}
public LinkedHashMap getCollectiveActions(DiagramSelection sel, double x, double y, Object o, int context) {
LinkedHashMap res = super.getCollectiveActions(sel, x, y, o, context);
// Bar shapes are not able to be rotated
res.remove(Abstract1DShape.resources.getString("rotation") + ";" + Abstract1DShape.resources.getString("leftRotation"));
res.remove(Abstract1DShape.resources.getString("rotation") + ";" + Abstract1DShape.resources.getString("rightRotation"));
return res;
}
public Object getPropertyValue(String name) {
Object ret = rectangle.getPropertyValue(name);
if (ret == null){
if (name.endsWith("_OK")) {
ret = new Boolean (validity);
} else if (name.endsWith("_GRID")) {
ret = new Boolean (axis.isWithGridlines());
} else if (name.endsWith("_DASHEDGRID")) {
ret = new Boolean (axis.isWithDashedGrid());
} else if (name.endsWith("_AUTO")) {
ret = new Boolean (auto);
}
else if (name.endsWith("_LOG")) {
}
else if (name.endsWith("_MIN")) {
ret = new Double(min);
} else if (name.endsWith("_MAX")) {
ret = new Double(max);
} else if (name.endsWith("_STEP")) {
ret = new Double(step);
} else if ((name.endsWith("_LABEL"))) {
ret = label;
}
}
return ret;
}
public static class BarShapePropertiesNames extends Abstract2DShapePropertiesNames{
public BarShapePropertiesNames(){
super();
propertyNames.add("PROGRESS_SOURCE");
String[] ap = new AxePropertiesNames(barAxisId).getPropertyNames();
for (int i=0;i<ap.length;i++){
propertyNames.add(ap[i]);
}
}
}
public boolean doAction(double x, double y, Object o, String action, CompoundEdit undoableEdit) {
boolean res;
if (action.equals(resources.getString("setSource"))) {
// Save old params
CompoundEdit ce = new CompoundEdit();
HashMap oldValues = new HashMap();
oldValues.put("PROGRESS_SOURCE", progressSource);
oldValues.put("FILL_COLOR", rectangle.getFillColor());
addDataSource((DataSource)o);
// 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);
}
res = true;
} else {
res = super.doAction(x,y,o,action, undoableEdit);
}
return res;
}
/* (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 BarShapePropertiesNames().getPropertyNames()))){
return new BarPropertiesPanel(Builtin.resources.getString("Bar"));
} else {
return super.getPanel(properties);
}
}
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;
}
ArrayList v = new ArrayList();
if ( (context == EDITOR_CONTEXT) && (o instanceof DataSource)){
v.add(resources.getString("setSource"));
}
return (String[])v.toArray(new String[v.size()]);
}
/* (non-Javadoc)
* @see jsynoptic.builtin.Abstract1DShape#getDelegateShape()
*/
protected Shape getDelegateShape() {
return null;
}
}