/*
* Plotter.java
*
* Created on January 22, 2002, 3:08 PM
*/
package hep.aida.ref.plotter;
import hep.aida.IPlotter;
import hep.aida.IPlotterRegion;
import hep.aida.IPlotterStyle;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import org.freehep.application.PropertyUtilities;
import org.freehep.swing.Headless;
import org.freehep.util.export.ExportFileType;
/**
* A dummy implementation of an AIDA Plotter, useful in batch jobs where no
* graphical output is required.
* @author tonyj
* @version $Id: DummyPlotter.java 13006 2007-07-13 22:59:05Z serbo $
*/
public class DummyPlotter implements IPlotter {
private ArrayList parameters = new ArrayList();
private ArrayList parOptions = new ArrayList();
private ArrayList parValues = new ArrayList();
private ArrayList parDefaults = new ArrayList();
protected IPlotterStyle plotterStyle = new PlotterStyle();
private static final String[] emptyArray = new String[0];
private List regions = new ArrayList();
private int currentRegion = 0;
private String title = "";
static final int DEFAULT_WIDTH = 600;
static final int DEFAULT_HEIGHT = 600;
private boolean warned = false;
protected DummyPlotter() {
// This constructor should not invoke createRegion() or the JAS plotter will have problems
initializeParameters();
}
DummyPlotter(String name) {
this(name, null);
}
DummyPlotter(String name, String options) {
initializeParameters();
createRegion();
}
private void initializeParameters() {
if (plotterStyle != null) plotterStyle.setParameter(Style.PLOTTER_STYLE_NAME, "PlotterStyle");
addParameter("plotterWidth",String.valueOf(-1));
addParameter("plotterHeight",String.valueOf(-1));
}
protected IPlotterRegion justCreateRegion(double x, double y, double width, double height) {
return new DummyPlotterRegion(x,y,width,height);
}
public void show() {
System.err.println("Warning: Dummy plotter used, no plot will appear");
}
public void hide() {
}
public void refresh() {
}
public void interact() {
}
public IPlotterRegion next() {
return (IPlotterRegion) regions.get(++currentRegion);
}
public IPlotterRegion createRegion(double x) {
return createRegion(x,0,1-x,1);
}
public IPlotterRegion createRegion() {
return createRegion(0,0,1,1);
}
public IPlotterRegion createRegion(double x, double y) {
return createRegion(x,y,1-x,1-y);
}
public IPlotterRegion createRegion(double x, double y, double w) {
return createRegion(x,y,w,1-y);
}
public IPlotterRegion createRegion(double x, double y, double w, double h) {
if (x<0 || x>1) throw new IllegalArgumentException("x");
if (y<0 || y>1) throw new IllegalArgumentException("y");
if (w<0 || x+w>1) throw new IllegalArgumentException("w");
if (h<0 || y+h>1) throw new IllegalArgumentException("h");
IPlotterRegion region = justCreateRegion(x,y,w,h);
regions.add(region);
return region;
}
public IPlotterRegion currentRegion() {
return (IPlotterRegion) regions.get(currentRegion);
}
public void createRegions() {
createRegions(1,1,0);
}
public void createRegions(int columns) {
createRegions(columns,1,0);
}
public void createRegions(int columns, int rows) {
createRegions(columns,rows,0);
}
public void createRegions(int columns, int rows, int start) {
if (columns <= 0) throw new IllegalArgumentException("columns");
if (rows <= 0) throw new IllegalArgumentException("rows");
if (start < 0 || start >= rows*columns) throw new IllegalArgumentException("start");
// Does this destroy current regions?
destroyRegions();
double width = 1./columns;
double height = 1./rows;
for (int i=0; i<columns; i++) {
for (int j=0; j<rows; j++) {
regions.add(justCreateRegion(i*width,j*height,width,height));
}
}
currentRegion = start;
}
public void setCurrentRegionNumber(int value) {
if (value < 0 || value >= regions.size()) throw new IllegalArgumentException();
currentRegion = value;
}
public int currentRegionNumber() {
return currentRegion;
}
public IPlotterRegion region(int index) {
if (index < 0 || index >= regions.size()) throw new IllegalArgumentException();
currentRegion = index;
return (IPlotterRegion) regions.get(index);
}
public void destroyRegions() {
if (regions != null && regions.size() > 0) {
clearRegions();
regions.clear();
}
currentRegion = 0;
}
public void clearRegions() {
if (regions == null || regions.size() == 0) return;
for (Iterator i = regions.iterator(); i.hasNext(); ) {
((IPlotterRegion) i.next()).clear();
}
}
public String[] availableParameterOptions(String parameterName) {
int parIndex = parameterIndex( parameterName );
Object obj = parOptions.get(parIndex);
return obj == null ? emptyArray : (String[]) obj;
}
public String[] availableParameters() {
int size = parameters.size();
String[] pars = new String[ size ];
for ( int i = 0; i < size; i++ )
pars[i] = (String) parameters.get(i);
return pars;
}
public String parameterValue(String parameterName) {
int parIndex = parameterIndex( parameterName );
return (String) parValues.get(parIndex);
}
private int parameterIndex( String parameterName ) {
for ( int i = 0; i < parameters.size(); i++ )
if ( ( (String) parameters.get(i) ).toLowerCase().equals( parameterName.toLowerCase() ) )
return i;
throw new IllegalArgumentException("Parameter "+parameterName+" is not a plotter parameter.");
}
public void setParameter(String name) {
setParameter(name,null);
}
public void setParameter(String name, String value) {
int parIndex = parameterIndex( name );
if ( value == null )
parValues.set(parIndex,parDefaults.get(parIndex));
else
parValues.set(parIndex,value);
}
public int numberOfRegions() {
return regions.size();
}
public void setTitle(String str) {
title = str;
}
public String title() {
return title;
}
public hep.aida.ITitleStyle titleStyle() {
return plotterStyle.titleStyle();
}
public void setTitleStyle(hep.aida.ITitleStyle iTitleStyle) {
plotterStyle.setTitleStyle(iTitleStyle);
}
public IPlotterStyle style() {
return plotterStyle;
}
public void setStyle(IPlotterStyle style) {
if (style == plotterStyle) return;
this.plotterStyle = style;
if (plotterStyle != null) plotterStyle.setParameter(Style.PLOTTER_STYLE_NAME, "PlotterStyle");
if (regions != null && regions.size() > 0) {
for (int i=0; i<regions.size(); i++) {
Object obj = regions.get(i);
if (obj instanceof IPlotterRegion) ((IPlotterRegion) obj).refresh();
}
}
}
public void writeToFile(String file) throws IOException {
writeToFile(file, null);
}
public void writeToFile(String file, String type) throws IOException {
System.err.println("Warning: Dummy plotter used, no file will be written");
}
public void writeToFile(String fileName, String fileType, Properties props) throws IOException {
if (fileType == null) {
int pos = fileName.lastIndexOf('.');
if (pos > 0) fileType = fileName.substring(pos+1);
}
OutputStream out = new BufferedOutputStream(new FileOutputStream(fileName));
writeToFile(out,fileType,props, true);
}
void writeToFile(OutputStream out, String type, Properties props) throws IOException {
writeToFile(out, type, props, false);
}
void writeToFile(OutputStream out, String type, Properties props, boolean closeOut) throws IOException {
int delay = 0;
if ( isShowing() ) {
delay = 1500;
if ( ! warned ) {
warned = true;
System.out.println("There might be a synchronization problem when the plotter is being shown and it is written to file.\n" +
"Please refer to the JAIDA release notes for more details: http://java.freehep.org/jaida.\n" +
"To avoid this problem don't invoke the show() method on the Plotter when writing to file.");
}
}
if (props == null)
props = new Properties();
if ( props.getProperty("plotWidth") == null )
PropertyUtilities.setInteger(props,"plotWidth",plotterWidth());
if ( props.getProperty("plotHeight") == null )
PropertyUtilities.setInteger(props,"plotHeight",plotterHeight());
WriteToFile writeToFile = new WriteToFile( panel(), isShowing(), out, type, props, closeOut );
if ( isShowing() ) {
WriteToFileActionListener actionListener = new WriteToFileActionListener(writeToFile, isShowing());
Timer timer = new Timer(delay,actionListener);
timer.setRepeats(false);
timer.start();
} else {
writeToFile.run();
}
}
public boolean isShowing() {
return false;
}
public JPanel panel() {
return null;
}
protected int plotterWidth() {
int width = Integer.parseInt(parameterValue("plotterWidth"));
if ( width > 0 )
return width;
return PropertyUtilities.getInteger(System.getProperties(),"plotWidth",DEFAULT_WIDTH);
}
protected int plotterHeight() {
int height = Integer.parseInt(parameterValue("plotterHeight"));
if ( height > 0 )
return height;
return PropertyUtilities.getInteger(System.getProperties(),"plotHeight",DEFAULT_HEIGHT);
}
public static void invokeOnSwingThread(Runnable run) {
try {
if (SwingUtilities.isEventDispatchThread()) run.run();
else SwingUtilities.invokeAndWait(run);
}
catch (java.lang.reflect.InvocationTargetException x) {
x.printStackTrace();
}
catch (InterruptedException x) {
x.printStackTrace();
}
}
private class WriteToFileActionListener implements ActionListener {
private WriteToFile writeToFile;
private boolean isShowing;
WriteToFileActionListener( WriteToFile writeToFile, boolean isShowing ) {
this.writeToFile = writeToFile;
this.isShowing = isShowing;
}
public void actionPerformed(ActionEvent e) {
if ( isShowing )
invokeOnSwingThread(writeToFile);
else
writeToFile.run();
}
}
private class WriteToFile implements Runnable {
private JPanel panel;
private boolean isShowing;
private OutputStream out;
private String fileType;
private Properties props;
private boolean closeOut;
WriteToFile(JPanel panel, boolean showing, OutputStream out, String type, Properties props, boolean closeOut) {
this.panel = panel;
isShowing = showing;
this.out = out;
fileType = type;
this.props = props;
}
public void run() {
Headless headLess = null;
if (!isShowing) {
// OK, this actually has to do something!
headLess = new Headless(panel);
int width = props == null ? DEFAULT_WIDTH : PropertyUtilities.getInteger(props,"plotWidth",DEFAULT_WIDTH);
int height = props == null ? DEFAULT_HEIGHT : PropertyUtilities.getInteger(props,"plotHeight",DEFAULT_HEIGHT);
panel.setPreferredSize(new Dimension(width,height));
headLess.pack();
headLess.setVisible(true);
}
try {
List types = ExportFileType.getExportFileTypes(fileType);
if (types == null || types.size() == 0) throw new IllegalArgumentException("Unsupported file type: "+fileType);
ExportFileType fType = (ExportFileType) types.get(0);
try {
fType.exportToFile(out, panel, null, props, "AIDA");
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
} finally {
if (headLess != null) {
if (!isShowing) {
panel.removeNotify();
}
headLess.removeAll();
headLess.dispose();
}
}
if ( closeOut )
try {
out.close();
} catch (IOException ioe) {
throw new RuntimeException(ioe.getMessage());
}
}
}
protected void addParameter( String parameterName ) {
addParameter( parameterName, null, null );
}
protected void addParameter( String parameterName, String defaultValue ) {
addParameter( parameterName, null, defaultValue );
}
protected void addParameter( String parameterName, String[] options ) {
addParameter( parameterName, options, null );
}
protected void addParameter( String parameterName, String[] options, String defaultValue ) {
try {
parameterIndex(parameterName);
throw new IllegalArgumentException("Parameter "+parameterName+" already belongs to this BaseStyle");
} catch (IllegalArgumentException iae) {
parameters.add(parameterName);
parOptions.add(options);
parDefaults.add(defaultValue);
parValues.add(defaultValue);
}
}
}