org.jimcat.gui.SwingClient.java Source code

Java tutorial

Introduction

Here is the source code for org.jimcat.gui.SwingClient.java

Source

/*
 *  This file is part of JimCat.
 *
 *  JimCat is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation version 2.
 *
 *  JimCat is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with JimCat; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

package org.jimcat.gui;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.Window;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.RejectedExecutionException;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.UIManager;

import org.jimcat.gui.dialog.exportdialog.ExportDialog;
import org.jimcat.gui.dialog.failurefeedbackdialog.FailureFeedbackDialog;
import org.jimcat.gui.dialog.importdialog.ImportDialog;
import org.jimcat.gui.dialog.printdialog.PrintDialog;
import org.jimcat.gui.dialog.renamedialog.RenameDialog;
import org.jimcat.gui.frame.AboutDialog;
import org.jimcat.gui.frame.JimCatFrame;
import org.jimcat.gui.fullscreen.FullScreenView;
import org.jimcat.gui.imagepopup.ImagePopupMenu;
import org.jimcat.gui.jobmanager.JobFace;
import org.jimcat.gui.jobmanager.JobManagerDialog;
import org.jimcat.gui.smartlisteditor.SmartListEditor;
import org.jimcat.gui.splashscreen.SplashScreen;
import org.jimcat.model.Image;
import org.jimcat.model.SmartList;
import org.jimcat.services.JobOperations;
import org.jimcat.services.OperationsLocator;
import org.jimcat.services.SystemOperations;
import org.jimcat.services.configuration.Configuration;
import org.jimcat.services.instancecontrol.InstanceListener;
import org.jimcat.services.jobs.Job;
import org.jimcat.services.jobs.JobFailureDescription;
import org.jimcat.services.jobs.JobManager;
import org.jvnet.lafwidget.LafWidget;
import org.jvnet.lafwidget.utils.LafConstants.AnimationKind;
import org.jvnet.substance.SubstanceLookAndFeel;
import org.jvnet.substance.skin.OfficeSilver2007Skin;

import com.jgoodies.looks.plastic.PlasticLookAndFeel;
import com.jgoodies.looks.plastic.PlasticXPLookAndFeel;
import com.jgoodies.looks.plastic.theme.SkyBlue;

/**
 * This is the main class for the jimcat swing client.
 * 
 * It is the root of the compleate Component tree and proviedes some basic IO
 * methodes.
 * 
 * $Id: SwingClient.java 970 2007-06-19 18:39:26Z 07g1t1u3 $
 * 
 * @author Herbert
 */
public final class SwingClient {

    /**
     * singelton Instance
     */
    private static final SwingClient INSTANCE = new SwingClient();

    /**
     * the default theme to be used
     */
    private static final String DEFAULT_THEME = "substance";

    /**
     * to prevent multible instanziation
     */
    private boolean started = false;

    /**
     * a reference to the main element
     */
    private JimCatFrame mainFrame;

    /**
     * a reference to the jobManager Dialog used by this GUI
     */
    private JobManagerDialog jobManagerDialog;

    /**
     * a reference to the about frame
     */
    private JDialog aboutFrame;

    /**
     * a reference to the fullscreen view;
     */
    private FullScreenView fullScreenView;

    /**
     * the importdialog used for import-setup
     */
    private ImportDialog importDialog;

    /**
     * the exportDialog used for export-setup
     */
    private ExportDialog exportDialog;

    /**
     * The Print Dialog
     */
    private PrintDialog printDialog;

    /**
     * The Rename Dialog
     */
    private RenameDialog renameDialog;

    /**
     * the smartList editor used for editing
     */
    private SmartListEditor smartListEditor;

    /**
     * the central filter control instance
     */
    private ViewControl viewControl;

    /**
     * a collection of extracted tag operations
     */
    private TagControl tagControl;

    /**
     * a collection of more complex album operations
     */
    private AlbumControl albumControl;

    /**
     * a collection of more complex smartlist operations
     */
    private SmartListControl smartListControl;

    /**
     * a collection of extracted image operations
     */
    private ImageControl imageControl;

    /**
     * set to true if the background thread has finished preloading the
     * components
     */
    private boolean startupCompleted = false;

    /**
     * if startupCompleted == false a method has to wait until it gets a notify
     * on this object
     */
    private Object startupLock = new Object();

    /**
     * initializes windows for later use
     */
    private final BackgroundGuiLoader guiLoader = new BackgroundGuiLoader();

