    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}