content: /* ===========================================================
   * JFreeChart : a free chart library for the Java(tm) platform
   * ===========================================================
   *
   * (C) Copyright 2000-2013, by Object Refinery Limited and Contributors.
   *
   * Project Info:  http://www.jfree.org/jfreechart/index.html
   *
   * This library is free software; you can redistribute it and/or modify it
   * under the terms of the GNU Lesser General Public License as published by
   * the Free Software Foundation; either version 2.1 of the License, or
   * (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
   * License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
   * USA.
   *
   * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
   * in the United States and other countries.]
   *
   * ----------------
   * ZoomHandler.java
   * ----------------
   * (C) Copyright 2013, by Object Refinery Limited and Contributors.
   *
   * Original Author:  David Gilbert (for Object Refinery Limited);
   * Contributor(s):   Michael Zinsmaier;
   *
   * Changes:
   * --------
   * 11-Jun-2009 : Version 1 (DG);
   *
   */
  
  package org.jfree.chart.panel;
  
  import java.awt.Color;
  import java.awt.Graphics2D;
  import java.awt.event.MouseEvent;
  import java.awt.geom.Point2D;
  import java.awt.geom.Rectangle2D;
  
  import org.jfree.chart.ChartPanel;
  import org.jfree.chart.plot.PlotOrientation;
  import org.jfree.chart.util.ShapeUtilities;
  
  /**
   * A mouse handler than performs a zooming operation on a ChartPanel.
   */
  public class ZoomHandler extends AbstractMouseHandler {
  
      /** a generated serial id. */
      private static final long serialVersionUID = -3796063183854513802L;
  
      private Point2D zoomPoint;
  
      private Rectangle2D zoomRectangle;
  
      public ZoomHandler(int modifier) {
          super(modifier);
          zoomPoint = null;
      }
      
      public ZoomHandler() {
          super();
          zoomPoint = null;
      }
  
      @Override
      public void mousePressed(MouseEvent e) {
          ChartPanel chartPanel = (ChartPanel) e.getSource();
          Rectangle2D screenDataArea = chartPanel.getScreenDataArea(e.getX(),
                  e.getY());
          if (screenDataArea != null) {
              this.zoomPoint = ShapeUtilities.getPointInRectangle(e.getX(),
                      e.getY(), screenDataArea);
          }
          else {
              this.zoomPoint = null;
              chartPanel.clearLiveMouseHandler();
          }
      }
  
      @Override
      public void mouseDragged(MouseEvent e) {
          ChartPanel panel = (ChartPanel) e.getSource();
  
          if (this.zoomPoint == null) {
              //no initial zoom rectangle exists but the handler is set
              //as life handler unregister
              panel.clearLiveMouseHandler();
              return;
          }
  
          Graphics2D g2 = (Graphics2D) panel.getGraphics();
  
          // erase the previous zoom rectangle (if any).  We only need to do
          // this is we are using XOR mode, which we do when we're not using
          // the buffer (if there is a buffer, then at the end of this method we
          // just trigger a repaint)
          if (!panel.getUseBuffer()) {
              drawZoomRectangle(panel, g2, true);
          }
  
          boolean hZoom, vZoom;
          if (panel.getOrientation() == PlotOrientation.HORIZONTAL) {
              hZoom = panel.isRangeZoomable();
              vZoom = panel.isDomainZoomable();
          }
          else {
              hZoom = panel.isDomainZoomable();
              vZoom = panel.isRangeZoomable();
          }
          Rectangle2D scaledDataArea = panel.getScreenDataArea(
                  (int) this.zoomPoint.getX(), (int) this.zoomPoint.getY());
          if (hZoom && vZoom) {
              // selected rectangle shouldn't extend outside the data area...
              double xmax = Math.min(e.getX(), scaledDataArea.getMaxX());
              double ymax = Math.min(e.getY(), scaledDataArea.getMaxY());
              this.zoomRectangle = new Rectangle2D.Double(
                      this.zoomPoint.getX(), this.zoomPoint.getY(),
                      xmax - this.zoomPoint.getX(), ymax - this.zoomPoint.getY());
          }
          else if (hZoom) {
              double xmax = Math.min(e.getX(), scaledDataArea.getMaxX());
              this.zoomRectangle = new Rectangle2D.Double(
                      this.zoomPoint.getX(), scaledDataArea.getMinY(),
                      xmax - this.zoomPoint.getX(), scaledDataArea.getHeight());
          }
          else if (vZoom) {
              double ymax = Math.min(e.getY(), scaledDataArea.getMaxY());
              this.zoomRectangle = new Rectangle2D.Double(
                      scaledDataArea.getMinX(), this.zoomPoint.getY(),
                      scaledDataArea.getWidth(), ymax - this.zoomPoint.getY());
          }
          panel.setZoomRectangle(this.zoomRectangle);
          // Draw the new zoom rectangle...
          if (panel.getUseBuffer()) {
              panel.repaint();
          }
          else {
              // with no buffer, we use XOR to draw the rectangle "over" the
              // chart...
              drawZoomRectangle(panel, g2, true);
          }
          g2.dispose();
      }
  
      @Override
      public void mouseReleased(MouseEvent e) {
          ChartPanel panel = (ChartPanel) e.getSource();
          
          if (this.zoomRectangle == null) {
              //no initial zoom rectangle exists but the handler is set
              //as life handler unregister
              panel.clearLiveMouseHandler();
              return;
          }
          
          boolean hZoom, vZoom;
          if (panel.getOrientation() == PlotOrientation.HORIZONTAL) {
              hZoom = panel.isRangeZoomable();
              vZoom = panel.isDomainZoomable();
          }
          else {
              hZoom = panel.isDomainZoomable();
              vZoom = panel.isRangeZoomable();
          }
  
          boolean zoomTrigger1 = hZoom && Math.abs(e.getX()
                  - this.zoomPoint.getX()) >= panel.getZoomTriggerDistance();
          boolean zoomTrigger2 = vZoom && Math.abs(e.getY()
                  - this.zoomPoint.getY()) >= panel.getZoomTriggerDistance();
          if (zoomTrigger1 || zoomTrigger2) {
              if ((hZoom && (e.getX() < this.zoomPoint.getX()))
                      || (vZoom && (e.getY() < this.zoomPoint.getY()))) {
                  panel.restoreAutoBounds();
              }
              else {
                  double x, y, w, h;
                  Rectangle2D screenDataArea = panel.getScreenDataArea(
                          (int) this.zoomPoint.getX(),
                          (int) this.zoomPoint.getY());
                  double maxX = screenDataArea.getMaxX();
                  double maxY = screenDataArea.getMaxY();
                  // for mouseReleased event, (horizontalZoom || verticalZoom)
                  // will be true, so we can just test for either being false;
                  // otherwise both are true
                  if (!vZoom) {
                      x = this.zoomPoint.getX();
                      y = screenDataArea.getMinY();
                      w = Math.min(this.zoomRectangle.getWidth(),
                              maxX - this.zoomPoint.getX());
                      h = screenDataArea.getHeight();
                  }
                  else if (!hZoom) {
                      x = screenDataArea.getMinX();
                      y = this.zoomPoint.getY();
                      w = screenDataArea.getWidth();
                      h = Math.min(this.zoomRectangle.getHeight(),
                              maxY - this.zoomPoint.getY());
                  }
                  else {
                      x = this.zoomPoint.getX();
                      y = this.zoomPoint.getY();
                      w = Math.min(this.zoomRectangle.getWidth(),
                              maxX - this.zoomPoint.getX());
                      h = Math.min(this.zoomRectangle.getHeight(),
                              maxY - this.zoomPoint.getY());
                  }
                  Rectangle2D zoomArea = new Rectangle2D.Double(x, y, w, h);
                  panel.zoom(zoomArea);
              }
              this.zoomPoint = null;
              this.zoomRectangle = null;
              panel.setZoomRectangle(null);
              panel.clearLiveMouseHandler();
          }
          else {
              // erase the zoom rectangle
              Graphics2D g2 = (Graphics2D) panel.getGraphics();
              if (panel.getUseBuffer()) {
                  panel.repaint();
              }
              else {
                  drawZoomRectangle(panel, g2, true);
              }
              g2.dispose();
              this.zoomPoint = null;
              this.zoomRectangle = null;
              panel.setZoomRectangle(null);
              panel.clearLiveMouseHandler();
          }
      }
  
      /**
       * Draws zoom rectangle (if present).
       * The drawing is performed in XOR mode, therefore
       * when this method is called twice in a row,
       * the second call will completely restore the state
       * of the canvas.
       *
       * @param g2 the graphics device.
       * @param xor  use XOR for drawing?
       */
      private void drawZoomRectangle(ChartPanel panel, Graphics2D g2,
              boolean xor) {
          if (this.zoomRectangle != null) {
              if (xor) {
                   // Set XOR mode to draw the zoom rectangle
                  g2.setXORMode(Color.gray);
              }
              if (panel.getFillZoomRectangle()) {
                  g2.setPaint(panel.getZoomFillPaint());
                  g2.fill(this.zoomRectangle);
              }
              else {
                  g2.setPaint(panel.getZoomOutlinePaint());
                  g2.draw(this.zoomRectangle);
              }
              if (xor) {
                  // Reset to the default 'overwrite' mode
                  g2.setPaintMode();
              }
          }
      }
  
      /**
       * @see AbstractMouseHandler#isLiveHandler()
       */
      public boolean isLiveHandler() {
          return true;
      }
  
  }
  