    /**
     * singelton - getInstance()
     * 
     * @return an instance of the SwingClient
     */
    public static SwingClient getInstance() {
        return INSTANCE;
    }

    /**
     * a call to this Methode will cause the Swing GUI to create a new Frame and
     * show it.
     */
    public void startup() {
        // check if it hasn't been started yet
        if (started) {
            return;
        }

        SplashScreen.setProgressText("Loading Library");
        // create controles
        tagControl = new TagControl(this);
        imageControl = new ImageControl();
        albumControl = new AlbumControl(this);
        smartListControl = new SmartListControl(this);
        // create a new ViewControl
        viewControl = new ViewControl();

        started = true;

        SplashScreen.setProgressText("Creating GUI");
        // SplashScreen.fadeProgressBar();
        // Install LookAndFeel
        try {

            String theme = Configuration.getString("theme", DEFAULT_THEME);

            if (theme.equals("substance")) {
                UIManager.setLookAndFeel(new SubstanceLookAndFeel());
                SubstanceLookAndFeel.setSkin(new OfficeSilver2007Skin());
                UIManager.put(SubstanceLookAndFeel.NO_EXTRA_ELEMENTS, Boolean.TRUE);
                UIManager.put(LafWidget.ANIMATION_KIND, AnimationKind.NONE);
            } else if (theme.equals("jgoodies")) {
                PlasticLookAndFeel.setPlasticTheme(new SkyBlue());
                UIManager.setLookAndFeel(new PlasticXPLookAndFeel());
            }

        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        // Build up Frame - in right Thread
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                startupProcess();
            }
        });
    }

    /**
     * the actual startup process
     */
    private void startupProcess() {
        // set default local for all components
        Locale.setDefault(Locale.ENGLISH);

        // build fullscreen - shouldn't be decorated
        fullScreenView = new FullScreenView();

        // Install Decorations
        if (Configuration.getString("theme", DEFAULT_THEME).equals("substance")) {
            String osName = System.getProperty("os.name").toLowerCase();
            if (!osName.startsWith("linux")) {
                JFrame.setDefaultLookAndFeelDecorated(true);
                JDialog.setDefaultLookAndFeelDecorated(true);
            }
        }

        // build mainFrame
        mainFrame = new JimCatFrame();

        // preload Image popup
        ImagePopupMenu.getInstance();

        // build JobManager
        JobOperations jobOps = OperationsLocator.getJobOperations();
        JobManager jobManager = jobOps.getJobManager();
        jobManagerDialog = new JobManagerDialog(jobManager);

        new Thread(guiLoader).start();

        // add InstanceListener
        SystemOperations sysOp = OperationsLocator.getSystemOperations();
        sysOp.addInstanceListener(new InstanceListener() {
            /**
             * React on surpressed instance
             * 
             * @see org.jimcat.services.instancecontrol.InstanceListener#otherInstanceSurpressed()
             */
            public void otherInstanceSurpressed() {
                // This will bring this Window to the front
                mainFrame.toFront();
            }
        });

        // add failure listener
        sysOp.addFailureFeedbackListener(new FailureFeedbackDialog(this));

        mainFrame.setVisible(true);
        SplashScreen.hideSplashScreen();
    }

    /**
     * this will check the status and try to shutdown the system
     */
    public void initateShutdown() {
        // check if there are still running jobs
        JobOperations jobOps = OperationsLocator.getJobOperations();
        List<Job> jobs = jobOps.getJobManager().getActiveJobs();
        if (jobs.size() > 0) {
            JOptionPane.showMessageDialog(mainFrame, "There are still jobs running.", "Can't shut down",
                    JOptionPane.ERROR_MESSAGE);
            displayJobManager();
            return;
        }

        guiLoader.kill();

        // TODO: integrate other shutdown checks

        // Performe shutdown
        // Shutdown gui
        shutdown();

        // Shutdown backend
        SystemOperations sysOp = OperationsLocator.getSystemOperations();
        sysOp.shutdown();
    }

    /**
     * this will cause the SwingClient to shutdown
     */
    private void shutdown() {
        // if not started, do nothing
        if (!started) {
            return;
        }
        started = false;

        if (EventQueue.isDispatchThread()) {
            // its the right thread
            shutdownProcess();
        } else {
            // enqueue in right Thread
            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    shutdownProcess();
                }
            });
        }
    }

    /**
     * This method blocks as long as the startup isn't complete
     */
    private void blockWhileInitializing() {
        if (!startupCompleted) {
            synchronized (startupLock) {
                try {
                    while (!startupCompleted) {
                        startupLock.wait();
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }

    /**
     * the actual gui-shutdown process
     */
    private void shutdownProcess() {

        for (Window w : new Window[] { mainFrame, importDialog, exportDialog, smartListEditor, jobManagerDialog,
                fullScreenView, aboutFrame }) {

            if (w == null) {
                continue;
            }

            w.setVisible(false);
            w.dispose();
        }
    }

    /**
     * This methode provides access to the associated ViewControl
     * 
     * @return the associated ViewControl
     */
    public ViewControl getViewControl() {
        if (viewControl == null) {
            viewControl = new ViewControl();
        }
        return viewControl;
    }

    /**
     * Returns the central element containing TagOperations. All operations on
     * tags should be performed through this Control.
     * 
     * @return the TagControl
     */
    public TagControl getTagControl() {
        if (tagControl == null) {
            tagControl = new TagControl(this);
        }
        return tagControl;
    }

    /**
     * Returns a reference to the up and running album control.
     * 
     * @return the AlbumControl
     */
    public AlbumControl getAlbumControl() {
        return albumControl;
    }

    /**
     * Returns a reference to the up and running smartlist control.
     * 
     * @return the SmartListControl
     */
    public SmartListControl getSmartListControl() {
        return smartListControl;
    }

    /**
     * @return the imageControl
     */
    public ImageControl getImageControl() {
        if (imageControl == null) {
            imageControl = new ImageControl();
        }
        return imageControl;
    }

    /**
     * return current top element visible
     * 
     * @return the current top Component
     */
    public Component getCurrentTopWindow() {
        if (fullScreenView.isVisible()) {
            return fullScreenView;
        }
        return mainFrame;
    }

    /**
     * the main frame of this GUI
     * 
     * @return the MainFrame
     */
    public JimCatFrame getMainFrame() {
        return mainFrame;
    }

    /**
     * this will display the jobmanger
     */
    public void displayJobManager() {
        if (!jobManagerDialog.isVisible()) {
            // move to current screen
            Rectangle screen = mainFrame.getGraphicsConfiguration().getBounds();

            Dimension size = jobManagerDialog.getSize();

            int x = (screen.width - size.width) / 10 * 9 + screen.x;
            int y = (screen.height - size.height) / 4 * 3 + screen.y;
            jobManagerDialog.setLocation(x, y);

            // show job manager
            jobManagerDialog.setVisible(true);
        } else {
            jobManagerDialog.toFront();
        }
    }

    /**
     * this will display the about frame
     */
    public void displayAboutFrame() {
        blockWhileInitializing();

        if (!aboutFrame.isVisible()) {
            centerWindow(aboutFrame);
            aboutFrame.setVisible(true);
        }
    }

    /**
     * call this to display import dialog
     */
    public void displayImportDialog() {
        blockWhileInitializing();
        if (!importDialog.isVisible()) {
            centerWindow(importDialog);
            importDialog.clearFileList();
            importDialog.setVisible(true);
        }
    }

    /**
     * call this to display the print dialog
     */
    public void displayPrintDialog() {
        blockWhileInitializing();
        if (!printDialog.isVisible()) {
            centerWindow(printDialog);
            printDialog.updatePreviewImages();
            boolean selectedImages = getViewControl().getSelectedImages().size() != 0;
            printDialog.setSelectedImagesAvailable(selectedImages);
            printDialog.setVisible(true);
        }
    }

    /**
     * call this to display export dialog
     * 
     * @param onlySelected
     */
    public void displayExportDialog(boolean onlySelected) {
        blockWhileInitializing();
        if (!exportDialog.isVisible()) {
            centerWindow(exportDialog);
            exportDialog.clearFileList();
            exportDialog.setOnlySelection(onlySelected);
            exportDialog.setVisible(true);
        }
    }

    /**
     * call this to display export dialog
     */
    public void displayRenameDialog() {
        blockWhileInitializing();
        if (!renameDialog.isVisible()) {
            centerWindow(renameDialog);
            renameDialog.setSelectedImages(new ArrayList<Image>(getViewControl().getSelectedImages()));
            renameDialog.setVisible(true);
        }
    }

    /**
     * call this to display the smartlist editor
     * 
     * @param list -
     *            the smartlist to edit
     */
    public void displaySmartListEditor(SmartList list) {
        blockWhileInitializing();
        if (!smartListEditor.isVisible()) {
            centerWindow(smartListEditor);
            smartListEditor.setSmartList(list);
            smartListEditor.setVisible(true);
        }
    }

    /**
     * use this to start a new job.
     * 
     * it will display a new JobFace to control the running job.
     * 
     * @param job
     */
    public void startJob(Job job) {
        // build up face
        JobFace face = new JobFace();
        face.setJob(job);

        // show jobmanager
        displayJobManager();

        // add job to jobmanager and start it
        JobOperations jobOps = OperationsLocator.getJobOperations();
        JobManager jobManager = jobOps.getJobManager();
        jobManager.excecuteJob(job);
    }

    /**
     * Shows a Confirmation Dialog using JOptionPane
     * 
     * @param message
     * @param title
     * @param options
     * @param typ
     * @return the result of the dialog
     * 
     * @see JOptionPane#showConfirmDialog(java.awt.Component, Object, String,
     *      int, int)
     */
    public int showConfirmDialog(String message, String title, int options, int typ) {
        return JOptionPane.showConfirmDialog(getCurrentTopWindow(), message, title, options, typ);
    }

    /**
     * Shows a Input Dialog using JOptionPane
     * 
     * @param message
     * @param title
     * @param typ
     * @return the result of the input dialog
     * 
     * @see JOptionPane#showInputDialog(java.awt.Component, Object, String, int)
     */
    public String showInputDialog(String message, String title, int typ) {
        return JOptionPane.showInputDialog(getCurrentTopWindow(), message, title, typ);
    }

    /**
     * shows a simple message with a ok button
     * 
     * @param message
     * @param title
     * @param typ
     * 
     * @see JOptionPane#showMessageDialog(java.awt.Component, Object, String,
     *      int)
     */
    public void showMessage(String message, String title, int typ) {
        JOptionPane.showMessageDialog(getCurrentTopWindow(), message, title, typ);
    }

    /**
     * this will show a JobFailure description and allowes the user to choose an
     * option
     * 
     * @param description
     */
    public void showJobFailure(JobFailureDescription description) {
        // show Failure description
        int result = JOptionPane.showOptionDialog(getCurrentTopWindow(), description.getDescription(),
                "Failure during job execution", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE, null,
                description.getOptions().toArray(), description.getRespond());

        // react on result
        if (result != JOptionPane.CLOSED_OPTION) {
            description.setRespond(description.getOptions().get(result));
        }
    }

    /**
     * switch to fullscreen
     */
    public void showFullScreen() {
        if (fullScreenView.isVisible()) {
            return;
        }
        centerWindow(fullScreenView);
        fullScreenView.display();
    }

    /**
     * close fullscreen
     */
    public void hideFullScreen() {
        fullScreenView.closeFullScreenView();
    }

    /**
     * this will center the given window on the screen currently occupied by the
     * main frame
     * 
     * @param window
     */
    private void centerWindow(Window window) {
        Rectangle screen = mainFrame.getGraphicsConfiguration().getBounds();

        Dimension size = window.getSize();

        int x = (screen.width - size.width) / 2 + screen.x;
        int y = (screen.height - size.height) / 2 + screen.y;
        window.setLocation(x, y);
    }

    /**
     * initialize components for faster access in the future done in a
     * background thread so the startup feels faster
     */
    private class BackgroundGuiLoader implements Runnable {

        private boolean kill = false;

        private RuntimeException ex = new RuntimeException();

        public void run() {
            synchronized (startupLock) {

                try {
                    // build ImportDiaolg
                    importDialog = new ImportDialog(SwingClient.this, mainFrame);
                    checkKill();

                    // build ExportDialog
                    exportDialog = new ExportDialog(SwingClient.this, mainFrame);
                    checkKill();

                    // build RenameDialog
                    renameDialog = new RenameDialog(SwingClient.this, mainFrame);
                    checkKill();

                    // build PrintDialog
                    printDialog = new PrintDialog(SwingClient.this, mainFrame);
                    checkKill();

                    // build SmartList editor
                    smartListEditor = new SmartListEditor(mainFrame);
                    checkKill();

                    // build about dialog
                    aboutFrame = new AboutDialog(mainFrame);

                    startupCompleted = true;
                    startupLock.notifyAll();
                } catch (RejectedExecutionException e) {
                    // sometimes thrown in internal swing classes if there's
                    // a shutdown in progress. we ignore it.
                } catch (RuntimeException e) {
                    if (e == ex) {
                        // aborted
                    } else {
                        throw e; // unexpected exception, rethrow it
                    }
                }
            }
        }

        private void checkKill() {
            if (!kill) {
                return;
            }

            startupCompleted = true;
            startupLock.notifyAll();
            throw ex;
        }

        public void kill() {
            this.kill = true;
        }
    }

}