001/* =========================================================== 002 * Orson Charts : a 3D chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C)opyright 2013-2016, by Object Refinery Limited. All rights reserved. 006 * 007 * http://www.object-refinery.com/orsoncharts/index.html 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 com.orsoncharts.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 com.orsoncharts.Resources; 053import com.orsoncharts.util.ArgChecks; 054import com.orsoncharts.util.ExportFormat; 055import com.orsoncharts.util.ExportFormats; 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 ex) { 087 Logger.getLogger(Panel3D.class.getName()).log(Level.SEVERE, 088 null, ex); 089 } catch (IOException ex) { 090 Logger.getLogger(Panel3D.class.getName()).log(Level.SEVERE, 091 null, ex); 092 } 093 } 094 return FONT_AWESOME.deriveFont(Font.PLAIN, size); 095 } 096 097 /** The 3D content. */ 098 Panel3D content; 099 100 /** The popup menu. */ 101 private JPopupMenu popup; 102 103 /** 104 * Creates a new display panel for the given content, with a toolbar 105 * and popup menu configured. 106 * 107 * @param content the content ({@code null} not permitted). 108 */ 109 public DisplayPanel3D(Panel3D content) { 110 this(content, true, true); 111 } 112 113 /** 114 * Creates a new display panel. 115 * 116 * @param content the content ({@code null} not permitted). 117 * @param toolbar toolbar? 118 * @param popupMenu popup menu? 119 */ 120 public DisplayPanel3D(Panel3D content, boolean toolbar, boolean popupMenu) { 121 super(new BorderLayout()); 122 123 this.content = content; 124 add(this.content); 125 126 if (toolbar) { 127 JToolBar tb = createToolBar(content); 128 add(tb, BorderLayout.EAST); 129 } 130 if (popupMenu) { 131 this.popup = createPopupMenu(ExportFormat.values()); 132 } 133 this.content.addMouseListener(this); 134 } 135 136 /** 137 * Returns a reference to the content panel. 138 * 139 * @return A reference to the content panel. 140 */ 141 public Panel3D getContent() { 142 return this.content; 143 } 144 145 /** 146 * Sets the list of export formats that will be shown in the popup menu. 147 * If you provide an empty list, there will be no export submenu in the 148 * popup menu. 149 * 150 * @param formats the list of formats ({@code null} not permitted). 151 * 152 * @since 1.2 153 */ 154 public void setExportFormats(ExportFormat... formats) { 155 // defer argument checking 156 this.popup = createPopupMenu(formats); 157 } 158 159 /** 160 * Creates the toolbar used to control zooming etc. 161 * 162 * @param content the 3D content that will be updated by toolbar actions. 163 * 164 * @return The toolbar. 165 */ 166 private JToolBar createToolBar(Panel3D content) { 167 JToolBar tb = new JToolBar(JToolBar.VERTICAL); 168 Font font = getFontAwesomeFont(FONT_SIZE); 169 JButton zoomInButton = new JButton(new ZoomInAction(this.content, 170 true)); 171 zoomInButton.setFont(font); 172 JButton zoomOutButton = new JButton(new ZoomOutAction(this.content, 173 true)); 174 zoomOutButton.setFont(font); 175 JButton zoomToFitButton = new JButton(new ZoomToFitAction(this.content, 176 true)); 177 zoomToFitButton.setFont(font); 178 JButton leftButton = new JButton(new LeftAction(content)); 179 leftButton.setFont(font); 180 JButton rightButton = new JButton(new RightAction(content)); 181 rightButton.setFont(font); 182 JButton upButton = new JButton(new UpAction(content)); 183 upButton.setFont(font); 184 JButton downButton = new JButton(new DownAction(content)); 185 downButton.setFont(font); 186 JButton rotateLeftButton = new JButton(new RollLeftAction(content)); 187 rotateLeftButton.setFont(font); 188 JButton rotateRightButton = new JButton(new RollRightAction(content)); 189 rotateRightButton.setFont(font); 190 tb.add(zoomInButton); 191 tb.add(zoomOutButton); 192 tb.add(zoomToFitButton); 193 tb.add(new JToolBar.Separator()); 194 tb.add(leftButton); 195 tb.add(rightButton); 196 tb.add(upButton); 197 tb.add(downButton); 198 tb.add(rotateLeftButton); 199 tb.add(rotateRightButton); 200 return tb; 201 } 202 203 /** 204 * Creates a popup menu containing zooming items plus, if exportFormats 205 * is not empty, a submenu of export items. 206 * 207 * @param exportFormats an ordered list of export formats to add to the 208 * submenu ({@code null} not permitted). 209 * 210 * @return A popup menu. 211 */ 212 private JPopupMenu createPopupMenu(ExportFormat... exportFormats) { 213 ArgChecks.nullNotPermitted(exportFormats, "exportFormats"); 214 JPopupMenu popupMenu = new JPopupMenu(); 215 popupMenu.add(new JMenuItem(new ZoomInAction(this.content, false))); 216 popupMenu.add(new JMenuItem(new ZoomOutAction(this.content, false))); 217 popupMenu.add(new JMenuItem(new ZoomToFitAction(this.content, false))); 218 219 if (exportFormats.length > 0) { 220 JMenu exportSubMenu = new JMenu(Resources.localString("EXPORT_AS")); 221 for (ExportFormat f : exportFormats) { 222 if (f.equals(ExportFormat.PNG)) { 223 JMenuItem pngItem = new JMenuItem(new ExportToPNGAction( 224 this.content)); 225 exportSubMenu.add(pngItem); 226 } else if (f.equals(ExportFormat.JPEG)) { 227 JMenuItem jpgItem = new JMenuItem(new ExportToJPEGAction( 228 this.content)); 229 exportSubMenu.add(jpgItem); 230 } else if (f.equals(ExportFormat.PDF)) { 231 if (ExportFormats.isOrsonPDFAvailable()) { 232 JMenuItem pdfItem = new JMenuItem(new ExportToPDFAction( 233 this.content)); 234 exportSubMenu.add(pdfItem); 235 } 236 } else if (f.equals(ExportFormat.SVG)) { 237 if (ExportFormats.isJFreeSVGAvailable()) { 238 JMenuItem svgItem = new JMenuItem(new ExportToSVGAction( 239 this.content)); 240 exportSubMenu.add(svgItem); 241 } 242 } 243 } 244 if (exportSubMenu.getItemCount() > 0) { 245 popupMenu.addSeparator(); 246 popupMenu.add(exportSubMenu); 247 } 248 } 249 return popupMenu; 250 } 251 252 /** 253 * This method does nothing. 254 * 255 * @param e the mouse event. 256 */ 257 @Override 258 public void mouseClicked(MouseEvent e) { 259 // nothing to do 260 } 261 262 /** 263 * Checks if the popup is triggered in which case it is displayed. 264 * 265 * @param e the mouse event. 266 */ 267 @Override 268 public void mousePressed(MouseEvent e) { 269 // popup is triggered on mousePressed for Linux and Mac, but Windows 270 // is mouseReleased 271 if (e.isPopupTrigger()) { 272 if (this.popup != null) { 273 this.popup.show(this, e.getX(), e.getY()); 274 e.consume(); 275 } 276 } 277 } 278 279 /** 280 * Checks if the popup is triggered in which case it is displayed. 281 * 282 * @param e the mouse event. 283 */ 284 @Override 285 public void mouseReleased(MouseEvent e) { 286 // popup is triggered on mouseReleased for Windows, but Linux and Mac 287 // is mousePressed 288 if (e.isPopupTrigger()) { 289 if (this.popup != null) { 290 this.popup.show(this, e.getX(), e.getY()); 291 e.consume(); 292 } 293 } 294 } 295 296 /** 297 * This method does nothing. 298 * 299 * @param e the mouse event. 300 */ 301 @Override 302 public void mouseEntered(MouseEvent e) { 303 // nothing to do 304 } 305 306 /** 307 * This method does nothing. 308 * 309 * @param e the mouse event. 310 */ 311 @Override 312 public void mouseExited(MouseEvent e) { 313 // nothing to do 314 } 315 316}