org.tinymediamanager.ui.MainWindow.java Source code

Java tutorial

Introduction

Here is the source code for org.tinymediamanager.ui.MainWindow.java

Source

/*
 * Copyright 2012 - 2016 Manuel Laggner
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.tinymediamanager.ui;

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker.StateValue;
import javax.swing.Timer;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
import javax.swing.text.JTextComponent;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tinymediamanager.Globals;
import org.tinymediamanager.core.Message;
import org.tinymediamanager.core.Message.MessageLevel;
import org.tinymediamanager.core.MessageManager;
import org.tinymediamanager.core.TmmModuleManager;
import org.tinymediamanager.core.UpdaterTask;
import org.tinymediamanager.core.Utils;
import org.tinymediamanager.core.WolDevice;
import org.tinymediamanager.core.threading.TmmTaskManager;
import org.tinymediamanager.thirdparty.MediaInfo;
import org.tinymediamanager.ui.actions.AboutAction;
import org.tinymediamanager.ui.actions.BugReportAction;
import org.tinymediamanager.ui.actions.ClearDatabaseAction;
import org.tinymediamanager.ui.actions.ClearImageCacheAction;
import org.tinymediamanager.ui.actions.DonateAction;
import org.tinymediamanager.ui.actions.ExitAction;
import org.tinymediamanager.ui.actions.FaqAction;
import org.tinymediamanager.ui.actions.FeedbackAction;
import org.tinymediamanager.ui.actions.ForumAction;
import org.tinymediamanager.ui.actions.LaunchUpdaterAction;
import org.tinymediamanager.ui.actions.RebuildImageCacheAction;
import org.tinymediamanager.ui.actions.RegisterDonatorVersionAction;
import org.tinymediamanager.ui.actions.SettingsAction;
import org.tinymediamanager.ui.actions.WikiAction;
import org.tinymediamanager.ui.components.StatusBar;
import org.tinymediamanager.ui.components.TextFieldPopupMenu;
import org.tinymediamanager.ui.components.VerticalTextIcon;
import org.tinymediamanager.ui.dialogs.LogDialog;
import org.tinymediamanager.ui.dialogs.MessageHistoryDialog;
import org.tinymediamanager.ui.dialogs.UpdateDialog;
import org.tinymediamanager.ui.images.Logo;
import org.tinymediamanager.ui.movies.MoviePanel;
import org.tinymediamanager.ui.moviesets.MovieSetPanel;
import org.tinymediamanager.ui.tvshows.TvShowPanel;

import com.jgoodies.forms.factories.FormFactory;
import com.jgoodies.forms.layout.ColumnSpec;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.RowSpec;
import com.sun.jna.Platform;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;

/**
 * The Class MainWindow.
 * 
 * @author Manuel Laggner
 */
public class MainWindow extends JFrame {
    /**
     * @wbp.nls.resourceBundle messages
     */
    private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("messages", new UTF8Control()); //$NON-NLS-1$
    private final static Logger LOGGER = LoggerFactory.getLogger(MainWindow.class);
    private static final long serialVersionUID = 1L;

    public final static List<Image> LOGOS = createLogos();
    private static MainWindow instance;

    private JPanel panelMovies;
    private JPanel panelMovieSets;
    private JPanel panelTvShows;
    private JPanel panelStatusBar;

