diff --git a/pom.xml b/pom.xml index 5887c5e89dd6f69ef542419c96098b47e5886504..2b353c13be437e80a0652d538e5385b88aae4acd 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ <groupId>fr.cemagref</groupId> <artifactId>observation</artifactId> - <version>0.1.3-SNAPSHOT</version> + <version>0.1.3</version> <dependencies> <dependency> @@ -62,8 +62,8 @@ <packaging>jar</packaging> <scm> - <connection>scm:svn:http://trac.clermont.cemagref.fr/svn/LISC/Observation/tags/observation-0.1.1</connection> - <url>http://trac.clermont.cemagref.fr/projets/LISC/browser/Observation/tags/observation-0.1.1</url> + <connection>scm:svn:http://trac.clermont.cemagref.fr/svn/LISC/Observation/tags/observation-0.1.3</connection> + <url>http://trac.clermont.cemagref.fr/projets/LISC/browser/Observation/tags/observation-0.1.3</url> </scm> <build> <plugins> diff --git a/src/main/java/fr/cemagref/observation/kernel/Observable.java b/src/main/java/fr/cemagref/observation/kernel/Observable.java index c87ab68a61d39ac7ae29899e5cbe2d74b1e4ec03..91d7afc0455a95c953c4b3a53d71432634c19861 100644 --- a/src/main/java/fr/cemagref/observation/kernel/Observable.java +++ b/src/main/java/fr/cemagref/observation/kernel/Observable.java @@ -1,6 +1,3 @@ -/** - * L'interface "annotation" pour marquer les observables. - */ package fr.cemagref.observation.kernel; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -19,4 +16,25 @@ public @interface Observable { * @return the textual description of the observable. */ String description(); + + /** + * Indicates the size of each dimension of the observable. If a labelsMethod + * is provided, the size will be ignored, but the number of dimensions is needed. + * + * @return + */ + int[] size() default {}; + + /** + * Indicates the name of the method to invoke for having the labels of the data. + * It is usefull, when the size of the data vector isn't a constant, but can be + * retrieved programmaticaly. + * + * The target method must accept a single <tt>Integer</tt> argument that is the dimension + * concerned. For example, if your observed data is a matrix (dimension 2), you should + * give "{0,0}" as size, and your method will return an array of labels for each dimension. + * + * @return + */ + String labelsMethod() default ""; } diff --git a/src/main/java/fr/cemagref/observation/kernel/ObservableManager.java b/src/main/java/fr/cemagref/observation/kernel/ObservableManager.java index 76cb0b3ee3a285c7aa6f02ca1ef8c6fc4c4434bb..810ce71b5602b17db3baf3d84ddfb7c487bbb615 100644 --- a/src/main/java/fr/cemagref/observation/kernel/ObservableManager.java +++ b/src/main/java/fr/cemagref/observation/kernel/ObservableManager.java @@ -2,7 +2,6 @@ package fr.cemagref.observation.kernel; import java.io.Reader; import java.util.ArrayList; -import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -14,6 +13,7 @@ import javax.swing.event.ListDataListener; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; +import java.util.HashMap; /** * TODO traduce in english @@ -28,7 +28,7 @@ public class ObservableManager implements ListModel { * se faire exclusivement via la méthode statique getObservableManager(). */ private ObservableManager() { - observables = new Hashtable<Class,ObservablesHandler>(); + observables = new HashMap<Class, ObservablesHandler>(); } /** @@ -44,10 +44,10 @@ public class ObservableManager implements ListModel { * clear method clears all class-observers associations */ public static void clear() { - for (ObservablesHandler co : om.observables.values()) { + for (ObservablesHandler co : getObservableManager().observables.values()) { co.clearObservers(); } - om.fireObservableManagerStructureChanged(); + getObservableManager().fireObservableManagerStructureChanged(); } /** @@ -129,8 +129,8 @@ public class ObservableManager implements ListModel { } public static void setObservers(Reader observablesReader, XStream xstream) { - Map<Class,ObservablesHandler> observablesReaded = (Map<Class,ObservablesHandler>) xstream.fromXML(observablesReader); - for (Map.Entry<Class,ObservablesHandler> entry : observablesReaded.entrySet()) { + Map<Class, ObservablesHandler> observablesReaded = (Map<Class, ObservablesHandler>) xstream.fromXML(observablesReader); + for (Map.Entry<Class, ObservablesHandler> entry : observablesReaded.entrySet()) { // add to the list of observers those readed from the file ObservablesHandler clObservable = addObservable(entry.getKey()); for (ObserverListener observer : entry.getValue().getObservers()) { diff --git a/src/main/java/fr/cemagref/observation/kernel/ObservablesHandler.java b/src/main/java/fr/cemagref/observation/kernel/ObservablesHandler.java index 98a805408960c0b9a34c6feff4ef11e375827929..327a5b43561ba4926d4d7a5d933799cdf451d8be 100644 --- a/src/main/java/fr/cemagref/observation/kernel/ObservablesHandler.java +++ b/src/main/java/fr/cemagref/observation/kernel/ObservablesHandler.java @@ -5,8 +5,11 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; // TODO troduce in english public class ObservablesHandler { @@ -217,9 +220,78 @@ public class ObservablesHandler { public abstract Object fetchValue(Object instance) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException; + public Object fetchValueOrNull(Object instance) { + try { + return fetchValue(instance); + } catch (IllegalArgumentException ex) { + Logger.getLogger(ObservablesHandler.class.getName()).log(Level.SEVERE, null, ex); + return null; + } catch (IllegalAccessException ex) { + Logger.getLogger(ObservablesHandler.class.getName()).log(Level.SEVERE, null, ex); + return null; + } catch (InvocationTargetException ex) { + Logger.getLogger(ObservablesHandler.class.getName()).log(Level.SEVERE, null, ex); + return null; + } + } + + /** + * Return the size of each dimension. If a "labelsMethod" is declared, it will be used, otherwise, the given sizes will be returned. See the @Observable documentation. + * @param instance + * @return + * @throws NoSuchMethodException + * @throws IllegalAccessException + * @throws IllegalArgumentException + * @throws InvocationTargetException + */ + public int[] getSizes(Object instance) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + int[] sizes; + if (getLabelsMethod().length() > 0) { + sizes = new int[getSize().length]; + for (int i = 0; i < sizes.length; i++) { + String[] localLabels = (String[]) instance.getClass().getDeclaredMethod(getLabelsMethod(), Integer.class).invoke(instance, i); + sizes[i] = (localLabels).length; + } + } else { + sizes = getSize(); + } + return sizes; + } + + public List<String>[] getLabels(Object instance) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + List<String>[] labels = new List[getSize().length]; + if (getLabelsMethod().length() > 0) { + for (int i = 0; i < getSize().length; i++) { + String[] localLabels = (String[]) instance.getClass().getDeclaredMethod(getLabelsMethod(), Integer.class).invoke(instance, i); + labels[i] = Arrays.asList(localLabels); + } + } else { + for (int i = 0; i < getSize().length; i++) { + labels[i] = new ArrayList<String>(getSize()[i]); + labels[i].add(getDeclaredName() + "[0]"); + for (int j = 1; j < getSize()[i]; j++) { + labels[i].add("[" + j + "]"); + } + } + } + return labels; + } + + public abstract Observable getAnnotation(); + public abstract String getDeclaredName(); - public abstract String getDescription(); + public String getDescription() { + return getAnnotation().description(); + } + + protected final int[] getSize() { + return getAnnotation().size(); + } + + public String getLabelsMethod() { + return getAnnotation().labelsMethod(); + } public abstract Class getDeclaredType(); } @@ -241,8 +313,8 @@ public class ObservablesHandler { } @Override - public String getDescription() { - return method.getAnnotation(Observable.class).description(); + public Observable getAnnotation() { + return method.getAnnotation(Observable.class); } @Override @@ -272,8 +344,8 @@ public class ObservablesHandler { } @Override - public String getDescription() { - return field.getAnnotation(Observable.class).description(); + public Observable getAnnotation() { + return field.getAnnotation(Observable.class); } @Override diff --git a/src/main/java/fr/cemagref/observation/observers/CSVObserver.java b/src/main/java/fr/cemagref/observation/observers/CSVObserver.java index 3791290d8e03fe3362f7da1fdcde11e5cec8c70c..668dba1ac438a55332d8963cc985855ce3d1ce11 100644 --- a/src/main/java/fr/cemagref/observation/observers/CSVObserver.java +++ b/src/main/java/fr/cemagref/observation/observers/CSVObserver.java @@ -4,67 +4,106 @@ import java.lang.reflect.InvocationTargetException; import fr.cemagref.observation.kernel.ObservablesHandler; import fr.cemagref.ohoui.annotations.Description; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; public class CSVObserver extends ConsoleObserver { - @Description(name="Field separator", tooltip="") - private char separator = ';'; - + @Description(name = "Field separator", tooltip = "") + protected char separator = ';'; + private List<String> observables; + protected transient List<ObservablesHandler.ObservableFetcher> fetchers; /** <code>classObservable</code> is used to display name of attributes as header */ private transient ObservablesHandler classObservable; + public CSVObserver() { + } + public CSVObserver(boolean sysout, String outputFile) { super(sysout, outputFile); } - + + public CSVObserver(boolean sysout, String outputFile, String... obsvervables) { + super(sysout, outputFile); + this.observables = Arrays.asList(obsvervables); + } + + public List<String> getObservables() { + return observables; + } + @Override public void addObservable(ObservablesHandler classObservable) { ObservablesHandler bak = this.classObservable; this.classObservable = classObservable; if (bak != null) // The observable has been changed + { this.init(); + } } @Override public void valueChanged(ObservablesHandler clObservable, Object instance, long t) { - StringBuffer buf = new StringBuffer(); - StringBuffer sbSeparator = new StringBuffer(" "+this.separator+" "); - // print current Time - buf.append(t); - // print value of each field - for (int i =0;i<clObservable.numberOfAttributes();i++) { - buf.append(sbSeparator); - try { - buf.append(clObservable.getObservableFetcher(i).fetchValue(instance)); - } catch (IllegalArgumentException e) { - buf.append("N/A"); - e.printStackTrace(); - } catch (IllegalAccessException e) { - buf.append("N/A"); - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - return; + if (isInDates(t)) { + StringBuffer buf = new StringBuffer(); + StringBuffer sbSeparator = new StringBuffer(" " + this.separator + " "); + // print current Time + buf.append(t); + // print value of each field + for (ObservablesHandler.ObservableFetcher fetcher : fetchers) { + buf.append(sbSeparator); + Object value = getValue(fetcher, instance); + buf.append(value == null ? "N/A" : value); } + outputStream.println(buf); + } + } + + /** + * + * @param fetcher + * @param instance + * @return the value returned by the fetcher or null if a problem has occured due to the introspection. + */ + protected Object getValue(ObservablesHandler.ObservableFetcher fetcher, Object instance) { + try { + return fetcher.fetchValue(instance); + } catch (IllegalArgumentException ex) { + Logger.getLogger(CSVObserver.class.getName()).log(Level.SEVERE, null, ex); + return null; + } catch (IllegalAccessException ex) { + Logger.getLogger(CSVObserver.class.getName()).log(Level.SEVERE, null, ex); + return null; + } catch (InvocationTargetException ex) { + Logger.getLogger(CSVObserver.class.getName()).log(Level.SEVERE, null, ex); + return null; } - outputStream.println(buf); } @Override public void init() { super.init(); if (classObservable != null) { + fetchers = new ArrayList<ObservablesHandler.ObservableFetcher>(); + if (observables != null) { + for (String name : observables) { + fetchers.add(classObservable.getObservableFetcherByName(name)); + } + } else { + fetchers.addAll(Arrays.asList(classObservable.getObservableFetchers())); + } // Headers printing StringBuffer buf = new StringBuffer(); - StringBuffer sbSeparator = new StringBuffer(" "+this.separator+" "); + StringBuffer sbSeparator = new StringBuffer(" " + this.separator + " "); buf.append("Time"); - for (int i =0;i<classObservable.numberOfAttributes();i++) { + for (ObservablesHandler.ObservableFetcher fetcher : fetchers) { buf.append(sbSeparator); - buf.append(classObservable.getDescription(i)); + buf.append(fetcher.getDescription()); } outputStream.println(buf); } } - - } diff --git a/src/main/java/fr/cemagref/observation/observers/ConsoleObserver.java b/src/main/java/fr/cemagref/observation/observers/ConsoleObserver.java index 0a8af0a0bda8819bb912d9e35fc3377ce9c4665a..a2e6e61995cdc2eb2c7aed6dbe2539186d903888 100644 --- a/src/main/java/fr/cemagref/observation/observers/ConsoleObserver.java +++ b/src/main/java/fr/cemagref/observation/observers/ConsoleObserver.java @@ -17,63 +17,77 @@ import fr.cemagref.ohoui.swing.OhOUI; import fr.cemagref.ohoui.swing.OhOUIDialog; import java.io.BufferedOutputStream; import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.List; public class ConsoleObserver implements ObserverListener, Configurable { - @Description(name="Use standard output",tooltip = "") - @Link(action="disable",target="filename") + @Description(name = "Use standard output", tooltip = "") + @Link(action = "disable", target = "filename") private boolean sysout = true; - - @Anchor(id="filename") + @Anchor(id = "filename") private File outputFile = new File(""); - private transient File outputFileBak = outputFile; protected transient PrintStream outputStream = System.out; + private List<Integer> dates; + + public ConsoleObserver() { + } public ConsoleObserver(boolean sysout, String outputFile) { this.sysout = sysout; this.outputFile = new File(outputFile); this.init(); } - + @Override public void addObservable(ObservablesHandler classObservable) { // nothing to do } + protected boolean isInDates(long date) { + return dates == null || dates.contains((int) date); + } + @Override public void valueChanged(ObservablesHandler clObservable, Object instance, long t) { - StringBuffer buf = new StringBuffer(t+" "+instance.getClass().getName() + " :\n"); - for (int i =0;i<clObservable.numberOfAttributes();i++) { - buf.append(" "+clObservable.getDescription(i)+" = "); - try { - buf.append(clObservable.getObservableFetcher(i).fetchValue(instance)); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - return; + if (isInDates(t)) { + StringBuffer buf = new StringBuffer(t + " " + instance.getClass().getName() + " :\n"); + for (int i = 0; i < clObservable.numberOfAttributes(); i++) { + buf.append(" " + clObservable.getDescription(i) + " = "); + try { + buf.append(clObservable.getObservableFetcher(i).fetchValue(instance)); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + return; + } + if (i < clObservable.numberOfAttributes() - 1) { + buf.append("\n"); + } } - if (i<clObservable.numberOfAttributes()-1) buf.append("\n"); + outputStream.println(buf); } - outputStream.println(buf); } protected void println(CharSequence message) { if (sysout) { - outputStream.print(this.getClass().getSimpleName()+" :: "); + outputStream.print(this.getClass().getSimpleName() + " :: "); } outputStream.println(message); } - + @Override public void configure() { - OhOUIDialog dialog = OhOUI.getDialog(null,this,new NoTransientField()); + OhOUIDialog dialog = OhOUI.getDialog(null, this, new NoTransientField()); dialog.setSize(new Dimension(510, 160)); dialog.setVisible(true); - if (!outputFile.equals(outputFileBak)) init(); + if (!outputFile.equals(outputFileBak)) { + init(); + } outputFileBak = outputFile; } @@ -83,20 +97,24 @@ public class ConsoleObserver implements ObserverListener, Configurable { outputStream = System.out; } else { try { + File outputDir = outputFile.getParentFile(); + if (!outputDir.exists()) { + outputDir.mkdirs(); + } // it's rather better to use a buffetred outputstream, and to disable to default buffer of the PrintStream outputStream = new PrintStream(new BufferedOutputStream(new FileOutputStream(outputFile), 1024), false); } catch (FileNotFoundException e) { - // TODO bring info to the user. Or prevent exception when directory of file doesn't exist + // TODO bring info to the user. Or prevent exception when directory of file doesn't exist e.printStackTrace(); outputStream = System.out; } - } + } } @Override public void close() { - if (outputStream != System.out) + if (outputStream != System.out) { outputStream.close(); + } } - } diff --git a/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalChart.java b/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalChart.java index a6e510d32699d88e1eb5d6658c2a7d3b0725a978..07edf10ec70929039a8820def2e9529598315e75 100644 --- a/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalChart.java +++ b/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalChart.java @@ -24,6 +24,7 @@ public abstract class TemporalChart implements ObserverListener, Configurable, D private transient JFreeChart jfchart; protected transient XYSeriesCollection dataset; protected GraphType graphType = GraphType.LINE; + protected String variableName; /** * <code>variable</code> is the variable to represent */ @@ -43,6 +44,7 @@ public abstract class TemporalChart implements ObserverListener, Configurable, D protected void variableUpdated() { if (variable != null) { + variableName = variable.getDeclaredName(); yAxisLabel = variable.getDescription(); title = titlePrefix + yAxisLabel; } @@ -136,7 +138,9 @@ public abstract class TemporalChart implements ObserverListener, Configurable, D public void init() { if (variable == null) { if (classObservable != null) { - if (classObservable.numberOfAttributes() > 0) { + if (variableName!=null) { + variable = classObservable.getObservableFetcherByName(variableName); + } else if (classObservable.numberOfAttributes() > 0) { variable = classObservable.getObservableFetcher(0); } } diff --git a/src/main/java/fr/cemagref/observation/observers/jfreechart/TwoObservablesChart.java b/src/main/java/fr/cemagref/observation/observers/jfreechart/TwoObservablesChart.java new file mode 100644 index 0000000000000000000000000000000000000000..0939310fa3e46ef6fa8547ed9234fc0af784a559 --- /dev/null +++ b/src/main/java/fr/cemagref/observation/observers/jfreechart/TwoObservablesChart.java @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2010 Cemagref + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package fr.cemagref.observation.observers.jfreechart; + +import fr.cemagref.observation.gui.Configurable; +import fr.cemagref.observation.gui.Drawable; +import fr.cemagref.observation.kernel.ObservablesHandler; +import fr.cemagref.observation.kernel.ObserverListener; +import fr.cemagref.ohoui.filters.NoTransientField; +import fr.cemagref.ohoui.swing.OUIPanel; +import fr.cemagref.ohoui.swing.OhOUI; +import fr.cemagref.ohoui.swing.OhOUIDialog; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import org.jfree.chart.ChartFactory; +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; + +/** + * + * @author Nicolas Dumoulin <nicolas.dumoulin@cemagref.fr> + */ +public class TwoObservablesChart implements ObserverListener, Configurable, Drawable { + + private transient ChartPanel chartPanel; + private transient JFreeChart jfchart; + protected transient XYSeriesCollection dataset; + protected GraphType graphType = GraphType.LINE; + protected String variableXName; + protected String variableYName; + protected transient ObservablesHandler.ObservableFetcher variableX; + protected transient ObservablesHandler.ObservableFetcher variableY; + protected transient ObservablesHandler classObservable; + private String titlePrefix = "Observation of ", title = "", xAxisLabel = "", yAxisLabel = ""; + + public TwoObservablesChart() { + super(); + graphTypeUpdated(); + } + + public TwoObservablesChart(ObservablesHandler.ObservableFetcher variableX, ObservablesHandler.ObservableFetcher variableY) { + this(); + this.variableX = variableX; + this.variableY = variableY; + variablesUpdated(); + init(); + dataset = new XYSeriesCollection(); + graphTypeUpdated(); + } + + /** + * @see fr.cemagref.observation.kernel.ObserverListener#valueChanged(fr.cemagref.observation.kernel.ObservablesHandler, java.lang.Object, int) + */ + @Override + public void valueChanged(ObservablesHandler clObservable, Object instance, long t) { + System.err.println("Value changed"); + // we fetch the value of the observable + double valueX; + double valueY; + try { + Object objectValue = variableX.fetchValue(instance); + if (objectValue instanceof Integer) { + valueX = (Integer) objectValue; + } else { + valueX = (Double) objectValue; + } + objectValue = variableY.fetchValue(instance); + if (objectValue instanceof Integer) { + valueY = (Integer) objectValue; + } else { + valueY = (Double) objectValue; + } + } catch (IllegalArgumentException e1) { + e1.printStackTrace(); + return; + } catch (IllegalAccessException e1) { + e1.printStackTrace(); + return; + } catch (InvocationTargetException e) { + e.printStackTrace(); + return; + } + int index = dataset.indexOf(instance.hashCode()); + XYSeries serie; + if (index >= 0) { + serie = dataset.getSeries(index); + } else { + // This is the first value of the observable + serie = new XYSeries(instance.hashCode()); + dataset.addSeries(serie); + } + System.err.println("hc : " + instance.hashCode()); + System.err.println("Appending (" + valueX + "," + valueY + ") on " + serie); + serie.add(valueX, valueY); + } + + protected void variablesUpdated() { + if (variableX != null) { + variableXName = variableX.getDeclaredName(); + xAxisLabel = variableX.getDescription(); + } + if (variableY != null) { + variableYName = variableY.getDeclaredName(); + yAxisLabel = variableY.getDescription(); + title = titlePrefix + yAxisLabel; + } + } + + /** + * Modify the prefix used for updating the title. By default, it is "Observation of ". + * @param prefix + */ + protected void setTitlePrefix(String prefix) { + this.titlePrefix = prefix; + } + + protected void graphTypeUpdated() { + PlotOrientation orientation = PlotOrientation.VERTICAL; + boolean legend = true; + boolean tooltips = true; + boolean urls = false; + + if (graphType.equals(GraphType.POINT)) { + jfchart = ChartFactory.createScatterPlot(title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls); + } else if (graphType.equals(GraphType.LINE)) { + jfchart = ChartFactory.createXYLineChart(title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls); + } else if (graphType.equals(GraphType.AREA)) { + jfchart = ChartFactory.createXYAreaChart(title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls); + } else if (graphType.equals(GraphType.STEP)) { + jfchart = ChartFactory.createXYStepChart(title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls); + } else if (graphType.equals(GraphType.AREASTEP)) { + jfchart = ChartFactory.createXYStepAreaChart(title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls); + } + if (chartPanel == null) { + chartPanel = new ChartPanel(jfchart); + } else { + chartPanel.setChart(jfchart); + } + } + + public JFreeChart getJfchart() { + return jfchart; + } + + @Override + public void configure() { + OhOUIDialog dialog = OhOUI.getDialog(null, this, new NoTransientField()); + // X + ObservablesHandler.ObservableFetcher variableXBak = variableX; + JComboBox comboBoxX = new JComboBox(classObservable.getDescriptions()); + if (variableX != null) { + comboBoxX.setSelectedItem(variableX.getDescription()); + } + OUIPanel ouiPanel = OUIPanel.makeLabelComponentOUIPanel(variableX, comboBoxX, "Variable for X", ""); + dialog.getContentPane().add(ouiPanel.getPanel(), 0); + // Y + ObservablesHandler.ObservableFetcher variableYBak = variableY; + JComboBox comboBoxY = new JComboBox(classObservable.getDescriptions()); + if (variableY != null) { + comboBoxY.setSelectedItem(variableY.getDescription()); + } + ouiPanel = OUIPanel.makeLabelComponentOUIPanel(variableY, comboBoxY, "Variable for Y", ""); + dialog.getContentPane().add(ouiPanel.getPanel(), 1); + // pack + dialog.pack(); + dialog.setVisible(true); + variableX = classObservable.getObservableFetcher((String) comboBoxX.getSelectedItem()); + if (variableX != null) { + if (!variableX.equals(variableXBak)) { + variablesUpdated(); + } + } + variableY = classObservable.getObservableFetcher((String) comboBoxY.getSelectedItem()); + if (variableY != null) { + if (!variableY.equals(variableYBak)) { + variablesUpdated(); + } + } + graphTypeUpdated(); + } + + @Override + public void addObservable(ObservablesHandler classObservable) { + this.classObservable = classObservable; + } + + @Override + public JComponent getDisplay() { + return chartPanel; + } + + @Override + public String getTitle() { + return title; + } + + @Override + public void init() { + if (variableX == null) { + if (classObservable != null) { + if (variableXName != null) { + variableX = classObservable.getObservableFetcherByName(variableXName); + } else if (classObservable.numberOfAttributes() > 0) { + variableX = classObservable.getObservableFetcher(0); + } + } + dataset = new XYSeriesCollection(); + graphTypeUpdated(); + } + if (variableY == null) { + if (classObservable != null) { + if (variableYName != null) { + variableY = classObservable.getObservableFetcherByName(variableYName); + } else if (classObservable.numberOfAttributes() > 1) { + variableY = classObservable.getObservableFetcher(1); + } + } + dataset = new XYSeriesCollection(); + graphTypeUpdated(); + } + } + + /** + * @see fr.cemagref.observation.kernel.ObserverListener#close() + */ + @Override + public void close() { + } +}