You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/02/17 12:45:34 UTC
[10/52] [abbrv] incubator-taverna-workbench git commit:
taverna-ui-impl/
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/OpenWorkflowAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/OpenWorkflowAction.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/OpenWorkflowAction.java
new file mode 100644
index 0000000..e2ecbd7
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/OpenWorkflowAction.java
@@ -0,0 +1,395 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl.actions;
+
+import static java.awt.Toolkit.getDefaultToolkit;
+import static java.awt.event.KeyEvent.VK_O;
+import static java.util.prefs.Preferences.userNodeForPackage;
+import static javax.swing.JFileChooser.APPROVE_OPTION;
+import static javax.swing.JOptionPane.CANCEL_OPTION;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.QUESTION_MESSAGE;
+import static javax.swing.JOptionPane.WARNING_MESSAGE;
+import static javax.swing.JOptionPane.YES_NO_CANCEL_OPTION;
+import static javax.swing.JOptionPane.YES_OPTION;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static javax.swing.JOptionPane.showOptionDialog;
+import static javax.swing.KeyStroke.getKeyStroke;
+import static javax.swing.SwingUtilities.invokeLater;
+import static net.sf.taverna.t2.workbench.icons.WorkbenchIcons.openIcon;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+import java.util.prefs.Preferences;
+
+import javax.swing.AbstractAction;
+import javax.swing.JFileChooser;
+import javax.swing.filechooser.FileFilter;
+
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.FileType;
+import net.sf.taverna.t2.workbench.file.exceptions.OpenException;
+import net.sf.taverna.t2.workbench.file.impl.FileTypeFileFilter;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * An action for opening a workflow from a file. All file types exposed by the
+ * {@link FileManager} as compatible with the {@link File} type are supported.
+ *
+ * @author Stian Soiland-Reyes
+ */
+public class OpenWorkflowAction extends AbstractAction {
+ private static final long serialVersionUID = 103237694130052153L;
+ private static Logger logger = Logger.getLogger(OpenWorkflowAction.class);
+ private static final String OPEN_WORKFLOW = "Open workflow...";
+
+ public final OpenCallback DUMMY_OPEN_CALLBACK = new OpenCallbackAdapter();
+ protected FileManager fileManager;
+
+ public OpenWorkflowAction(FileManager fileManager) {
+ super(OPEN_WORKFLOW, openIcon);
+ this.fileManager = fileManager;
+ putValue(
+ ACCELERATOR_KEY,
+ getKeyStroke(VK_O, getDefaultToolkit().getMenuShortcutKeyMask()));
+ putValue(MNEMONIC_KEY, VK_O);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ final Component parentComponent;
+ if (e.getSource() instanceof Component)
+ parentComponent = (Component) e.getSource();
+ else
+ parentComponent = null;
+ openWorkflows(parentComponent);
+ }
+
+ /**
+ * Pop up an Open-dialogue to select one or more workflow files to open.
+ * <p>
+ * Note that the file opening occurs in a separate thread. If you want to
+ * check if the file was opened or not, which workflow was opened, etc, use
+ * {@link #openWorkflows(Component, OpenCallback)} instead.
+ *
+ * @see #openWorkflows(Component, OpenCallback)
+ * @param parentComponent
+ * The UI parent component to use for pop up dialogues
+ *
+ * @return <code>false</code> if no files were selected or the dialogue was
+ * cancelled, or <code>true</code> if the process of opening one or
+ * more files has been started.
+ */
+ public void openWorkflows(Component parentComponent) {
+ openWorkflows(parentComponent, DUMMY_OPEN_CALLBACK);
+ }
+
+ /**
+ * Open an array of workflow files.
+ *
+ * @param parentComponent
+ * Parent component for UI dialogues
+ * @param files
+ * Array of files to be opened
+ * @param fileType
+ * {@link FileType} of the files that are to be opened, for
+ * instance
+ * {@link net.sf.taverna.t2.workbench.file.impl.T2FlowFileType},
+ * or <code>null</code> to guess.
+ * @param openCallback
+ * An {@link OpenCallback} to be invoked during and after opening
+ * the file. Use {@link OpenWorkflowAction#DUMMY_OPEN_CALLBACK}
+ * if no callback is needed.
+ */
+ public void openWorkflows(final Component parentComponent, File[] files,
+ FileType fileType, OpenCallback openCallback) {
+ ErrorLoggingOpenCallbackWrapper callback = new ErrorLoggingOpenCallbackWrapper(
+ openCallback);
+ for (File file : files)
+ try {
+ Object canonicalSource = fileManager.getCanonical(file);
+ WorkflowBundle alreadyOpen = fileManager.getDataflowBySource(canonicalSource);
+ if (alreadyOpen != null) {
+ /*
+ * The workflow from the same source is already opened - ask
+ * the user if they want to switch to it or open another
+ * copy...
+ */
+
+ Object[] options = { "Switch to opened", "Open new copy",
+ "Cancel" };
+ switch (showOptionDialog(
+ null,
+ "The workflow from the same location is already opened.\n"
+ + "Do you want to switch to it or open a new copy?",
+ "File Manager Alert", YES_NO_CANCEL_OPTION,
+ QUESTION_MESSAGE, null, options, // the titles of buttons
+ options[0])) { // default button title
+ case YES_OPTION:
+ fileManager.setCurrentDataflow(alreadyOpen);
+ return;
+ case CANCEL_OPTION:
+ // do nothing
+ return;
+ }
+ // else open the workflow as usual
+ }
+
+ callback.aboutToOpenDataflow(file);
+ WorkflowBundle workflowBundle = fileManager.openDataflow(fileType, file);
+ callback.openedDataflow(file, workflowBundle);
+ } catch (RuntimeException ex) {
+ logger.warn("Failed to open workflow from " + file, ex);
+ if (!callback.couldNotOpenDataflow(file, ex))
+ showErrorMessage(parentComponent, file, ex);
+ } catch (Exception ex) {
+ logger.warn("Failed to open workflow from " + file, ex);
+ if (!callback.couldNotOpenDataflow(file, ex))
+ showErrorMessage(parentComponent, file, ex);
+ return;
+ }
+ }
+
+ /**
+ * Pop up an Open-dialogue to select one or more workflow files to open.
+ *
+ * @param parentComponent
+ * The UI parent component to use for pop up dialogues
+ * @param openCallback
+ * An {@link OpenCallback} to be called during the file opening.
+ * The callback will be invoked for each file that has been
+ * opened, as file opening happens in a separate thread that
+ * might execute after the return of this method.
+ * @return <code>false</code> if no files were selected or the dialogue was
+ * cancelled, or <code>true</code> if the process of opening one or
+ * more files has been started.
+ */
+ public boolean openWorkflows(final Component parentComponent,
+ OpenCallback openCallback) {
+ JFileChooser fileChooser = new JFileChooser();
+ Preferences prefs = userNodeForPackage(getClass());
+ String curDir = prefs
+ .get("currentDir", System.getProperty("user.home"));
+ fileChooser.setDialogTitle(OPEN_WORKFLOW);
+
+ fileChooser.resetChoosableFileFilters();
+ fileChooser.setAcceptAllFileFilterUsed(false);
+ List<FileFilter> fileFilters = fileManager.getOpenFileFilters();
+ if (fileFilters.isEmpty()) {
+ logger.warn("No file types found for opening workflow");
+ showMessageDialog(parentComponent,
+ "No file types found for opening workflow.", "Error",
+ ERROR_MESSAGE);
+ return false;
+ }
+ for (FileFilter fileFilter : fileFilters)
+ fileChooser.addChoosableFileFilter(fileFilter);
+ fileChooser.setFileFilter(fileFilters.get(0));
+ fileChooser.setCurrentDirectory(new File(curDir));
+ fileChooser.setMultiSelectionEnabled(true);
+
+ int returnVal = fileChooser.showOpenDialog(parentComponent);
+ if (returnVal == APPROVE_OPTION) {
+ prefs.put("currentDir", fileChooser.getCurrentDirectory()
+ .toString());
+ final File[] selectedFiles = fileChooser.getSelectedFiles();
+ if (selectedFiles.length == 0) {
+ logger.warn("No files selected");
+ return false;
+ }
+ FileFilter fileFilter = fileChooser.getFileFilter();
+ FileType fileType;
+ if (fileFilter instanceof FileTypeFileFilter)
+ fileType = ((FileTypeFileFilter) fileChooser.getFileFilter())
+ .getFileType();
+ else
+ // Unknown filetype, try all of them
+ fileType = null;
+ new FileOpenerThread(parentComponent, selectedFiles, fileType,
+ openCallback).start();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Show an error message if a file could not be opened
+ *
+ * @param parentComponent
+ * @param file
+ * @param throwable
+ */
+ protected void showErrorMessage(final Component parentComponent,
+ final File file, final Throwable throwable) {
+ invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ Throwable cause = throwable;
+ while (cause.getCause() != null)
+ cause = cause.getCause();
+ showMessageDialog(
+ parentComponent,
+ "Failed to open workflow from " + file + ": \n"
+ + cause.getMessage(), "Warning",
+ WARNING_MESSAGE);
+ }
+ });
+
+ }
+
+ /**
+ * Callback interface for openWorkflows().
+ * <p>
+ * The callback will be invoked during the invocation of
+ * {@link OpenWorkflowAction#openWorkflows(Component, OpenCallback)} and
+ * {@link OpenWorkflowAction#openWorkflows(Component, File[], FileType, OpenCallback)}
+ * as file opening happens in a separate thread.
+ *
+ * @author Stian Soiland-Reyes
+ */
+ public interface OpenCallback {
+ /**
+ * Called before a workflowBundle is to be opened from the given file
+ *
+ * @param file
+ * File which workflowBundle is to be opened
+ */
+ void aboutToOpenDataflow(File file);
+
+ /**
+ * Called if an exception happened while attempting to open the
+ * workflowBundle.
+ *
+ * @param file
+ * File which was attempted to be opened
+ * @param ex
+ * An {@link OpenException} or a {@link RuntimeException}.
+ * @return <code>true</code> if the error has been handled, or
+ * <code>false</code>3 if a UI warning dialogue is to be opened.
+ */
+ boolean couldNotOpenDataflow(File file, Exception ex);
+
+ /**
+ * Called when a workflowBundle has been successfully opened. The workflowBundle
+ * will be registered in {@link FileManager#getOpenDataflows()}.
+ *
+ * @param file
+ * File from which workflowBundle was opened
+ * @param workflowBundle
+ * WorkflowBundle that was opened
+ */
+ void openedDataflow(File file, WorkflowBundle workflowBundle);
+ }
+
+ /**
+ * Adapter for {@link OpenCallback}
+ *
+ * @author Stian Soiland-Reyes
+ */
+ public static class OpenCallbackAdapter implements OpenCallback {
+ @Override
+ public void aboutToOpenDataflow(File file) {
+ }
+
+ @Override
+ public boolean couldNotOpenDataflow(File file, Exception ex) {
+ return false;
+ }
+
+ @Override
+ public void openedDataflow(File file, WorkflowBundle workflowBundle) {
+ }
+ }
+
+ private final class FileOpenerThread extends Thread {
+ private final File[] files;
+ private final FileType fileType;
+ private final OpenCallback openCallback;
+ private final Component parentComponent;
+
+ private FileOpenerThread(Component parentComponent,
+ File[] selectedFiles, FileType fileType,
+ OpenCallback openCallback) {
+ super("Opening workflows(s) " + Arrays.asList(selectedFiles));
+ this.parentComponent = parentComponent;
+ this.files = selectedFiles;
+ this.fileType = fileType;
+ this.openCallback = openCallback;
+ }
+
+ @Override
+ public void run() {
+ openWorkflows(parentComponent, files, fileType, openCallback);
+ }
+ }
+
+ /**
+ * A wrapper for {@link OpenCallback} implementations that logs exceptions
+ * thrown without disrupting the caller of the callback.
+ *
+ * @author Stian Soiland-Reyes
+ */
+ protected class ErrorLoggingOpenCallbackWrapper implements OpenCallback {
+ private final OpenCallback wrapped;
+
+ public ErrorLoggingOpenCallbackWrapper(OpenCallback wrapped) {
+ this.wrapped = wrapped;
+ }
+
+ @Override
+ public void aboutToOpenDataflow(File file) {
+ try {
+ wrapped.aboutToOpenDataflow(file);
+ } catch (RuntimeException wrapperEx) {
+ logger.warn("Failed OpenCallback " + wrapped
+ + ".aboutToOpenDataflow(File)", wrapperEx);
+ }
+ }
+
+ @Override
+ public boolean couldNotOpenDataflow(File file, Exception ex) {
+ try {
+ return wrapped.couldNotOpenDataflow(file, ex);
+ } catch (RuntimeException wrapperEx) {
+ logger.warn("Failed OpenCallback " + wrapped
+ + ".couldNotOpenDataflow(File, Exception)", wrapperEx);
+ return false;
+ }
+ }
+
+ @Override
+ public void openedDataflow(File file, WorkflowBundle workflowBundle) {
+ try {
+ wrapped.openedDataflow(file, workflowBundle);
+ } catch (RuntimeException wrapperEx) {
+ logger.warn("Failed OpenCallback " + wrapped
+ + ".openedDataflow(File, Dataflow)", wrapperEx);
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/OpenWorkflowFromURLAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/OpenWorkflowFromURLAction.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/OpenWorkflowFromURLAction.java
new file mode 100644
index 0000000..e98a8f2
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/OpenWorkflowFromURLAction.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (C) 2008 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl.actions;
+
+import static java.awt.Toolkit.getDefaultToolkit;
+import static java.awt.event.KeyEvent.VK_L;
+import static javax.swing.JOptionPane.CANCEL_OPTION;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.QUESTION_MESSAGE;
+import static javax.swing.JOptionPane.YES_NO_CANCEL_OPTION;
+import static javax.swing.JOptionPane.YES_OPTION;
+import static javax.swing.JOptionPane.showInputDialog;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static javax.swing.JOptionPane.showOptionDialog;
+import static javax.swing.KeyStroke.getKeyStroke;
+import static net.sf.taverna.t2.workbench.icons.WorkbenchIcons.openurlIcon;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.net.URL;
+import java.util.prefs.Preferences;
+
+import javax.swing.AbstractAction;
+
+import net.sf.taverna.t2.workbench.file.FileManager;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * An action for opening a workflow from a url.
+ *
+ * @author David Withers
+ */
+public class OpenWorkflowFromURLAction extends AbstractAction {
+ private static final long serialVersionUID = 1474356457949961974L;
+ private static Logger logger = Logger
+ .getLogger(OpenWorkflowFromURLAction.class);
+ private static Preferences prefs = Preferences
+ .userNodeForPackage(OpenWorkflowFromURLAction.class);
+ private static final String PREF_CURRENT_URL = "currentUrl";
+ private static final String ACTION_NAME = "Open workflow location...";
+ private static final String ACTION_DESCRIPTION = "Open a workflow from the web into a new workflow";
+
+ private Component component;
+ private FileManager fileManager;
+
+ public OpenWorkflowFromURLAction(final Component component,
+ FileManager fileManager) {
+ this.component = component;
+ this.fileManager = fileManager;
+ putValue(SMALL_ICON, openurlIcon);
+ putValue(NAME, ACTION_NAME);
+ putValue(SHORT_DESCRIPTION, ACTION_DESCRIPTION);
+ putValue(MNEMONIC_KEY, VK_L);
+ putValue(
+ ACCELERATOR_KEY,
+ getKeyStroke(VK_L, getDefaultToolkit().getMenuShortcutKeyMask()));
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String currentUrl = prefs.get(PREF_CURRENT_URL, "http://");
+
+ final String url = (String) showInputDialog(component,
+ "Enter the URL of a workflow definition to load",
+ "Workflow URL", QUESTION_MESSAGE, null, null, currentUrl);
+ if (url != null)
+ new Thread("OpenWorkflowFromURLAction") {
+ @Override
+ public void run() {
+ openFromURL(url);
+ }
+ }.start();
+ }
+
+ private void openFromURL(String urlString) {
+ try {
+ URL url = new URL(urlString);
+
+ Object canonicalSource = fileManager.getCanonical(url);
+ WorkflowBundle alreadyOpen = fileManager
+ .getDataflowBySource(canonicalSource);
+ if (alreadyOpen != null) {
+ /*
+ * The workflow from the same source is already opened - ask the
+ * user if they want to switch to it or open another copy.
+ */
+
+ Object[] options = { "Switch to opened", "Open new copy",
+ "Cancel" };
+ int iSelected = showOptionDialog(
+ null,
+ "The workflow from the same location is already opened.\n"
+ + "Do you want to switch to it or open a new copy?",
+ "File Manager Alert", YES_NO_CANCEL_OPTION,
+ QUESTION_MESSAGE, null, options, // the titles of buttons
+ options[0]); // default button title
+
+ if (iSelected == YES_OPTION) {
+ fileManager.setCurrentDataflow(alreadyOpen);
+ return;
+ } else if (iSelected == CANCEL_OPTION) {
+ // do nothing
+ return;
+ }
+ // else open the workflow as usual
+ }
+
+ fileManager.openDataflow(null, url);
+ prefs.put(PREF_CURRENT_URL, urlString);
+ } catch (Exception ex) {
+ logger.warn("Failed to open the workflow from url " + urlString
+ + " \n", ex);
+ showMessageDialog(component,
+ "Failed to open the workflow from url " + urlString + " \n"
+ + ex.getMessage(), "Error!", ERROR_MESSAGE);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/PasswordInput.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/PasswordInput.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/PasswordInput.java
new file mode 100644
index 0000000..401a232
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/PasswordInput.java
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl.actions;
+
+import static java.awt.EventQueue.invokeLater;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.showMessageDialog;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+
+import net.sf.taverna.t2.workbench.helper.HelpEnabledDialog;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.log4j.Logger;
+
+/**
+ * Simple dialogue to handle username/password input for workflow URL requiring
+ * http authentication.
+ *
+ * @author Stuart Owen
+ * @author Stian Soiland-Reyes
+ * @author Alan R Williams
+ */
+@SuppressWarnings("serial")
+public class PasswordInput extends HelpEnabledDialog {
+ private static Logger logger = Logger.getLogger(PasswordInput.class);
+
+ private String password = null;
+ private String username = null;
+ private URL url = null;
+ private int tryCount = 0;
+ private final static int MAX_TRIES = 3;
+
+ private JButton cancelButton;
+ private JLabel jLabel1;
+ private JLabel jLabel2;
+ private JLabel messageLabel;
+ private JButton okButton;
+ private JPasswordField passwordTextField;
+ private JLabel urlLabel;
+ private JTextField usernameTextField;
+
+ public void setUrl(URL url) {
+ this.url = url;
+ urlLabel.setText(url.toExternalForm());
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public PasswordInput(JFrame parent) {
+ super(parent, "Authorization", true, null);
+ initComponents();
+ }
+
+ /** Creates new form PasswordInput */
+ public PasswordInput() {
+ super((JFrame) null, "Authorization", true, null);
+ initComponents();
+ }
+
+ /**
+ * This method is called from within the constructor to initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is always
+ * regenerated by the Form Editor.
+ */
+ private void initComponents() {
+ usernameTextField = new javax.swing.JTextField();
+ cancelButton = new javax.swing.JButton();
+ okButton = new javax.swing.JButton();
+ passwordTextField = new javax.swing.JPasswordField();
+ jLabel1 = new javax.swing.JLabel();
+ jLabel2 = new javax.swing.JLabel();
+ messageLabel = new javax.swing.JLabel();
+ urlLabel = new javax.swing.JLabel();
+
+ getContentPane().setLayout(null);
+
+ setModal(true);
+ // setResizable(false);
+ getContentPane().add(usernameTextField);
+ usernameTextField.setBounds(20, 80, 280, 22);
+
+ cancelButton.setText("Cancel");
+ cancelButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent evt) {
+ cancelButtonActionPerformed(evt);
+ }
+ });
+
+ getContentPane().add(cancelButton);
+ cancelButton.setBounds(230, 160, 75, 29);
+
+ okButton.setText("OK");
+ okButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent evt) {
+ okButtonActionPerformed(evt);
+ }
+ });
+
+ getContentPane().add(okButton);
+ okButton.setBounds(150, 160, 75, 29);
+
+ getContentPane().add(passwordTextField);
+ passwordTextField.setBounds(20, 130, 280, 22);
+
+ jLabel1.setText("Username");
+ getContentPane().add(jLabel1);
+ jLabel1.setBounds(20, 60, 70, 16);
+
+ jLabel2.setText("Password");
+ getContentPane().add(jLabel2);
+ jLabel2.setBounds(20, 110, 70, 16);
+
+ messageLabel.setText("A username and password is required for:");
+ getContentPane().add(messageLabel);
+ messageLabel.setBounds(20, 10, 270, 20);
+
+ urlLabel.setText("service");
+ getContentPane().add(urlLabel);
+ urlLabel.setBounds(20, 30, 270, 16);
+
+ pack();
+ }
+
+ private void okButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
+ String password = String.valueOf(passwordTextField.getPassword());
+ String username = usernameTextField.getText();
+ HttpURLConnection connection;
+ try {
+ connection = (HttpURLConnection) url.openConnection();
+ String userPassword = username + ":" + password;
+ /*
+ * Note: non-latin1 support for basic auth is fragile/unsupported
+ * and must be MIME-encoded (RFC2047) according to
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=41489
+ */
+ byte[] encoded = Base64.encodeBase64(userPassword
+ .getBytes("latin1"));
+ connection.setRequestProperty("Authorization", "Basic "
+ + new String(encoded, "ascii"));
+ connection.setRequestProperty("Accept", "text/xml");
+ int code = connection.getResponseCode();
+
+ /*
+ * NB: myExperiment gives a 500 response for an invalid
+ * username/password
+ */
+ if (code == 401 || code == 500) {
+ tryCount++;
+ showMessageDialog(this, "The username and password failed",
+ "Invalid username or password", ERROR_MESSAGE);
+ if (tryCount >= MAX_TRIES) { // close after 3 attempts.
+ this.password = null;
+ this.username = null;
+ this.setVisible(false);
+ }
+ } else {
+ this.username = username;
+ this.password = password;
+ this.setVisible(false);
+ }
+ } catch (IOException ex) {
+ logger.error("Could not get password", ex);
+ }
+ }
+
+ private void cancelButtonActionPerformed(ActionEvent evt) {
+ this.password = null;
+ this.username = null;
+ this.setVisible(false);
+ }
+
+ /**
+ * @param args
+ * the command line arguments
+ */
+ public static void main(String args[]) {
+ invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ new PasswordInput().setVisible(true);
+ }
+ });
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/SaveAllWorkflowsAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/SaveAllWorkflowsAction.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/SaveAllWorkflowsAction.java
new file mode 100644
index 0000000..6b011d3
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/SaveAllWorkflowsAction.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl.actions;
+
+import static java.awt.Toolkit.getDefaultToolkit;
+import static java.awt.event.InputEvent.SHIFT_DOWN_MASK;
+import static java.awt.event.KeyEvent.VK_A;
+import static java.awt.event.KeyEvent.VK_S;
+import static javax.swing.KeyStroke.getKeyStroke;
+import static net.sf.taverna.t2.workbench.icons.WorkbenchIcons.saveAllIcon;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.events.FileManagerEvent;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+@SuppressWarnings("serial")
+public class SaveAllWorkflowsAction extends AbstractAction {
+ private final class FileManagerObserver implements
+ Observer<FileManagerEvent> {
+ @Override
+ public void notify(Observable<FileManagerEvent> sender,
+ FileManagerEvent message) throws Exception {
+ updateEnabled();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static Logger logger = Logger
+ .getLogger(SaveAllWorkflowsAction.class);
+ private static final String SAVE_ALL_WORKFLOWS = "Save all workflows";
+
+ private final SaveWorkflowAction saveWorkflowAction;
+ private FileManager fileManager;
+ private FileManagerObserver fileManagerObserver = new FileManagerObserver();
+
+ public SaveAllWorkflowsAction(EditManager editManager,
+ FileManager fileManager) {
+ super(SAVE_ALL_WORKFLOWS, saveAllIcon);
+ this.fileManager = fileManager;
+ saveWorkflowAction = new SaveWorkflowAction(editManager, fileManager);
+ putValue(
+ ACCELERATOR_KEY,
+ getKeyStroke(VK_S, getDefaultToolkit().getMenuShortcutKeyMask()
+ | SHIFT_DOWN_MASK));
+ putValue(MNEMONIC_KEY, VK_A);
+
+ fileManager.addObserver(fileManagerObserver);
+ updateEnabled();
+ }
+
+ public void updateEnabled() {
+ setEnabled(!(fileManager.getOpenDataflows().isEmpty()));
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent ev) {
+ Component parentComponent = null;
+ if (ev.getSource() instanceof Component)
+ parentComponent = (Component) ev.getSource();
+ saveAllDataflows(parentComponent);
+ }
+
+ public void saveAllDataflows(Component parentComponent) {
+ // Save in reverse so we save nested workflows first
+ List<WorkflowBundle> workflowBundles = fileManager.getOpenDataflows();
+ Collections.reverse(workflowBundles);
+
+ for (WorkflowBundle workflowBundle : workflowBundles)
+ if (!saveWorkflowAction.saveDataflow(parentComponent,
+ workflowBundle))
+ break;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/SaveWorkflowAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/SaveWorkflowAction.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/SaveWorkflowAction.java
new file mode 100644
index 0000000..9776550
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/SaveWorkflowAction.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl.actions;
+
+import static java.awt.Toolkit.getDefaultToolkit;
+import static java.awt.event.KeyEvent.VK_S;
+import static javax.swing.JOptionPane.NO_OPTION;
+import static javax.swing.JOptionPane.WARNING_MESSAGE;
+import static javax.swing.JOptionPane.YES_NO_CANCEL_OPTION;
+import static javax.swing.JOptionPane.YES_OPTION;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static javax.swing.KeyStroke.getKeyStroke;
+import static net.sf.taverna.t2.workbench.icons.WorkbenchIcons.saveIcon;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.edits.EditManager.AbstractDataflowEditEvent;
+import net.sf.taverna.t2.workbench.edits.EditManager.EditManagerEvent;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.events.FileManagerEvent;
+import net.sf.taverna.t2.workbench.file.events.SavedDataflowEvent;
+import net.sf.taverna.t2.workbench.file.events.SetCurrentDataflowEvent;
+import net.sf.taverna.t2.workbench.file.exceptions.OverwriteException;
+import net.sf.taverna.t2.workbench.file.exceptions.SaveException;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+@SuppressWarnings("serial")
+public class SaveWorkflowAction extends AbstractAction {
+ private static Logger logger = Logger.getLogger(SaveWorkflowAction.class);
+ private static final String SAVE_WORKFLOW = "Save workflow";
+
+ private final SaveWorkflowAsAction saveWorkflowAsAction;
+ private EditManagerObserver editManagerObserver = new EditManagerObserver();
+ private FileManager fileManager;
+ private FileManagerObserver fileManagerObserver = new FileManagerObserver();
+
+ public SaveWorkflowAction(EditManager editManager, FileManager fileManager) {
+ super(SAVE_WORKFLOW, saveIcon);
+ this.fileManager = fileManager;
+ saveWorkflowAsAction = new SaveWorkflowAsAction(fileManager);
+ putValue(
+ ACCELERATOR_KEY,
+ getKeyStroke(VK_S, getDefaultToolkit().getMenuShortcutKeyMask()));
+ putValue(MNEMONIC_KEY, VK_S);
+ editManager.addObserver(editManagerObserver);
+ fileManager.addObserver(fileManagerObserver);
+ updateEnabledStatus(fileManager.getCurrentDataflow());
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent ev) {
+ Component parentComponent = null;
+ if (ev.getSource() instanceof Component)
+ parentComponent = (Component) ev.getSource();
+ saveCurrentDataflow(parentComponent);
+ }
+
+ public boolean saveCurrentDataflow(Component parentComponent) {
+ WorkflowBundle workflowBundle = fileManager.getCurrentDataflow();
+ return saveDataflow(parentComponent, workflowBundle);
+ }
+
+ public boolean saveDataflow(Component parentComponent,
+ WorkflowBundle workflowBundle) {
+ if (!fileManager.canSaveWithoutDestination(workflowBundle))
+ return saveWorkflowAsAction.saveDataflow(parentComponent,
+ workflowBundle);
+
+ try {
+ try {
+ fileManager.saveDataflow(workflowBundle, true);
+ Object workflowBundleSource = fileManager
+ .getDataflowSource(workflowBundle);
+ logger.info("Saved workflow " + workflowBundle + " to "
+ + workflowBundleSource);
+ return true;
+ } catch (OverwriteException ex) {
+ Object workflowBundleSource = fileManager
+ .getDataflowSource(workflowBundle);
+ logger.info("Workflow was changed on source: "
+ + workflowBundleSource);
+ fileManager.setCurrentDataflow(workflowBundle);
+ String msg = "Workflow destination " + workflowBundleSource
+ + " has been changed from elsewhere, "
+ + "are you sure you want to overwrite?";
+ int ret = showConfirmDialog(parentComponent, msg,
+ "Workflow changed", YES_NO_CANCEL_OPTION);
+ if (ret == YES_OPTION) {
+ fileManager.saveDataflow(workflowBundle, false);
+ logger.info("Saved workflow " + workflowBundle
+ + " by overwriting " + workflowBundleSource);
+ return true;
+ } else if (ret == NO_OPTION) {
+ // Pop up Save As instead to choose another name
+ return saveWorkflowAsAction.saveDataflow(parentComponent,
+ workflowBundle);
+ } else {
+ logger.info("Aborted overwrite of " + workflowBundleSource);
+ return false;
+ }
+ }
+ } catch (SaveException ex) {
+ logger.warn("Could not save workflow " + workflowBundle, ex);
+ showMessageDialog(parentComponent, "Could not save workflow: \n\n"
+ + ex.getMessage(), "Warning", WARNING_MESSAGE);
+ return false;
+ } catch (RuntimeException ex) {
+ logger.warn("Could not save workflow " + workflowBundle, ex);
+ showMessageDialog(parentComponent, "Could not save workflow: \n\n"
+ + ex.getMessage(), "Warning", WARNING_MESSAGE);
+ return false;
+ }
+ }
+
+ protected void updateEnabledStatus(WorkflowBundle workflowBundle) {
+ setEnabled(workflowBundle != null
+ && fileManager.isDataflowChanged(workflowBundle));
+ }
+
+ private final class EditManagerObserver implements
+ Observer<EditManagerEvent> {
+ @Override
+ public void notify(Observable<EditManagerEvent> sender,
+ EditManagerEvent message) throws Exception {
+ if (message instanceof AbstractDataflowEditEvent) {
+ WorkflowBundle workflowBundle = ((AbstractDataflowEditEvent) message)
+ .getDataFlow();
+ if (workflowBundle == fileManager.getCurrentDataflow())
+ updateEnabledStatus(workflowBundle);
+ }
+ }
+ }
+
+ private final class FileManagerObserver implements
+ Observer<FileManagerEvent> {
+ @Override
+ public void notify(Observable<FileManagerEvent> sender,
+ FileManagerEvent message) throws Exception {
+ if (message instanceof SavedDataflowEvent)
+ updateEnabledStatus(((SavedDataflowEvent) message)
+ .getDataflow());
+ else if (message instanceof SetCurrentDataflowEvent)
+ updateEnabledStatus(((SetCurrentDataflowEvent) message)
+ .getDataflow());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/SaveWorkflowAsAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/SaveWorkflowAsAction.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/SaveWorkflowAsAction.java
new file mode 100644
index 0000000..1872d5d
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/actions/SaveWorkflowAsAction.java
@@ -0,0 +1,219 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl.actions;
+
+import static java.awt.event.KeyEvent.VK_F6;
+import static java.awt.event.KeyEvent.VK_S;
+import static javax.swing.JFileChooser.APPROVE_OPTION;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.NO_OPTION;
+import static javax.swing.JOptionPane.WARNING_MESSAGE;
+import static javax.swing.JOptionPane.YES_NO_CANCEL_OPTION;
+import static javax.swing.JOptionPane.YES_OPTION;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static javax.swing.KeyStroke.getKeyStroke;
+import static net.sf.taverna.t2.workbench.icons.WorkbenchIcons.saveAsIcon;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.net.URL;
+import java.util.List;
+import java.util.prefs.Preferences;
+
+import javax.swing.AbstractAction;
+import javax.swing.JFileChooser;
+import javax.swing.filechooser.FileFilter;
+
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.FileType;
+import net.sf.taverna.t2.workbench.file.events.FileManagerEvent;
+import net.sf.taverna.t2.workbench.file.events.SetCurrentDataflowEvent;
+import net.sf.taverna.t2.workbench.file.exceptions.OverwriteException;
+import net.sf.taverna.t2.workbench.file.exceptions.SaveException;
+import net.sf.taverna.t2.workbench.file.impl.FileTypeFileFilter;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.core.Workflow;
+
+@SuppressWarnings("serial")
+public class SaveWorkflowAsAction extends AbstractAction {
+ private static final String SAVE_WORKFLOW_AS = "Save workflow as...";
+ private static final String PREF_CURRENT_DIR = "currentDir";
+ private static Logger logger = Logger.getLogger(SaveWorkflowAsAction.class);
+ private FileManager fileManager;
+
+ public SaveWorkflowAsAction(FileManager fileManager) {
+ super(SAVE_WORKFLOW_AS, saveAsIcon);
+ this.fileManager = fileManager;
+ fileManager.addObserver(new FileManagerObserver());
+ putValue(ACCELERATOR_KEY, getKeyStroke(VK_F6, 0));
+ putValue(MNEMONIC_KEY, VK_S);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Component parentComponent = null;
+ if (e.getSource() instanceof Component)
+ parentComponent = (Component) e.getSource();
+ WorkflowBundle workflowBundle = fileManager.getCurrentDataflow();
+ if (workflowBundle == null) {
+ showMessageDialog(parentComponent, "No workflow open yet",
+ "No workflow to save", ERROR_MESSAGE);
+ return;
+ }
+ saveCurrentDataflow(parentComponent);
+ }
+
+ public boolean saveCurrentDataflow(Component parentComponent) {
+ WorkflowBundle workflowBundle = fileManager.getCurrentDataflow();
+ return saveDataflow(parentComponent, workflowBundle);
+ }
+
+ private String determineFileName(final WorkflowBundle workflowBundle) {
+ String result;
+ Object source = fileManager.getDataflowSource(workflowBundle);
+ String fileName = null;
+ if (source instanceof File)
+ fileName = ((File) source).getName();
+ else if (source instanceof URL)
+ fileName = ((URL) source).getPath();
+
+ if (fileName != null) {
+ int lastIndex = fileName.lastIndexOf(".");
+ if (lastIndex > 0)
+ fileName = fileName.substring(0, fileName.lastIndexOf("."));
+ result = fileName;
+ } else {
+ Workflow mainWorkflow = workflowBundle.getMainWorkflow();
+ if (mainWorkflow != null)
+ result = mainWorkflow.getName();
+ else
+ result = workflowBundle.getName();
+ }
+ return result;
+ }
+
+ public boolean saveDataflow(Component parentComponent, WorkflowBundle workflowBundle) {
+ fileManager.setCurrentDataflow(workflowBundle);
+ JFileChooser fileChooser = new JFileChooser();
+ Preferences prefs = Preferences.userNodeForPackage(getClass());
+ String curDir = prefs
+ .get(PREF_CURRENT_DIR, System.getProperty("user.home"));
+ fileChooser.setDialogTitle(SAVE_WORKFLOW_AS);
+
+ fileChooser.resetChoosableFileFilters();
+ fileChooser.setAcceptAllFileFilterUsed(false);
+
+ List<FileFilter> fileFilters = fileManager
+ .getSaveFileFilters(File.class);
+ if (fileFilters.isEmpty()) {
+ logger.warn("No file types found for saving workflow "
+ + workflowBundle);
+ showMessageDialog(parentComponent,
+ "No file types found for saving workflow.", "Error",
+ ERROR_MESSAGE);
+ return false;
+ }
+ for (FileFilter fileFilter : fileFilters)
+ fileChooser.addChoosableFileFilter(fileFilter);
+ fileChooser.setFileFilter(fileFilters.get(0));
+ fileChooser.setCurrentDirectory(new File(curDir));
+
+ File possibleName = new File(determineFileName(workflowBundle));
+ boolean tryAgain = true;
+ while (tryAgain) {
+ tryAgain = false;
+ fileChooser.setSelectedFile(possibleName);
+ int returnVal = fileChooser.showSaveDialog(parentComponent);
+ if (returnVal == APPROVE_OPTION) {
+ prefs.put(PREF_CURRENT_DIR, fileChooser.getCurrentDirectory()
+ .toString());
+ File file = fileChooser.getSelectedFile();
+ FileTypeFileFilter fileFilter = (FileTypeFileFilter) fileChooser
+ .getFileFilter();
+ FileType fileType = fileFilter.getFileType();
+ String extension = "." + fileType.getExtension();
+ if (!file.getName().toLowerCase().endsWith(extension)) {
+ String newName = file.getName() + extension;
+ file = new File(file.getParentFile(), newName);
+ }
+
+ // TODO: Open in separate thread to avoid hanging UI
+ try {
+ try {
+ fileManager.saveDataflow(workflowBundle, fileType,
+ file, true);
+ logger.info("Saved workflow " + workflowBundle + " to "
+ + file);
+ return true;
+ } catch (OverwriteException ex) {
+ logger.info("File already exists: " + file);
+ String msg = "Are you sure you want to overwrite existing file "
+ + file + "?";
+ int ret = showConfirmDialog(parentComponent, msg,
+ "File already exists", YES_NO_CANCEL_OPTION);
+ if (ret == YES_OPTION) {
+ fileManager.saveDataflow(workflowBundle, fileType,
+ file, false);
+ logger.info("Saved workflow " + workflowBundle
+ + " by overwriting " + file);
+ return true;
+ } else if (ret == NO_OPTION) {
+ tryAgain = true;
+ continue;
+ } else {
+ logger.info("Aborted overwrite of " + file);
+ return false;
+ }
+ }
+ } catch (SaveException ex) {
+ logger.warn("Could not save workflow to " + file, ex);
+ showMessageDialog(parentComponent,
+ "Could not save workflow to " + file + ": \n\n"
+ + ex.getMessage(), "Warning",
+ WARNING_MESSAGE);
+ return false;
+ }
+ }
+ }
+ return false;
+ }
+
+ protected void updateEnabledStatus(WorkflowBundle workflowBundle) {
+ setEnabled(workflowBundle != null);
+ }
+
+ private final class FileManagerObserver implements Observer<FileManagerEvent> {
+ @Override
+ public void notify(Observable<FileManagerEvent> sender,
+ FileManagerEvent message) throws Exception {
+ if (message instanceof SetCurrentDataflowEvent)
+ updateEnabledStatus(((SetCurrentDataflowEvent) message)
+ .getDataflow());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/hooks/CloseWorkflowsOnShutdown.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/hooks/CloseWorkflowsOnShutdown.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/hooks/CloseWorkflowsOnShutdown.java
new file mode 100644
index 0000000..6c0be19
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/hooks/CloseWorkflowsOnShutdown.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (C) 2010 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl.hooks;
+
+import net.sf.taverna.t2.workbench.ShutdownSPI;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.impl.actions.CloseAllWorkflowsAction;
+
+/**
+ * Close open workflows (and ask the user if she wants to save changes) on
+ * shutdown.
+ *
+ * @author Stian Soiland-Reyes
+ */
+public class CloseWorkflowsOnShutdown implements ShutdownSPI {
+ private CloseAllWorkflowsAction closeAllWorkflowsAction;
+
+ public CloseWorkflowsOnShutdown(EditManager editManager,
+ FileManager fileManager) {
+ closeAllWorkflowsAction = new CloseAllWorkflowsAction(editManager,
+ fileManager);
+ }
+
+ @Override
+ public int positionHint() {
+ /*
+ * Quite early, we don't want to do various clean-up in case the user
+ * clicks Cancel
+ */
+ return 50;
+ }
+
+ @Override
+ public boolean shutdown() {
+ return closeAllWorkflowsAction.closeAllWorkflows(null);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileCloseAllMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileCloseAllMenuAction.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileCloseAllMenuAction.java
new file mode 100644
index 0000000..e8e5252
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileCloseAllMenuAction.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl.menu;
+
+import static net.sf.taverna.t2.workbench.file.impl.menu.FileOpenMenuSection.FILE_URI;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.impl.actions.CloseAllWorkflowsAction;
+
+public class FileCloseAllMenuAction extends AbstractMenuAction {
+ private static final URI FILE_CLOSE_URI = URI
+ .create("http://taverna.sf.net/2008/t2workbench/menu#fileCloseAll");
+ private final EditManager editManager;
+ private final FileManager fileManager;
+
+ public FileCloseAllMenuAction(EditManager editManager,
+ FileManager fileManager) {
+ super(FILE_URI, 39, FILE_CLOSE_URI);
+ this.editManager = editManager;
+ this.fileManager = fileManager;
+ }
+
+ @Override
+ protected Action createAction() {
+ return new CloseAllWorkflowsAction(editManager, fileManager);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileCloseMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileCloseMenuAction.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileCloseMenuAction.java
new file mode 100644
index 0000000..a97219f
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileCloseMenuAction.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl.menu;
+
+import static net.sf.taverna.t2.workbench.file.impl.menu.FileOpenMenuSection.FILE_URI;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.impl.actions.CloseWorkflowAction;
+
+public class FileCloseMenuAction extends AbstractMenuAction {
+ private static final URI FILE_CLOSE_URI = URI
+ .create("http://taverna.sf.net/2008/t2workbench/menu#fileClose");
+ private final EditManager editManager;
+ private final FileManager fileManager;
+
+ public FileCloseMenuAction(EditManager editManager, FileManager fileManager) {
+ super(FILE_URI, 30, FILE_CLOSE_URI);
+ this.editManager = editManager;
+ this.fileManager = fileManager;
+ }
+
+ @Override
+ protected Action createAction() {
+ return new CloseWorkflowAction(editManager, fileManager);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileNewMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileNewMenuAction.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileNewMenuAction.java
new file mode 100644
index 0000000..3a48e0d
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileNewMenuAction.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl.menu;
+
+import static net.sf.taverna.t2.workbench.file.impl.menu.FileOpenMenuSection.FILE_OPEN_SECTION_URI;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.impl.actions.NewWorkflowAction;
+
+public class FileNewMenuAction extends AbstractMenuAction {
+ private static final URI FILE_NEW_URI = URI
+ .create("http://taverna.sf.net/2008/t2workbench/menu#fileNew");
+ private final FileManager fileManager;
+
+ public FileNewMenuAction(FileManager fileManager) {
+ super(FILE_OPEN_SECTION_URI, 10, FILE_NEW_URI);
+ this.fileManager = fileManager;
+ }
+
+ @Override
+ protected Action createAction() {
+ return new NewWorkflowAction(fileManager);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenFromURLMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenFromURLMenuAction.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenFromURLMenuAction.java
new file mode 100644
index 0000000..9af1d6b
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenFromURLMenuAction.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl.menu;
+
+import static net.sf.taverna.t2.workbench.file.impl.menu.FileOpenMenuSection.FILE_OPEN_SECTION_URI;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.impl.actions.OpenWorkflowFromURLAction;
+
+public class FileOpenFromURLMenuAction extends AbstractMenuAction {
+
+ private static final URI FILE_OPEN_FROM_URL_URI = URI
+ .create("http://taverna.sf.net/2008/t2workbench/menu#fileOpenURL");
+ private final FileManager fileManager;
+
+ public FileOpenFromURLMenuAction(FileManager fileManager) {
+ super(FILE_OPEN_SECTION_URI, 30, FILE_OPEN_FROM_URL_URI);
+ this.fileManager = fileManager;
+ }
+
+ @Override
+ protected Action createAction() {
+ return new OpenWorkflowFromURLAction(null, fileManager);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenMenuAction.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenMenuAction.java
new file mode 100644
index 0000000..4ee4e39
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenMenuAction.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl.menu;
+
+import static net.sf.taverna.t2.workbench.file.impl.menu.FileOpenMenuSection.FILE_OPEN_SECTION_URI;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.impl.actions.OpenWorkflowAction;
+
+public class FileOpenMenuAction extends AbstractMenuAction {
+ private static final URI FILE_OPEN_URI = URI
+ .create("http://taverna.sf.net/2008/t2workbench/menu#fileOpen");
+ private final FileManager fileManager;
+
+ public FileOpenMenuAction(FileManager fileManager) {
+ super(FILE_OPEN_SECTION_URI, 20, FILE_OPEN_URI);
+ this.fileManager = fileManager;
+ }
+
+ @Override
+ protected Action createAction() {
+ return new OpenWorkflowAction(fileManager);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenMenuSection.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenMenuSection.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenMenuSection.java
new file mode 100644
index 0000000..46ef476
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenMenuSection.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl.menu;
+
+import java.net.URI;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuSection;
+
+public class FileOpenMenuSection extends AbstractMenuSection {
+ public static final URI FILE_URI = URI
+ .create("http://taverna.sf.net/2008/t2workbench/menu#file");
+ public static final URI FILE_OPEN_SECTION_URI = URI
+ .create("http://taverna.sf.net/2008/t2workbench/menu#fileOpenSection");
+
+ public FileOpenMenuSection() {
+ super(FILE_URI, 20, FILE_OPEN_SECTION_URI);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenRecentMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenRecentMenuAction.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenRecentMenuAction.java
new file mode 100644
index 0000000..76ef759
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileOpenRecentMenuAction.java
@@ -0,0 +1,418 @@
+package net.sf.taverna.t2.workbench.file.impl.menu;
+
+import static java.awt.event.KeyEvent.VK_0;
+import static java.awt.event.KeyEvent.VK_R;
+import static javax.swing.Action.MNEMONIC_KEY;
+import static javax.swing.Action.NAME;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static javax.swing.SwingUtilities.invokeLater;
+import static net.sf.taverna.t2.workbench.file.impl.menu.FileOpenMenuSection.FILE_OPEN_SECTION_URI;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.ui.menu.AbstractMenuCustom;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.FileType;
+import net.sf.taverna.t2.workbench.file.events.AbstractDataflowEvent;
+import net.sf.taverna.t2.workbench.file.events.ClosedDataflowEvent;
+import net.sf.taverna.t2.workbench.file.events.FileManagerEvent;
+import net.sf.taverna.t2.workbench.file.events.OpenedDataflowEvent;
+import net.sf.taverna.t2.workbench.file.events.SavedDataflowEvent;
+import net.sf.taverna.t2.workbench.file.exceptions.OpenException;
+
+import org.apache.log4j.Logger;
+import org.jdom.Document;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+public class FileOpenRecentMenuAction extends AbstractMenuCustom implements
+ Observer<FileManagerEvent> {
+ public static final URI RECENT_URI = URI
+ .create("http://taverna.sf.net/2008/t2workbench/menu#fileOpenRecent");
+ private static final String CONF = "conf";
+ private static Logger logger = Logger
+ .getLogger(FileOpenRecentMenuAction.class);
+ private static final String RECENT_WORKFLOWS_XML = "recentWorkflows.xml";
+ private static final int MAX_ITEMS = 10;
+
+ private FileManager fileManager;
+ private ApplicationConfiguration applicationConfiguration;
+ private JMenu menu;
+ private List<Recent> recents = new ArrayList<>();
+ private Thread loadRecentThread;
+
+ public FileOpenRecentMenuAction(FileManager fileManager) {
+ super(FILE_OPEN_SECTION_URI, 30, RECENT_URI);
+ this.fileManager = fileManager;
+ fileManager.addObserver(this);
+ }
+
+ @Override
+ public void notify(Observable<FileManagerEvent> sender,
+ FileManagerEvent message) throws Exception {
+ FileManager fileManager = (FileManager) sender;
+ if (message instanceof OpenedDataflowEvent
+ || message instanceof SavedDataflowEvent) {
+ AbstractDataflowEvent dataflowEvent = (AbstractDataflowEvent) message;
+ WorkflowBundle dataflow = dataflowEvent.getDataflow();
+ Object dataflowSource = fileManager.getDataflowSource(dataflow);
+ FileType dataflowType = fileManager.getDataflowType(dataflow);
+ addRecent(dataflowSource, dataflowType);
+ }
+ if (message instanceof ClosedDataflowEvent)
+ // Make sure enabled/disabled status is correct
+ updateRecentMenu();
+ }
+
+ public void updateRecentMenu() {
+ invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ updateRecentMenuGUI();
+ }
+ });
+ saveRecent();
+ }
+
+ protected void addRecent(Object dataflowSource, FileType dataflowType) {
+ if (dataflowSource == null)
+ return;
+ if (!(dataflowSource instanceof Serializable)) {
+ logger.warn("Can't serialize workflow source for 'Recent workflows': "
+ + dataflowSource);
+ return;
+ }
+ synchronized (recents) {
+ Recent recent = new Recent((Serializable) dataflowSource, dataflowType);
+ if (recents.contains(recent))
+ recents.remove(recent);
+ recents.add(0, recent); // Add to front
+ }
+ updateRecentMenu();
+ }
+
+ @Override
+ protected Component createCustomComponent() {
+ action = new DummyAction("Recent workflows");
+ action.putValue(MNEMONIC_KEY, VK_R);
+ menu = new JMenu(action);
+ // Disabled until we have loaded the recent workflows
+ menu.setEnabled(false);
+ loadRecentThread = new Thread("Loading recent workflow menu") {
+ // Avoid hanging GUI initialization while deserialising
+ @Override
+ public void run() {
+ loadRecent();
+ updateRecentMenu();
+ }
+ };
+ loadRecentThread.start();
+ return menu;
+ }
+
+ protected synchronized void loadRecent() {
+ File confDir = new File(applicationConfiguration.getApplicationHomeDir(), CONF);
+ confDir.mkdir();
+ File recentFile = new File(confDir, RECENT_WORKFLOWS_XML);
+ if (!recentFile.isFile())
+ return;
+ try {
+ loadRecent(recentFile);
+ } catch (JDOMException|IOException e) {
+ logger.warn("Could not read recent workflows from file "
+ + recentFile, e);
+ }
+ }
+
+ private void loadRecent(File recentFile) throws FileNotFoundException,
+ IOException, JDOMException {
+ SAXBuilder builder = new SAXBuilder();
+ @SuppressWarnings("unused")
+ Document document;
+ try (InputStream fileInputStream = new BufferedInputStream(
+ new FileInputStream(recentFile))) {
+ document = builder.build(fileInputStream);
+ }
+ synchronized (recents) {
+ recents.clear();
+ //RecentDeserializer deserialiser = new RecentDeserializer();
+ try {
+ // recents.addAll(deserialiser.deserializeRecent(document
+ // .getRootElement()));
+ } catch (Exception e) {
+ logger.warn("Could not read recent workflows from file "
+ + recentFile, e);
+ }
+ }
+ }
+
+ protected synchronized void saveRecent() {
+ File confDir = new File(applicationConfiguration.getApplicationHomeDir(), CONF);
+ confDir.mkdir();
+ File recentFile = new File(confDir, RECENT_WORKFLOWS_XML);
+
+ try {
+ saveRecent(recentFile);
+// } catch (JDOMException e) {
+// logger.warn("Could not generate XML for recent workflows to file "
+// + recentFile, e);
+ } catch (IOException e) {
+ logger.warn("Could not write recent workflows to file "
+ + recentFile, e);
+ }
+ }
+
+ private void saveRecent(File recentFile) throws FileNotFoundException,
+ IOException {
+ // RecentSerializer serializer = new RecentSerializer();
+ // XMLOutputter outputter = new XMLOutputter();
+
+ // Element serializedRecent;
+ synchronized (recents) {
+ if (recents.size() > MAX_ITEMS)
+ // Remove excess entries
+ recents.subList(MAX_ITEMS, recents.size()).clear();
+ // serializedRecent = serializer.serializeRecent(recents);
+ }
+ try (OutputStream outputStream = new BufferedOutputStream(
+ new FileOutputStream(recentFile))) {
+ // outputter.output(serializedRecent, outputStream);
+ }
+ }
+
+ protected void updateRecentMenuGUI() {
+ int items = 0;
+ menu.removeAll();
+ synchronized (recents) {
+ for (Recent recent : recents) {
+ if (++items >= MAX_ITEMS)
+ break;
+ OpenRecentAction openRecentAction = new OpenRecentAction(
+ recent, fileManager);
+ if (fileManager.getDataflowBySource(recent.getDataflowSource()) != null)
+ openRecentAction.setEnabled(false);
+ // else setEnabled(true)
+ JMenuItem menuItem = new JMenuItem(openRecentAction);
+ if (items < 10) {
+ openRecentAction.putValue(NAME, items + " "
+ + openRecentAction.getValue(NAME));
+ menuItem.setMnemonic(VK_0 + items);
+ }
+ menu.add(menuItem);
+ }
+ }
+ menu.setEnabled(items > 0);
+ menu.revalidate();
+ }
+
+ @SuppressWarnings("serial")
+ public static class OpenRecentAction extends AbstractAction implements
+ Runnable {
+ private final Recent recent;
+ private Component component = null;
+ private final FileManager fileManager;
+
+ public OpenRecentAction(Recent recent, FileManager fileManager) {
+ this.recent = recent;
+ this.fileManager = fileManager;
+ Serializable source = recent.getDataflowSource();
+ String name;
+ if (source instanceof File)
+ name = ((File) source).getAbsolutePath();
+ else
+ name = source.toString();
+ this.putValue(NAME, name);
+ this.putValue(SHORT_DESCRIPTION, "Open the workflow " + name);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ component = null;
+ if (e.getSource() instanceof Component)
+ component = (Component) e.getSource();
+ setEnabled(false);
+ new Thread(this, "Opening workflow from "
+ + recent.getDataflowSource()).start();
+ }
+
+ /**
+ * Opening workflow in separate thread
+ */
+ @Override
+ public void run() {
+ final Serializable source = recent.getDataflowSource();
+ try {
+ fileManager.openDataflow(recent.makefileType(), source);
+ } catch (OpenException ex) {
+ logger.warn("Failed to open the workflow from " + source
+ + " \n", ex);
+ showMessageDialog(component,
+ "Failed to open the workflow from url " + source
+ + " \n" + ex.getMessage(), "Error!",
+ ERROR_MESSAGE);
+ } finally {
+ setEnabled(true);
+ }
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Recent implements Serializable {
+ private final class RecentFileType extends FileType {
+ @Override
+ public String getMimeType() {
+ return mimeType;
+ }
+
+ @Override
+ public String getExtension() {
+ return extension;
+ }
+
+ @Override
+ public String getDescription() {
+ return "File type " + extension + " " + mimeType;
+ }
+ }
+
+ private Serializable dataflowSource;
+ private String mimeType;
+ private String extension;
+
+ public String getMimeType() {
+ return mimeType;
+ }
+
+ public void setMimeType(String mimeType) {
+ this.mimeType = mimeType;
+ }
+
+ public String getExtension() {
+ return extension;
+ }
+
+ public void setExtension(String extension) {
+ this.extension = extension;
+ }
+
+ public Recent() {
+ }
+
+ public FileType makefileType() {
+ if (mimeType == null && extension == null)
+ return null;
+ return new RecentFileType();
+ }
+
+ public Recent(Serializable dataflowSource, FileType dataflowType) {
+ setDataflowSource(dataflowSource);
+ if (dataflowType != null) {
+ setMimeType(dataflowType.getMimeType());
+ setExtension(dataflowType.getExtension());
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime
+ * result
+ + ((dataflowSource == null) ? 0 : dataflowSource.hashCode());
+ result = prime * result
+ + ((extension == null) ? 0 : extension.hashCode());
+ result = prime * result
+ + ((mimeType == null) ? 0 : mimeType.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (!(obj instanceof Recent))
+ return false;
+ Recent other = (Recent) obj;
+
+ if (dataflowSource == null) {
+ if (other.dataflowSource != null)
+ return false;
+ } else if (!dataflowSource.equals(other.dataflowSource))
+ return false;
+
+ if (extension == null) {
+ if (other.extension != null)
+ return false;
+ } else if (!extension.equals(other.extension))
+ return false;
+
+ if (mimeType == null) {
+ if (other.mimeType != null)
+ return false;
+ } else if (!mimeType.equals(other.mimeType))
+ return false;
+
+ return true;
+ }
+
+ public Serializable getDataflowSource() {
+ return dataflowSource;
+ }
+
+ public void setDataflowSource(Serializable dataflowSource) {
+ this.dataflowSource = dataflowSource;
+ }
+
+ @Override
+ public String toString() {
+ return getDataflowSource() + "";
+ }
+ }
+
+ // TODO find new serialization
+// protected static class RecentDeserializer extends AbstractXMLDeserializer {
+// public Collection<Recent> deserializeRecent(Element el) {
+// return (Collection<Recent>) super.createBean(el, getClass()
+// .getClassLoader());
+// }
+// }
+//
+// protected static class RecentSerializer extends AbstractXMLSerializer {
+// public Element serializeRecent(List<Recent> x) throws JDOMException,
+// IOException {
+// Element beanAsElement = super.beanAsElement(x);
+// return beanAsElement;
+// }
+// }
+
+ public void setApplicationConfiguration(
+ ApplicationConfiguration applicationConfiguration) {
+ this.applicationConfiguration = applicationConfiguration;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveAllMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveAllMenuAction.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveAllMenuAction.java
new file mode 100644
index 0000000..86edacb
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveAllMenuAction.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl.menu;
+
+import static net.sf.taverna.t2.workbench.file.impl.menu.FileSaveMenuSection.FILE_SAVE_SECTION_URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.impl.actions.SaveAllWorkflowsAction;
+
+public class FileSaveAllMenuAction extends AbstractMenuAction {
+ private final EditManager editManager;
+ private final FileManager fileManager;
+
+ public FileSaveAllMenuAction(EditManager editManager,
+ FileManager fileManager) {
+ super(FILE_SAVE_SECTION_URI, 30);
+ this.editManager = editManager;
+ this.fileManager = fileManager;
+ }
+
+ @Override
+ protected Action createAction() {
+ return new SaveAllWorkflowsAction(editManager, fileManager);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveAsMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveAsMenuAction.java b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveAsMenuAction.java
new file mode 100644
index 0000000..77917c9
--- /dev/null
+++ b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveAsMenuAction.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl.menu;
+
+import static net.sf.taverna.t2.workbench.file.impl.menu.FileSaveMenuSection.FILE_SAVE_SECTION_URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.impl.actions.SaveWorkflowAsAction;
+
+public class FileSaveAsMenuAction extends AbstractMenuAction {
+ private final FileManager fileManager;
+
+ public FileSaveAsMenuAction(FileManager fileManager) {
+ super(FILE_SAVE_SECTION_URI, 20);
+ this.fileManager = fileManager;
+ }
+
+ @Override
+ protected Action createAction() {
+ return new SaveWorkflowAsAction(fileManager);
+ }
+}