    /**
     * Create the application.
     * 
     * @param name
     *          the name
     */
    public MainWindow(String name) {
        super(name);
        setName("mainWindow");
        setMinimumSize(new Dimension(1000, 700));

        instance = this;

        JMenuBar menuBar = new JMenuBar();
        setJMenuBar(menuBar);

        JMenu mnTmm = new JMenu("tinyMediaManager");
        mnTmm.setMnemonic(KeyEvent.VK_T);
        menuBar.add(mnTmm);

        if (!Globals.isDonator()) {
            mnTmm.add(new RegisterDonatorVersionAction());
        }

        mnTmm.add(new SettingsAction());
        mnTmm.addSeparator();
        mnTmm.add(new LaunchUpdaterAction());
        mnTmm.addSeparator();
        mnTmm.add(new ExitAction());
        initialize();

        // tools menu
        JMenu tools = new JMenu(BUNDLE.getString("tmm.tools")); //$NON-NLS-1$
        tools.setMnemonic(KeyEvent.VK_O);
        tools.add(new ClearDatabaseAction());

        JMenu cache = new JMenu(BUNDLE.getString("tmm.cache")); //$NON-NLS-1$
        cache.setMnemonic(KeyEvent.VK_C);
        tools.add(cache);
        JMenuItem clearImageCache = new JMenuItem(new ClearImageCacheAction());
        clearImageCache.setMnemonic(KeyEvent.VK_I);
        cache.add(clearImageCache);

        JMenuItem rebuildImageCache = new JMenuItem(new RebuildImageCacheAction());
        rebuildImageCache.setMnemonic(KeyEvent.VK_R);
        cache.add(rebuildImageCache);

        JMenuItem tmmFolder = new JMenuItem(BUNDLE.getString("tmm.gotoinstalldir")); //$NON-NLS-1$
        tmmFolder.setMnemonic(KeyEvent.VK_I);
        tools.add(tmmFolder);
        tmmFolder.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                Path path = Paths.get(System.getProperty("user.dir"));
                try {
                    // check whether this location exists
                    if (Files.exists(path)) {
                        TmmUIHelper.openFile(path);
                    }
                } catch (Exception ex) {
                    LOGGER.error("open filemanager", ex);
                    MessageManager.instance.pushMessage(new Message(MessageLevel.ERROR, path,
                            "message.erroropenfolder", new String[] { ":", ex.getLocalizedMessage() }));
                }
            }
        });

        JMenuItem tmmLogs = new JMenuItem(BUNDLE.getString("tmm.errorlogs")); //$NON-NLS-1$
        tmmLogs.setMnemonic(KeyEvent.VK_L);
        tools.add(tmmLogs);
        tmmLogs.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                JDialog logDialog = new LogDialog();
                logDialog.setLocationRelativeTo(MainWindow.getActiveInstance());
                logDialog.setVisible(true);
            }
        });

        JMenuItem tmmMessages = new JMenuItem(BUNDLE.getString("tmm.messages")); //$NON-NLS-1$
        tmmMessages.setMnemonic(KeyEvent.VK_L);
        tools.add(tmmMessages);
        tmmMessages.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                JDialog messageDialog = MessageHistoryDialog.getInstance();
                messageDialog.setVisible(true);
            }
        });

        tools.addSeparator();
        final JMenu menuWakeOnLan = new JMenu(BUNDLE.getString("tmm.wakeonlan")); //$NON-NLS-1$
        menuWakeOnLan.setMnemonic(KeyEvent.VK_W);
        menuWakeOnLan.addMenuListener(new MenuListener() {
            @Override
            public void menuCanceled(MenuEvent arg0) {
            }

            @Override
            public void menuDeselected(MenuEvent arg0) {
            }

            @Override
            public void menuSelected(MenuEvent arg0) {
                menuWakeOnLan.removeAll();
                for (final WolDevice device : Globals.settings.getWolDevices()) {
                    JMenuItem item = new JMenuItem(device.getName());
                    item.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent arg0) {
                            Utils.sendWakeOnLanPacket(device.getMacAddress());
                        }
                    });
                    menuWakeOnLan.add(item);
                }
            }
        });
        tools.add(menuWakeOnLan);

        // activate/deactivate WakeOnLan menu item
        tools.addMenuListener(new MenuListener() {
            @Override
            public void menuSelected(MenuEvent e) {
                if (Globals.settings.getWolDevices().size() > 0) {
                    menuWakeOnLan.setEnabled(true);
                } else {
                    menuWakeOnLan.setEnabled(false);
                }
            }

            @Override
            public void menuDeselected(MenuEvent e) {
            }

            @Override
            public void menuCanceled(MenuEvent e) {
            }
        });

        if (Globals.isDebug()) {
            final JMenu debugMenu = new JMenu("Debug"); //$NON-NLS-1$

            JMenuItem trace = new JMenuItem("set Logger to TRACE"); //$NON-NLS-1$
            trace.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
                    lc.getLogger("org.tinymediamanager").setLevel(Level.TRACE);
                    MessageManager.instance.pushMessage(new Message("Trace levels set!", ""));
                    LOGGER.trace("if you see that, we're now on TRACE logging level ;)");
                }
            });

            debugMenu.add(trace);
            tools.add(debugMenu);
        }

        menuBar.add(tools);

        mnTmm = new JMenu(BUNDLE.getString("tmm.contact")); //$NON-NLS-1$
        mnTmm.setMnemonic(KeyEvent.VK_C);
        mnTmm.add(new FeedbackAction()).setMnemonic(KeyEvent.VK_F);
        mnTmm.add(new BugReportAction()).setMnemonic(KeyEvent.VK_B);
        menuBar.add(mnTmm);

        mnTmm = new JMenu(BUNDLE.getString("tmm.help")); //$NON-NLS-1$
        mnTmm.setMnemonic(KeyEvent.VK_H);
        menuBar.add(mnTmm);

        mnTmm.add(new WikiAction()).setMnemonic(KeyEvent.VK_W);
        mnTmm.add(new FaqAction()).setMnemonic(KeyEvent.VK_F);
        mnTmm.add(new ForumAction()).setMnemonic(KeyEvent.VK_O);
        mnTmm.addSeparator();

        mnTmm.add(new AboutAction()).setMnemonic(KeyEvent.VK_A);

        menuBar.add(Box.createGlue());

        if (!Globals.isDonator()) {
            JButton btnDonate = new JButton(new DonateAction());
            btnDonate.setBorderPainted(false);
            btnDonate.setFocusPainted(false);
            btnDonate.setContentAreaFilled(false);
            menuBar.add(btnDonate);
        }

        checkForUpdate();
    }

    /**
     * load all predefined logo sizes
     * 
     * @return a list of all predefined logos
     */
    private static List<Image> createLogos() {
        List<Image> logos = new ArrayList<>();

        logos.add(new Logo(48).getImage());
        logos.add(new Logo(64).getImage());
        logos.add(new Logo(96).getImage());
        logos.add(new Logo(128).getImage());
        logos.add(new Logo(256).getImage());

        return logos;
    }

    private void checkForUpdate() {
        try {
            final UpdaterTask updateWorker = new UpdaterTask();

            updateWorker.addPropertyChangeListener(new PropertyChangeListener() {
                public void propertyChange(PropertyChangeEvent evt) {
                    if ("state".equals(evt.getPropertyName()) && evt.getNewValue() == StateValue.DONE) {
                        try {
                            boolean update = updateWorker.get();
                            LOGGER.debug("update result was: " + update);
                            if (update) {

                                // we might need this somewhen...
                                if (updateWorker.isForcedUpdate()) {
                                    LOGGER.info("Updating (forced)...");
                                    closeTmmAndStart(Utils.getPBforTMMupdate());
                                    return;
                                }

                                // show whatsnewdialog with the option to update
                                if (StringUtils.isNotBlank(updateWorker.getChangelog())) {
                                    UpdateDialog dialog = new UpdateDialog(updateWorker.getChangelog());
                                    dialog.setVisible(true);
                                } else {
                                    // do the update without changelog popup

                                    int answer = JOptionPane.showConfirmDialog(null,
                                            BUNDLE.getString("tmm.update.message"),
                                            BUNDLE.getString("tmm.update.title"), JOptionPane.YES_NO_OPTION);
                                    if (answer == JOptionPane.OK_OPTION) {
                                        LOGGER.info("Updating...");

                                        // spawn getdown and exit TMM
                                        closeTmmAndStart(Utils.getPBforTMMupdate());
                                    }
                                }
                            }
                        } catch (Exception e) {
                            LOGGER.error("Update task failed!" + e.getMessage());
                        }
                    }
                }
            });

            // update task start a few secs after GUI...
            Timer timer = new Timer(5000, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    updateWorker.execute();
                }
            });
            timer.setRepeats(false);
            timer.start();
        } catch (Exception e) {
            LOGGER.error("Update task failed!" + e.getMessage());
        }
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        // set the logo
        setIconImages(LOGOS);
        setBounds(5, 5, 1100, 727);
        // do nothing, we have our own windowClosing() listener
        // setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        getContentPane().setLayout(new BorderLayout(0, 0));

        JLayeredPane content = new JLayeredPane();
        content.setLayout(new FormLayout(
                new ColumnSpec[] { ColumnSpec.decode("default:grow"), FormFactory.RELATED_GAP_COLSPEC,
                        ColumnSpec.decode("right:270px"), },
                new RowSpec[] { RowSpec.decode("fill:max(500px;default):grow"), }));
        getContentPane().add(content, BorderLayout.CENTER);

        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new FormLayout(new ColumnSpec[] { ColumnSpec.decode("default:grow") },
                new RowSpec[] { RowSpec.decode("fill:max(500px;default):grow") }));
        content.add(mainPanel, "1, 1, 3, 1, fill, fill");
        content.setLayer(mainPanel, 1);

        JTabbedPane tabbedPane = VerticalTextIcon.createTabbedPane(JTabbedPane.LEFT);
        tabbedPane.setTabPlacement(JTabbedPane.LEFT);
        mainPanel.add(tabbedPane, "1, 1, fill, fill");
        // getContentPane().add(tabbedPane, "1, 2, fill, fill");

        panelStatusBar = new StatusBar();
        getContentPane().add(panelStatusBar, BorderLayout.SOUTH);

        panelMovies = new MoviePanel();
        VerticalTextIcon.addTab(tabbedPane, BUNDLE.getString("tmm.movies"), panelMovies); //$NON-NLS-1$

        panelMovieSets = new MovieSetPanel();
        VerticalTextIcon.addTab(tabbedPane, BUNDLE.getString("tmm.moviesets"), panelMovieSets); //$NON-NLS-1$

        panelTvShows = new TvShowPanel();
        VerticalTextIcon.addTab(tabbedPane, BUNDLE.getString("tmm.tvshows"), panelTvShows); //$NON-NLS-1$

        // shutdown listener - to clean database connections safely
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                closeTmm();
            }
        });

        MessageManager.instance.addListener(TmmUIMessageCollector.instance);

        // mouse event listener for context menu
        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
            @Override
            public void eventDispatched(AWTEvent arg0) {
                if (arg0 instanceof MouseEvent && MouseEvent.MOUSE_RELEASED == arg0.getID()
                        && arg0.getSource() instanceof JTextComponent) {
                    MouseEvent me = (MouseEvent) arg0;
                    JTextComponent tc = (JTextComponent) arg0.getSource();
                    if (me.isPopupTrigger() && tc.getComponentPopupMenu() == null) {
                        TextFieldPopupMenu.buildCutCopyPaste().show(tc, me.getX(), me.getY());
                    }
                }
            }
        }, AWTEvent.MOUSE_EVENT_MASK);

        // temp info for users using Java 6
        if (SystemUtils.IS_JAVA_1_6) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JOptionPane.showMessageDialog(MainWindow.this, BUNDLE.getString("tmm.java6")); //$NON-NLS-1$
                }
            });
        }

        // inform user is MI could not be loaded
        if (Platform.isLinux() && StringUtils.isBlank(MediaInfo.version())) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JOptionPane.showMessageDialog(MainWindow.this, BUNDLE.getString("mediainfo.failed.linux")); //$NON-NLS-1$
                }
            });
        }
    }

    public void closeTmm() {
        closeTmmAndStart(null);
    }

    public void closeTmmAndStart(ProcessBuilder pb) {
        int confirm = JOptionPane.YES_OPTION;
        // if there are some threads running, display exit confirmation
        if (TmmTaskManager.getInstance().poolRunning()) {
            confirm = JOptionPane.showOptionDialog(null, BUNDLE.getString("tmm.exit.runningtasks"),
                    BUNDLE.getString("tmm.exit.confirmation"), JOptionPane.YES_NO_OPTION,
                    JOptionPane.QUESTION_MESSAGE, null, null, null); // $NON-NLS-1$
        }
        if (confirm == JOptionPane.YES_OPTION) {
            LOGGER.info("bye bye");
            try {
                Utils.trackEvent("shutdown");
                // send shutdown signal
                TmmTaskManager.getInstance().shutdown();
                // save unsaved settings
                Globals.settings.saveSettings();
                // hard kill
                TmmTaskManager.getInstance().shutdownNow();
                // close database connection
                TmmModuleManager.getInstance().shutDown();
            } catch (Exception ex) {
                LOGGER.warn("", ex);
            }
            dispose();

            // spawn our process
            if (pb != null) {
                try {
                    LOGGER.info("Going to execute: " + pb.command());
                    pb.start();
                } catch (IOException e) {
                    LOGGER.error("Cannot spawn process:", e);
                }
            }

            System.exit(0); // calling the method is a must
        }
    }

    /**
     * Gets the active instance.
     * 
     * @return the active instance
     */
    public static MainWindow getActiveInstance() {
        return instance;
    }

    /**
     * Gets the movie panel.
     * 
     * @return the movie panel
     */
    public MoviePanel getMoviePanel() {
        return (MoviePanel) panelMovies;
    }

    public MovieSetPanel getMovieSetPanel() {
        return (MovieSetPanel) panelMovieSets;
    }

    public TvShowPanel getTvShowPanel() {
        return (TvShowPanel) panelTvShows;
    }

    /**
     * Gets the frame.
     * 
     * @return the frame
     */
    public static JFrame getFrame() {
        return instance;
    }

    public void createLightbox(String pathToFile, String urlToFile) {
        LightBox.showLightBox(instance, pathToFile, urlToFile);
    }
}