001/* =========================================================== 002 * Orson Charts : a 3D chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C)opyright 2013-2022, by David Gilbert. All rights reserved. 006 * 007 * https://github.com/jfree/orson-charts 008 * 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as published by 011 * the Free Software Foundation, either version 3 of the License, or 012 * (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public License 020 * along with this program. If not, see <http://www.gnu.org/licenses/>. 021 * 022 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 023 * Other names may be trademarks of their respective owners.] 024 * 025 * If you do not wish to be bound by the terms of the GPL, an alternative 026 * commercial license can be purchased. For details, please see visit the 027 * Orson Charts home page: 028 * 029 * http://www.object-refinery.com/orsoncharts/index.html 030 * 031 */ 032 033package org.jfree.chart3d; 034 035import java.awt.event.ComponentEvent; 036import java.awt.event.ComponentListener; 037import java.awt.event.MouseEvent; 038import java.io.IOException; 039import java.io.ObjectInputStream; 040import java.util.EventListener; 041import javax.swing.event.EventListenerList; 042 043import org.jfree.chart3d.data.ItemKey; 044import org.jfree.chart3d.graphics3d.Object3D; 045import org.jfree.chart3d.graphics3d.RenderedElement; 046import org.jfree.chart3d.graphics3d.RenderingInfo; 047import org.jfree.chart3d.graphics3d.swing.DisplayPanel3D; 048import org.jfree.chart3d.graphics3d.swing.Panel3D; 049import org.jfree.chart3d.interaction.Chart3DMouseEvent; 050import org.jfree.chart3d.interaction.Chart3DMouseListener; 051import org.jfree.chart3d.internal.Args; 052 053/** 054 * A panel designed to display a {@link Chart3D} in a Swing-based desktop 055 * application. The panel registers with the chart to receive change 056 * notifications, and when these are received the chart is automatically 057 * repainted. 058 * <br><br> 059 * This panel will display the chart, but does not include additional features 060 * such as the view toolbar and popup menu (these are provided by the 061 * {@link DisplayPanel3D} class). 062 * <br><br> 063 * NOTE: This class is serializable, but the serialization format is subject 064 * to change in future releases and should not be relied upon for persisting 065 * instances of this class. 066 */ 067@SuppressWarnings("serial") 068public class Chart3DPanel extends Panel3D implements Chart3DChangeListener, 069 ComponentListener { 070 071 /** 072 * The chart being rendered. 073 */ 074 private final Chart3D chart; 075 076 /** Auto-fit the chart on resize? */ 077 private final boolean autoFitOnPanelResize; 078 079 /** Storage for registered (chart) mouse listeners. */ 080 private transient EventListenerList chartMouseListeners; 081 082 /** 083 * Creates a new chart panel to display the specified chart. 084 * 085 * @param chart the chart. 086 */ 087 public Chart3DPanel(Chart3D chart) { 088 super(chart); 089 this.chartMouseListeners = new EventListenerList(); 090 this.chart = chart; 091 this.chart.addChangeListener(this); 092 addComponentListener(this); 093 this.autoFitOnPanelResize = false; 094 registerForTooltips(); 095 } 096 097 /** 098 * Returns the chart being displayed in this panel. 099 * 100 * @return The chart (never {@code null}). 101 * 102 * @since 1.3 103 */ 104 public Chart3D getChart() { 105 return this.chart; 106 } 107 108 /** 109 * Receives notification when the chart has been modified, and responds 110 * by completely repainting the panel and chart. 111 * 112 * @param event the event. 113 */ 114 @Override 115 public void chartChanged(Chart3DChangeEvent event) { 116 repaint(); 117 } 118 119 @Override 120 public void componentResized(ComponentEvent e) { 121 if (this.autoFitOnPanelResize) { 122 zoomToFit(); 123 } 124 } 125 126 @Override 127 public void componentMoved(ComponentEvent e) { 128 // do nothing 129 } 130 131 @Override 132 public void componentShown(ComponentEvent e) { 133 // do nothing 134 } 135 136 @Override 137 public void componentHidden(ComponentEvent e) { 138 // do nothing 139 } 140 141 @Override 142 public String getToolTipText(MouseEvent e) { 143 RenderingInfo info = getRenderingInfo(); 144 if (info == null) { 145 return null; 146 } 147 Object3D object = info.fetchObjectAt(e.getX(), e.getY()); 148 if (object != null) { 149 ItemKey key = (ItemKey) object.getProperty(Object3D.ITEM_KEY); 150 if (key != null) { 151 return chart.getPlot().generateToolTipText(key); 152 } 153 } 154 return null; 155 } 156 157 /** 158 * Receives a mouse event and passes it on to registered 159 * {@link Chart3DMouseListener}s along with the underlying rendered 160 * element if any. 161 * 162 * @param e the mouse event. 163 */ 164 @Override 165 public void mouseClicked(MouseEvent e) { 166 Object[] listeners = this.chartMouseListeners.getListeners( 167 Chart3DMouseListener.class); 168 if (listeners.length == 0) { 169 return; 170 } 171 RenderedElement element = null; 172 RenderingInfo info = getRenderingInfo(); 173 if (info != null) { 174 element = info.findElementAt(e.getX(), e.getY()); 175 } 176 Chart3DMouseEvent chartEvent = new Chart3DMouseEvent(this.chart, e, 177 element); 178 for (int i = listeners.length - 1; i >= 0; i -= 1) { 179 ((Chart3DMouseListener) listeners[i]).chartMouseClicked(chartEvent); 180 } 181 super.mouseClicked(e); 182 } 183 184 /** 185 * Receives a mouse event and passes it on to registered 186 * {@link Chart3DMouseListener}s along with the underlying rendered 187 * element if any. 188 * 189 * @param e the mouse event. 190 */ 191 @Override 192 public void mouseMoved(MouseEvent e) { 193 Object[] listeners = this.chartMouseListeners.getListeners( 194 Chart3DMouseListener.class); 195 if (listeners.length == 0) { 196 return; 197 } 198 RenderedElement element = null; 199 RenderingInfo info = getRenderingInfo(); 200 if (info != null) { 201 element = info.findElementAt(e.getX(), e.getY()); 202 } 203 Chart3DMouseEvent chartEvent = new Chart3DMouseEvent(this.chart, e, 204 element); 205 for (int i = listeners.length - 1; i >= 0; i -= 1) { 206 ((Chart3DMouseListener) listeners[i]).chartMouseMoved(chartEvent); 207 } 208 super.mouseMoved(e); 209 } 210 211 /** 212 * Adds a listener to the list of objects listening for chart mouse events. 213 * 214 * @param listener the listener ({@code null} not permitted). 215 * 216 * @since 1.3 217 */ 218 public void addChartMouseListener(Chart3DMouseListener listener) { 219 Args.nullNotPermitted(listener, "listener"); 220 this.chartMouseListeners.add(Chart3DMouseListener.class, listener); 221 } 222 223 /** 224 * Removes a listener from the list of objects listening for chart mouse 225 * events. 226 * 227 * @param listener the listener ({@code null} not permitted). 228 * 229 * @since 1.3 230 */ 231 public void removeChartMouseListener(Chart3DMouseListener listener) { 232 Args.nullNotPermitted(listener, "listener"); 233 this.chartMouseListeners.remove(Chart3DMouseListener.class, listener); 234 } 235 236 /** 237 * Returns an array of the listeners of the given type registered with the 238 * panel. 239 * 240 * @param listenerType the listener type. 241 * 242 * @return An array of listeners. 243 */ 244 @Override 245 public <T extends EventListener> T[] getListeners(Class<T> listenerType) { 246 if (listenerType == Chart3DMouseListener.class) { 247 // fetch listeners from local storage 248 return this.chartMouseListeners.getListeners(listenerType); 249 } 250 else { 251 return super.getListeners(listenerType); 252 } 253 } 254 255 /** 256 * Provides serialization support. 257 * 258 * @param stream the input stream. 259 * 260 * @throws IOException if there is an I/O error. 261 * @throws ClassNotFoundException if there is a classpath problem. 262 */ 263 private void readObject(ObjectInputStream stream) 264 throws IOException, ClassNotFoundException { 265 stream.defaultReadObject(); 266 // we create a new but empty chartMouseListeners list 267 this.chartMouseListeners = new EventListenerList(); 268 // register as a listener with sub-components... 269 if (this.chart != null) { 270 this.chart.addChangeListener(this); 271 } 272 } 273 274}