    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}