/*
 * This code is part of Project Waterloo from King's College London
 * 
 *
 * Copyright King's College London 2011-
 *
 * @author Malcolm Lidierth, King's College London  [Contact]
 *
 * Project Waterloo 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 3 of the License, or
 * (at your option) any later version.
 *
 * Project Waterloo is distributed in the hope that it will  be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 *
 * -----------------------------------------------------------------------------
 *
 * GJAbstractGraph. Developed from the JXGraph class from the
 * SwingLabs SwingX Project.
 *
 * JXGraph was originally written by Romain Guy to display functions.
 * See Filthy Rich Clients, C. Haase & R. Guy - Addison Wesley (2008).
 *
 * GJAbstractGraph and its subclasses were developed to display experimental data.
 *
 * -----------------------------------------------------------------------------
 *
 * $Id: JXGraph.java 3671 2010-04-23 20:57:49Z kschaefe $
 *
 * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser 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 Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 *
 * -----------------------------------------------------------------------------
 *
 * 

This version is part of the Waterloo Scientific Graphics package from * King's College London

* * The Waterloo Scientific Graphics library is free software; you can redistribute * it and/or modify it under the terms of the GNU Lesser Lesser General Public License * as published by the Free Software Foundation; either version 3 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 Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * @author Malcolm Lidierth, King's College London [Contact] */ package kcl.waterloo.graphics; import java.awt.*; import java.awt.event.*; import java.awt.geom.Path2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.ref.Reference; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import javax.swing.*; import kcl.waterloo.actions.ActionManager; import kcl.waterloo.annotation.GJAnnotationInterface; import kcl.waterloo.defaults.Colors; import kcl.waterloo.defaults.GJDefaults; import kcl.waterloo.graphics.data.Category; import kcl.waterloo.graphics.images.Images; import kcl.waterloo.graphics.plots2D.GJPlotInterface; import kcl.waterloo.graphics.plots2D.GJPolarPlotInterface; import kcl.waterloo.graphics.plots2D.GJTransformUpdateInterface; import kcl.waterloo.graphics.transforms.GJDataTransformInterface; import kcl.waterloo.graphics.transforms.NOPTransform; import kcl.waterloo.math.ArrayMath; import kcl.waterloo.serviceproviders.GJEditorInterface; import kcl.waterloo.serviceproviders.GUIFactory; import kcl.waterloo.swing.GCGrid; import kcl.waterloo.xml.GJEncoder; /** * Abstract class implementing the {@code GJGraphInterface}. At present, the * only concrete implementation is through the {@code GJGraph} class. * * While {@code GJGraph} instances can be independent of their containers, they * will normally be added to a {@code GJAbstractGraphContainer} instance. * *

* GJAbstractGraph. Developed from the JXGraph class from the SwingLabs SwingX * Project.

* *

* JXGraph was originally written by Romain Guy to display functions. See Filthy Rich Clients , C. Haase & R. * Guy - Addison Wesley (2008).

* *

* GJAbstractGraph and its subclasses were developed to display experimental * data.

* *

* -----------------------------------------------------------------------------

* *

* $Id: JXGraph.java 3671 2010-04-23 20:57:49Z kschaefe $

* *

* Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * California 95054, U.S.A. All rights reserved.

* *

* This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser 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 Lesser General Public License * for more details.

* *

* You should have received a copy of the GNU Lesser Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

* * ----------------------------------------------------------------------------- * *

* This version is part of the Waterloo Scientific Graphics package from King's * College London

* *

* The Waterloo Scientific Graphics library is free software; you can * redistribute it and/or modify it under the terms of the GNU Lesser Lesser * General Public License as published by the Free Software Foundation; either * version 3 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 Lesser General Public License * for more details.

* *

* You should have received a copy of the GNU Lesser Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

* * @author Malcolm Lidierth, King's College London [Contact] */ public abstract class GJAbstractGraph extends GJAbstractGraph1 { /** * stroke width used to draw the main axis and grid * */ private float axisStrokeWeight = ((Float) GJDefaults.getMap().get("GJAbstractGraph.axisStroke")); /** * stroke width used to draw the minor grid */ float minorGridStrokeWeight = ((Float) GJDefaults.getMap().get("GJAbstractGraph.minorGridStrokeWeight")); float majorGridStrokeWeight = ((Float) GJDefaults.getMap().get("GJAbstractGraph.majorGridStrokeWeight")); /** * Key anti-aliasing value */ private Object keyAntialiasing = GJDefaults.getMap2().get("GJAbstractGraph.keyAntialiasing"); /** * Text anti-aliasing value */ private Object textAntialiasing = GJDefaults.getMap2().get("GJAbstractGraph.textAntialiasing"); /** * Set true to paint the major grid */ private boolean majorGridPainted = ((Boolean) GJDefaults.getMap().get("GJAbstractGraph.majorGridPainted")); /** * Set true to paint the minor grid */ private boolean minorGridPainted = ((Boolean) GJDefaults.getMap().get("GJAbstractGraph.minorGridPainted")); /** * Major grid color */ private Color majorGridColor = (Color) GJDefaults.getMap().get("GJAbstractGraph.majorGridColor"); /** * Minor grid color */ private Color minorGridColor = (Color) GJDefaults.getMap().get("GJAbstractGraph.minorGridColor"); /** * Inner axis color */ private Color axisColor = (Color) GJDefaults.getMap().get("GJAbstractGraph.axisColor"); /** * set true to paint the axes within the view */ private boolean innerAxisPainted = ((Boolean) GJDefaults.getMap().get("GJAbstractGraph.innerAxisPainted")); /** * set true to paint the labels for axes within the view */ private boolean innerAxisLabelled = ((Boolean) GJDefaults.getMap().get("GJAbstractGraph.innerAxisLabelled")); /** * Set true to painted left axis */ private boolean leftAxisPainted = true; /** * Set true to painted right axis */ private boolean rightAxisPainted = false; /** * Set true to painted top axis */ private boolean topAxisPainted = false; /** * Set true to painted bottom axis */ private boolean bottomAxisPainted = true; /** * Set true to label the left axis */ private boolean leftAxisLabelled = true; /** * Set true to label the right axis */ private boolean rightAxisLabelled = false; /** * Set true to label the top axis */ private boolean topAxisLabelled = false; /** * Set true to label the bottom axis */ private boolean bottomAxisLabelled = true; /** * If true, displayed mouse positions will be inverse transformed for * display via the transform for the relevant axis */ private boolean mouseTextAsInverse = ((Boolean) GJDefaults.getMap().get("GJAbstractGraph.mouseTextAsInverse")).booleanValue(); /** * Main formatter for axis labels */ /** * Formatter for the mouse Position text */ private String mousePositionTextFormat = (String) GJDefaults.getMap().get("GJAbstractGraph.mousePositionTextFormat"); private NumberFormat mainFormatter = (NumberFormat) GJDefaults.getMap().get("GJAbstractGraph.mainFormatter"); /** * Secondary formatter for axis labels e.g. to use enginering notation for * small or large numbers */ private NumberFormat secondFormatter = (NumberFormat) GJDefaults.getMap().get("GJAbstractGraph.secondFormatter"); /** * Value for the separation between major grid lines on the x-axis. */ private double majorXHint; /** * Value for the separation between major grid lines on the y-axis. */ private double majorYHint; /** * Number of minor grid lines to paint between major grids */ private int minorCountXHint; /** * Number of minor grid lines to paint between major grids */ private int minorCountYHint; /** * used by the GraphMouseHandler to move the view */ private Point2D dragStart = new Point2D.Double(); private Point2D mouseDown; /** * If true, axes will not be padded */ boolean tightAxes = ((Boolean) GJDefaults.getMap().get("GJAbstractGraph.tightAxes")); /** * Fraction to pad axes by - 0 to 1. */ double axesPadding = ((Double) GJDefaults.getMap().get("GJAbstractGraph.axesPadding")).floatValue(); /** * Mouse Position - used internally */ private Point2D currentMousePosition; /** * Internal flag */ private boolean dragX = false; /** * Internal flag */ private boolean dragY = false; /** * The current ROI in pixels */ private final Rectangle2D.Double pixelROI = new Rectangle2D.Double(Double.NaN, Double.NaN, 0d, 0d); /** * Current ROI in axes units */ private Rectangle2D.Double currentROI = null; /** * List of ROIs in axes units. */ private ArrayList availableROI = null; /** * Reference to the leftAxisPanel that will be painted in the * {@code GJGraphContainer} if there is one. */ private GJAxisPanel leftAxisPanel = null; /** * Reference to the rightAxisPanel that will be painted in the * {@code GJGraphContainer} if there is one. */ private GJAxisPanel rightAxisPanel = null; /** * Reference to the topAxisPanel that will be painted in the * {@code GJGraphContainer} if there is one. */ private GJAxisPanel topAxisPanel = null; /** * Reference to the bottomAxisPanel that will be painted in the * {@code GJGraphContainer} if there is one. */ private GJAxisPanel bottomAxisPanel = null; /** * List of plots that are top plots for this graph */ private final ArrayList plots = new ArrayList(); /** * List of plots that are currently selected (e.g. with the mouse). */ private ArrayList selectedPlots = null; /** * Reference to the graph container (if there is one). */ private GJAbstractGraphContainer graphContainer = null; /** * Used internally */ private final static Cursor originCursor = Toolkit.getDefaultToolkit().createCustomCursor(Images.getImage("origin.gif"), new Point(8, 8), "Origin"); /** * List of layers. The first element is the View, i.e. the principal * ancestor of other graphs in the array */ private final ArrayList layers = new ArrayList(); /** * List of linked objects for this graph */ private final ArrayList links = new ArrayList(); /** * {@code currentLayer} is maintained in the top level graph of a hierarchy * of graphs and provides a reference to the graph that presently has focus. * Code that changes the focus should also update the value of * {@code currentLayer}. {@code currentLayer} has no useful meaning for * graphs that are not the principal ancestor (layers[0]) and should be left * as null in those. */ private GJGraphInterface currentLayer = null; /* * JTextField that will be updated with the current mouse Position */ JLabel mousePosition; /** * Editor GUI for this graph. */ private transient GJEditorInterface editor = null; /** * Handler for mouse events and drags over the outer axes */ private final MouseAdapter axisMouseHandler = new AxisMouseHandler(); /** * listens to changes to plots and repaints the graph */ PropertyChangeListener plotChangeListener = null; /** * Set true for polar grid, false for Cartesian. */ private boolean polar = false; /** * If this graph (or its container) is housed in a higher level container * supporting the {code GJGridInterface}, that container should be * referenced here. */ private GJGridInterface gridInterface = null; private final JPopupMenu contextMenu = new JPopupMenu(); private JMenu gridMenu = null; /** * Default constructor. */ GJAbstractGraph() { super(); setLayout(new GraphLayout()); setFocusable(true); setEnabled(true); setForeground(Color.BLACK); setBackground((Color) GJDefaults.getMap().get("GJAbstractGraph.backgroundColor")); setBackgroundPainted(((Boolean) GJDefaults.getMap().get("GJAbstractGraph.backgroundPainted"))); // addMouseListener(GJEventManager.getInstance()); addMouseWheelListener(GraphMouseWheelHandler.getInstance()); // addListeners(); createPopup(); getLayers().add(this); this.addPropertyChangeListener(this); } /** * */ private void createPopup() { GraphMenuAction listener0 = new GraphMenuAction(this); // Main menu items JPopupMenu mainMenu = contextMenu; // Set up for save JMenuItem graphSave = new JMenuItem("Save Graph"); graphSave.setActionCommand("Save Graph"); graphSave.addActionListener(listener0); mainMenu.add(graphSave); // Set up for export graphSave = new JMenuItem("Export Graph"); graphSave.setActionCommand("Save As"); graphSave.addActionListener(listener0); mainMenu.add(graphSave); //Copy As Image graphSave = new JMenuItem("Copy Graph"); graphSave.setActionCommand("Copy"); graphSave.addActionListener(listener0); mainMenu.add(graphSave); //Edit graphSave = new JMenuItem("Edit Graph"); graphSave.addActionListener(new EditMenuAction(this)); mainMenu.add(graphSave); graphSave = new JMenuItem("Autoscale Axes"); graphSave.setActionCommand("Autoscale axes"); graphSave.addActionListener(listener0); mainMenu.add(graphSave); } @Override public final void createAxes() { if (getGraphContainer() != null) { if (leftAxisPanel == null) { leftAxisPanel = GJAxisPanel.createInstance(this, GJAxisPanel.Position.LEFT); } //getGraphContainer().add(leftAxisPanel); leftAxisPanel.setTickLabelsPainted(leftAxisLabelled); if (rightAxisPanel == null) { rightAxisPanel = GJAxisPanel.createInstance(this, GJAxisPanel.Position.RIGHT); } //getGraphContainer().add(rightAxisPanel); rightAxisPanel.setTickLabelsPainted(rightAxisLabelled); if (topAxisPanel == null) { topAxisPanel = GJAxisPanel.createInstance(this, GJAxisPanel.Position.TOP); } //getGraphContainer().add(topAxisPanel); topAxisPanel.setTickLabelsPainted(topAxisLabelled); if (bottomAxisPanel == null) { bottomAxisPanel = GJAxisPanel.createInstance(this, GJAxisPanel.Position.BOTTOM); } //getGraphContainer().add(bottomAxisPanel); bottomAxisPanel.setTickLabelsPainted(bottomAxisLabelled); getGraphContainer().revalidate(); getGraphContainer().repaint(); } } void removeAxes() { if (getParent() != null) { if (leftAxisPanel != null) { getParent().remove(leftAxisPanel); } if (rightAxisPanel != null) { getParent().remove(rightAxisPanel); } if (topAxisPanel != null) { getParent().remove(topAxisPanel); } if (bottomAxisPanel != null) { getParent().remove(bottomAxisPanel); } } leftAxisPanel = null; rightAxisPanel = null; topAxisPanel = null; bottomAxisPanel = null; } /** * Adds the specified graph as a new layer. * * @param graph the graph to add * @return the added graph */ public final GJGraphInterface plus(GJGraphInterface graph) { return add(graph); } @Override public final GJGraphInterface add(GJGraphInterface graph) { GraphLayout layout = (GraphLayout) this.getLayout(); layout.putConstraint(SpringLayout.NORTH, (Component) graph, 0, SpringLayout.NORTH, this); layout.putConstraint(SpringLayout.SOUTH, (Component) graph, 0, SpringLayout.SOUTH, this); layout.putConstraint(SpringLayout.WEST, (Component) graph, 0, SpringLayout.WEST, this); layout.putConstraint(SpringLayout.EAST, (Component) graph, 0, SpringLayout.EAST, this); if (graphContainer != null) { graph.setGraphContainer(this.graphContainer); } //graph.addListeners(); ((GJAbstractGraph) graph).setEnabled(true); if (graphContainer != null) { graph.createAxes(); graph.addPropertyChangeListener(graphContainer); } graph.setBackgroundPainted(false); ((Component) graph).setBackground(Colors.getColor("TRANSPARENT")); graph.setMajorGridPainted(false); graph.setMinorGridPainted(false); super.add((Component) graph); this.getLayers().add(graph); this.setCurrentLayer(graph); return graph; } /** * Overridden {@code add} method. Performs some class checking to ensure the * correct {@code add} method gets called during XML deserialization. * * Users calling this method need to add appropriate constraints to the * layout. * * @param c * @return the added Component */ @Override public Component add(final Component c) { if (c instanceof GJGraphInterface) { add((GJGraphInterface) c); } else if (c instanceof GJRoi) { GJRoi roi = (GJRoi) c; super.add(roi); addComponentListener(roi); addPropertyChangeListener(roi); revalidate(); repaint(); } else { super.add(c); revalidate(); repaint(); } return c; } // For deserialisation public GJAbstractGraph add(GJAbstractGraph gr) { return (GJAbstractGraph) add((GJGraphInterface) gr); } @Override public final void add(GJAnnotationInterface a) { if (graphContainer != null) { graphContainer.getAnnotations().add(a); a.setParentGraph(this); } } // public void addFast(final GJPlotInterface plot) { // if (plot.isTopPlot()) { // plots.add(plot); // plot.setParentGraph(this); // } // } /** * Adds the specified plot as a top plot * * @param plot the plot to add * @return the added plot */ public final GJPlotInterface plus(final GJPlotInterface plot) { return add(plot, true); } @Override public final GJPlotInterface add(final GJPlotInterface plot) { return add(plot, true); } @Override public final GJPlotInterface add(final GJPlotInterface plot, final boolean flag) { if (plot.isTopPlot()) { plots.add(plot); plot.setParentGraph(this); if (flag) { if (plot instanceof GJPolarPlotInterface) { setPolar(true); getGraphContainer().setAspectRatio(1d); setInnerAxisLabelled(true); setTopAxisPainted(false); setBottomAxisPainted(false); setLeftAxisPainted(false); setRightAxisPainted(false); updatePlots(); autoScale(); } else { updatePlots(); boolean previous = tightAxes; tightAxes = true; autoScale(); tightAxes = previous; } plot.addPropertyChangeListener(this); } if (plot instanceof GJTransformUpdateInterface) { plot.firePropertyChange(new PropertyChangeEvent(this, "parentGraph", null, this)); } } else { } // If titles not yet set, take them from the added plot if (getBottomAxisPanel() != null && getBottomAxisPanel().getText().isEmpty()) { if (plot.getXData() != null) { getBottomAxisPanel().setText(plot.getXData().getName()); } } if (getTopAxisPanel() != null && getTopAxisPanel().getText().isEmpty()) { if (plot.getXData() != null) { getTopAxisPanel().setText(plot.getXData().getName()); } } if (getLeftAxisPanel() != null && getLeftAxisPanel().getText().isEmpty()) { if (plot.getYData() != null) { getLeftAxisPanel().setText(plot.getYData().getName()); } } if (getRightAxisPanel() != null && getRightAxisPanel().getText().isEmpty()) { if (plot.getYData() != null) { getRightAxisPanel().setText(plot.getYData().getName()); } } return plot; } @Override public void remove(GJPlotInterface plot) { if (plots.contains(plot)) { plot.removePropertyChangeListener(this); plots.remove(plot); } } /** * Returns the plots below the screen pixel location specified. * * @param x the x-Position * @param y the y-Position * @return the plots as an ArrayList */ public final ArrayList getPlotAt(double x, double y) { ArrayList ch = this.getLayers(); ArrayList found = new ArrayList(); ArrayList temp; for (GJGraphInterface gr : ch) { for (GJPlotInterface p : gr.getPlots()) { temp = p.findPlotBelow(x, y); found.addAll(temp); if (found.size() > 0) { return found; } } } return found; } @Override public final ArrayList getLayers() { return layers; } @Override public final GJGraphInterface getLayer(int n) { return layers.get(n); } @Override public final GJGraphInterface getCurrentLayer() { return currentLayer; } @Override public final void setCurrentLayer(final GJGraphInterface layer) { int idx = layers.indexOf(layer); if (idx >= 0) { currentLayer = layer; ((GJAbstractGraph) currentLayer).requestFocusInWindow(); } if (editor != null) { int i = layer.indexOf(); editor.setSelectedTab(i); } } @Override public final void setCurrentLayerIndex(int n) { if (n < layers.size()) { setCurrentLayer(layers.get(n)); } } @Override public final int getCurrentLayerIndex() { return layers.indexOf(currentLayer); } @Override public final int indexOf() { return this.getAncestorGraph().getLayers().indexOf(this); } @Override public final GJAbstractGraph getAncestorGraph() { Component previous = this; while (previous.getParent() != null && previous.getParent() instanceof GJGraphInterface) { previous = previous.getParent(); } return (GJAbstractGraph) previous; } @Override public final Component add(Component c, double x, double y) { return this.add(c, x, y, SwingConstants.CENTER, SwingConstants.CENTER); } @Override public final Component add(Component c, double x, double y, int alignX, int alignY) { c = super.add(c, 0); GraphLayout layout = (GraphLayout) getLayout(); layout.putGraphicConstraint(c, x, y, alignX, alignY); //setComponentZOrder(c, 0); revalidate(); if (this.graphContainer != null) { c.addMouseListener(this.graphContainer.getContainerMouseHandler()); c.addMouseMotionListener(this.graphContainer.getContainerMouseHandler()); } return c; } @Override public final void remove(Component c) { GraphLayout layout = (GraphLayout) getLayout(); if (layout.getComponentMap().containsKey(c)) { layout.getComponentMap().remove(c); } super.remove(c); } final void nullifyParent() { getLayout().removeLayoutComponent(getParent()); validate(); graphContainer = null; } @Override public final void setGraphContainer(GJAbstractGraphContainer c) { //Insets insets = new Insets(50, 50, 50, 50); this.setGraphContainer(c, null); } // TODO: Insets not used, get rid of this. @Override public final void setGraphContainer(GJAbstractGraphContainer c, Insets insets) { if (c == null && graphContainer != null) { graphContainer.remove(this); return; } if (c != null) { SpringLayout layout = (SpringLayout) getLayout(); graphContainer = c; Insets summedInsets = graphContainer.getInsets(); layout.putConstraint(SpringLayout.WEST, this, summedInsets.left, SpringLayout.WEST, c); layout.putConstraint(SpringLayout.NORTH, this, summedInsets.top, SpringLayout.NORTH, c); layout.putConstraint(SpringLayout.EAST, c, summedInsets.right, SpringLayout.EAST, this); layout.putConstraint(SpringLayout.SOUTH, c, summedInsets.bottom, SpringLayout.SOUTH, this); setFont(c.getFont()); } else { graphContainer = null; } } @Override public final GJAbstractGraphContainer getGraphContainer() { return graphContainer; // // This fixes the break from non-standard bean getter setter // if (graphContainer == null && (getParent() instanceof GJAbstractGraphContainer)) { // graphContainer = (GJAbstractGraphContainer) getParent(); // return graphContainer; // } // if (getAncestorGraph() == this) { // return graphContainer; // } else if (getAncestorGraph() != null) { // // recursive call // return getAncestorGraph().getGraphContainer(); // } else { // return null; // } } @Override public final boolean isInnerAxisPainted() { return innerAxisPainted; } @Override public final void setInnerAxisPainted(boolean flag) { boolean old = innerAxisPainted; innerAxisPainted = flag; firePropertyChange("InnerAxisPainted", old, this.innerAxisPainted); } @Override public final boolean isInnerAxisLabelled() { return innerAxisLabelled; } @Override public final void setInnerAxisLabelled(boolean textPainted) { boolean old = isInnerAxisLabelled(); this.innerAxisLabelled = textPainted; firePropertyChange("innerAxisLabelsPainted", old, this.isInnerAxisLabelled()); } @Override public final boolean isMajorGridPainted() { return majorGridPainted; } @Override public final void setMajorGridPainted(boolean gridPainted) { boolean old = isMajorGridPainted(); this.majorGridPainted = gridPainted; firePropertyChange("majorGridPainted", old, isMajorGridPainted()); } @Override public final boolean isMinorGridPainted() { return minorGridPainted; } @Override public final void setMinorGridPainted(boolean gridPainted) { boolean old = isMinorGridPainted(); this.minorGridPainted = gridPainted; firePropertyChange("minorGridPainted", old, isMinorGridPainted()); } @Override public final boolean isLeftAxisPainted() { return leftAxisPainted; } @Override public final boolean isRightAxisPainted() { return rightAxisPainted; } @Override public final boolean isTopAxisPainted() { return topAxisPainted; } @Override public final boolean isBottomAxisPainted() { return bottomAxisPainted; } @Override public final boolean isLeftAxisLabelled() { return leftAxisLabelled; } @Override public final void setLeftAxisLabelled(boolean flag) { leftAxisLabelled = flag; if (leftAxisPanel != null) { leftAxisPanel.setTickLabelsPainted(flag); } } @Override public final boolean isRightAxisLabelled() { return rightAxisLabelled; } @Override public final void setRightAxisLabelled(boolean flag) { rightAxisLabelled = flag; if (rightAxisPanel != null) { rightAxisPanel.setTickLabelsPainted(flag); } } @Override public final boolean isTopAxisLabelled() { return topAxisLabelled; } @Override public final void setTopAxisLabelled(boolean flag) { topAxisLabelled = flag; if (topAxisPanel != null) { topAxisPanel.setTickLabelsPainted(flag); } } @Override public final boolean isBottomAxisLabelled() { return bottomAxisLabelled; } @Override public final void setBottomAxisLabelled(boolean flag) { bottomAxisLabelled = flag; if (bottomAxisPanel != null) { bottomAxisPanel.setTickLabelsPainted(flag); } } @Override public final GJAxisPanel getLeftAxisPanel() { return leftAxisPanel; } public final void setLeftAxisPanel(GJAxisPanel axp) { leftAxisPanel = axp; } @Override public final GJAxisPanel getRightAxisPanel() { return rightAxisPanel; } public final void setRightAxisPanel(GJAxisPanel axp) { rightAxisPanel = axp; } @Override public final GJAxisPanel getTopAxisPanel() { return topAxisPanel; } public final void setTopAxisPanel(GJAxisPanel axp) { topAxisPanel = axp; } @Override public final GJAxisPanel getBottomAxisPanel() { return bottomAxisPanel; } public final void setBottomAxisPanel(GJAxisPanel axp) { bottomAxisPanel = axp; } @Override public final void setBackgroundPainted(boolean backPainted) { boolean old = isBackgroundPainted(); super.setBackgroundPainted(backPainted); firePropertyChange("backgroundPainted", old, isBackgroundPainted()); } @Override public final Color getMajorGridColor() { return majorGridColor; } @Override public final void setMajorGridColor(Color majorGridColor) { if (majorGridColor == null) { majorGridColor=Color.DARK_GRAY; } Color old = getMajorGridColor(); this.majorGridColor = majorGridColor; firePropertyChange("majorGridColor", old, getMajorGridColor()); } @Override public final Color getMinorGridColor() { return minorGridColor; } @Override public final void setMinorGridColor(Color minorGridColor) { if (minorGridColor == null) { majorGridColor=Color.DARK_GRAY; } Paint old = getMinorGridColor(); this.minorGridColor = minorGridColor; firePropertyChange("minorGridColor", old, getMinorGridColor()); } @Override public final double getMajorXHint() { return majorXHint; } private double calcMajorX() { double width = Math.abs(this.getAxesBounds().getWidth()); double lg = Math.log10(width); double rem = lg - Math.floor(lg); double scope = Math.pow(10, rem); double scale = Math.pow(10, Math.floor(lg)); double inc; if (scope > 5) { inc = scale; } else if (scope > 2) { inc = scale / 2d; } else { inc = scale / 5d; } return inc; } @Override public final void setMajorXHint() { setMajorXHint(calcMajorX()); } @Override public final void setMajorXHint(double majorX) { if (majorX <= 0.0) { majorX = 1e-15; } double old = getMajorXHint(); this.majorXHint = majorX; firePropertyChange("majorXHint", old, getMajorXHint()); } @Override public final void setMinorCountXHint(int minorCountX) { if (minorCountX < 0) { return; } int old = getMinorCountXHint(); this.minorCountXHint = minorCountX; //repaint(); firePropertyChange("minorCountXHint", old, getMinorCountXHint()); } @Override public final double getMajorYHint() { return majorYHint; } private double calcMajorY() { double height = Math.abs(this.getAxesBounds().getHeight()); double lg = Math.log10(height); double rem = lg - Math.floor(lg); double scope = Math.pow(10, rem); double scale = Math.pow(10, Math.floor(lg)); double inc; if (scope > 5) { inc = scale; } else if (scope > 2) { inc = scale / 2d; } else { inc = scale / 5d; } return inc; } @Override public final void setMajorYHint() { this.setMajorYHint(calcMajorY()); } @Override public final void setMajorYHint(double majorY) { if (majorY <= 0.0) { majorY = 1e-15; } double old = getMajorYHint(); this.majorYHint = majorY; firePropertyChange("majorYHint", old, getMajorYHint()); } @Override public final int getMinorCountXHint() { return minorCountXHint; } @Override public final int getMinorCountYHint() { return minorCountYHint; } @Override public final void setMinorCountYHint(int minorCountY) { if (minorCountY < 0) { return; } int old = getMinorCountYHint(); this.minorCountYHint = minorCountY; //repaint(); firePropertyChange("minorCountYHint", old, getMinorCountYHint()); } /** *

* Sets the view and the origin of the graph at the same time. The view * minimum boundaries are defined by the location of the rectangle passed as * parameter. The width and height of the rectangle define the distance * between the minimum and maximum boundaries:

* *
  • xLeft: bounds.getX()
  • yBottom: * bounds.getY()
  • yTop: bounds.getMaxX() (xLeft + * bounds.getWidth())
  • xRight: bounds.getMaxY() (yBottom + * bounds.getHeight())
* *

* The origin is located at the center of the view. Its coordinates are * defined by calling bounds.getCenterX() and bounds.getCenterY().

* * @param bounds the rectangle defining the graph's view and its origin */ public final void setAxesBoundsAndOrigin(Rectangle2D bounds) { setAxesBounds(bounds); setOrigin(new Point2D.Double(bounds.getCenterX(), bounds.getCenterY())); } public final void setAxesBounds(double x, double y, double w, double h) { setAxesBounds(new Rectangle.Double(x, y, w, h)); } @Override public final void setAxesBounds(final Rectangle2D bounds) { if (bounds == null) { return; } Rectangle2D old = getAxesBounds(); xLeft = bounds.getMinX(); xRight = bounds.getMaxX(); yBottom = bounds.getMinY(); yTop = bounds.getMaxY(); setMajorXHint(); setMajorYHint(); firePropertyChange("axesBounds", old, getAxesBounds()); } @Override public final Rectangle2D getAxesBounds() { return new Rectangle2D.Double(xLeft, yBottom, xRight - xLeft, yTop - yBottom); } /** *

* Resets the view to the default view if it has been changed by the user by * panning and zooming. The default view is defined by the view last * specified in a constructor call or a call to the methods * {@code #setAxesBounds(Rectangle2D)} and * {@code #setAxesBoundsAndOrigin(Rectangle2D)}.

* * @see #setAxesBounds(Rectangle2D) * @see #setAxesBoundsAndOrigin(Rectangle2D) */ public final void resetView() { if (plots.isEmpty()) { setAxesBounds(-1, -1, 2, 2); } else { setAxesBounds(plots.get(0).getDataRange()); updatePlots(); } } public final void updatePlots() { recalcAxes(); } /** * Returns the data range for the x- and y-data of the plots for this graph. * This range takes no account of the size of markers and does not require * the plot to have been rendered to the graphics device. * * @return the data range as a Rectangle2D object [X min, Y min * ,width,height] */ public final Rectangle2D getDataRange() { Rectangle2D r; if (plots.size() > 0) { r = plots.get(0).getDataRange(); for (GJPlotInterface p : plots) { r = r.createUnion(p.getDataRange()); } } else { r = new Rectangle2D.Double(0.1, 0.1, 2, 2); } return r; } /** * Calculates the required axes ranges for the plot in this graph. Uses * {@code getDataRange} so may be called before a plot is rendered. * */ private void recalcAxes() { Rectangle2D bounds = getDataRange(); if (Double.isNaN(bounds.getX()) || Double.isNaN(bounds.getY()) || Double.isNaN(bounds.getWidth()) || Double.isNaN(bounds.getHeight())) { return; } if (isPolar()) { double radius; radius = ArrayMath.max(ArrayMath.absi(new double[]{bounds.getMinX(), bounds.getMinY(), bounds.getMaxX(), bounds.getMaxY()})); radius *= Math.sqrt(2) / 2d; bounds.setRect(-radius, -radius, 2 * radius, 2 * radius); } setAxesBounds(bounds); setMajorXHint(); setMajorYHint(); } @Override public final Color getAxisColor() { return axisColor; } @Override public final void setAxisColor(Color axisColor) { if (axisColor == null) { axisColor = new Color(0, 0, 0, 0); } Paint old = getAxisColor(); this.axisColor = axisColor; firePropertyChange("axisColor", old, getAxisColor()); } @Override public final String getXLabel() { if (this.bottomAxisPanel != null) { return this.bottomAxisPanel.getText(); } else if (this.topAxisPanel != null) { return this.topAxisPanel.getText(); } else { return ""; } } @Override public final void setXLabel(String s) { String old = getXLabel(); if (this.bottomAxisPanel != null) { this.bottomAxisPanel.setText(s); } if (this.topAxisPanel != null) { this.topAxisPanel.setText(s); } firePropertyChange("XLabel", old, getXLabel()); } @Override public final String getYLabel() { if (this.leftAxisPanel != null) { return this.leftAxisPanel.getText(); } else if (this.rightAxisPanel != null) { return this.rightAxisPanel.getText(); } else { return ""; } } @Override public final void setYLabel(String s) { String old = getYLabel(); if (this.leftAxisPanel != null) { this.leftAxisPanel.setText(s); } if (this.rightAxisPanel != null) { this.rightAxisPanel.setText(s); } firePropertyChange("YLabel", old, getYLabel()); } @Override public final ArrayList getPlots() { ArrayList list = new ArrayList(); list.addAll(plots); return list; } public final ArrayList getAllPlots() { ArrayList list = new ArrayList(); for (GJPlotInterface p : plots) { if (p.getNode() != null) { list.addAll(p.getNode()); } } return list; } @Override public final void setPlots(final ArrayList list) { /** * N.B. As this method is called during de-serialization, force reset of * some properties that may not have invoked property change listeners * because they have not yet been installed in the de-serialization * process. */ Rectangle2D r = getAxesBounds(); plots.clear(); plots.addAll(list); boolean hasTransformUpdateInterface = false; for (GJPlotInterface p : getAllPlots()) { if (p instanceof GJTransformUpdateInterface) { hasTransformUpdateInterface = true; } } if (hasTransformUpdateInterface) { GJDataTransformInterface tr = getXTransform(); if (!tr.equals(NOPTransform.getInstance())) { setXTransform(NOPTransform.getInstance()); setXTransform(tr); } tr = getYTransform(); if (!tr.equals(NOPTransform.getInstance())) { setYTransform(NOPTransform.getInstance()); setYTransform(tr); } } setAxesBounds(r); } /** *

* Removes the specified plot from this layer.

* * @param n */ public final void removePlotAt(int n) { plots.remove(n); repaint(); } /** *

* Removes all the plots currently associated with this layer.

*/ public final void removeAllPlots() { for (GJPlotInterface p : plots) { remove(p); } repaint(); } public final void removeListeners() { Component c; if (graphContainer != null) { c = graphContainer; } else { c = this; } MouseMotionListener[] mmlist = c.getMouseMotionListeners(); for (int k = 0; k < mmlist.length - 1; k++) { c.removeMouseMotionListener(mmlist[k]); } MouseListener[] mlist = c.getMouseListeners(); for (int k = 0; k < mlist.length - 1; k++) { c.removeMouseListener(mlist[k]); } MouseWheelListener[] mwlist = c.getMouseWheelListeners(); for (int k = 0; k < mlist.length - 1; k++) { c.removeMouseWheelListener(mwlist[k]); } removeMouseWheelListener(GraphMouseWheelHandler.getInstance()); removeKeyListener(GraphCycler.getInstance()); } @Override public final void addListeners() { removeListeners(); if (graphContainer != null) { addMouseListener(graphContainer.getAddedComponentMouseHandler()); addMouseMotionListener(graphContainer.getAddedComponentMouseHandler()); } else { addMouseListener(GraphMouseHandler.getInstance()); addMouseMotionListener(GraphMouseHandler.getInstance()); } addMouseWheelListener(GraphMouseWheelHandler.getInstance()); addKeyListener(GraphCycler.getInstance()); } /** * Convenience caller to inverseTransformPoint(Point) * * @param x Position in the graph * @param y Position in the graph * @return Point rotated,scaled and translated according to the * graphContainer's Rotation and Zoom settings. Null if there is no * graphContainer associated with this graph */ public final Point2D inverseTransform(int x, int y) { return inverseTransform(new Point(x, y)); } /** * Transfrom a point according to latest AffineTransform * * @param p Point in graph * @return Point2D. If there is no AffineTransForm, returns the input * * inverseTransformPoint should be used before xPixelToPosition and * yPixelToPosition. */ private Point2D inverseTransform(Point2D p) { if (graphContainer == null) { return p; } else { p = graphContainer.inverseTransform(this, p); return p; } } @Override public final void autoScale() { if (!this.equals(this.getAncestorGraph())) { // Redirect call to the View getAncestorGraph().autoScale(); return; } for (GJGraphInterface thisLayer : layers) { if (thisLayer instanceof GJAbstractGraph) { GJAbstractGraph thisGraph = (GJAbstractGraph) thisLayer; thisGraph.updatePlots(); Rectangle2D bounds = thisGraph.getDataRange(); if (Double.isNaN(bounds.getX()) || Double.isNaN(bounds.getY()) || Double.isNaN(bounds.getWidth()) || Double.isNaN(bounds.getHeight())) { setAxesBounds(0.1, 0.1, 2, 2); } if (bounds.getWidth() == 0 && bounds.getHeight() == 0) { thisGraph.setAxesBounds(-1, -1, 1, 1); } else if (bounds.getWidth() == 0) { thisGraph.setAxesBounds(bounds.getX(), bounds.getY(), 1, bounds.getHeight()); } else if (bounds.getHeight() == 0) { thisGraph.setAxesBounds(bounds.getX(), bounds.getY(), bounds.getWidth(), 1); } try { thisGraph.paintImmediately(getBounds()); } catch (Exception ex) { // JComponent.paintImmediately may throw exception if set up not complete thisGraph.setAxesBounds(-1, -1, 1, 1); thisGraph.paintImmediately(getBounds()); } bounds = thisGraph.getAxesBounds(); for (GJPlotInterface p : thisGraph.getPlots()) { bounds = bounds.createUnion(p.getVisualRange()); } if (!thisGraph.tightAxes) { bounds = new Rectangle2D.Double(bounds.getX() - thisGraph.axesPadding * bounds.getWidth(), bounds.getY() - thisGraph.axesPadding * bounds.getHeight(), bounds.getWidth() + 2 * thisGraph.axesPadding * bounds.getWidth(), bounds.getHeight() + 2 * thisGraph.axesPadding * bounds.getHeight()); } if (thisGraph.getAxesBounds().getX() != bounds.getX() || thisGraph.getAxesBounds().getY() != bounds.getY() || thisGraph.getAxesBounds().getWidth() != bounds.getWidth() || thisGraph.getAxesBounds().getHeight() != bounds.getHeight()) { if (thisGraph.isPolar()) { double extent = Math.max(Math.abs(bounds.getX()), Math.abs(bounds.getX() + bounds.getWidth())); extent = Math.floor(Math.sqrt(2 * Math.pow(extent, 2)) + 0.5d); thisGraph.setAxesBounds(-extent, -extent, 2 * extent, 2 * extent); } else { thisGraph.setAxesBounds(bounds); } } } } } /** * Draw all plots to the current canvas * * @param g2 current Graphics2D object */ protected void drawPlots(Graphics2D g2) { for (GJPlotInterface p : plots) { drawPlot(g2, p); } } /** * Draws a plot to the current canvas. Child plots of the plot will also be * painted by the paintPlot method of the specified plot * * @param g2 Graphics2D object * @param plot a GJAbstractPlot subclass */ protected void drawPlot(Graphics2D g2, GJPlotInterface plot) { plot.paintPlotEntry(g2); } @Override public final JLabel getMousePositionTextField() { if (this.equals(getAncestorGraph())) { return mousePosition; } else { return getAncestorGraph().getMousePositionTextField(); } } @Override public final void setMousePositionTextField(JLabel t) { if (this.equals(getAncestorGraph())) { mousePosition = t; } else { getAncestorGraph().setMousePositionTextField(t); } } /** * Sets the keyAntialiasing value * * @param o */ @Override public final void setKeyAntialiasing(Object o) { keyAntialiasing = o; } public final void setAntialiasing(boolean flag) { if (flag) { setKeyAntialiasing(RenderingHints.VALUE_ANTIALIAS_ON); } else { setKeyAntialiasing(RenderingHints.VALUE_ANTIALIAS_OFF); } } /** * Sets the textAntialiasing value * * @param o */ @Override public final void setTextAntialiasing(Object o) { textAntialiasing = o; } /** *

* This method is called by the component prior to any drawing operation to * configure the drawing surface. The default implementation enables * antialiasing on the graphics.

*

* This method can be overriden by subclasses to modify the drawing surface * before any painting happens.

* * @param g2 the graphics surface to set up */ protected void setupGraphics(Graphics2D g2) { g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, keyAntialiasing); g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, textAntialiasing); } @Override public final void setReverseX(boolean flag) { double temp = xLeft, xleft = xLeft, xright = xRight; boolean old = isXReversed(); if (flag) { if (xLeft < xRight) { xleft = xRight; xright = temp; } } else { if (xLeft > xRight) { xleft = xRight; xright = temp; } } setAxesBounds(xleft, yBottom, xright - xleft, yTop - yBottom); firePropertyChange("xReversed", old, flag); } @Override public final boolean isXReversed() { return xLeft > xRight; } @Override public final void setReverseY(boolean flag) { boolean old = isYReversed(); double temp = yBottom, ybottom = yBottom, ytop = yTop; if (flag) { if (yBottom < yTop) { ybottom = yTop; ytop = temp; } } else { if (yBottom > yTop) { ybottom = yTop; ytop = temp; } } setAxesBounds(xLeft, ybottom, xRight - xLeft, ytop - ybottom); firePropertyChange("yReversed", old, flag); } @Override public final boolean isYReversed() { return yBottom > yTop; } @Override public final String format(double number) { boolean farAway = (!isCloseToZero(number) && Math.abs(number) < 0.001d) || Math.abs(number) > 10000.0d; if (!isCloseToZero(number)) { return (farAway ? getSecondFormatter() : getMainFormatter()).format(number); } else { return (farAway ? getSecondFormatter() : getMainFormatter()).format(0); } } /** * Returns true if any plot contained in this graph has categorical labels * associated with its data for the specified axis. * * @param or * @return the flag */ @Override public boolean isCategorical(GJAxisPanel.Orientation or) { if (getPlots() != null) { switch (or) { case X: for (GJPlotInterface p : getPlots()) { if (p.getXData() != null && p.getXData().isCategorical()) { return true; } } break; case Y: for (GJPlotInterface p : getPlots()) { if (p.getYData() != null && p.getYData().isCategorical()) { return true; } } } } return false; } @Override public ArrayList getCategoricalLabels(GJAxisPanel.Orientation o) { ArrayList coll = new ArrayList(); if (isCategorical(o)) { for (GJPlotInterface p : getPlots()) { if (p.getXData().getCategories() != null) { coll.addAll(p.getXData().getCategories().values()); } } } return coll; } // Zero-test with tolerance protected boolean isCloseToZero(double number) { return (Math.abs(number) < 1e-15); } @Override public final void setLeftAxisPainted(boolean flag) { boolean old = leftAxisPainted; leftAxisPainted = flag; firePropertyChange("leftAxisPainted", old, isLeftAxisPainted()); } @Override public final void setRightAxisPainted(boolean flag) { boolean old = rightAxisPainted; rightAxisPainted = flag; firePropertyChange("rightAxisPainted", old, isRightAxisPainted()); } @Override public final void setBottomAxisPainted(boolean flag) { boolean old = bottomAxisPainted; bottomAxisPainted = flag; firePropertyChange("bottomAxisPainted", old, isBottomAxisPainted()); } @Override public final void setTopAxisPainted(boolean flag) { boolean old = topAxisPainted; topAxisPainted = flag; firePropertyChange("topAxisPainted", old, isTopAxisPainted()); } @Override public final ArrayList getSelectedPlots() { return selectedPlots; } @Override public final void setSelectedPlots(ArrayList arr) { if (selectedPlots != null) { for (GJPlotInterface p : selectedPlots) { p.setSelected(false); } } selectedPlots = arr; if (selectedPlots != null) { for (GJPlotInterface p : selectedPlots) { p.setSelected(true); } } } @Override public final void setEditor(GJEditorInterface Editor) { editor = Editor; } @Override public final GJEditorInterface fetchEditor() { return editor; } @Override public final MouseAdapter getMouseHandler() { return GraphMouseHandler.getInstance(); } @Override public final MouseAdapter getAxisMouseHandler() { return axisMouseHandler; } public final MouseWheelListener getMouseWheelHandler() { return GraphMouseWheelHandler.getInstance(); } /** * @return the tightAxes */ public final boolean isTightAxes() { return tightAxes; } /** * @param tightAxes the tightAxes to set */ public final void setTightAxes(boolean tightAxes) { this.tightAxes = tightAxes; } /** * @return the axesPadding */ public final double getAxesPadding() { return axesPadding; } /** * @param axesPadding the axesPadding to set */ public final void setAxesPadding(double axesPadding) { this.axesPadding = axesPadding; } /** * @return the mouseTextAsInverse */ @Override public final boolean isTextAsInverse() { return isMouseTextAsInverse(); } /** * {@inheritDoc} * * @param flag */ @Override public final void setTextAsInverse(boolean flag) { this.setMouseTextAsInverse(flag); } /** * @return the mainFormatter */ public final NumberFormat getMainFormatter() { return mainFormatter; } /** * @param mainFormatter the mainFormatter to set */ public final void setMainFormatter(NumberFormat mainFormatter) { this.mainFormatter = mainFormatter; } /** * @return the mouseTextAsInverse */ public final boolean isMouseTextAsInverse() { return mouseTextAsInverse; } /** * @param mouseTextAsInverse the mouseTextAsInverse to set */ public final void setMouseTextAsInverse(boolean mouseTextAsInverse) { this.mouseTextAsInverse = mouseTextAsInverse; } /** * @return the secondFormatter */ public final NumberFormat getSecondFormatter() { return secondFormatter; } /** * @param secondFormatter the secondFormatter to set */ public final void setSecondFormatter(NumberFormat secondFormatter) { this.secondFormatter = secondFormatter; } /** * @return the mousePositionTextFormat */ public final String getMousePositionTextFormat() { return mousePositionTextFormat; } /** * @param mousePositionTextFormat the mousePositionTextFormat to set */ public final void setMousePositionTextFormat(String mousePositionTextFormat) { this.mousePositionTextFormat = mousePositionTextFormat; } /** * @return the dragStart */ public final Point2D getDragStart() { return dragStart; } /** * @param dragStart the dragStart to set */ public final void setDragStart(Point2D dragStart) { this.dragStart = dragStart; } /** * @return the dragX */ public final boolean isDragX() { return dragX; } /** * @param dragX the dragX to set */ public final void setDragX(boolean dragX) { this.dragX = dragX; } /** * @return the dragY */ public final boolean isDragY() { return dragY; } /** * @param dragY the dragY to set */ public final void setDragY(boolean dragY) { this.dragY = dragY; } /** * @return the currentMousePosition */ public final Point2D getCurrentMousePosition() { return currentMousePosition; } /** * @param currentMousePosition the currentMousePosition to set */ private void setCurrentMousePosition(Point2D currentMousePosition) { this.currentMousePosition = currentMousePosition; } /** * @return the polar */ @Override public boolean isPolar() { return polar; } /** * @param polar the polar to set */ public void setPolar(boolean polar) { boolean old = this.polar; this.polar = polar; firePropertyChange("polar", this.polar, old); } @Override public float getAxisStrokeWeight() { return axisStrokeWeight; } @Override public void setAxisStrokeWeight(float axisStrokeWeight) { this.axisStrokeWeight = axisStrokeWeight; } @Override public float getMinorGridStrokeWeight() { return minorGridStrokeWeight; } @Override public void setMinorGridStrokeWeight(float minorGridStrokeWeight) { this.minorGridStrokeWeight = minorGridStrokeWeight; } @Override public float getMajorGridStrokeWeight() { return majorGridStrokeWeight; } @Override public void setMajorGridStrokeWeight(float majorGridStrokeWeight) { this.majorGridStrokeWeight = majorGridStrokeWeight; } /** * * @return the gridInterface */ public GJGridInterface getGridInterface() { return gridInterface; } /** * @param gridInterface the gridInterface to set */ public void setGridInterface(GJGridInterface gridInterface) { this.gridInterface = gridInterface; } /** * @return a copy of the currentROI */ public Rectangle2D.Double getCurrentROI() { if (currentROI != null) { return (Rectangle2D.Double) currentROI.clone(); } else { return null; } } /** * @param currentROI the currentROI to set */ public void setCurrentROI(Rectangle2D.Double currentROI) { this.currentROI = (Rectangle2D.Double) currentROI.clone(); firePropertyChange("selectedRegion", null, getCurrentROI()); } /** * @return the availableROI */ public ArrayList getAvailableROI() { return availableROI; } /** * @param availableROI the availableROI to set */ public void setAvailableROI(ArrayList availableROI) { this.availableROI = availableROI; } public void clearSelectedRegions() { availableROI.clear(); } /** * @return the mouseDown */ public Point2D getMouseDown() { return mouseDown; } /** * @param mouseDown the mouseDown to set */ public void setMouseDown(Point2D mouseDown) { this.mouseDown = mouseDown; } /** * @return the contentMenu */ public JPopupMenu getContextMenu() { return contextMenu; } /** * Links both the x- and y-axes of this graph to the specified graph * * @param gr */ public void linkAxes(GJAbstractGraph gr) { addLink(gr); gr.addLink(this); } private void linkAxes(AxisLink link) { addLink(link); } /** * Links the x-axis of this graph to that of the specified graph. * * @param gr the graph to link the axis of. */ public void linkAxesXX(GJAbstractGraph gr) { if (!gr.equals(this)) { linkAxes(new AxisLink(gr, AxisLink.PAIRING.XX)); gr.linkAxes(new AxisLink(this, AxisLink.PAIRING.XX)); } } /** * Links the y-axis of this graph to that of the specified graph. * * @param gr the graph to link the axis of. */ public void linkAxesYY(GJAbstractGraph gr) { if (!gr.equals(this)) { linkAxes(new AxisLink(gr, AxisLink.PAIRING.YY)); gr.linkAxes(new AxisLink(this, AxisLink.PAIRING.YY)); } } /** * Links the x-axis of this graph to the y-axis of the specified graph. * * @param gr the graph to link the axis of. */ public void linkAxesXY(GJAbstractGraph gr) { linkAxes(new AxisLink(gr, AxisLink.PAIRING.XY)); gr.linkAxes(new AxisLink(this, AxisLink.PAIRING.YX)); } /** * Links the y-axis of this graph to the x-axis of the specified graph. * * @param gr the graph to link the axis of. */ public void linkAxesYX(GJAbstractGraph gr) { linkAxes(new AxisLink(gr, AxisLink.PAIRING.YX)); gr.linkAxes(new AxisLink(this, AxisLink.PAIRING.XY)); } /** * Makes any linked graphs referenced by this graph visible - housing them * in a standard Waterloo swing hierarchy if required. */ public void openLinks() { for (Object o : links) { if (o instanceof GJAbstractGraph) { GJAbstractGraph gr = (GJAbstractGraph) o; if (gr.getTopLevelAncestor() == null) { GJGraphContainer.createInstance(gr).createFrame(); } else { gr.getTopLevelAncestor().setVisible(true); } } else if (o instanceof AxisLink) { GJAbstractGraph gr = ((AxisLink) o).getPairedTarget(); if (gr.getTopLevelAncestor() == null) { GJGraphContainer.createInstance(gr).createFrame(); } else { gr.getTopLevelAncestor().setVisible(true); } } } } private static final class GraphMouseWheelHandler implements MouseWheelListener { private static final GraphMouseWheelHandler instance = new GraphMouseWheelHandler(); private GraphMouseWheelHandler() { } private static GraphMouseWheelHandler getInstance() { return instance; } @Override public final void mouseWheelMoved(MouseWheelEvent e) { GJAbstractGraph gr = (GJAbstractGraph) ((GJAbstractGraph) e.getSource()).getAncestorGraph().getCurrentLayer(); if (e.getWheelRotation() < 0) { double xdiff = (gr.getXMax() - gr.getXMin()); double ydiff = (gr.getYMax() - gr.getYMin()); gr.setAxesBounds(gr.getXMin() + xdiff / 100.0, gr.getYMin() + ydiff / 100.0, xdiff - 2 * xdiff / 100.0, ydiff - 2 * ydiff / 100.0); } else if (e.getWheelRotation() > 0) { double xdiff = (gr.getXMax() - gr.getXMin()); double ydiff = (gr.getYMax() - gr.getYMin()); gr.setAxesBounds(gr.getXMin() - xdiff / 100.0, gr.getYMin() - ydiff / 100.0, xdiff + 2 * xdiff / 100.0, ydiff + 2 * ydiff / 100.0); } } } private static final class GraphMouseHandler extends MouseAdapter { private static final GraphMouseHandler instance = new GraphMouseHandler(); GJAbstractGraph gr; private GraphMouseHandler() { } private static GraphMouseHandler getInstance() { return instance; } @Override public final void mouseClicked(MouseEvent e) { GJGraphInterface source = (GJGraphInterface) e.getSource(); source = source.getAncestorGraph(); gr = (GJAbstractGraph) source.getCurrentLayer(); if (e.getButton() == MouseEvent.BUTTON1) { switch (e.getClickCount()) { case 1: gr = (GJAbstractGraph) e.getSource(); gr = (GJAbstractGraph) gr.getAncestorGraph().getCurrentLayer(); gr.setDragStart(gr.inverseTransform(e.getPoint())); ArrayList old = gr.selectedPlots; ArrayList o = gr.getPlotAt(gr.getDragStart().getX(), gr.getDragStart().getY()); gr.setSelectedPlots(o); gr.firePropertyChange("selectedPlots", old, gr.selectedPlots); if (gr.selectedPlots.isEmpty()) { GJContainerMouseHandler.setLastSelected(gr); } else { ArrayList pp = new ArrayList(); for (GJPlotInterface ppp : gr.selectedPlots) { if (!pp.contains(ppp.getTopPlot())) { pp.add(ppp.getTopPlot()); } } GJContainerMouseHandler.setLastSelected(pp); } break; default: if (source.fetchEditor() == null) { GUIFactory.graphEditor(source.getGraphContainer().getView()); } else { GJEditorInterface ed = source.fetchEditor(); if (!ed.isShowing()) { ed.setVisible(true); } ed.setState(Frame.NORMAL); ed.refresh(); } } } } @Override public final void mousePressed(MouseEvent e) { gr = (GJAbstractGraph) ((GJAbstractGraph) e.getSource()).getAncestorGraph().getCurrentLayer(); if (SwingUtilities.isLeftMouseButton(e)) { if (gr != null) { gr.setMouseDown(gr.inverseTransform(e.getPoint())); gr.pixelROI.setRect(Double.NaN, Double.NaN, 0d, 0d); if (gr.currentROI == null) { gr.currentROI = new Rectangle2D.Double(Double.NaN, Double.NaN, 0d, 0d); gr.availableROI = new ArrayList(); } gr.currentROI.setRect(Double.NaN, Double.NaN, 0d, 0d); gr.repaint(); if (e.isShiftDown()) { // ROI Selection start double x = gr.xPixelToPosition(e.getPoint().getX()); double y = gr.yPixelToPosition(e.getPoint().getY()); gr.setCurrentMousePosition(new Point.Double(x, y)); gr.pixelROI.setRect(e.getPoint().getX(), e.getPoint().getY(), 0d, 0d); } } } else if (SwingUtilities.isRightMouseButton(e) && !e.isShiftDown()) { // If the parent is a grid with more than one element, supplement // the context menu. GCGrid grid = (GCGrid) SwingUtilities.getAncestorOfClass(GCGrid.class, gr); if ((grid == null || grid.getElements().size() < 2) && gr.gridMenu != null) { gr.contextMenu.remove(gr.gridMenu); gr.gridMenu = null; } else if (grid != null && grid.getElements().size() > 1 && gr.gridMenu == null) { gr.gridMenu = grid.getGridMenu(); gr.contextMenu.add(gr.gridMenu); } gr.contextMenu.show(gr, e.getX(), e.getY()); } } @Override public final void mouseReleased(MouseEvent e) { gr = (GJAbstractGraph) ((GJAbstractGraph) e.getSource()).getAncestorGraph().getCurrentLayer(); gr.contextMenu.setVisible(false); if (SwingUtilities.isRightMouseButton(e)) { Rectangle2D.Double r = gr.getCurrentROI(); if (r != null && !Double.isNaN(r.x) && !Double.isNaN(r.y)) { gr.setAxesBounds(r.x, r.y - r.height, r.width, r.height); // This is needed when there is an area fill in a plot. // Call always as this code is run rarely. gr.paintImmediately(0, 0, gr.getWidth(), gr.getHeight()); } } } @Override public final void mouseEntered(MouseEvent e) { } @Override public final void mouseExited(MouseEvent e) { // if (gr != null && gr.contextMenu != null && gr.contextMenu.isShowing()) { // gr.contextMenu.setVisible(false); // } } @Override public final void mouseMoved(MouseEvent e) { gr = (GJAbstractGraph) ((GJAbstractGraph) e.getSource()).getAncestorGraph().getCurrentLayer(); double x, y; if (!gr.contextMenu.isShowing()) { gr.setCursor(Cursor.getDefaultCursor()); gr.setDragStart(e.getPoint()); gr.setDragStart(gr.inverseTransform(gr.getDragStart())); x = gr.xPixelToPosition(gr.getDragStart().getX()); y = gr.yPixelToPosition(gr.getDragStart().getY()); gr.setCurrentMousePosition(new Point.Double(x, y)); if (gr.isTextAsInverse()) { x = gr.getXTransform().getInverse(x); y = gr.getYTransform().getInverse(y); } String str = String.format(gr.getMousePositionTextFormat(), x, y); if (gr.getMousePositionTextField() != null) { gr.getMousePositionTextField().setText(str); } GJAbstractGraph View = gr.getAncestorGraph(); if (View.getGridInterface() != null) { double[] mn = View.getGridInterface().getLocation(View); View.getGridInterface().getGridIndicator().setText("Subplot [" + mn[0] + ", " + mn[1] + "] Layer:" + View.getLayers().indexOf(gr)); View.getGridInterface().getMousePositionIndicator().setText(str); } /* * Set dragX and dragY which control mouse-driven axis expansion and * location of the origin */ double tol = 10; if ((x > gr.originX && x < gr.originX + gr.majorXHint / tol) || (x < gr.originX && x > gr.originX - gr.majorXHint / tol)) { gr.setDragY(true); } else { gr.setDragY(false); } if ((y > gr.originY && y < gr.originY + gr.majorYHint / tol) || (y < gr.originY && y > gr.originY - gr.majorYHint / tol)) { gr.setDragX(true); } else { gr.setDragX(false); } if (!gr.isDragX() && !gr.isDragY()) { gr.setCursor(Cursor.getDefaultCursor()); } else if (gr.isDragX() && gr.isDragY()) { gr.setCursor(originCursor); } else if (gr.isDragX()) { gr.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)); } else if (gr.isDragY()) { gr.setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)); } } } @Override public final void mouseDragged(MouseEvent e) { gr = (GJAbstractGraph) ((GJAbstractGraph) e.getSource()).getAncestorGraph().getCurrentLayer(); if (gr.contextMenu == null || !gr.contextMenu.isShowing()) { Rectangle2D old = gr.getAxesBounds(); if (e.isShiftDown()) { double xmin = Math.min(gr.inverseTransform(e.getPoint()).getX(), gr.getMouseDown().getX()); double ymin = Math.min(gr.inverseTransform(e.getPoint()).getY(), gr.getMouseDown().getY()); double w = Math.max(gr.inverseTransform(e.getPoint()).getX(), gr.getMouseDown().getX()) - xmin; double h = Math.max(gr.inverseTransform(e.getPoint()).getY(), gr.getMouseDown().getY()) - ymin; gr.pixelROI.setRect(xmin, ymin, w, h); gr.currentROI.setRect(gr.xPixelToPosition(xmin), gr.yPixelToPosition(ymin), w * gr.getPixelWidth(), h * gr.getPixelHeight()); double x = gr.xPixelToPosition(e.getPoint().getX()); double y = gr.yPixelToPosition(gr.getDragStart().getY()); gr.setCurrentMousePosition(new Point.Double(x, y)); gr.repaint(); } if (gr.getDragStart() == null) { gr.setDragStart(gr.inverseTransform(e.getPoint())); return; } Point2D dragEnd = gr.inverseTransform(e.getPoint()); double distanceX = gr.xPixelToPosition(dragEnd.getX()) - gr.xPixelToPosition(gr.getDragStart().getX()); double distanceY = gr.yPixelToPosition(dragEnd.getY()) - gr.yPixelToPosition(gr.getDragStart().getY()); double diff; if (!gr.isDragX() && !gr.isDragY() && !e.isShiftDown()) { /* * Move the axes */ gr.xLeft = gr.xLeft - distanceX; gr.xRight = gr.xRight - distanceX; gr.yBottom = gr.yBottom - distanceY; gr.yTop = gr.yTop - distanceY; } else if (gr.isDragX() && gr.isDragY()) { /* * Move the origin */ gr.setOrigin(new Point2D.Double( gr.xPixelToPosition(dragEnd.getX()), gr.yPixelToPosition(dragEnd.getY()))); } else if (gr.isDragX()) { /* * Change the X-Axis range */ double pos = gr.xPixelToPosition(gr.getDragStart().getX()); diff = Math.signum(pos) * distanceX; if (gr.xRight < gr.xLeft) { diff = -diff; } gr.xRight = gr.xRight - diff; if (Math.signum(gr.xRight) * Math.signum(gr.xLeft) > 0) { gr.xLeft = gr.xLeft + diff; } gr.setAxesBounds(new Rectangle2D.Double(gr.xLeft, gr.yBottom, gr.xRight - gr.xLeft, gr.yTop - gr.yBottom)); gr.setMajorXHint(); } else if (gr.isDragY()) { /* * Change the Y-Axis range */ double pos = gr.yPixelToPosition(gr.getDragStart().getY()); diff = Math.signum(pos) * distanceY; if (gr.yTop < gr.yBottom) { diff = -diff; } gr.yTop = gr.yTop - diff; if (Math.signum(gr.yTop) * Math.signum(gr.yBottom) > 0) { gr.yBottom = gr.yBottom + diff; } gr.setAxesBounds(new Rectangle2D.Double(gr.xLeft, gr.yBottom, gr.xRight - gr.xLeft, gr.yTop - gr.yBottom)); gr.setMajorYHint(); } gr.setDragStart(dragEnd); gr.firePropertyChange("axesBounds", old, gr.getAxesBounds()); } } } /** * Mouse motion handler for the Axis Panels */ private class AxisMouseHandler extends MouseAdapter { public boolean dragOriginX = false, dragOriginY = false; @Override public final void mouseEntered(MouseEvent e) { GJAxisPanel panel = (GJAxisPanel) e.getSource(); switch (panel.getPosition()) { case TOP: case BOTTOM: if (graphContainer != null && graphContainer.getAddedComponentMouseHandler().getSwingComponent() != null) { graphContainer.getAddedComponentMouseHandler().getSwingComponent(). setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)); } break; case LEFT: case RIGHT: if (graphContainer != null && graphContainer.getAddedComponentMouseHandler().getSwingComponent() != null) { graphContainer.getAddedComponentMouseHandler().getSwingComponent(). setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)); } break; default: } } @Override public final void mouseExited(MouseEvent e) { setDragX(false); setDragY(false); setCursor(Cursor.getDefaultCursor()); } @Override public final void mouseReleased(MouseEvent e) { GJAxisPanel panel = (GJAxisPanel) e.getSource(); GJAbstractGraph View = (GJAbstractGraph) panel.getParentGraph(); View.setDragX(false); View.setDragY(false); } @Override public final void mousePressed(MouseEvent e) { GJAxisPanel panel = (GJAxisPanel) e.getSource(); Component View = (Component) panel.getParentGraph(); setDragStart(inverseTransform(SwingUtilities.convertPoint(panel, e.getPoint(), View))); } @Override public final void mouseMoved(MouseEvent e) { GJAxisPanel panel = (GJAxisPanel) e.getSource(); GJAbstractGraphContainer container = (GJAbstractGraphContainer) panel.getParent(); GJAbstractGraph View = (GJAbstractGraph) panel.getParentGraph(); if (View.getAncestorGraph().getMousePositionTextField() != null) { View.getAncestorGraph().getMousePositionTextField().setText(""); if (View.getGridInterface() != null) { View.getGridInterface().getGridIndicator().setText(""); } } Point2D dragStartLocal = SwingUtilities.convertPoint(panel, e.getPoint(), View); dragStartLocal = inverseTransform(dragStartLocal); double x, y; x = View.xPixelToPosition(dragStartLocal.getX()); y = View.yPixelToPosition(dragStartLocal.getY()); switch (panel.getPosition()) { case TOP: case BOTTOM: if ((x < View.originX + 0.1 * View.majorXHint) && (x > View.originX - 0.1 * View.majorXHint)) { dragOriginX = true; View.setDragX(false); container.getAddedComponentMouseHandler().getSwingComponent().setCursor(originCursor); } else { View.setDragX(true); dragOriginX = false; container.getAddedComponentMouseHandler().getSwingComponent().setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)); } break; case LEFT: case RIGHT: if ((y < View.originY + 0.1 * View.majorYHint) && (y > View.originY - 0.1 * View.majorYHint)) { dragOriginY = true; View.setDragY(false); container.getAddedComponentMouseHandler().getSwingComponent().setCursor(originCursor); } else { dragOriginY = false; View.setDragY(true); container.getAddedComponentMouseHandler().getSwingComponent().setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)); break; } default: } } @Override public final void mouseDragged(MouseEvent e) { Rectangle2D old = getAxesBounds(); GJAxisPanel panel = (GJAxisPanel) e.getSource(); GJAbstractGraph View = (GJAbstractGraph) panel.getParentGraph(); GJAbstractGraphContainer container = View.getGraphContainer(); View.getAncestorGraph().setCurrentLayer(View); Point2D dragEnd = SwingUtilities.convertPoint(panel, e.getPoint(), View); dragEnd = inverseTransform(dragEnd); double distanceX = View.xPixelToPosition(dragEnd.getX()) - View.xPixelToPosition(getDragStart().getX()); double distanceY = View.yPixelToPosition(dragEnd.getY()) - View.yPixelToPosition(getDragStart().getY()); double diff; if (dragOriginX) { /* * Move the axes */ View.setOrigin(new Point2D.Double(View.xPixelToPosition(dragEnd.getX()), View.getOriginY())); } else if (dragOriginY) { /* * Move the axes */ View.setOrigin(new Point2D.Double(View.getOriginX(), View.yPixelToPosition(dragEnd.getY()))); } else if (View.isDragX()) { /* * Change the X-Axis range */ double pos = View.xPixelToPosition(getDragStart().getX()); diff = Math.signum(pos) * distanceX; if (View.xRight < View.xLeft) { diff = -diff; } View.xRight = View.xRight - diff; if (Math.signum(View.xRight) * Math.signum(View.xLeft) > 0) { View.xLeft = View.xLeft + diff; } View.setAxesBounds(new Rectangle2D.Double(View.xLeft, View.yBottom, View.xRight - View.xLeft, View.yTop - View.yBottom)); View.setMajorXHint(); } else if (View.isDragY()) { /* * Change the Y-Axis range */ double pos = View.yPixelToPosition(getDragStart().getY()); diff = Math.signum(pos) * distanceY; if (View.yTop < View.yBottom) { diff = -diff; } View.yTop = View.yTop - diff; if (Math.signum(View.yTop) * Math.signum(View.yBottom) > 0) { View.yBottom = View.yBottom + diff; } View.setAxesBounds(new Rectangle2D.Double(View.xLeft, View.yBottom, View.xRight - View.xLeft, View.yTop - View.yBottom)); View.setMajorYHint(); } setDragStart(dragEnd); //revalidate(); if (container != null) { container.validate(); } //container.repaint(); firePropertyChange("axesBounds", old, getAxesBounds()); } } public final KeyListener getKeyListener() { return GraphCycler.getInstance(); } /** * Handles keyboard input when the graph has focus. GraphCycler is a * singleton instance of a KeyListener that is shared by all graphs in a JVM * session. */ public static class GraphCycler implements KeyListener { private static final GraphCycler instance = new GraphCycler(); private GraphCycler() { } /** * Return the singleton instance * * @return the GraphCycler instance */ public static GraphCycler getInstance() { return instance; } @Override public final void keyTyped(KeyEvent e) { } @Override public final void keyPressed(KeyEvent e) { GJAbstractGraph thisGraph; if (GJAbstractGraph.class.isAssignableFrom(e.getSource().getClass())) { thisGraph = (GJAbstractGraph) e.getSource(); } else { JComponent comp = (JComponent) e.getSource(); comp.getParent().setComponentZOrder(comp, comp.getParent().getComponentCount() - 1); return; } if (e.getKeyCode() == KeyEvent.VK_SPACE) { if (e.getSource() instanceof GJAbstractGraph) { thisGraph = (GJAbstractGraph) e.getSource(); ArrayList LocalLayers = thisGraph.getAncestorGraph().getLayers(); if (LocalLayers.size() == 1) { return; } int idx = LocalLayers.indexOf(thisGraph) + 1; if (idx >= LocalLayers.size()) { idx = 0; } GJGraphInterface thisLayer = thisGraph.getAncestorGraph().getLayers().get(idx); thisGraph.getAncestorGraph().setCurrentLayer(thisLayer); } } else if (e.getKeyChar() == 'f') { if (thisGraph.getGraphContainer() != null) { GJAbstractGraphContainer container = thisGraph.getGraphContainer(); JComponent comp = container.getFeaturePane(); if (comp != null) { if (container.getComponentZOrder(comp) != 0) { container.setComponentZOrder(comp, 0); } else { container.setComponentZOrder(comp, container.getComponentCount() - 1); } container.repaint(); } } } } @Override public final void keyReleased(KeyEvent ke) { } } @Override public final void addLink(Object o) { links.add(o); } @Override public final void removeLink(Object o) { links.remove(o); } public final void clearLinks() { links.clear(); } @Override public final ArrayList getLinks() { return new ArrayList(links); } @Override public final void setLinks(ArrayList links) { this.links.clear(); this.links.addAll(links); } @Override public final boolean hasListeners(String propertyName) { return getPropertyChangeListeners().length > 0; } @Override public boolean hasSelfListener() { return Arrays.asList(getPropertyChangeListeners()).contains(this); } @Override public final void saveAsXML(String fileName) { GJEncoder.save(fileName, this); } @Override public void firePropertyChange(PropertyChangeEvent pce) { propertyChange(pce); } private static class GraphMenuAction implements ActionListener { final Component target; public GraphMenuAction(Component target) { this.target = target; } @Override public void actionPerformed(ActionEvent e) { Component c2 = SwingUtilities.getAncestorOfClass(GJGraphContainer.class, target); e.setSource(c2); if (e.getActionCommand().equals("Autoscale axes")) { ((GJAbstractGraphContainer) e.getSource()).getView().getCurrentLayer().autoScale(); return; } if (c2 != null) { ActionManager.processAction(e, (Component) e.getSource()); } } } private static class EditMenuAction implements ActionListener { final GJAbstractGraph target; public EditMenuAction(GJAbstractGraph target) { this.target = target; } @Override public void actionPerformed(ActionEvent e) { // 1.1 if (target.fetchEditor() == null && target.getGraphContainer() != null) { GUIFactory.graphEditor(target.getGraphContainer().getView()); } else { GJEditorInterface ed = target.fetchEditor(); if (!ed.isShowing()) { ed.setVisible(true); } ed.setState(Frame.NORMAL); ed.refresh(); } } } @Override public void propertyChange(final PropertyChangeEvent evt) { if (!EventQueue.isDispatchThread()) { EventQueue.invokeLater(new Runnable() { @Override public void run() { propertyChange(evt); } }); return; } if (evt.getPropertyName().contains("XTransform") || evt.getPropertyName().contains("YTransform")) { boolean needsUpdate = false; for (GJPlotInterface p : getAllPlots()) { if (p instanceof GJTransformUpdateInterface) { needsUpdate = needsUpdate | ((GJTransformUpdateInterface) p).transformUpdate(); } } } if (!evt.getPropertyName().contains(".")) { revalidate(); repaint(); } if (links.size() > 0 && evt.getPropertyName().contains("axesBounds")) { for (Object linkedGr : new ArrayList(links)) { if (linkedGr instanceof Reference) { if (((Reference) linkedGr).get() == null) { // Remove reference to gc'd object from original links.remove(linkedGr); break; } // Get the referenced object linkedGr = ((Reference) linkedGr).get(); } // Do the work if (linkedGr instanceof GJAbstractGraph) { ((GJAbstractGraph) linkedGr).setAxesBounds(getAxesBounds()); } else if (linkedGr instanceof AxisLink) { AxisLink arr = (AxisLink) linkedGr; updateLinkedAxes(arr); } } } } /** * Updates the linked axes from the propertyChange listener * * @param link */ private void updateLinkedAxes(AxisLink link) { if (link.getPairing().equals(AxisLink.PAIRING.XX)) { link.getPairedTarget().setXLeft(this.getXLeft()); link.getPairedTarget().setXRight(this.getXRight()); } else if (link.getPairing().equals(AxisLink.PAIRING.XY)) { link.getPairedTarget().setYBottom(this.getXLeft()); link.getPairedTarget().setYTop(this.getXRight()); } else if (link.getPairing().equals(AxisLink.PAIRING.YY)) { link.getPairedTarget().setYBottom(this.getYBottom()); link.getPairedTarget().setYTop(this.getYTop()); } else if (link.getPairing().equals(AxisLink.PAIRING.YX)) { link.getPairedTarget().setXLeft(this.getYBottom()); link.getPairedTarget().setXRight(this.getYTop()); } } }

Ads help maintain this website.