org.kepler.gui.kar.OpenArchiveAction.java Source code

Java tutorial

Introduction

Here is the source code for org.kepler.gui.kar.OpenArchiveAction.java

Source

/*
 * Copyright (c) 2004-2011 The Regents of the University of California.
 * All rights reserved.
 *
 * '$Author: barseghian $'
 * '$Date: 2013-01-15 13:33:01 -0800 (Tue, 15 Jan 2013) $' 
 * '$Revision: 31328 $'
 * 
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the above
 * copyright notice and the following two paragraphs appear in all copies
 * of this software.
 *
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
 * ENHANCEMENTS, OR MODIFICATIONS.
 *
 */

package org.kepler.gui.kar;

import java.awt.Color;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.io.File;
import java.net.URL;

import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.kepler.gui.KeplerGraphFrame;
import org.kepler.kar.KARFile;

import ptolemy.actor.gui.Configuration;
import ptolemy.actor.gui.Tableau;
import ptolemy.actor.gui.TableauFrame;
import ptolemy.gui.ExtensionFilenameFilter;
import ptolemy.gui.JFileChooserBugFix;
import ptolemy.gui.PtFileChooser;
import ptolemy.kernel.util.InternalErrorException;
import ptolemy.kernel.util.Nameable;
import ptolemy.vergil.basic.BasicGraphFrame;
import ptolemy.vergil.toolbox.FigureAction;
import diva.gui.GUIUtilities;

/**
 * This action opens a kar file to the system. It is called from File -> Open.
 *
 * @author Ben Leinfelder, Christopher Brooks
 * @since 05/28/2009
 */
public class OpenArchiveAction extends FigureAction {

