/* ===========================================================
* Orson Charts : a 3D chart library for the Java(tm) platform
* ===========================================================
*
* (C)opyright 2013-2016, by Object Refinery Limited. All rights reserved.
*
* http://www.object-refinery.com/orsoncharts/index.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* [Oracle and Java are registered trademarks of Oracle and/or its affiliates.
* Other names may be trademarks of their respective owners.]
*
* If you do not wish to be bound by the terms of the GPL, an alternative
* commercial license can be purchased. For details, please see visit the
* Orson Charts home page:
*
* http://www.object-refinery.com/orsoncharts/index.html
*
*/
package com.orsoncharts;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.EventListener;
import javax.swing.event.EventListenerList;
import com.orsoncharts.data.ItemKey;
import com.orsoncharts.graphics3d.Object3D;
import com.orsoncharts.graphics3d.RenderingInfo;
import com.orsoncharts.graphics3d.swing.Panel3D;
import com.orsoncharts.graphics3d.swing.DisplayPanel3D;
import com.orsoncharts.interaction.Chart3DMouseEvent;
import com.orsoncharts.interaction.Chart3DMouseListener;
import com.orsoncharts.graphics3d.RenderedElement;
import com.orsoncharts.util.ArgChecks;
/**
* A panel designed to display a {@link Chart3D} in a Swing-based desktop
* application. The panel registers with the chart to receive change
* notifications, and when these are received the chart is automatically
* repainted.
* <br><br>
* This panel will display the chart, but does not include additional features
* such as the view toolbar and popup menu (these are provided by the
* {@link DisplayPanel3D} class).
* <br><br>
* NOTE: This class is serializable, but the serialization format is subject
* to change in future releases and should not be relied upon for persisting
* instances of this class.
*/
@SuppressWarnings("serial")
public class Chart3DPanel extends Panel3D implements Chart3DChangeListener,
ComponentListener {
/**
* The chart being rendered.
*/
private Chart3D chart;
/** Auto-fit the chart on resize? */
private boolean autoFitOnPanelResize;
/** Storage for registered (chart) mouse listeners. */
private transient EventListenerList chartMouseListeners;
/**
* Creates a new chart panel to display the specified chart.
*
* @param chart the chart.
*/
public Chart3DPanel(Chart3D chart) {
super(chart);
this.chartMouseListeners = new EventListenerList();
this.chart = chart;
this.chart.addChangeListener(this);
addComponentListener(this);
this.autoFitOnPanelResize = false;
registerForTooltips();
}
/**
* Returns the chart being displayed in this panel.
*
* @return The chart (never {@code null}).
*
* @since 1.3
*/
public Chart3D getChart() {
return this.chart;
}
/**
* Receives notification when the chart has been modified, and responds
* by completely repainting the panel and chart.
*
* @param event the event.
*/
@Override
public void chartChanged(Chart3DChangeEvent event) {
repaint();
}
@Override
public void componentResized(ComponentEvent e) {
if (this.autoFitOnPanelResize) {
zoomToFit();
}
}
@Override
public void componentMoved(ComponentEvent e) {
// do nothing
}
@Override
public void componentShown(ComponentEvent e) {
// do nothing
}
@Override
public void componentHidden(ComponentEvent e) {
// do nothing
}
@Override
public String getToolTipText(MouseEvent e) {
RenderingInfo info = getRenderingInfo();
if (info == null) {
return null;
}
Object3D object = info.fetchObjectAt(e.getX(), e.getY());
if (object != null) {
ItemKey key = (ItemKey) object.getProperty(Object3D.ITEM_KEY);
if (key != null) {
return chart.getPlot().generateToolTipText(key);
}
}
return null;
}
/**
* Receives a mouse event and passes it on to registered
* {@link Chart3DMouseListener}s along with the underlying rendered
* element if any.
*
* @param e the mouse event.
*/
@Override
public void mouseClicked(MouseEvent e) {
Object[] listeners = this.chartMouseListeners.getListeners(
Chart3DMouseListener.class);
if (listeners.length == 0) {
return;
}
RenderedElement element = null;
RenderingInfo info = getRenderingInfo();
if (info != null) {
element = info.findElementAt(e.getX(), e.getY());
}
Chart3DMouseEvent chartEvent = new Chart3DMouseEvent(this.chart, e,
element);
for (int i = listeners.length - 1; i >= 0; i -= 1) {
((Chart3DMouseListener) listeners[i]).chartMouseClicked(chartEvent);
}
super.mouseClicked(e);
}
/**
* Receives a mouse event and passes it on to registered
* {@link Chart3DMouseListener}s along with the underlying rendered
* element if any.
*
* @param e the mouse event.
*/
@Override
public void mouseMoved(MouseEvent e) {
Object[] listeners = this.chartMouseListeners.getListeners(
Chart3DMouseListener.class);
if (listeners.length == 0) {
return;
}
RenderedElement element = null;
RenderingInfo info = getRenderingInfo();
if (info != null) {
element = info.findElementAt(e.getX(), e.getY());
}
Chart3DMouseEvent chartEvent = new Chart3DMouseEvent(this.chart, e,
element);
for (int i = listeners.length - 1; i >= 0; i -= 1) {
((Chart3DMouseListener) listeners[i]).chartMouseMoved(chartEvent);
}
super.mouseMoved(e);
}
/**
* Adds a listener to the list of objects listening for chart mouse events.
*
* @param listener the listener ({@code null} not permitted).
*
* @since 1.3
*/
public void addChartMouseListener(Chart3DMouseListener listener) {
ArgChecks.nullNotPermitted(listener, "listener");
this.chartMouseListeners.add(Chart3DMouseListener.class, listener);
}
/**
* Removes a listener from the list of objects listening for chart mouse
* events.
*
* @param listener the listener ({@code null} not permitted).
*
* @since 1.3
*/
public void removeChartMouseListener(Chart3DMouseListener listener) {
ArgChecks.nullNotPermitted(listener, "listener");
this.chartMouseListeners.remove(Chart3DMouseListener.class, listener);
}
/**
* Returns an array of the listeners of the given type registered with the
* panel.
*
* @param listenerType the listener type.
*
* @return An array of listeners.
*/
@Override
public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
if (listenerType == Chart3DMouseListener.class) {
// fetch listeners from local storage
return this.chartMouseListeners.getListeners(listenerType);
}
else {
return super.getListeners(listenerType);
}
}
/**
* Provides serialization support.
*
* @param stream the input stream.
*
* @throws IOException if there is an I/O error.
* @throws ClassNotFoundException if there is a classpath problem.
*/
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
// we create a new but empty chartMouseListeners list
this.chartMouseListeners = new EventListenerList();
// register as a listener with sub-components...
if (this.chart != null) {
this.chart.addChangeListener(this);
}
}
}