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.graphics3d.swing; 034 035import java.awt.BorderLayout; 036import java.awt.Font; 037import java.awt.FontFormatException; 038import java.awt.event.MouseEvent; 039import java.awt.event.MouseListener; 040import java.io.IOException; 041import java.io.InputStream; 042import java.util.logging.Level; 043import java.util.logging.Logger; 044 045import javax.swing.JButton; 046import javax.swing.JMenuItem; 047import javax.swing.JPanel; 048import javax.swing.JPopupMenu; 049import javax.swing.JToolBar; 050import javax.swing.JMenu; 051 052import org.jfree.chart3d.Resources; 053import org.jfree.chart3d.export.ExportFormat; 054import org.jfree.chart3d.export.ExportFormats; 055import org.jfree.chart3d.internal.Args; 056 057/** 058 * A panel for displaying 3D content, with a toolbar and popup menu to control 059 * the view. 060 * <br><br> 061 * NOTE: This class is serializable, but the serialization format is subject 062 * to change in future releases and should not be relied upon for persisting 063 * instances of this class. 064 */ 065@SuppressWarnings("serial") 066public class DisplayPanel3D extends JPanel implements MouseListener { 067 068 private static final int FONT_SIZE = 22; 069 070 private static Font FONT_AWESOME; 071 072 /** 073 * Returns a font for "Font Awesome" (http://fontawesome.io) at the 074 * specified size. 075 * 076 * @param size the point size. 077 * 078 * @return A font. 079 */ 080 public static Font getFontAwesomeFont(int size) { 081 if (FONT_AWESOME == null) { 082 try { 083 InputStream in = DisplayPanel3D.class.getResourceAsStream( 084 "fontawesome-webfont.ttf"); 085 FONT_AWESOME = Font.createFont(Font.TRUETYPE_FONT, in); 086 } catch (FontFormatException | IOException ex) { 087 Logger.getLogger(Panel3D.class.getName()).log(Level.SEVERE, 088 null, ex); 089 } 090 } 091 return FONT_AWESOME.deriveFont(Font.PLAIN, size); 092 } 093 094 /** The 3D content. */ 095 Panel3D content; 096 097 /** The popup menu. */ 098 private JPopupMenu popup; 099 100 /** 101 * Creates a new display panel for the given content, with a toolbar 102 * and popup menu configured. 103 * 104 * @param content the content ({@code null} not permitted). 105 */ 106 public DisplayPanel3D(Panel3D content) { 107 this(content, true, true); 108 } 109 110 /** 111 * Creates a new display panel. 112 * 113 * @param content the content ({@code null} not permitted). 114 * @param toolbar toolbar? 115 * @param popupMenu popup menu? 116 */ 117 public DisplayPanel3D(Panel3D content, boolean toolbar, boolean popupMenu) { 118 super(new BorderLayout()); 119 120 this.content = content; 121 add(this.content); 122 123 if (toolbar) { 124 JToolBar tb = createToolBar(content); 125 add(tb, BorderLayout.EAST); 126 } 127 if (popupMenu) { 128 this.popup = createPopupMenu(ExportFormat.values()); 129 } 130 this.content.addMouseListener(this); 131 } 132 133 /** 134 * Returns a reference to the content panel. 135 * 136 * @return A reference to the content panel. 137 */ 138 public Panel3D getContent() { 139 return this.content; 140 } 141 142 /** 143 * Sets the list of export formats that will be shown in the popup menu. 144 * If you provide an empty list, there will be no export submenu in the 145 * popup menu. 146 * 147 * @param formats the list of formats ({@code null} not permitted). 148 * 149 * @since 1.2 150 */ 151 public void setExportFormats(ExportFormat... formats) { 152 // defer argument checking 153 this.popup = createPopupMenu(formats); 154 } 155 156 /** 157 * Creates the toolbar used to control zooming etc. 158 * 159 * @param content the 3D content that will be updated by toolbar actions. 160 * 161 * @return The toolbar. 162 */ 163 private JToolBar createToolBar(Panel3D content) { 164 JToolBar tb = new JToolBar(JToolBar.VERTICAL); 165 Font font = getFontAwesomeFont(FONT_SIZE); 166 JButton zoomInButton = new JButton(new ZoomInAction(this.content, 167 true)); 168 zoomInButton.setFont(font); 169 JButton zoomOutButton = new JButton(new ZoomOutAction(this.content, 170 true)); 171 zoomOutButton.setFont(font); 172 JButton zoomToFitButton = new JButton(new ZoomToFitAction(this.content, 173 true)); 174 zoomToFitButton.setFont(font); 175 JButton leftButton = new JButton(new LeftAction(content)); 176 leftButton.setFont(font); 177 JButton rightButton = new JButton(new RightAction(content)); 178 rightButton.setFont(font); 179 JButton upButton = new JButton(new UpAction(content)); 180 upButton.setFont(font); 181 JButton downButton = new JButton(new DownAction(content)); 182 downButton.setFont(font); 183 JButton rotateLeftButton = new JButton(new RollLeftAction(content)); 184 rotateLeftButton.setFont(font); 185 JButton rotateRightButton = new JButton(new RollRightAction(content)); 186 rotateRightButton.setFont(font); 187 tb.add(zoomInButton); 188 tb.add(zoomOutButton); 189 tb.add(zoomToFitButton); 190 tb.add(new JToolBar.Separator()); 191 tb.add(leftButton); 192 tb.add(rightButton); 193 tb.add(upButton); 194 tb.add(downButton); 195 tb.add(rotateLeftButton); 196 tb.add(rotateRightButton); 197 return tb; 198 } 199 200 /** 201 * Creates a popup menu containing zooming items plus, if exportFormats 202 * is not empty, a submenu of export items. 203 * 204 * @param exportFormats an ordered list of export formats to add to the 205 * submenu ({@code null} not permitted). 206 * 207 * @return A popup menu. 208 */ 209 private JPopupMenu createPopupMenu(ExportFormat... exportFormats) { 210 Args.nullNotPermitted(exportFormats, "exportFormats"); 211 JPopupMenu popupMenu = new JPopupMenu(); 212 popupMenu.add(new JMenuItem(new ZoomInAction(this.content, false))); 213 popupMenu.add(new JMenuItem(new ZoomOutAction(this.content, false))); 214 popupMenu.add(new JMenuItem(new ZoomToFitAction(this.content, false))); 215 216 if (exportFormats.length > 0) { 217 JMenu exportSubMenu = new JMenu(Resources.localString("EXPORT_AS")); 218 for (ExportFormat f : exportFormats) { 219 if (f.equals(ExportFormat.PNG)) { 220 JMenuItem pngItem = new JMenuItem(new ExportToPNGAction( 221 this.content)); 222 exportSubMenu.add(pngItem); 223 } else if (f.equals(ExportFormat.JPEG)) { 224 JMenuItem jpgItem = new JMenuItem(new ExportToJPEGAction( 225 this.content)); 226 exportSubMenu.add(jpgItem); 227 } else if (f.equals(ExportFormat.PDF)) { 228 if (ExportFormats.isJFreePDFAvailable()) { 229 JMenuItem pdfItem = new JMenuItem(new ExportToPDFAction( 230 this.content)); 231 exportSubMenu.add(pdfItem); 232 } 233 } else if (f.equals(ExportFormat.SVG)) { 234 if (ExportFormats.isJFreeSVGAvailable()) { 235 JMenuItem svgItem = new JMenuItem(new ExportToSVGAction( 236 this.content)); 237 exportSubMenu.add(svgItem); 238 } 239 } 240 } 241 if (exportSubMenu.getItemCount() > 0) { 242 popupMenu.addSeparator(); 243 popupMenu.add(exportSubMenu); 244 } 245 } 246 return popupMenu; 247 } 248 249 /** 250 * This method does nothing. 251 * 252 * @param e the mouse event. 253 */ 254 @Override 255 public void mouseClicked(MouseEvent e) { 256 // nothing to do 257 } 258 259 /** 260 * Checks if the popup is triggered in which case it is displayed. 261 * 262 * @param e the mouse event. 263 */ 264 @Override 265 public void mousePressed(MouseEvent e) { 266 // popup is triggered on mousePressed for Linux and Mac, but Windows 267 // is mouseReleased 268 if (e.isPopupTrigger()) { 269 if (this.popup != null) { 270 this.popup.show(this, e.getX(), e.getY()); 271 e.consume(); 272 } 273 } 274 } 275 276 /** 277 * Checks if the popup is triggered in which case it is displayed. 278 * 279 * @param e the mouse event. 280 */ 281 @Override 282 public void mouseReleased(MouseEvent e) { 283 // popup is triggered on mouseReleased for Windows, but Linux and Mac 284 // is mousePressed 285 if (e.isPopupTrigger()) { 286 if (this.popup != null) { 287 this.popup.show(this, e.getX(), e.getY()); 288 e.consume(); 289 } 290 } 291 } 292 293 /** 294 * This method does nothing. 295 * 296 * @param e the mouse event. 297 */ 298 @Override 299 public void mouseEntered(MouseEvent e) { 300 // nothing to do 301 } 302 303 /** 304 * This method does nothing. 305 * 306 * @param e the mouse event. 307 */ 308 @Override 309 public void mouseExited(MouseEvent e) { 310 // nothing to do 311 } 312 313}