    private static String DISPLAY_NAME = "Open";
    private static String TOOLTIP = "Open a KAR file archive.";
    private static ImageIcon LARGE_ICON = null;
    private static KeyStroke ACCELERATOR_KEYSTROKE = KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O,
            Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());

    // //////////////////////////////////////////////////////////////////////////////

    private TableauFrame parent;

    private final static Log log = LogFactory.getLog(OpenArchiveAction.class);
    private static final boolean isDebugging = log.isDebugEnabled();

    private File archiveFileToOpen = null;
    private boolean updateHistoryAndLastDirectory = true;

    private ActionEvent actionEvent = null;

    /** The exception generated when trying to open the KAR. */
    private Exception _openException = null;

    /**
     * Constructor
     *
     * @param parent the "frame" (derived from ptolemy.gui.Top) where the menu is
     *               being added.
     */
    public OpenArchiveAction(TableauFrame parent) {
        super("Open...");

        if (parent == null) {
            IllegalArgumentException iae = new IllegalArgumentException(
                    "OpenArchiveAction constructor received NULL argument for TableauFrame");
            iae.fillInStackTrace();
            throw iae;
        }
        this.parent = parent;

        this.putValue(Action.NAME, DISPLAY_NAME);
        this.putValue(GUIUtilities.LARGE_ICON, LARGE_ICON);
        this.putValue("tooltip", TOOLTIP);
        this.putValue(GUIUtilities.ACCELERATOR_KEY, ACCELERATOR_KEYSTROKE);
    }

    /**
     * Explicitly set the Archive file that the action will open. If not file is
     * set a File chooser dialog is displayed to the user.
     *
     * @param archiveFile
     */
    public void setArchiveFileToOpen(File archiveFile) {
        archiveFileToOpen = archiveFile;
    }

    /**
     * Change whether or not to update Kepler's Recent Files menu, and 
     * last directory setting.
     * Default is true.
     *
     * @param updateHistoryAndLastDirectory
     */
    public void updateHistoryAndLastDirectory(boolean updateHistoryAndLastDirectory) {
        this.updateHistoryAndLastDirectory = updateHistoryAndLastDirectory;
    }

    /**
     * Attempt to open the KAR. Any exception that is generated can be
     * retrieved with getOpenException().
     *
     * @param e ActionEvent
     */
    public void actionPerformed(ActionEvent e) {

        // must call this first...
        super.actionPerformed(e);
        actionEvent = e;
        // ...before calling this:
        // NamedObj target = super.getTarget();

        File karFile = null;
        if (archiveFileToOpen != null) {
            karFile = archiveFileToOpen;
        } else {
            // Create a file filter that accepts .kar files.
            ExtensionFilenameFilter filter = new ExtensionFilenameFilter(new String[] { "kar", "xml", "moml" });

            // Avoid white boxes in file chooser, see
            // http://bugzilla.ecoinformatics.org/show_bug.cgi?id=3801
            JFileChooserBugFix jFileChooserBugFix = new JFileChooserBugFix();
            Color background = null;
            PtFileChooser chooser = null;

            try {
                background = jFileChooserBugFix.saveBackground();
                chooser = new PtFileChooser(parent, "Open", JFileChooser.OPEN_DIALOG);
                if (parent instanceof BasicGraphFrame && updateHistoryAndLastDirectory) {
                    chooser.setCurrentDirectory(((BasicGraphFrame) parent).getLastDirectory());
                }
                chooser.addChoosableFileFilter(filter);

                int returnVal = chooser.showDialog(parent, "Open");
                if (returnVal == JFileChooser.APPROVE_OPTION) {
                    // process the given file
                    karFile = chooser.getSelectedFile();
                }
            } finally {
                jFileChooserBugFix.restoreBackground(background);
            }

        }
        if (karFile != null) {
            String karFileName = karFile.getName().toLowerCase();
            if (karFileName.endsWith(".kar")) {
                //System.out.println("DEBUG: Opening KAR");
                try {
                    openKAR(karFile, false, updateHistoryAndLastDirectory);
                } catch (Exception exc) {
                    _openException = exc;
                }
            } else if (karFileName.endsWith(".xml") || karFileName.endsWith(".moml")) {
                //System.out.println("DEBUG: Opening XML");
                _open(karFile);
            }
        }
    }

    /** Return any exception generated while trying to open the KAR. */
    public Exception getOpenException() {
        return _openException;
    }

    /**
     * Process the new kar file into the actor library.
     *
     * @param karFile the file to process
     * @param forceOpen
     * @parem updateHistory update recently opened history menu. Default true.
     */
    public void openKAR(File karFile, boolean forceOpen, boolean updateHistory) throws Exception {
        updateHistoryAndLastDirectory(updateHistory);

        if (isDebugging)
            log.debug("openKAR(" + karFile.toString() + ")");

        // Read in the KAR file
        KARFile karf = new KARFile(karFile);

        if (forceOpen || karf.isOpenable()) {
            boolean opened = karf.openKARContents(parent, forceOpen);
            log.debug("called openKARContents. opened:" + opened);

            if (!opened) {
                JOptionPane.showMessageDialog(null, "The contents of this KAR are not openable.");
            } else {
                // update the history menu
                if (parent instanceof KeplerGraphFrame && updateHistoryAndLastDirectory) {
                    ((KeplerGraphFrame) parent).updateHistory(karFile.getAbsolutePath());
                }
                if (parent instanceof BasicGraphFrame && updateHistoryAndLastDirectory) {
                    ((BasicGraphFrame) parent).setLastDirectory(karFile.getParentFile());
                }
            }

        } else {
            if (!karf.areAllModuleDependenciesSatisfied()) {
                log.debug("KAR file module dependencies are not satisfied, calling ImportModuleDependenciesAction");

                //module-dependencies aren't satisfied, invoke ImportModuleDependenciesAction
                ImportModuleDependenciesAction imda = new ImportModuleDependenciesAction(parent);
                imda.setArchiveFile(karFile);
                imda.actionPerformed(actionEvent);
            } else {
                JOptionPane.showMessageDialog(null, "This KAR is not openable.");
            }

        }

        karf.close();

    }

    /**
     * Open a file dialog to identify a file to be opened, and then call
     * _read() to open the file.
     */
    protected void _open(File file) {

        try {
            // NOTE: It would be nice if it were possible to enter
            // a URL in the file chooser, but Java's file chooser does
            // not permit this, regrettably.  So we have a separate
            // menu item for this.

            // Report on the time it takes to open the model.
            long startTime = System.currentTimeMillis();
            _read(file.toURI().toURL());
            long endTime = System.currentTimeMillis();
            if (endTime > startTime + 10000) {
                // Only print the time if it is more than 10
                // seconds See also PtolemyEffigy.  Perhaps
                // this code should be in PtolemyEffigy, but
                // if it is here, we get the time it takes to
                // read any file, not just a Ptolemy model.
                System.out.println("Opened " + file + " in " + (System.currentTimeMillis() - startTime) + " ms.");
            }
            // update the history menu
            if (parent instanceof KeplerGraphFrame && updateHistoryAndLastDirectory) {
                ((KeplerGraphFrame) parent).updateHistory(file.getAbsolutePath());
            }
            if (parent instanceof BasicGraphFrame && updateHistoryAndLastDirectory) {
                ((BasicGraphFrame) parent).setLastDirectory(file.getParentFile());
            }
        } catch (Error error) {
            // Be sure to catch Error here so that if we throw an
            // Error, then we will report it to with a window.
            try {
                throw new RuntimeException(error);
            } catch (Exception ex2) {
                ex2.printStackTrace();
            }
        } catch (Exception ex) {
            // NOTE: The XML parser can only throw an
            // XmlException.  It signals that it is a user
            // cancellation with the special string pattern
            // "*** Canceled." in the message.

            if ((ex.getMessage() != null) && !ex.getMessage().startsWith("*** Canceled.")) {
                // No need to report a CancelException, since
                // it results from the user clicking a
                // "Cancel" button.
                ex.printStackTrace();
            }
        }
    }

    /**
     * Read the specified URL.  This delegates to the ModelDirectory
     * to ensure that the preferred tableau of the model is opened, and
     * that a model is not opened more than once.
     *
     * @param url The URL to read.
     * @throws Exception If the URL cannot be read, or if there is no
     *                   tableau.
     */
    protected void _read(URL url) throws Exception {
        Tableau _tableau = parent.getTableau();
        if (_tableau == null) {
            throw new Exception("No associated Tableau!" + " Can't open a file.");
        }

        // NOTE: Used to use for the first argument the following, but
        // it seems to not work for relative file references:
        // new URL("file", null, _directory.getAbsolutePath()
        Nameable configuration = _tableau.toplevel();

        if (configuration instanceof Configuration) {
            ((Configuration) configuration).openModel(url, url, url.toExternalForm());
        } else {
            throw new InternalErrorException(
                    "Expected top-level to be a Configuration: " + _tableau.toplevel().getFullName());
        }
    }

    /** True if a message about failing to find last directory was printed. */
    private static boolean _printedFailedLastDirectoryMessage = false;
}