0001: /* ===========================================================
0002: * JFreeChart : a free chart library for the Java(tm) platform
0003: * ===========================================================
0004: *
0005: * (C) Copyright 2000-2006, by Object Refinery Limited and Contributors.
0006: *
0007: * Project Info: http://www.jfree.org/jfreechart/index.html
0008: *
0009: * This library is free software; you can redistribute it and/or modify it
0010: * under the terms of the GNU Lesser General Public License as published by
0011: * the Free Software Foundation; either version 2.1 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * This library is distributed in the hope that it will be useful, but
0015: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
0016: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
0017: * License for more details.
0018: *
0019: * You should have received a copy of the GNU Lesser General Public
0020: * License along with this library; if not, write to the Free Software
0021: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
0022: * USA.
0023: *
0024: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
0025: * in the United States and other countries.]
0026: *
0027: * -------------------
0028: * ChartComposite.java
0029: * -------------------
0030: * (C) Copyright 2006, by Henry Proudhon and Contributors.
0031: *
0032: * Original Author: Henry Proudhon (henry.proudhon AT insa-lyon.fr);
0033: * Contributor(s): David Gilbert (for Object Refinery Limited);
0034: * Cedric Chabanois (cchabanois AT no-log.org);
0035: *
0036: * Changes
0037: * -------
0038: * 19-Jun-2006 : New class (HP);
0039: * 06-Nov-2006 : Added accessor methods for zoomInFactor and zoomOutFactor (DG);
0040: * 28-Nov-2006 : Added support for trace lines (HP);
0041: * 30-Nov-2006 : Improved zoom box handling (HP);
0042: * 06-Dec-2006 : Added (simplified) tool tip support (HP);
0043: * 11-Dec-2006 : Fixed popup menu location by fgiust, bug 1612770 (HP);
0044: * 31-Jan-2007 : Fixed some issues with the trace lines, fixed cross hair not being drawn,
0045: * added getter and setter methods for the trace lines (HP);
0046: * 07-Apr-2007 : Changed this.redraw() into canvas.redraw() to fix redraw problems (HP);
0047: * 19-May-2007 : Small fix in paintControl to check for null charts, bug 1719260 (HP);
0048: * 19-May-2007 : Corrected bug with scaling when the drawing region is larger
0049: * than maximum draw width/height (HP);
0050: * 23-May-2007 : Added some dispose call to free SWT resources, patch sent by Cédric
0051: * Chabanois (CC);
0052: * 06-Jun-2007 : Fixed minor issues with tooltips. bug reported and fix proposed
0053: * by Christoph Beck, bug 1726404 (HP);
0054: */
0055:
0056: package org.jfree.experimental.chart.swt;
0057:
0058: import java.awt.Graphics;
0059: import java.awt.Point;
0060: import java.awt.geom.Point2D;
0061: import java.awt.geom.Rectangle2D;
0062: import java.awt.print.PageFormat;
0063: import java.awt.print.Printable;
0064: import java.awt.print.PrinterException;
0065: import java.awt.print.PrinterJob;
0066: import java.io.File;
0067: import java.io.IOException;
0068: import java.util.ResourceBundle;
0069:
0070: import javax.swing.event.EventListenerList;
0071:
0072: import org.eclipse.swt.SWT;
0073: import org.eclipse.swt.events.MouseEvent;
0074: import org.eclipse.swt.events.PaintEvent;
0075: import org.eclipse.swt.events.PaintListener;
0076: import org.eclipse.swt.events.SelectionEvent;
0077: import org.eclipse.swt.events.SelectionListener;
0078: import org.eclipse.swt.graphics.GC;
0079: import org.eclipse.swt.graphics.Rectangle;
0080: import org.eclipse.swt.layout.FillLayout;
0081: import org.eclipse.swt.widgets.Canvas;
0082: import org.eclipse.swt.widgets.Composite;
0083: import org.eclipse.swt.widgets.Event;
0084: import org.eclipse.swt.widgets.FileDialog;
0085: import org.eclipse.swt.widgets.Listener;
0086: import org.eclipse.swt.widgets.Menu;
0087: import org.eclipse.swt.widgets.MenuItem;
0088: import org.eclipse.swt.widgets.MessageBox;
0089: import org.jfree.chart.ChartMouseEvent;
0090: import org.jfree.chart.ChartMouseListener;
0091: import org.jfree.chart.ChartRenderingInfo;
0092: import org.jfree.chart.ChartUtilities;
0093: import org.jfree.chart.JFreeChart;
0094: import org.jfree.chart.entity.ChartEntity;
0095: import org.jfree.chart.entity.EntityCollection;
0096: import org.jfree.chart.event.ChartChangeEvent;
0097: import org.jfree.chart.event.ChartChangeListener;
0098: import org.jfree.chart.event.ChartProgressEvent;
0099: import org.jfree.chart.event.ChartProgressListener;
0100: import org.jfree.chart.plot.Plot;
0101: import org.jfree.chart.plot.PlotOrientation;
0102: import org.jfree.chart.plot.PlotRenderingInfo;
0103: import org.jfree.chart.plot.ValueAxisPlot;
0104: import org.jfree.chart.plot.Zoomable;
0105: import org.jfree.experimental.chart.swt.editor.SWTChartEditor;
0106: import org.jfree.experimental.swt.SWTGraphics2D;
0107: import org.jfree.experimental.swt.SWTUtils;
0108:
0109: /**
0110: * A SWT GUI composite for displaying a {@link JFreeChart} object.
0111: * <p>
0112: * The composite listens to the chart to receive notification of changes to any
0113: * component of the chart. The chart is redrawn automatically whenever this
0114: * notification is received.
0115: */
0116: public class ChartComposite extends Composite implements
0117: ChartChangeListener, ChartProgressListener, SelectionListener,
0118: Printable {
0119: /** Default setting for buffer usage. */
0120: public static final boolean DEFAULT_BUFFER_USED = false;
0121:
0122: /** The default panel width. */
0123: public static final int DEFAULT_WIDTH = 680;
0124:
0125: /** The default panel height. */
0126: public static final int DEFAULT_HEIGHT = 420;
0127:
0128: /** The default limit below which chart scaling kicks in. */
0129: public static final int DEFAULT_MINIMUM_DRAW_WIDTH = 300;
0130:
0131: /** The default limit below which chart scaling kicks in. */
0132: public static final int DEFAULT_MINIMUM_DRAW_HEIGHT = 200;
0133:
0134: /** The default limit below which chart scaling kicks in. */
0135: public static final int DEFAULT_MAXIMUM_DRAW_WIDTH = 800;
0136:
0137: /** The default limit below which chart scaling kicks in. */
0138: public static final int DEFAULT_MAXIMUM_DRAW_HEIGHT = 600;
0139:
0140: /** The minimum size required to perform a zoom on a rectangle */
0141: public static final int DEFAULT_ZOOM_TRIGGER_DISTANCE = 10;
0142:
0143: /** Properties action command. */
0144: public static final String PROPERTIES_COMMAND = "PROPERTIES";
0145:
0146: /** Save action command. */
0147: public static final String SAVE_COMMAND = "SAVE";
0148:
0149: /** Print action command. */
0150: public static final String PRINT_COMMAND = "PRINT";
0151:
0152: /** Zoom in (both axes) action command. */
0153: public static final String ZOOM_IN_BOTH_COMMAND = "ZOOM_IN_BOTH";
0154:
0155: /** Zoom in (domain axis only) action command. */
0156: public static final String ZOOM_IN_DOMAIN_COMMAND = "ZOOM_IN_DOMAIN";
0157:
0158: /** Zoom in (range axis only) action command. */
0159: public static final String ZOOM_IN_RANGE_COMMAND = "ZOOM_IN_RANGE";
0160:
0161: /** Zoom out (both axes) action command. */
0162: public static final String ZOOM_OUT_BOTH_COMMAND = "ZOOM_OUT_BOTH";
0163:
0164: /** Zoom out (domain axis only) action command. */
0165: public static final String ZOOM_OUT_DOMAIN_COMMAND = "ZOOM_DOMAIN_BOTH";
0166:
0167: /** Zoom out (range axis only) action command. */
0168: public static final String ZOOM_OUT_RANGE_COMMAND = "ZOOM_RANGE_BOTH";
0169:
0170: /** Zoom reset (both axes) action command. */
0171: public static final String ZOOM_RESET_BOTH_COMMAND = "ZOOM_RESET_BOTH";
0172:
0173: /** Zoom reset (domain axis only) action command. */
0174: public static final String ZOOM_RESET_DOMAIN_COMMAND = "ZOOM_RESET_DOMAIN";
0175:
0176: /** Zoom reset (range axis only) action command. */
0177: public static final String ZOOM_RESET_RANGE_COMMAND = "ZOOM_RESET_RANGE";
0178:
0179: /** The chart that is displayed in the panel. */
0180: public JFreeChart chart;
0181:
0182: /** The canvas to display the chart */
0183: private Canvas canvas;
0184:
0185: /** Storage for registered (chart) mouse listeners. */
0186: private EventListenerList chartMouseListeners;
0187:
0188: /** A flag that controls whether or not the off-screen buffer is used. */
0189: private boolean useBuffer;
0190:
0191: /** A flag that indicates that the buffer should be refreshed. */
0192: private boolean refreshBuffer;
0193:
0194: /** A flag that indicates that the tooltips should be displayed. */
0195: private boolean displayToolTips;
0196:
0197: /** A buffer for the rendered chart. */
0198: private org.eclipse.swt.graphics.Image chartBuffer;
0199:
0200: /** The height of the chart buffer. */
0201: private int chartBufferHeight;
0202:
0203: /** The width of the chart buffer. */
0204: private int chartBufferWidth;
0205:
0206: /**
0207: * The minimum width for drawing a chart (uses scaling for smaller widths).
0208: */
0209: private int minimumDrawWidth;
0210:
0211: /**
0212: * The minimum height for drawing a chart (uses scaling for smaller
0213: * heights).
0214: */
0215: private int minimumDrawHeight;
0216:
0217: /**
0218: * The maximum width for drawing a chart (uses scaling for bigger
0219: * widths).
0220: */
0221: private int maximumDrawWidth;
0222:
0223: /**
0224: * The maximum height for drawing a chart (uses scaling for bigger
0225: * heights).
0226: */
0227: private int maximumDrawHeight;
0228:
0229: /** The popup menu for the frame. */
0230: private Menu popup;
0231:
0232: /** The drawing info collected the last time the chart was drawn. */
0233: private ChartRenderingInfo info;
0234:
0235: /** The chart anchor point. */
0236: private Point2D anchor;
0237:
0238: /** The scale factor used to draw the chart. */
0239: private double scaleX;
0240:
0241: /** The scale factor used to draw the chart. */
0242: private double scaleY;
0243:
0244: /** The plot orientation. */
0245: private PlotOrientation orientation = PlotOrientation.VERTICAL;
0246:
0247: /** A flag that controls whether or not domain zooming is enabled. */
0248: private boolean domainZoomable = false;
0249:
0250: /** A flag that controls whether or not range zooming is enabled. */
0251: private boolean rangeZoomable = false;
0252:
0253: /**
0254: * The zoom rectangle starting point (selected by the user with a mouse
0255: * click). This is a point on the screen, not the chart (which may have
0256: * been scaled up or down to fit the panel).
0257: */
0258: private org.eclipse.swt.graphics.Point zoomPoint = null;
0259:
0260: /** The zoom rectangle (selected by the user with the mouse). */
0261: private transient Rectangle zoomRectangle = null;
0262:
0263: /** Controls if the zoom rectangle is drawn as an outline or filled. */
0264: //TODO private boolean fillZoomRectangle = true;
0265: /** The minimum distance required to drag the mouse to trigger a zoom. */
0266: private int zoomTriggerDistance;
0267:
0268: /** A flag that controls whether or not horizontal tracing is enabled. */
0269: private boolean horizontalAxisTrace = false;
0270:
0271: /** A flag that controls whether or not vertical tracing is enabled. */
0272: private boolean verticalAxisTrace = false;
0273:
0274: /** A vertical trace line. */
0275: private transient int verticalTraceLineX;
0276:
0277: /** A horizontal trace line. */
0278: private transient int horizontalTraceLineY;
0279:
0280: /** Menu item for zooming in on a chart (both axes). */
0281: private MenuItem zoomInBothMenuItem;
0282:
0283: /** Menu item for zooming in on a chart (domain axis). */
0284: private MenuItem zoomInDomainMenuItem;
0285:
0286: /** Menu item for zooming in on a chart (range axis). */
0287: private MenuItem zoomInRangeMenuItem;
0288:
0289: /** Menu item for zooming out on a chart. */
0290: private MenuItem zoomOutBothMenuItem;
0291:
0292: /** Menu item for zooming out on a chart (domain axis). */
0293: private MenuItem zoomOutDomainMenuItem;
0294:
0295: /** Menu item for zooming out on a chart (range axis). */
0296: private MenuItem zoomOutRangeMenuItem;
0297:
0298: /** Menu item for resetting the zoom (both axes). */
0299: private MenuItem zoomResetBothMenuItem;
0300:
0301: /** Menu item for resetting the zoom (domain axis only). */
0302: private MenuItem zoomResetDomainMenuItem;
0303:
0304: /** Menu item for resetting the zoom (range axis only). */
0305: private MenuItem zoomResetRangeMenuItem;
0306:
0307: /** A flag that controls whether or not file extensions are enforced. */
0308: private boolean enforceFileExtensions;
0309:
0310: /** The factor used to zoom in on an axis range. */
0311: private double zoomInFactor = 0.5;
0312:
0313: /** The factor used to zoom out on an axis range. */
0314: private double zoomOutFactor = 2.0;
0315:
0316: /** The resourceBundle for the localization. */
0317: protected static ResourceBundle localizationResources = ResourceBundle
0318: .getBundle("org.jfree.chart.LocalizationBundle");
0319:
0320: /**
0321: * Create a new chart composite with a default FillLayout.
0322: * This way, when drawn, the chart will fill all the space.
0323: * @param comp The parent.
0324: * @param style The style of the composite.
0325: */
0326: public ChartComposite(Composite comp, int style) {
0327: this (comp, style, null, DEFAULT_WIDTH, DEFAULT_HEIGHT,
0328: DEFAULT_MINIMUM_DRAW_WIDTH,
0329: DEFAULT_MINIMUM_DRAW_HEIGHT,
0330: DEFAULT_MAXIMUM_DRAW_WIDTH,
0331: DEFAULT_MAXIMUM_DRAW_HEIGHT, DEFAULT_BUFFER_USED, true, // properties
0332: true, // save
0333: true, // print
0334: true, // zoom
0335: true // tooltips
0336: );
0337: }
0338:
0339: /**
0340: * Constructs a panel that displays the specified chart.
0341: *
0342: * @param comp The parent.
0343: * @param style The style of the composite.
0344: * @param chart the chart.
0345: */
0346: public ChartComposite(Composite comp, int style, JFreeChart chart) {
0347: this (comp, style, chart, DEFAULT_WIDTH, DEFAULT_HEIGHT,
0348: DEFAULT_MINIMUM_DRAW_WIDTH,
0349: DEFAULT_MINIMUM_DRAW_HEIGHT,
0350: DEFAULT_MAXIMUM_DRAW_WIDTH,
0351: DEFAULT_MAXIMUM_DRAW_HEIGHT, DEFAULT_BUFFER_USED, true, // properties
0352: true, // save
0353: true, // print
0354: true, // zoom
0355: true // tooltips
0356: );
0357: }
0358:
0359: /**
0360: * Constructs a panel containing a chart.
0361: *
0362: * @param comp The parent.
0363: * @param style The style of the composite.
0364: * @param chart the chart.
0365: * @param useBuffer a flag controlling whether or not an off-screen buffer
0366: * is used.
0367: */
0368: public ChartComposite(Composite comp, int style, JFreeChart chart,
0369: boolean useBuffer) {
0370:
0371: this (comp, style, chart, DEFAULT_WIDTH, DEFAULT_HEIGHT,
0372: DEFAULT_MINIMUM_DRAW_WIDTH,
0373: DEFAULT_MINIMUM_DRAW_HEIGHT,
0374: DEFAULT_MAXIMUM_DRAW_WIDTH,
0375: DEFAULT_MAXIMUM_DRAW_HEIGHT, useBuffer, true, // properties
0376: true, // save
0377: true, // print
0378: true, // zoom
0379: true // tooltips
0380: );
0381: }
0382:
0383: /**
0384: * Constructs a JFreeChart panel.
0385: *
0386: * @param comp The parent.
0387: * @param style The style of the composite.
0388: * @param chart the chart.
0389: * @param properties a flag indicating whether or not the chart property
0390: * editor should be available via the popup menu.
0391: * @param save a flag indicating whether or not save options should be
0392: * available via the popup menu.
0393: * @param print a flag indicating whether or not the print option
0394: * should be available via the popup menu.
0395: * @param zoom a flag indicating whether or not zoom options should
0396: * be added to the popup menu.
0397: * @param tooltips a flag indicating whether or not tooltips should be
0398: * enabled for the chart.
0399: */
0400: public ChartComposite(Composite comp, int style, JFreeChart chart,
0401: boolean properties, boolean save, boolean print,
0402: boolean zoom, boolean tooltips) {
0403: this (comp, style, chart, DEFAULT_WIDTH, DEFAULT_HEIGHT,
0404: DEFAULT_MINIMUM_DRAW_WIDTH,
0405: DEFAULT_MINIMUM_DRAW_HEIGHT,
0406: DEFAULT_MAXIMUM_DRAW_WIDTH,
0407: DEFAULT_MAXIMUM_DRAW_HEIGHT, DEFAULT_BUFFER_USED,
0408: properties, save, print, zoom, tooltips);
0409: }
0410:
0411: /**
0412: * Constructs a JFreeChart panel.
0413: *
0414: * @param comp The parent.
0415: * @param style The style of the composite.
0416: * @param jfreechart the chart.
0417: * @param width the preferred width of the panel.
0418: * @param height the preferred height of the panel.
0419: * @param minimumDrawW the minimum drawing width.
0420: * @param minimumDrawH the minimum drawing height.
0421: * @param maximumDrawW the maximum drawing width.
0422: * @param maximumDrawH the maximum drawing height.
0423: * @param usingBuffer a flag that indicates whether to use the off-screen
0424: * buffer to improve performance (at the expense of
0425: * memory).
0426: * @param properties a flag indicating whether or not the chart property
0427: * editor should be available via the popup menu.
0428: * @param save a flag indicating whether or not save options should be
0429: * available via the popup menu.
0430: * @param print a flag indicating whether or not the print option
0431: * should be available via the popup menu.
0432: * @param zoom a flag indicating whether or not zoom options should be
0433: * added to the popup menu.
0434: * @param tooltips a flag indicating whether or not tooltips should be
0435: * enabled for the chart.
0436: */
0437: public ChartComposite(Composite comp, int style,
0438: JFreeChart jfreechart, int width, int height,
0439: int minimumDrawW, int minimumDrawH, int maximumDrawW,
0440: int maximumDrawH, boolean usingBuffer, boolean properties,
0441: boolean save, boolean print, boolean zoom, boolean tooltips) {
0442: super (comp, style);
0443: this .setChart(jfreechart);
0444: this .chartMouseListeners = new EventListenerList();
0445: this .setLayout(new FillLayout());
0446: this .info = new ChartRenderingInfo();
0447: this .useBuffer = usingBuffer;
0448: this .refreshBuffer = false;
0449: this .minimumDrawWidth = minimumDrawW;
0450: this .minimumDrawHeight = minimumDrawH;
0451: this .maximumDrawWidth = maximumDrawW;
0452: this .maximumDrawHeight = maximumDrawH;
0453: this .zoomTriggerDistance = DEFAULT_ZOOM_TRIGGER_DISTANCE;
0454: this .setDisplayToolTips(tooltips);
0455: canvas = new Canvas(this , SWT.NO_BACKGROUND);
0456: canvas.addPaintListener(new PaintListener() {
0457:
0458: public void paintControl(PaintEvent e) {
0459: // first determine the size of the chart rendering area...
0460: // TODO workout insets for SWT
0461: Rectangle available = getBounds();
0462: // skip if chart is null
0463: if (chart == null) {
0464: canvas.drawBackground(e.gc, available.x,
0465: available.y, available.width,
0466: available.height);
0467: return;
0468: }
0469: SWTGraphics2D sg2 = new SWTGraphics2D(e.gc);
0470:
0471: // work out if scaling is required...
0472: boolean scale = false;
0473: int drawWidth = available.width;
0474: int drawHeight = available.height;
0475: if (drawWidth == 0.0 || drawHeight == 0.0)
0476: return;
0477: scaleX = 1.0;
0478: scaleY = 1.0;
0479: if (drawWidth < minimumDrawWidth) {
0480: scaleX = (double) drawWidth / minimumDrawWidth;
0481: drawWidth = minimumDrawWidth;
0482: scale = true;
0483: } else if (drawWidth > maximumDrawWidth) {
0484: scaleX = (double) drawWidth / maximumDrawWidth;
0485: drawWidth = maximumDrawWidth;
0486: scale = true;
0487: }
0488: if (drawHeight < minimumDrawHeight) {
0489: scaleY = (double) drawHeight / minimumDrawHeight;
0490: drawHeight = minimumDrawHeight;
0491: scale = true;
0492: } else if (drawHeight > maximumDrawHeight) {
0493: scaleY = (double) drawHeight / maximumDrawHeight;
0494: drawHeight = maximumDrawHeight;
0495: scale = true;
0496: }
0497: // are we using the chart buffer?
0498: if (useBuffer) {
0499: //SwtGraphics2D sg2 = new SwtGraphics2D( e.gc );
0500: chartBuffer = (org.eclipse.swt.graphics.Image) canvas
0501: .getData("double-buffer-image");
0502: // do we need to fill the buffer?
0503: if (chartBuffer == null
0504: || chartBufferWidth != available.width
0505: || chartBufferHeight != available.height) {
0506: chartBufferWidth = available.width;
0507: chartBufferHeight = available.height;
0508: if (chartBuffer != null) {
0509: chartBuffer.dispose();
0510: }
0511: chartBuffer = new org.eclipse.swt.graphics.Image(
0512: getDisplay(), chartBufferWidth,
0513: chartBufferHeight);
0514: refreshBuffer = true;
0515: }
0516:
0517: // do we need to redraw the buffer?
0518: if (refreshBuffer) {
0519: // Performs the actual drawing here ...
0520: GC gci = new GC(chartBuffer);
0521: SWTGraphics2D sg2d = new SWTGraphics2D(gci);
0522: if (scale) {
0523: sg2d.scale(scaleX, scaleY);
0524: chart.draw(sg2d, new Rectangle2D.Double(0,
0525: 0, drawWidth, drawHeight),
0526: getAnchor(), info);
0527: } else {
0528: chart.draw(sg2d, new Rectangle2D.Double(0,
0529: 0, drawWidth, drawHeight),
0530: getAnchor(), info);
0531: }
0532: canvas.setData("double-buffer-image",
0533: chartBuffer);
0534: sg2d.dispose();
0535: gci.dispose();
0536: refreshBuffer = false;
0537: }
0538:
0539: // zap the buffer onto the canvas...
0540: sg2.drawImage(chartBuffer, 0, 0);
0541: }
0542: // or redrawing the chart every time...
0543: else {
0544: chart.draw(sg2, new Rectangle2D.Double(0, 0,
0545: getBounds().width, getBounds().height),
0546: getAnchor(), info);
0547: }
0548: Rectangle area = getScreenDataArea();
0549: //TODO see if we need to apply some line color and style to the axis traces
0550: if (verticalAxisTrace && area.x < verticalTraceLineX
0551: && area.x + area.width > verticalTraceLineX)
0552: e.gc.drawLine(verticalTraceLineX, area.y,
0553: verticalTraceLineX, area.y + area.height);
0554: if (horizontalAxisTrace
0555: && area.y < horizontalTraceLineY
0556: && area.y + area.height > horizontalTraceLineY)
0557: e.gc.drawLine(area.x, horizontalTraceLineY, area.x
0558: + area.width, horizontalTraceLineY);
0559: verticalTraceLineX = 0;
0560: horizontalTraceLineY = 0;
0561: if (zoomRectangle != null)
0562: e.gc.drawRectangle(zoomRectangle);
0563: sg2.dispose();
0564: }
0565: });
0566: if (chart != null) {
0567: chart.addChangeListener(this );
0568: Plot plot = chart.getPlot();
0569: this .domainZoomable = false;
0570: this .rangeZoomable = false;
0571: if (plot instanceof Zoomable) {
0572: Zoomable z = (Zoomable) plot;
0573: this .domainZoomable = z.isDomainZoomable();
0574: this .rangeZoomable = z.isRangeZoomable();
0575: this .orientation = z.getOrientation();
0576: }
0577: }
0578:
0579: // set up popup menu...
0580: this .popup = null;
0581: if (properties || save || print || zoom)
0582: this .popup = createPopupMenu(properties, save, print, zoom);
0583:
0584: Listener listener = new Listener() {
0585: public void handleEvent(Event event) {
0586: switch (event.type) {
0587: case SWT.MouseDown:
0588: Rectangle scaledDataArea = getScreenDataArea(
0589: event.x, event.y);
0590: zoomPoint = getPointInRectangle(event.x, event.y,
0591: scaledDataArea);
0592: Rectangle insets = getClientArea();
0593: int x = (int) ((event.x - insets.x) / scaleX);
0594: int y = (int) ((event.y - insets.y) / scaleY);
0595:
0596: anchor = new Point2D.Double(x, y);
0597: chart.setNotify(true); // force a redraw
0598: canvas.redraw();
0599: // new entity code...
0600: Object[] listeners = chartMouseListeners
0601: .getListeners(ChartMouseListener.class);
0602: if (listeners.length == 0) {
0603: return;
0604: }
0605:
0606: ChartEntity entity = null;
0607: if (info != null) {
0608: EntityCollection entities = info
0609: .getEntityCollection();
0610: if (entities != null) {
0611: entity = entities.getEntity(x, y);
0612: }
0613: }
0614: java.awt.event.MouseEvent mouseEvent = SWTUtils
0615: .toAwtMouseEvent(event);
0616: ChartMouseEvent chartEvent = new ChartMouseEvent(
0617: getChart(), mouseEvent, entity);
0618: for (int i = listeners.length - 1; i >= 0; i -= 1) {
0619: ((ChartMouseListener) listeners[i])
0620: .chartMouseClicked(chartEvent);
0621: }
0622: break;
0623: case SWT.MouseMove:
0624: // handle axis trace
0625: if (horizontalAxisTrace || verticalAxisTrace) {
0626: horizontalTraceLineY = event.y;
0627: verticalTraceLineX = event.x;
0628: canvas.redraw();
0629: }
0630: // handle tool tips in a simple way
0631: if (displayToolTips) {
0632: String s = getToolTipText(new MouseEvent(event));
0633: if (s == null
0634: && canvas.getToolTipText() != null
0635: || s != null
0636: && !s.equals(canvas.getToolTipText()))
0637: canvas.setToolTipText(s);
0638: }
0639: // handle zoom box
0640: if (zoomPoint == null) {
0641: return;
0642: }
0643: scaledDataArea = getScreenDataArea(zoomPoint.x,
0644: zoomPoint.y);
0645: org.eclipse.swt.graphics.Point movingPoint = getPointInRectangle(
0646: event.x, event.y, scaledDataArea);
0647: // handle zoom
0648: boolean hZoom = false;
0649: boolean vZoom = false;
0650: if (orientation == PlotOrientation.HORIZONTAL) {
0651: hZoom = rangeZoomable;
0652: vZoom = domainZoomable;
0653: } else {
0654: hZoom = domainZoomable;
0655: vZoom = rangeZoomable;
0656: }
0657: if (hZoom && vZoom) {
0658: // selected rectangle shouldn't extend outside the data area...
0659: zoomRectangle = new Rectangle(zoomPoint.x,
0660: zoomPoint.y, movingPoint.x
0661: - zoomPoint.x, movingPoint.y
0662: - zoomPoint.y);
0663: } else if (hZoom) {
0664: zoomRectangle = new Rectangle(zoomPoint.x,
0665: scaledDataArea.y, movingPoint.x
0666: - zoomPoint.x,
0667: scaledDataArea.height);
0668: } else if (vZoom) {
0669: zoomRectangle = new Rectangle(scaledDataArea.x,
0670: zoomPoint.y, scaledDataArea.width,
0671: event.y - zoomPoint.y);
0672: }
0673: canvas.redraw();
0674: break;
0675: case SWT.MouseUp:
0676: if (zoomRectangle == null) {
0677: Rectangle screenDataArea = getScreenDataArea(
0678: event.x, event.y);
0679: if (screenDataArea != null) {
0680: zoomPoint = getPointInRectangle(event.x,
0681: event.y, screenDataArea);
0682: }
0683: if (popup != null && event.button == 3) {
0684: org.eclipse.swt.graphics.Point pt = canvas
0685: .toDisplay(event.x, event.y);
0686: displayPopupMenu(pt.x, pt.y);
0687: }
0688: } else {
0689: hZoom = false;
0690: vZoom = false;
0691: if (orientation == PlotOrientation.HORIZONTAL) {
0692: hZoom = rangeZoomable;
0693: vZoom = domainZoomable;
0694: } else {
0695: hZoom = domainZoomable;
0696: vZoom = rangeZoomable;
0697: }
0698: boolean zoomTrigger1 = hZoom
0699: && Math.abs(zoomRectangle.width) >= zoomTriggerDistance;
0700: boolean zoomTrigger2 = vZoom
0701: && Math.abs(zoomRectangle.height) >= zoomTriggerDistance;
0702: if (zoomTrigger1 || zoomTrigger2) {
0703: // if the box has been drawn backwards, restore the auto bounds
0704: if ((hZoom && (zoomRectangle.x
0705: + zoomRectangle.width < zoomPoint.x))
0706: || (vZoom && (zoomRectangle.y
0707: + zoomRectangle.height < zoomPoint.y)))
0708: restoreAutoBounds();
0709: else
0710: zoom(zoomRectangle);
0711: canvas.redraw();
0712: }
0713: }
0714: zoomPoint = null;
0715: zoomRectangle = null;
0716: break;
0717: default:
0718: zoomPoint = null;
0719: zoomRectangle = null;
0720: }
0721: }
0722: };
0723: canvas.addListener(SWT.MouseDown, listener);
0724: canvas.addListener(SWT.MouseMove, listener);
0725: canvas.addListener(SWT.MouseUp, listener);
0726:
0727: this .enforceFileExtensions = true;
0728: }
0729:
0730: /**
0731: * Returns the X scale factor for the chart. This will be 1.0 if no
0732: * scaling has been used.
0733: *
0734: * @return The scale factor.
0735: */
0736: public double getScaleX() {
0737: return this .scaleX;
0738: }
0739:
0740: /**
0741: * Returns the Y scale factory for the chart. This will be 1.0 if no
0742: * scaling has been used.
0743: *
0744: * @return The scale factor.
0745: */
0746: public double getScaleY() {
0747: return this .scaleY;
0748: }
0749:
0750: /**
0751: * Returns the anchor point.
0752: *
0753: * @return The anchor point (possibly <code>null</code>).
0754: */
0755: public Point2D getAnchor() {
0756: return this .anchor;
0757: }
0758:
0759: /**
0760: * Sets the anchor point. This method is provided for the use of
0761: * subclasses, not end users.
0762: *
0763: * @param anchor the anchor point (<code>null</code> permitted).
0764: */
0765: protected void setAnchor(Point2D anchor) {
0766: this .anchor = anchor;
0767: }
0768:
0769: /**
0770: * Returns the chart contained in the panel.
0771: *
0772: * @return The chart (possibly <code>null</code>).
0773: */
0774: public JFreeChart getChart() {
0775: return this .chart;
0776: }
0777:
0778: /**
0779: * Sets the chart that is displayed in the panel.
0780: *
0781: * @param chart the chart (<code>null</code> permitted).
0782: */
0783: public void setChart(JFreeChart chart) {
0784: // stop listening for changes to the existing chart
0785: if (this .chart != null) {
0786: this .chart.removeChangeListener(this );
0787: this .chart.removeProgressListener(this );
0788: }
0789:
0790: // add the new chart
0791: this .chart = chart;
0792: if (chart != null) {
0793: this .chart.addChangeListener(this );
0794: this .chart.addProgressListener(this );
0795: Plot plot = chart.getPlot();
0796: this .domainZoomable = false;
0797: this .rangeZoomable = false;
0798: if (plot instanceof Zoomable) {
0799: Zoomable z = (Zoomable) plot;
0800: this .domainZoomable = z.isDomainZoomable();
0801: this .rangeZoomable = z.isRangeZoomable();
0802: this .orientation = z.getOrientation();
0803: }
0804: } else {
0805: this .domainZoomable = false;
0806: this .rangeZoomable = false;
0807: }
0808: if (this .useBuffer) {
0809: this .refreshBuffer = true;
0810: }
0811: }
0812:
0813: /**
0814: * Returns the zoom in factor.
0815: *
0816: * @return The zoom in factor.
0817: *
0818: * @see #setZoomInFactor(double)
0819: */
0820: public double getZoomInFactor() {
0821: return this .zoomInFactor;
0822: }
0823:
0824: /**
0825: * Sets the zoom in factor.
0826: *
0827: * @param factor the factor.
0828: *
0829: * @see #getZoomInFactor()
0830: */
0831: public void setZoomInFactor(double factor) {
0832: this .zoomInFactor = factor;
0833: }
0834:
0835: /**
0836: * Returns the zoom out factor.
0837: *
0838: * @return The zoom out factor.
0839: *
0840: * @see #setZoomOutFactor(double)
0841: */
0842: public double getZoomOutFactor() {
0843: return this .zoomOutFactor;
0844: }
0845:
0846: /**
0847: * Sets the zoom out factor.
0848: *
0849: * @param factor the factor.
0850: *
0851: * @see #getZoomOutFactor()
0852: */
0853: public void setZoomOutFactor(double factor) {
0854: this .zoomOutFactor = factor;
0855: }
0856:
0857: /**
0858: * Displays a dialog that allows the user to edit the properties for the
0859: * current chart.
0860: */
0861: private void attemptEditChartProperties() {
0862: SWTChartEditor editor = new SWTChartEditor(canvas.getDisplay(),
0863: this .chart);
0864: //ChartEditorManager.getChartEditor( canvas.getDisplay(), this.chart );
0865: editor.open();
0866: }
0867:
0868: /**
0869: * Returns <code>true</code> if file extensions should be enforced, and
0870: * <code>false</code> otherwise.
0871: *
0872: * @return The flag.
0873: */
0874: public boolean isEnforceFileExtensions() {
0875: return this .enforceFileExtensions;
0876: }
0877:
0878: /**
0879: * Sets a flag that controls whether or not file extensions are enforced.
0880: *
0881: * @param enforce the new flag value.
0882: */
0883: public void setEnforceFileExtensions(boolean enforce) {
0884: this .enforceFileExtensions = enforce;
0885: }
0886:
0887: /**
0888: * Opens a file chooser and gives the user an opportunity to save the chart
0889: * in PNG format.
0890: *
0891: * @throws IOException if there is an I/O error.
0892: */
0893: public void doSaveAs() throws IOException {
0894: FileDialog fileDialog = new FileDialog(canvas.getShell(),
0895: SWT.SAVE);
0896: String[] extensions = { "*.png" };
0897: fileDialog.setFilterExtensions(extensions);
0898: String filename = fileDialog.open();
0899: if (filename != null) {
0900: if (isEnforceFileExtensions()) {
0901: if (!filename.endsWith(".png")) {
0902: filename = filename + ".png";
0903: }
0904: }
0905: //TODO replace getSize by getBounds ?
0906: ChartUtilities.saveChartAsPNG(new File(filename),
0907: this .chart, canvas.getSize().x, canvas.getSize().y);
0908: }
0909: }
0910:
0911: /**
0912: * Returns a point based on (x, y) but constrained to be within the bounds
0913: * of the given rectangle. This method could be moved to JCommon.
0914: *
0915: * @param x the x-coordinate.
0916: * @param y the y-coordinate.
0917: * @param area the rectangle (<code>null</code> not permitted).
0918: *
0919: * @return A point within the rectangle.
0920: */
0921: private org.eclipse.swt.graphics.Point getPointInRectangle(int x,
0922: int y, Rectangle area) {
0923: x = (int) Math.max(area.x, Math.min(x, area.x + area.width));
0924: y = (int) Math.max(area.y, Math.min(y, area.y + area.height));
0925: return new org.eclipse.swt.graphics.Point(x, y);
0926: }
0927:
0928: /**
0929: * Zooms in on an anchor point (specified in screen coordinate space).
0930: *
0931: * @param x the x value (in screen coordinates).
0932: * @param y the y value (in screen coordinates).
0933: */
0934: public void zoomInBoth(double x, double y) {
0935: zoomInDomain(x, y);
0936: zoomInRange(x, y);
0937: }
0938:
0939: /**
0940: * Decreases the length of the domain axis, centered about the given
0941: * coordinate on the screen. The length of the domain axis is reduced
0942: * by the value of {@link #getZoomInFactor()}.
0943: *
0944: * @param x the x coordinate (in screen coordinates).
0945: * @param y the y-coordinate (in screen coordinates).
0946: */
0947: public void zoomInDomain(double x, double y) {
0948: Plot p = this .chart.getPlot();
0949: if (p instanceof Zoomable) {
0950: Zoomable plot = (Zoomable) p;
0951: plot.zoomDomainAxes(this .zoomInFactor, this .info
0952: .getPlotInfo(), translateScreenToJava2D(new Point(
0953: (int) x, (int) y)));
0954: }
0955: }
0956:
0957: /**
0958: * Decreases the length of the range axis, centered about the given
0959: * coordinate on the screen. The length of the range axis is reduced by
0960: * the value of {@link #getZoomInFactor()}.
0961: *
0962: * @param x the x-coordinate (in screen coordinates).
0963: * @param y the y coordinate (in screen coordinates).
0964: */
0965: public void zoomInRange(double x, double y) {
0966: Plot p = this .chart.getPlot();
0967: if (p instanceof Zoomable) {
0968: Zoomable z = (Zoomable) p;
0969: z
0970: .zoomRangeAxes(this .zoomInFactor, this .info
0971: .getPlotInfo(),
0972: translateScreenToJava2D(new Point((int) x,
0973: (int) y)));
0974: }
0975: }
0976:
0977: /**
0978: * Zooms out on an anchor point (specified in screen coordinate space).
0979: *
0980: * @param x the x value (in screen coordinates).
0981: * @param y the y value (in screen coordinates).
0982: */
0983: public void zoomOutBoth(double x, double y) {
0984: zoomOutDomain(x, y);
0985: zoomOutRange(x, y);
0986: }
0987:
0988: /**
0989: * Increases the length of the domain axis, centered about the given
0990: * coordinate on the screen. The length of the domain axis is increased
0991: * by the value of {@link #getZoomOutFactor()}.
0992: *
0993: * @param x the x coordinate (in screen coordinates).
0994: * @param y the y-coordinate (in screen coordinates).
0995: */
0996: public void zoomOutDomain(double x, double y) {
0997: Plot p = this .chart.getPlot();
0998: if (p instanceof Zoomable) {
0999: Zoomable z = (Zoomable) p;
1000: z.zoomDomainAxes(this .zoomOutFactor, this .info
1001: .getPlotInfo(), translateScreenToJava2D(new Point(
1002: (int) x, (int) y)));
1003: }
1004: }
1005:
1006: /**
1007: * Increases the length the range axis, centered about the given
1008: * coordinate on the screen. The length of the range axis is increased
1009: * by the value of {@link #getZoomOutFactor()}.
1010: *
1011: * @param x the x coordinate (in screen coordinates).
1012: * @param y the y-coordinate (in screen coordinates).
1013: */
1014: public void zoomOutRange(double x, double y) {
1015: Plot p = this .chart.getPlot();
1016: if (p instanceof Zoomable) {
1017: Zoomable z = (Zoomable) p;
1018: z
1019: .zoomRangeAxes(this .zoomOutFactor, this .info
1020: .getPlotInfo(),
1021: translateScreenToJava2D(new Point((int) x,
1022: (int) y)));
1023: }
1024: }
1025:
1026: /**
1027: * Zooms in on a selected region.
1028: *
1029: * @param selection the selected region.
1030: */
1031: public void zoom(Rectangle selection) {
1032:
1033: // get the origin of the zoom selection in the Java2D space used for
1034: // drawing the chart (that is, before any scaling to fit the panel)
1035: Point2D selectOrigin = translateScreenToJava2D(new Point(
1036: selection.x, selection.y));
1037: PlotRenderingInfo plotInfo = this .info.getPlotInfo();
1038: Rectangle scaledDataArea = getScreenDataArea(
1039: (int) (selection.x + selection.width) / 2,
1040: (int) (selection.y + selection.height) / 2);
1041: if ((selection.height > 0) && (selection.width > 0)) {
1042:
1043: double hLower = (selection.x - scaledDataArea.x)
1044: / (double) scaledDataArea.width;
1045: double hUpper = (selection.x + selection.width - scaledDataArea.x)
1046: / (double) scaledDataArea.width;
1047: double vLower = (scaledDataArea.y + scaledDataArea.height
1048: - selection.y - selection.height)
1049: / (double) scaledDataArea.height;
1050: double vUpper = (scaledDataArea.y + scaledDataArea.height - selection.y)
1051: / (double) scaledDataArea.height;
1052: Plot p = this .chart.getPlot();
1053: if (p instanceof Zoomable) {
1054: Zoomable z = (Zoomable) p;
1055: if (z.getOrientation() == PlotOrientation.HORIZONTAL) {
1056: z.zoomDomainAxes(vLower, vUpper, plotInfo,
1057: selectOrigin);
1058: z.zoomRangeAxes(hLower, hUpper, plotInfo,
1059: selectOrigin);
1060: } else {
1061: z.zoomDomainAxes(hLower, hUpper, plotInfo,
1062: selectOrigin);
1063: z.zoomRangeAxes(vLower, vUpper, plotInfo,
1064: selectOrigin);
1065: }
1066: }
1067:
1068: }
1069:
1070: }
1071:
1072: /**
1073: * Receives notification of changes to the chart, and redraws the chart.
1074: *
1075: * @param event details of the chart change event.
1076: */
1077: public void chartChanged(ChartChangeEvent event) {
1078: this .refreshBuffer = true;
1079: Plot plot = chart.getPlot();
1080: if (plot instanceof Zoomable) {
1081: Zoomable z = (Zoomable) plot;
1082: this .orientation = z.getOrientation();
1083: }
1084: canvas.redraw();
1085: }
1086:
1087: /**
1088: * Forces a redraw of the canvas by invoking a new PaintEvent.
1089: */
1090: public void forceRedraw() {
1091: Event ev = new Event();
1092: ev.gc = new GC(canvas);
1093: ev.x = 0;
1094: ev.y = 0;
1095: ev.width = canvas.getBounds().width;
1096: ev.height = canvas.getBounds().height;
1097: ev.count = 0;
1098: canvas.notifyListeners(SWT.Paint, ev);
1099: ev.gc.dispose();
1100: }
1101:
1102: /**
1103: * Receives notification of a chart progress event.
1104: *
1105: * @param event the event.
1106: */
1107: public void chartProgress(ChartProgressEvent event) {
1108: // does nothing - override if necessary
1109: }
1110:
1111: /**
1112: * Restores the auto-range calculation on both axes.
1113: */
1114: public void restoreAutoBounds() {
1115: restoreAutoDomainBounds();
1116: restoreAutoRangeBounds();
1117: }
1118:
1119: /**
1120: * Restores the auto-range calculation on the domain axis.
1121: */
1122: public void restoreAutoDomainBounds() {
1123: Plot p = this .chart.getPlot();
1124: if (p instanceof Zoomable) {
1125: Zoomable z = (Zoomable) p;
1126: z.zoomDomainAxes(0.0, this .info.getPlotInfo(), SWTUtils
1127: .toAwtPoint(this .zoomPoint));
1128: }
1129: }
1130:
1131: /**
1132: * Restores the auto-range calculation on the range axis.
1133: */
1134: public void restoreAutoRangeBounds() {
1135: Plot p = this .chart.getPlot();
1136: if (p instanceof ValueAxisPlot) {
1137: Zoomable z = (Zoomable) p;
1138: z.zoomRangeAxes(0.0, this .info.getPlotInfo(), SWTUtils
1139: .toAwtPoint(this .zoomPoint));
1140: }
1141: }
1142:
1143: /**
1144: * Applies any scaling that is in effect for the chart drawing to the
1145: * given rectangle.
1146: *
1147: * @param rect the rectangle.
1148: *
1149: * @return A new scaled rectangle.
1150: */
1151: public Rectangle scale(Rectangle2D rect) {
1152: Rectangle insets = this .getClientArea();
1153: int x = (int) Math.round(rect.getX() * getScaleX()) + insets.x;
1154: int y = (int) Math.round(rect.getY() * this .getScaleY())
1155: + insets.y;
1156: int w = (int) Math.round(rect.getWidth() * this .getScaleX());
1157: int h = (int) Math.round(rect.getHeight() * this .getScaleY());
1158: return new Rectangle(x, y, w, h);
1159: }
1160:
1161: /**
1162: * Returns the data area for the chart (the area inside the axes) with the
1163: * current scaling applied (that is, the area as it appears on screen).
1164: *
1165: * @return The scaled data area.
1166: */
1167: public Rectangle getScreenDataArea() {
1168: Rectangle2D dataArea = this .info.getPlotInfo().getDataArea();
1169: Rectangle clientArea = this .getClientArea();
1170: int x = (int) (dataArea.getX() * this .scaleX + clientArea.x);
1171: int y = (int) (dataArea.getY() * this .scaleY + clientArea.y);
1172: int w = (int) (dataArea.getWidth() * this .scaleX);
1173: int h = (int) (dataArea.getHeight() * this .scaleY);
1174: return new Rectangle(x, y, w, h);
1175: }
1176:
1177: /**
1178: * Returns the data area (the area inside the axes) for the plot or subplot,
1179: * with the current scaling applied.
1180: *
1181: * @param x the x-coordinate (for subplot selection).
1182: * @param y the y-coordinate (for subplot selection).
1183: *
1184: * @return The scaled data area.
1185: */
1186: public Rectangle getScreenDataArea(int x, int y) {
1187: PlotRenderingInfo plotInfo = this .info.getPlotInfo();
1188: Rectangle result;
1189: if (plotInfo.getSubplotCount() == 0)
1190: result = getScreenDataArea();
1191: else {
1192: // get the origin of the zoom selection in the Java2D space used for
1193: // drawing the chart (that is, before any scaling to fit the panel)
1194: Point2D selectOrigin = translateScreenToJava2D(new Point(x,
1195: y));
1196: int subplotIndex = plotInfo.getSubplotIndex(selectOrigin);
1197: if (subplotIndex == -1) {
1198: return null;
1199: }
1200: result = scale(plotInfo.getSubplotInfo(subplotIndex)
1201: .getDataArea());
1202: }
1203: return result;
1204: }
1205:
1206: /**
1207: * Translates a Java2D point on the chart to a screen location.
1208: *
1209: * @param java2DPoint the Java2D point.
1210: *
1211: * @return The screen location.
1212: */
1213: public Point translateJava2DToScreen(Point2D java2DPoint) {
1214: Rectangle insets = this .getClientArea();
1215: int x = (int) (java2DPoint.getX() * this .scaleX + insets.x);
1216: int y = (int) (java2DPoint.getY() * this .scaleY + insets.y);
1217: return new Point(x, y);
1218: }
1219:
1220: /**
1221: * Translates a screen location to a Java SWT point.
1222: *
1223: * @param screenPoint the screen location.
1224: *
1225: * @return The Java2D coordinates.
1226: */
1227: public Point translateScreenToJavaSWT(Point screenPoint) {
1228: Rectangle insets = this .getClientArea();
1229: int x = (int) ((screenPoint.x - insets.x) / this .scaleX);
1230: int y = (int) ((screenPoint.y - insets.y) / this .scaleY);
1231: return new Point(x, y);
1232: }
1233:
1234: /**
1235: * Translates a screen location to a Java2D point.
1236: *
1237: * @param screenPoint the screen location.
1238: *
1239: * @return The Java2D coordinates.
1240: */
1241: public Point2D translateScreenToJava2D(Point screenPoint) {
1242: Rectangle insets = this .getClientArea();
1243: int x = (int) ((screenPoint.x - insets.x) / this .scaleX);
1244: int y = (int) ((screenPoint.y - insets.y) / this .scaleY);
1245: return new Point2D.Double(x, y);
1246: }
1247:
1248: /**
1249: * Returns the flag that controls whether or not a horizontal axis trace
1250: * line is drawn over the plot area at the current mouse location.
1251: *
1252: * @return A boolean.
1253: */
1254: public boolean getHorizontalAxisTrace() {
1255: return this .horizontalAxisTrace;
1256: }
1257:
1258: /**
1259: * A flag that controls trace lines on the horizontal axis.
1260: *
1261: * @param flag <code>true</code> enables trace lines for the mouse
1262: * pointer on the horizontal axis.
1263: */
1264: public void setHorizontalAxisTrace(boolean flag) {
1265: this .horizontalAxisTrace = flag;
1266: }
1267:
1268: /**
1269: * Returns the flag that controls whether or not a vertical axis trace
1270: * line is drawn over the plot area at the current mouse location.
1271: *
1272: * @return A boolean.
1273: */
1274: public boolean getVerticalAxisTrace() {
1275: return this .verticalAxisTrace;
1276: }
1277:
1278: /**
1279: * A flag that controls trace lines on the vertical axis.
1280: *
1281: * @param flag <code>true</code> enables trace lines for the mouse
1282: * pointer on the vertical axis.
1283: */
1284: public void setVerticalAxisTrace(boolean flag) {
1285: this .verticalAxisTrace = flag;
1286: }
1287:
1288: /**
1289: * @param displayToolTips the displayToolTips to set
1290: */
1291: public void setDisplayToolTips(boolean displayToolTips) {
1292: this .displayToolTips = displayToolTips;
1293: }
1294:
1295: /**
1296: * Returns a string for the tooltip.
1297: *
1298: * @param e the mouse event.
1299: *
1300: * @return A tool tip or <code>null</code> if no tooltip is available.
1301: */
1302: public String getToolTipText(org.eclipse.swt.events.MouseEvent e) {
1303: String result = null;
1304: if (this .info != null) {
1305: EntityCollection entities = this .info.getEntityCollection();
1306: if (entities != null) {
1307: Rectangle insets = getClientArea();
1308: ChartEntity entity = entities.getEntity(
1309: (int) ((e.x - insets.x) / this .scaleX),
1310: (int) ((e.y - insets.y) / this .scaleY));
1311: if (entity != null) {
1312: result = entity.getToolTipText();
1313: }
1314: }
1315: }
1316: return result;
1317:
1318: }
1319:
1320: /**
1321: * The idea is to modify the zooming options depending on the type of chart
1322: * being displayed by the panel.
1323: *
1324: * @param x horizontal position of the popup.
1325: * @param y vertical position of the popup.
1326: */
1327: protected void displayPopupMenu(int x, int y) {
1328: if (this .popup != null) {
1329: // go through each zoom menu item and decide whether or not to
1330: // enable it...
1331: Plot plot = this .chart.getPlot();
1332: boolean isDomainZoomable = false;
1333: boolean isRangeZoomable = false;
1334: if (plot instanceof Zoomable) {
1335: Zoomable z = (Zoomable) plot;
1336: isDomainZoomable = z.isDomainZoomable();
1337: isRangeZoomable = z.isRangeZoomable();
1338: }
1339: if (this .zoomInDomainMenuItem != null) {
1340: this .zoomInDomainMenuItem.setEnabled(isDomainZoomable);
1341: }
1342: if (this .zoomOutDomainMenuItem != null) {
1343: this .zoomOutDomainMenuItem.setEnabled(isDomainZoomable);
1344: }
1345: if (this .zoomResetDomainMenuItem != null) {
1346: this .zoomResetDomainMenuItem
1347: .setEnabled(isDomainZoomable);
1348: }
1349:
1350: if (this .zoomInRangeMenuItem != null) {
1351: this .zoomInRangeMenuItem.setEnabled(isRangeZoomable);
1352: }
1353: if (this .zoomOutRangeMenuItem != null) {
1354: this .zoomOutRangeMenuItem.setEnabled(isRangeZoomable);
1355: }
1356:
1357: if (this .zoomResetRangeMenuItem != null) {
1358: this .zoomResetRangeMenuItem.setEnabled(isRangeZoomable);
1359: }
1360:
1361: if (this .zoomInBothMenuItem != null) {
1362: this .zoomInBothMenuItem.setEnabled(isDomainZoomable
1363: & isRangeZoomable);
1364: }
1365: if (this .zoomOutBothMenuItem != null) {
1366: this .zoomOutBothMenuItem.setEnabled(isDomainZoomable
1367: & isRangeZoomable);
1368: }
1369: if (this .zoomResetBothMenuItem != null) {
1370: this .zoomResetBothMenuItem.setEnabled(isDomainZoomable
1371: & isRangeZoomable);
1372: }
1373:
1374: this .popup.setLocation(x, y);
1375: this .popup.setVisible(true);
1376: }
1377:
1378: }
1379:
1380: /**
1381: * Creates a print job for the chart.
1382: */
1383: public void createChartPrintJob() {
1384: //FIXME try to replace swing print stuff by swt
1385: PrinterJob job = PrinterJob.getPrinterJob();
1386: PageFormat pf = job.defaultPage();
1387: PageFormat pf2 = job.pageDialog(pf);
1388: if (pf2 != pf) {
1389: job.setPrintable(this , pf2);
1390: if (job.printDialog()) {
1391: try {
1392: job.print();
1393: } catch (PrinterException e) {
1394: MessageBox messageBox = new MessageBox(canvas
1395: .getShell(), SWT.OK | SWT.ICON_ERROR);
1396: messageBox.setMessage(e.getMessage());
1397: messageBox.open();
1398: }
1399: }
1400: }
1401: }
1402:
1403: /**
1404: * Creates a popup menu for the canvas.
1405: *
1406: * @param properties include a menu item for the chart property editor.
1407: * @param save include a menu item for saving the chart.
1408: * @param print include a menu item for printing the chart.
1409: * @param zoom include menu items for zooming.
1410: *
1411: * @return The popup menu.
1412: */
1413: protected Menu createPopupMenu(boolean properties, boolean save,
1414: boolean print, boolean zoom) {
1415:
1416: Menu result = new Menu(this );
1417: boolean separator = false;
1418:
1419: if (properties) {
1420: MenuItem propertiesItem = new MenuItem(result, SWT.PUSH);
1421: propertiesItem.setText(localizationResources
1422: .getString("Properties..."));
1423: propertiesItem.setData(PROPERTIES_COMMAND);
1424: propertiesItem.addSelectionListener(this );
1425: separator = true;
1426: }
1427: if (save) {
1428: if (separator) {
1429: new MenuItem(result, SWT.SEPARATOR);
1430: separator = false;
1431: }
1432: MenuItem saveItem = new MenuItem(result, SWT.NONE);
1433: saveItem.setText(localizationResources
1434: .getString("Save_as..."));
1435: saveItem.setData(SAVE_COMMAND);
1436: saveItem.addSelectionListener(this );
1437: separator = true;
1438: }
1439: if (print) {
1440: if (separator) {
1441: new MenuItem(result, SWT.SEPARATOR);
1442: separator = false;
1443: }
1444: MenuItem printItem = new MenuItem(result, SWT.NONE);
1445: printItem.setText(localizationResources
1446: .getString("Print..."));
1447: printItem.setData(PRINT_COMMAND);
1448: printItem.addSelectionListener(this );
1449: separator = true;
1450: }
1451: if (zoom) {
1452: if (separator) {
1453: new MenuItem(result, SWT.SEPARATOR);
1454: separator = false;
1455: }
1456:
1457: Menu zoomInMenu = new Menu(result);
1458: MenuItem zoomInMenuItem = new MenuItem(result, SWT.CASCADE);
1459: zoomInMenuItem.setText(localizationResources
1460: .getString("Zoom_In"));
1461: zoomInMenuItem.setMenu(zoomInMenu);
1462:
1463: this .zoomInBothMenuItem = new MenuItem(zoomInMenu, SWT.PUSH);
1464: this .zoomInBothMenuItem.setText(localizationResources
1465: .getString("All_Axes"));
1466: this .zoomInBothMenuItem.setData(ZOOM_IN_BOTH_COMMAND);
1467: this .zoomInBothMenuItem.addSelectionListener(this );
1468:
1469: new MenuItem(zoomInMenu, SWT.SEPARATOR);
1470:
1471: this .zoomInDomainMenuItem = new MenuItem(zoomInMenu,
1472: SWT.PUSH);
1473: this .zoomInDomainMenuItem.setText(localizationResources
1474: .getString("Domain_Axis"));
1475: this .zoomInDomainMenuItem.setData(ZOOM_IN_DOMAIN_COMMAND);
1476: this .zoomInDomainMenuItem.addSelectionListener(this );
1477:
1478: this .zoomInRangeMenuItem = new MenuItem(zoomInMenu,
1479: SWT.PUSH);
1480: this .zoomInRangeMenuItem.setText(localizationResources
1481: .getString("Range_Axis"));
1482: this .zoomInRangeMenuItem.setData(ZOOM_IN_RANGE_COMMAND);
1483: this .zoomInRangeMenuItem.addSelectionListener(this );
1484:
1485: Menu zoomOutMenu = new Menu(result);
1486: MenuItem zoomOutMenuItem = new MenuItem(result, SWT.CASCADE);
1487: zoomOutMenuItem.setText(localizationResources
1488: .getString("Zoom_Out"));
1489: zoomOutMenuItem.setMenu(zoomOutMenu);
1490:
1491: this .zoomOutBothMenuItem = new MenuItem(zoomOutMenu,
1492: SWT.PUSH);
1493: this .zoomOutBothMenuItem.setText(localizationResources
1494: .getString("All_Axes"));
1495: this .zoomOutBothMenuItem.setData(ZOOM_OUT_BOTH_COMMAND);
1496: this .zoomOutBothMenuItem.addSelectionListener(this );
1497:
1498: new MenuItem(zoomOutMenu, SWT.SEPARATOR);
1499:
1500: this .zoomOutDomainMenuItem = new MenuItem(zoomOutMenu,
1501: SWT.PUSH);
1502: this .zoomOutDomainMenuItem.setText(localizationResources
1503: .getString("Domain_Axis"));
1504: this .zoomOutDomainMenuItem.setData(ZOOM_OUT_DOMAIN_COMMAND);
1505: this .zoomOutDomainMenuItem.addSelectionListener(this );
1506:
1507: this .zoomOutRangeMenuItem = new MenuItem(zoomOutMenu,
1508: SWT.PUSH);
1509: this .zoomOutRangeMenuItem.setText(localizationResources
1510: .getString("Range_Axis"));
1511: this .zoomOutRangeMenuItem.setData(ZOOM_OUT_RANGE_COMMAND);
1512: this .zoomOutRangeMenuItem.addSelectionListener(this );
1513:
1514: Menu autoRangeMenu = new Menu(result);
1515: MenuItem autoRangeMenuItem = new MenuItem(result,
1516: SWT.CASCADE);
1517: autoRangeMenuItem.setText(localizationResources
1518: .getString("Auto_Range"));
1519: autoRangeMenuItem.setMenu(autoRangeMenu);
1520:
1521: this .zoomResetBothMenuItem = new MenuItem(autoRangeMenu,
1522: SWT.PUSH);
1523: this .zoomResetBothMenuItem.setText(localizationResources
1524: .getString("All_Axes"));
1525: this .zoomResetBothMenuItem.setData(ZOOM_RESET_BOTH_COMMAND);
1526: this .zoomResetBothMenuItem.addSelectionListener(this );
1527:
1528: new MenuItem(autoRangeMenu, SWT.SEPARATOR);
1529:
1530: this .zoomResetDomainMenuItem = new MenuItem(autoRangeMenu,
1531: SWT.PUSH);
1532: this .zoomResetDomainMenuItem.setText(localizationResources
1533: .getString("Domain_Axis"));
1534: this .zoomResetDomainMenuItem
1535: .setData(ZOOM_RESET_DOMAIN_COMMAND);
1536: this .zoomResetDomainMenuItem.addSelectionListener(this );
1537:
1538: this .zoomResetRangeMenuItem = new MenuItem(autoRangeMenu,
1539: SWT.PUSH);
1540: this .zoomResetRangeMenuItem.setText(localizationResources
1541: .getString("Range_Axis"));
1542: this .zoomResetRangeMenuItem
1543: .setData(ZOOM_RESET_RANGE_COMMAND);
1544: this .zoomResetRangeMenuItem.addSelectionListener(this );
1545: }
1546:
1547: return result;
1548: }
1549:
1550: /**
1551: * Handles action events generated by the popup menu.
1552: *
1553: * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(
1554: * org.eclipse.swt.events.SelectionEvent)
1555: */
1556: public void widgetDefaultSelected(SelectionEvent e) {
1557: // TODO Auto-generated method stub
1558:
1559: }
1560:
1561: /**
1562: * Handles action events generated by the popup menu.
1563: *
1564: * @see org.eclipse.swt.events.SelectionListener#widgetSelected(
1565: * org.eclipse.swt.events.SelectionEvent)
1566: */
1567: public void widgetSelected(SelectionEvent e) {
1568: String command = (String) ((MenuItem) e.getSource()).getData();
1569: if (command.equals(PROPERTIES_COMMAND)) {
1570: attemptEditChartProperties();
1571: } else if (command.equals(SAVE_COMMAND)) {
1572: try {
1573: doSaveAs();
1574: } catch (IOException ex) {
1575: ex.printStackTrace();
1576: }
1577: } else if (command.equals(PRINT_COMMAND)) {
1578: createChartPrintJob();
1579: }
1580: /* in the next zoomPoint.x and y replace by e.x and y for now.
1581: * this helps to handle the mouse events and besides,
1582: * those values are unused AFAIK. */
1583: else if (command.equals(ZOOM_IN_BOTH_COMMAND)) {
1584: zoomInBoth(e.x, e.y);
1585: } else if (command.equals(ZOOM_IN_DOMAIN_COMMAND)) {
1586: zoomInDomain(e.x, e.y);
1587: } else if (command.equals(ZOOM_IN_RANGE_COMMAND)) {
1588: zoomInRange(e.x, e.y);
1589: } else if (command.equals(ZOOM_OUT_BOTH_COMMAND)) {
1590: zoomOutBoth(e.x, e.y);
1591: } else if (command.equals(ZOOM_OUT_DOMAIN_COMMAND)) {
1592: zoomOutDomain(e.x, e.y);
1593: } else if (command.equals(ZOOM_OUT_RANGE_COMMAND)) {
1594: zoomOutRange(e.x, e.y);
1595: } else if (command.equals(ZOOM_RESET_BOTH_COMMAND)) {
1596: restoreAutoBounds();
1597: } else if (command.equals(ZOOM_RESET_DOMAIN_COMMAND)) {
1598: restoreAutoDomainBounds();
1599: } else if (command.equals(ZOOM_RESET_RANGE_COMMAND)) {
1600: restoreAutoRangeBounds();
1601: }
1602: this .forceRedraw();
1603: }
1604:
1605: public int print(Graphics graphics, PageFormat pageFormat,
1606: int pageIndex) throws PrinterException {
1607: if (pageIndex != 0) {
1608: return NO_SUCH_PAGE;
1609: }
1610: /*
1611: CairoImage image = new CairoImage(
1612: this.getBounds().width, this.getBounds().height );
1613: Graphics2D g2 = image.createGraphics2D();
1614: double x = pageFormat.getImageableX();
1615: double y = pageFormat.getImageableY();
1616: double w = pageFormat.getImageableWidth();
1617: double h = pageFormat.getImageableHeight();
1618: this.chart.draw(
1619: g2, new Rectangle2D.Double(x, y, w, h), this.anchor, null
1620: );
1621: */
1622: return PAGE_EXISTS;
1623: }
1624:
1625: }
|