http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/T2FlowFileType.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/T2FlowFileType.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/T2FlowFileType.java new file mode 100644 index 0000000..bfd170b --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/T2FlowFileType.java @@ -0,0 +1,41 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.workbench.file.impl; + +import org.apache.taverna.workbench.file.FileType; + +public class T2FlowFileType extends FileType { + public static final String APPLICATION_VND_TAVERNA_T2FLOW_XML = "application/vnd.taverna.t2flow+xml"; + + @Override + public String getDescription() { + return "Taverna 2 workflow"; + } + + @Override + public String getExtension() { + return "t2flow"; + } + + @Override + public String getMimeType() { + return APPLICATION_VND_TAVERNA_T2FLOW_XML; + } +}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleFileFilter.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleFileFilter.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleFileFilter.java new file mode 100644 index 0000000..0442589 --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleFileFilter.java @@ -0,0 +1,36 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.workbench.file.impl; + +import java.io.File; + +import javax.swing.filechooser.FileFilter; + +public class WorkflowBundleFileFilter extends FileFilter { + @Override + public boolean accept(final File file) { + return file.getName().toLowerCase().endsWith(".wfbundle"); + } + + @Override + public String getDescription() { + return "Taverna 3 workflows"; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleFileType.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleFileType.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleFileType.java new file mode 100644 index 0000000..a64fb0d --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleFileType.java @@ -0,0 +1,41 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.workbench.file.impl; + +import org.apache.taverna.workbench.file.FileType; + +public class WorkflowBundleFileType extends FileType { + public static final String APPLICATION_VND_TAVERNA_SCUFL2_WORKFLOW_BUNDLE = "application/vnd.taverna.scufl2.workflow-bundle"; + + @Override + public String getDescription() { + return "Taverna 3 workflow"; + } + + @Override + public String getExtension() { + return "wfbundle"; + } + + @Override + public String getMimeType() { + return APPLICATION_VND_TAVERNA_SCUFL2_WORKFLOW_BUNDLE; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleOpener.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleOpener.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleOpener.java new file mode 100644 index 0000000..d85e4ad --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleOpener.java @@ -0,0 +1,142 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.workbench.file.impl; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import org.apache.taverna.workbench.file.AbstractDataflowPersistenceHandler; +import org.apache.taverna.workbench.file.DataflowInfo; +import org.apache.taverna.workbench.file.DataflowPersistenceHandler; +import org.apache.taverna.workbench.file.FileType; +import org.apache.taverna.workbench.file.exceptions.OpenException; + +import org.apache.log4j.Logger; + +import org.apache.taverna.scufl2.api.container.WorkflowBundle; +import org.apache.taverna.scufl2.api.io.ReaderException; +import org.apache.taverna.scufl2.api.io.WorkflowBundleIO; + +public class WorkflowBundleOpener extends AbstractDataflowPersistenceHandler + implements DataflowPersistenceHandler { + private static final WorkflowBundleFileType WF_BUNDLE_FILE_TYPE = new WorkflowBundleFileType(); + private static Logger logger = Logger.getLogger(WorkflowBundleOpener.class); + private WorkflowBundleIO workflowBundleIO; + + @SuppressWarnings("resource") + @Override + public DataflowInfo openDataflow(FileType fileType, Object source) + throws OpenException { + if (!getOpenFileTypes().contains(fileType)) + throw new OpenException("Unsupported file type " + fileType); + InputStream inputStream; + Date lastModified = null; + Object canonicalSource = source; + if (source instanceof InputStream) { + inputStream = (InputStream) source; + } else if (source instanceof File) { + try { + inputStream = new FileInputStream((File) source); + } catch (FileNotFoundException e) { + throw new OpenException("Could not open file " + source + ":\n" + + e.getLocalizedMessage(), e); + } + } else if (source instanceof URL) { + URL url = ((URL) source); + try { + URLConnection connection = url.openConnection(); + connection.setRequestProperty("Accept", "application/zip"); + inputStream = connection.getInputStream(); + if (connection.getLastModified() != 0) + lastModified = new Date(connection.getLastModified()); + } catch (IOException e) { + throw new OpenException("Could not open connection to URL " + + source + ":\n" + e.getLocalizedMessage(), e); + } + try { + if (url.getProtocol().equalsIgnoreCase("file")) + canonicalSource = new File(url.toURI()); + } catch (URISyntaxException e) { + logger.warn("Invalid file URI created from " + url); + } + } else + throw new OpenException("Unsupported source type " + + source.getClass()); + + final WorkflowBundle workflowBundle; + try { + workflowBundle = openDataflowStream(inputStream); + } finally { + // We created the stream, we'll close it + try { + if (!(source instanceof InputStream)) + inputStream.close(); + } catch (IOException ex) { + logger.warn("Could not close inputstream " + inputStream, ex); + } + } + if (canonicalSource instanceof File) + return new FileDataflowInfo(WF_BUNDLE_FILE_TYPE, + (File) canonicalSource, workflowBundle); + return new DataflowInfo(WF_BUNDLE_FILE_TYPE, canonicalSource, + workflowBundle, lastModified); + } + + protected WorkflowBundle openDataflowStream(InputStream inputStream) + throws OpenException { + WorkflowBundle workflowBundle; + try { + workflowBundle = workflowBundleIO.readBundle(inputStream, null); + } catch (ReaderException e) { + throw new OpenException("Could not read the workflow", e); + } catch (IOException e) { + throw new OpenException("Could not open the workflow for parsing", + e); + } catch (Exception e) { + throw new OpenException("Error while opening workflow", e); + } + + return workflowBundle; + } + + @Override + public List<FileType> getOpenFileTypes() { + return Arrays.<FileType> asList(WF_BUNDLE_FILE_TYPE); + } + + @Override + public List<Class<?>> getOpenSourceTypes() { + return Arrays.<Class<?>> asList(InputStream.class, URL.class, + File.class); + } + + public void setWorkflowBundleIO(WorkflowBundleIO workflowBundleIO) { + this.workflowBundleIO = workflowBundleIO; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleSaver.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleSaver.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleSaver.java new file mode 100644 index 0000000..89043be --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/WorkflowBundleSaver.java @@ -0,0 +1,144 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.workbench.file.impl; + +import static org.apache.taverna.workbench.file.impl.WorkflowBundleFileType.APPLICATION_VND_TAVERNA_SCUFL2_WORKFLOW_BUNDLE; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import org.apache.taverna.workbench.file.AbstractDataflowPersistenceHandler; +import org.apache.taverna.workbench.file.DataflowInfo; +import org.apache.taverna.workbench.file.DataflowPersistenceHandler; +import org.apache.taverna.workbench.file.FileType; +import org.apache.taverna.workbench.file.exceptions.SaveException; + +import org.apache.log4j.Logger; + +import org.apache.taverna.scufl2.api.container.WorkflowBundle; +import org.apache.taverna.scufl2.api.io.WorkflowBundleIO; + +public class WorkflowBundleSaver extends AbstractDataflowPersistenceHandler + implements DataflowPersistenceHandler { + private static final WorkflowBundleFileType WF_BUNDLE_FILE_TYPE = new WorkflowBundleFileType(); + private static Logger logger = Logger.getLogger(WorkflowBundleSaver.class); + private WorkflowBundleIO workflowBundleIO; + + @Override + public DataflowInfo saveDataflow(WorkflowBundle workflowBundle, FileType fileType, + Object destination) throws SaveException { + if (!getSaveFileTypes().contains(fileType)) + throw new IllegalArgumentException("Unsupported file type " + + fileType); + OutputStream outStream; + if (destination instanceof File) + try { + outStream = new FileOutputStream((File) destination); + } catch (FileNotFoundException e) { + throw new SaveException("Can't create workflow file " + + destination + ":\n" + e.getLocalizedMessage(), e); + } + else if (destination instanceof OutputStream) + outStream = (OutputStream) destination; + else + throw new SaveException("Unsupported destination type " + + destination.getClass()); + + try { + saveDataflowToStream(workflowBundle, outStream); + } finally { + try { + // Only close if we opened the stream + if (!(destination instanceof OutputStream)) + outStream.close(); + } catch (IOException e) { + logger.warn("Could not close stream", e); + } + } + + if (destination instanceof File) + return new FileDataflowInfo(WF_BUNDLE_FILE_TYPE, (File) destination, + workflowBundle); + return new DataflowInfo(WF_BUNDLE_FILE_TYPE, destination, workflowBundle); + } + + protected void saveDataflowToStream(WorkflowBundle workflowBundle, + OutputStream fileOutStream) throws SaveException { + try { + workflowBundleIO.writeBundle(workflowBundle, fileOutStream, + APPLICATION_VND_TAVERNA_SCUFL2_WORKFLOW_BUNDLE); + } catch (Exception e) { + throw new SaveException("Can't write workflow:\n" + + e.getLocalizedMessage(), e); + } + } + + @Override + public List<FileType> getSaveFileTypes() { + return Arrays.<FileType> asList(WF_BUNDLE_FILE_TYPE); + } + + @Override + public List<Class<?>> getSaveDestinationTypes() { + return Arrays.<Class<?>> asList(File.class, OutputStream.class); + } + + @Override + public boolean wouldOverwriteDataflow(WorkflowBundle workflowBundle, FileType fileType, + Object destination, DataflowInfo lastDataflowInfo) { + if (!getSaveFileTypes().contains(fileType)) + throw new IllegalArgumentException("Unsupported file type " + + fileType); + if (!(destination instanceof File)) + return false; + + File file; + try { + file = ((File) destination).getCanonicalFile(); + } catch (IOException e) { + return false; + } + if (!file.exists()) + return false; + if (lastDataflowInfo == null) + return true; + Object lastDestination = lastDataflowInfo.getCanonicalSource(); + if (!(lastDestination instanceof File)) + return true; + File lastFile = (File) lastDestination; + if (!lastFile.getAbsoluteFile().equals(file)) + return true; + + Date lastModified = new Date(file.lastModified()); + if (lastModified.equals(lastDataflowInfo.getLastModified())) + return false; + return true; + } + + public void setWorkflowBundleIO(WorkflowBundleIO workflowBundleIO) { + this.workflowBundleIO = workflowBundleIO; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/CloseAllWorkflowsAction.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/CloseAllWorkflowsAction.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/CloseAllWorkflowsAction.java new file mode 100644 index 0000000..eb88068 --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/CloseAllWorkflowsAction.java @@ -0,0 +1,84 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.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_L; +import static java.awt.event.KeyEvent.VK_W; +import static javax.swing.KeyStroke.getKeyStroke; +import static org.apache.taverna.workbench.icons.WorkbenchIcons.closeAllIcon; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.util.Collections; +import java.util.List; + +import javax.swing.AbstractAction; + +import org.apache.taverna.workbench.edits.EditManager; +import org.apache.taverna.workbench.file.FileManager; + +import org.apache.log4j.Logger; + +import org.apache.taverna.scufl2.api.container.WorkflowBundle; + +@SuppressWarnings("serial") +public class CloseAllWorkflowsAction extends AbstractAction { + @SuppressWarnings("unused") + private static Logger logger = Logger.getLogger(CloseWorkflowAction.class); + private static final String CLOSE_ALL_WORKFLOWS = "Close all workflows"; + private FileManager fileManager; + private CloseWorkflowAction closeWorkflowAction; + + public CloseAllWorkflowsAction(EditManager editManager, FileManager fileManager) { + super(CLOSE_ALL_WORKFLOWS, closeAllIcon); + this.fileManager = fileManager; + closeWorkflowAction = new CloseWorkflowAction(editManager, fileManager); + putValue( + ACCELERATOR_KEY, + getKeyStroke(VK_W, getDefaultToolkit().getMenuShortcutKeyMask() + | SHIFT_DOWN_MASK)); + putValue(MNEMONIC_KEY, VK_L); + } + + @Override + public void actionPerformed(ActionEvent event) { + Component parentComponent = null; + if (event.getSource() instanceof Component) + parentComponent = (Component) event.getSource(); + closeAllWorkflows(parentComponent); + } + + public boolean closeAllWorkflows(Component parentComponent) { + // Close in reverse so we can save nested workflows first + List<WorkflowBundle> workflowBundles = fileManager.getOpenDataflows(); + + Collections.reverse(workflowBundles); + + for (WorkflowBundle workflowBundle : workflowBundles) { + boolean success = closeWorkflowAction.closeWorkflow( + parentComponent, workflowBundle); + if (!success) + return false; + } + return true; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/CloseWorkflowAction.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/CloseWorkflowAction.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/CloseWorkflowAction.java new file mode 100644 index 0000000..091a652 --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/CloseWorkflowAction.java @@ -0,0 +1,106 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.workbench.file.impl.actions; + +import static java.awt.Toolkit.getDefaultToolkit; +import static java.awt.event.KeyEvent.VK_C; +import static java.awt.event.KeyEvent.VK_W; +import static javax.swing.JOptionPane.CANCEL_OPTION; +import static javax.swing.JOptionPane.NO_OPTION; +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.KeyStroke.getKeyStroke; +import static org.apache.taverna.workbench.icons.WorkbenchIcons.closeIcon; + +import java.awt.Component; +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; + +import org.apache.taverna.workbench.edits.EditManager; +import org.apache.taverna.workbench.file.FileManager; +import org.apache.taverna.workbench.file.exceptions.UnsavedException; + +import org.apache.log4j.Logger; + +import org.apache.taverna.scufl2.api.container.WorkflowBundle; + +@SuppressWarnings("serial") +public class CloseWorkflowAction extends AbstractAction { + private static Logger logger = Logger.getLogger(CloseWorkflowAction.class); + private static final String CLOSE_WORKFLOW = "Close workflow"; + private final SaveWorkflowAction saveWorkflowAction; + private FileManager fileManager; + + public CloseWorkflowAction(EditManager editManager, FileManager fileManager) { + super(CLOSE_WORKFLOW, closeIcon); + this.fileManager = fileManager; + saveWorkflowAction = new SaveWorkflowAction(editManager, fileManager); + putValue( + ACCELERATOR_KEY, + getKeyStroke(VK_W, getDefaultToolkit().getMenuShortcutKeyMask())); + putValue(MNEMONIC_KEY, VK_C); + + } + @Override + public void actionPerformed(ActionEvent e) { + Component parentComponent = null; + if (e.getSource() instanceof Component) + parentComponent = (Component) e.getSource(); + closeWorkflow(parentComponent, fileManager.getCurrentDataflow()); + } + + public boolean closeWorkflow(Component parentComponent, WorkflowBundle workflowBundle) { + if (workflowBundle == null) { + logger.warn("Attempted to close a null workflow"); + return false; + } + + try { + return fileManager.closeDataflow(workflowBundle, true); + } catch (UnsavedException e1) { + fileManager.setCurrentDataflow(workflowBundle); + String msg = "Do you want to save changes before closing the workflow " + + fileManager.getDataflowName(workflowBundle) + "?"; + switch (showConfirmDialog(parentComponent, msg, "Save workflow?", + YES_NO_CANCEL_OPTION)) { + case NO_OPTION: + try { + fileManager.closeDataflow(workflowBundle, false); + return true; + } catch (UnsavedException e2) { + logger.error("Unexpected UnsavedException while " + + "closing workflow", e2); + return false; + } + case YES_OPTION: + boolean saved = saveWorkflowAction.saveDataflow( + parentComponent, workflowBundle); + if (!saved) + return false; + return closeWorkflow(parentComponent, workflowBundle); + case CANCEL_OPTION: + default: + return false; + } + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/NewWorkflowAction.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/NewWorkflowAction.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/NewWorkflowAction.java new file mode 100644 index 0000000..deb0926 --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/NewWorkflowAction.java @@ -0,0 +1,57 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.workbench.file.impl.actions; + +import static java.awt.Toolkit.getDefaultToolkit; +import static java.awt.event.KeyEvent.VK_N; +import static javax.swing.KeyStroke.getKeyStroke; +import static org.apache.taverna.workbench.icons.WorkbenchIcons.newIcon; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; + +import javax.swing.AbstractAction; + +import org.apache.taverna.workbench.file.FileManager; + +import org.apache.log4j.Logger; + +@SuppressWarnings("serial") +public class NewWorkflowAction extends AbstractAction { + @SuppressWarnings("unused") + private static Logger logger = Logger.getLogger(NewWorkflowAction.class); + private static final String NEW_WORKFLOW = "New workflow"; + private FileManager fileManager; + + public NewWorkflowAction(FileManager fileManager) { + super(NEW_WORKFLOW, newIcon); + this.fileManager = fileManager; + putValue(SHORT_DESCRIPTION, NEW_WORKFLOW); + putValue(MNEMONIC_KEY, KeyEvent.VK_N); + putValue( + ACCELERATOR_KEY, + getKeyStroke(VK_N, getDefaultToolkit().getMenuShortcutKeyMask())); + } + + @Override + public void actionPerformed(ActionEvent e) { + fileManager.newDataflow(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/OpenNestedWorkflowAction.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/OpenNestedWorkflowAction.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/OpenNestedWorkflowAction.java new file mode 100644 index 0000000..2e2124d --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/OpenNestedWorkflowAction.java @@ -0,0 +1,75 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.workbench.file.impl.actions; + +import java.awt.Component; +import java.io.File; + +import org.apache.taverna.workbench.file.FileManager; +import org.apache.taverna.workbench.file.FileType; +import org.apache.taverna.workbench.file.exceptions.OpenException; + +import org.apache.log4j.Logger; + +import org.apache.taverna.scufl2.api.container.WorkflowBundle; + +/** + * An action for opening a nested workflow from a file. + * + * @author Alex Nenadic + */ +public class OpenNestedWorkflowAction extends OpenWorkflowAction { + private static final long serialVersionUID = -5398423684000142379L; + private static Logger logger = Logger + .getLogger(OpenNestedWorkflowAction.class); + + public OpenNestedWorkflowAction(FileManager fileManager) { + super(fileManager); + } + + /** + * Opens a nested workflow from a file (should be one file even though the + * method takes a list of files - this is because it overrides the + * {@link OpenWorkflowAction#openWorkflows(Component, File[], FileType, OpenCallback) + * openWorkflows(...)} method). + */ + @Override + public void openWorkflows(final Component parentComponent, File[] files, + FileType fileType, OpenCallback openCallback) { + ErrorLoggingOpenCallbackWrapper callback = new ErrorLoggingOpenCallbackWrapper( + openCallback); + for (File file : files) + try { + callback.aboutToOpenDataflow(file); + WorkflowBundle workflowBundle = fileManager.openDataflow( + fileType, file); + callback.openedDataflow(file, workflowBundle); + } catch (final RuntimeException ex) { + logger.warn("Could not open workflow from " + file, ex); + if (!callback.couldNotOpenDataflow(file, ex)) + showErrorMessage(parentComponent, file, ex); + } catch (final OpenException ex) { + logger.warn("Could not open workflow from " + file, ex); + if (!callback.couldNotOpenDataflow(file, ex)) + showErrorMessage(parentComponent, file, ex); + return; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/OpenWorkflowAction.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/OpenWorkflowAction.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/OpenWorkflowAction.java new file mode 100644 index 0000000..3a7560a --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/OpenWorkflowAction.java @@ -0,0 +1,394 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.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 org.apache.taverna.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 org.apache.taverna.workbench.file.FileManager; +import org.apache.taverna.workbench.file.FileType; +import org.apache.taverna.workbench.file.exceptions.OpenException; +import org.apache.taverna.workbench.file.impl.FileTypeFileFilter; + +import org.apache.log4j.Logger; + +import org.apache.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 org.apache.taverna.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/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/OpenWorkflowFromURLAction.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/OpenWorkflowFromURLAction.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/OpenWorkflowFromURLAction.java new file mode 100644 index 0000000..3c1a4cc --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/OpenWorkflowFromURLAction.java @@ -0,0 +1,138 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.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 org.apache.taverna.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 org.apache.taverna.workbench.file.FileManager; + +import org.apache.log4j.Logger; + +import org.apache.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/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/PasswordInput.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/PasswordInput.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/PasswordInput.java new file mode 100644 index 0000000..61e80e6 --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/PasswordInput.java @@ -0,0 +1,220 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.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 org.apache.taverna.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/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/SaveAllWorkflowsAction.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/SaveAllWorkflowsAction.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/SaveAllWorkflowsAction.java new file mode 100644 index 0000000..b58b99f --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/SaveAllWorkflowsAction.java @@ -0,0 +1,103 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.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 org.apache.taverna.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 org.apache.taverna.lang.observer.Observable; +import org.apache.taverna.lang.observer.Observer; +import org.apache.taverna.workbench.edits.EditManager; +import org.apache.taverna.workbench.file.FileManager; +import org.apache.taverna.workbench.file.events.FileManagerEvent; + +import org.apache.log4j.Logger; + +import org.apache.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/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/SaveWorkflowAction.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/SaveWorkflowAction.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/SaveWorkflowAction.java new file mode 100644 index 0000000..2cf2775 --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/SaveWorkflowAction.java @@ -0,0 +1,174 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.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 org.apache.taverna.workbench.icons.WorkbenchIcons.saveIcon; + +import java.awt.Component; +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; + +import org.apache.taverna.lang.observer.Observable; +import org.apache.taverna.lang.observer.Observer; +import org.apache.taverna.workbench.edits.EditManager; +import org.apache.taverna.workbench.edits.EditManager.AbstractDataflowEditEvent; +import org.apache.taverna.workbench.edits.EditManager.EditManagerEvent; +import org.apache.taverna.workbench.file.FileManager; +import org.apache.taverna.workbench.file.events.FileManagerEvent; +import org.apache.taverna.workbench.file.events.SavedDataflowEvent; +import org.apache.taverna.workbench.file.events.SetCurrentDataflowEvent; +import org.apache.taverna.workbench.file.exceptions.OverwriteException; +import org.apache.taverna.workbench.file.exceptions.SaveException; + +import org.apache.log4j.Logger; + +import org.apache.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/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/SaveWorkflowAsAction.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/SaveWorkflowAsAction.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/SaveWorkflowAsAction.java new file mode 100644 index 0000000..b42fe1c --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/actions/SaveWorkflowAsAction.java @@ -0,0 +1,218 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.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 org.apache.taverna.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 org.apache.taverna.lang.observer.Observable; +import org.apache.taverna.lang.observer.Observer; +import org.apache.taverna.workbench.file.FileManager; +import org.apache.taverna.workbench.file.FileType; +import org.apache.taverna.workbench.file.events.FileManagerEvent; +import org.apache.taverna.workbench.file.events.SetCurrentDataflowEvent; +import org.apache.taverna.workbench.file.exceptions.OverwriteException; +import org.apache.taverna.workbench.file.exceptions.SaveException; +import org.apache.taverna.workbench.file.impl.FileTypeFileFilter; + +import org.apache.log4j.Logger; + +import org.apache.taverna.scufl2.api.container.WorkflowBundle; +import org.apache.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/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/hooks/CloseWorkflowsOnShutdown.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/hooks/CloseWorkflowsOnShutdown.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/hooks/CloseWorkflowsOnShutdown.java new file mode 100644 index 0000000..4e495a2 --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/hooks/CloseWorkflowsOnShutdown.java @@ -0,0 +1,55 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.workbench.file.impl.hooks; + +import org.apache.taverna.workbench.ShutdownSPI; +import org.apache.taverna.workbench.edits.EditManager; +import org.apache.taverna.workbench.file.FileManager; +import org.apache.taverna.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/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/menu/FileCloseAllMenuAction.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/menu/FileCloseAllMenuAction.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/menu/FileCloseAllMenuAction.java new file mode 100644 index 0000000..6449ba7 --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/menu/FileCloseAllMenuAction.java @@ -0,0 +1,50 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.workbench.file.impl.menu; + +import static org.apache.taverna.workbench.file.impl.menu.FileOpenMenuSection.FILE_URI; + +import java.net.URI; + +import javax.swing.Action; + +import org.apache.taverna.ui.menu.AbstractMenuAction; +import org.apache.taverna.workbench.edits.EditManager; +import org.apache.taverna.workbench.file.FileManager; +import org.apache.taverna.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/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/menu/FileCloseMenuAction.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/menu/FileCloseMenuAction.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/menu/FileCloseMenuAction.java new file mode 100644 index 0000000..8579c2e --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/menu/FileCloseMenuAction.java @@ -0,0 +1,49 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.workbench.file.impl.menu; + +import static org.apache.taverna.workbench.file.impl.menu.FileOpenMenuSection.FILE_URI; + +import java.net.URI; + +import javax.swing.Action; + +import org.apache.taverna.ui.menu.AbstractMenuAction; +import org.apache.taverna.workbench.edits.EditManager; +import org.apache.taverna.workbench.file.FileManager; +import org.apache.taverna.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/bf8a7ea2/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/menu/FileNewMenuAction.java ---------------------------------------------------------------------- diff --git a/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/menu/FileNewMenuAction.java b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/menu/FileNewMenuAction.java new file mode 100644 index 0000000..691729b --- /dev/null +++ b/taverna-file-impl/src/main/java/org/apache/taverna/workbench/file/impl/menu/FileNewMenuAction.java @@ -0,0 +1,46 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.apache.taverna.workbench.file.impl.menu; + +import static org.apache.taverna.workbench.file.impl.menu.FileOpenMenuSection.FILE_OPEN_SECTION_URI; + +import java.net.URI; + +import javax.swing.Action; + +import org.apache.taverna.ui.menu.AbstractMenuAction; +import org.apache.taverna.workbench.file.FileManager; +import org.apache.taverna.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); + } +}
