http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-renderers-impl/src/main/java/net/sf/taverna/t2/renderers/impl/XMLTree.java ---------------------------------------------------------------------- diff --git a/taverna-workbench-renderers-impl/src/main/java/net/sf/taverna/t2/renderers/impl/XMLTree.java b/taverna-workbench-renderers-impl/src/main/java/net/sf/taverna/t2/renderers/impl/XMLTree.java new file mode 100644 index 0000000..2d53218 --- /dev/null +++ b/taverna-workbench-renderers-impl/src/main/java/net/sf/taverna/t2/renderers/impl/XMLTree.java @@ -0,0 +1,329 @@ +/******************************************************************************* + * 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.renderers.impl; + +import static java.util.prefs.Preferences.userNodeForPackage; +import static javax.swing.JFileChooser.APPROVE_OPTION; +import static javax.swing.JOptionPane.ERROR_MESSAGE; +import static javax.swing.JOptionPane.showMessageDialog; +import static javax.swing.tree.TreeSelectionModel.SINGLE_TREE_SELECTION; +import static org.jdom.output.Format.getPrettyFormat; + +import java.awt.Color; +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringReader; +import java.util.Enumeration; +import java.util.prefs.Preferences; + +import javax.swing.JFileChooser; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; + +import org.jdom.Attribute; +import org.jdom.Content; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.JDOMException; +import org.jdom.Parent; +import org.jdom.Text; +import org.jdom.input.SAXBuilder; +import org.jdom.output.XMLOutputter; + +/** + * An extension of the {@link JTree} class, constructed with a String of XML and + * used to display the XML structure as an interactive tree. Derived from <a + * href="http://www.devx.com/gethelpon/10MinuteSolution/16694/0/page/1">original + * code by Kyle Gabhart</a> and then subsequently heavily rewritten to move to + * JDOM, and moved lots of the setup code to the renderer to cut down + * initialisation time. Added text node size limit as well. Displaying large + * gene sequences as base64 encoded text in a single node really, <i>really</i> + * hurts performance. + * + * @author Kyle Gabhart + * @author Tom Oinn + * @author Kevin Glover + * @author Ian Dunlop + */ +@SuppressWarnings("serial") +class XMLTree extends JTree { + private class XMLNode extends DefaultMutableTreeNode { + public XMLNode(Content userObject) { + super(userObject); + } + } + + int textSizeLimit = 1000; + final JFileChooser fc = new JFileChooser(); + Element rootElement = null; + + /** + * Build a new XMLTree from the supplied String containing XML. + * + * @param text + * @throws IOException + * @throws JDOMException + */ + public XMLTree(String text) throws IOException, JDOMException { + super(); + Document document = new SAXBuilder(false).build(new StringReader(text)); + init(document.getRootElement()); + revalidate(); + } + + public String getText() { + if (rootElement == null) + return ""; + XMLOutputter xo = new XMLOutputter(getPrettyFormat()); + return xo.outputString(rootElement); + } + + public XMLTree(String text, boolean limit) throws IOException, + JDOMException { + if (!limit) + textSizeLimit = -1; + Document document = new SAXBuilder(false).build(new StringReader(text)); + init(document.getRootElement()); + revalidate(); + } + + public XMLTree(Document document) { + this(document.getRootElement()); + } + + public XMLTree(Element element) { + super(); + init(element); + revalidate(); + } + + private void init(Content content) { + rootElement = (Element) content; + /* + * Fix for platforms other than metal which can't otherwise cope with + * arbitrary size rows + */ + setRowHeight(0); + getSelectionModel().setSelectionMode(SINGLE_TREE_SELECTION); + setShowsRootHandles(true); + setEditable(false); + setModel(new DefaultTreeModel(createTreeNode(content))); + setCellRenderer(new DefaultTreeCellRenderer() { + @Override + public Color getBackgroundNonSelectionColor() { + return null; + } + + @Override + public Color getBackground() { + return null; + } + + @Override + public Component getTreeCellRendererComponent(JTree tree, + Object value, boolean sel, boolean expanded, boolean leaf, + int row, boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, sel, expanded, + leaf, row, hasFocus); + setOpaque(false); + if (value instanceof XMLNode) { + XMLNode node = (XMLNode) value; + if (node.getUserObject() instanceof Element) + renderElementNode((Element) node.getUserObject()); + else if (node.getUserObject() instanceof Text) + renderTextNode((Text) node.getUserObject()); + // TODO what about other node types? + } + setBackground(new Color(0, 0, 0, 0)); + return this; + } + + private void renderElementNode(Element element) { + // setIcon(TavernaIcons.xmlNodeIcon); + StringBuilder nameBuffer = new StringBuilder("<html>") + .append(element.getQualifiedName()); + /* + * Bit of a quick and dirty hack here to try to ensure that the + * element namespace is shown. There appears no way to get the + * actual xmlns declarations that are part of an element through + * jdom. Also, please note, there's no namespace handling at all + * for attributes... + */ + if (element.getParent() instanceof Element) { + Element parent = (Element) element.getParent(); + if (parent.getNamespace(element.getNamespacePrefix()) == null) + nameBuffer + .append(" <font color=\"purple\">xmlns:") + .append(element.getNamespacePrefix()) + .append("</font>=\"<font color=\"green\">") + .append(element.getNamespaceURI() + "</font>\""); + } else + nameBuffer.append(" <font color=\"purple\">xmlns:") + .append(element.getNamespacePrefix()) + .append("</font>=\"<font color=\"green\">") + .append(element.getNamespaceURI() + "</font>\""); + + String sep = ""; + for (Object a : element.getAttributes()) { + Attribute attribute = (Attribute) a; + String name = attribute.getName().trim(); + String value = attribute.getValue().trim(); + if (value != null && value.length() > 0) { + // TODO xml-quote name and value + nameBuffer.append(sep) + .append(" <font color=\"purple\">") + .append(name) + .append("</font>=\"<font color=\"green\">") + .append(value).append("</font>\""); + sep = ","; + } + } + + nameBuffer.append("</html>"); + setText(nameBuffer.toString()); + } + + private void renderTextNode(Text text) { + // setIcon(TavernaIcons.leafIcon); + String name = text.getText(); + if (textSizeLimit > -1 && name.length() > textSizeLimit) + name = name.substring(0, textSizeLimit) + "..."; + setText("<html><pre><font color=\"blue\">" + + name.replaceAll("<br>", "\n").replaceAll("<", "<") + + "</font></pre></html>"); + } + }); + setAllNodesExpanded(); + + // Add a listener to present the 'save as text' option + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + if (e.isPopupTrigger()) + doEvent(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + if (e.isPopupTrigger()) + doEvent(e); + } + + public void doEvent(MouseEvent e) { + JPopupMenu menu = new JPopupMenu(); + JMenuItem item = new JMenuItem("Save as XML text"); + menu.add(item); + item.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + saveTreeXML(); + } + }); + menu.show(XMLTree.this, e.getX(), e.getY()); + } + }); + } + + private void saveTreeXML() { + try { + Preferences prefs = userNodeForPackage(XMLTree.class); + String curDir = prefs.get("currentDir", + System.getProperty("user.home")); + fc.resetChoosableFileFilters(); + fc.setFileFilter(new ExtensionFileFilter(new String[] { "xml" })); + fc.setCurrentDirectory(new File(curDir)); + if (fc.showSaveDialog(this) == APPROVE_OPTION) { + prefs.put("currentDir", fc.getCurrentDirectory().toString()); + saveTreeXML(fc.getSelectedFile()); + } + } catch (Exception ex) { + showMessageDialog(this, "Problem saving XML:\n" + ex.getMessage(), + "Error!", ERROR_MESSAGE); + } + } + + private void saveTreeXML(File file) throws IOException { + try (PrintWriter out = new PrintWriter(new FileWriter(file))) { + out.print(this.getText()); + } + } + + public void setAllNodesExpanded() { + synchronized (this.getModel()) { + expandAll(this, new TreePath(this.getModel().getRoot()), true); + } + } + + private void expandAll(JTree tree, TreePath parent, boolean expand) { + synchronized (this.getModel()) { + /* + * Traverse children + * + * Ignores nodes who's userObject is a Processor type to avoid + * overloading the UI with nodes at startup. + */ + TreeNode node = (TreeNode) parent.getLastPathComponent(); + for (Enumeration<?> e = node.children(); e.hasMoreElements(); ) { + TreeNode n = (TreeNode) e.nextElement(); + expandAll(tree, parent.pathByAddingChild(n), expand); + } + // Expansion or collapse must be done bottom-up + if (expand) + tree.expandPath(parent); + else + tree.collapsePath(parent); + } + } + + public void setTextNodeSizeLimit(int sizeLimit) { + textSizeLimit = sizeLimit; + } + + private XMLNode createTreeNode(Content content) { + XMLNode node = new XMLNode(content); + if (content instanceof Parent) { + Parent parent = (Parent) content; + for (Object child : parent.getContent()) { + if (child instanceof Element) + node.add(createTreeNode((Content) child)); + else if (textSizeLimit != 0 && child instanceof Text) { + Text text = (Text) child; + if (!text.getTextNormalize().isEmpty()) + node.add(createTreeNode(text)); + } + } + } + return node; + } +}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-renderers-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.renderers.Renderer ---------------------------------------------------------------------- diff --git a/taverna-workbench-renderers-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.renderers.Renderer b/taverna-workbench-renderers-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.renderers.Renderer new file mode 100644 index 0000000..044a396 --- /dev/null +++ b/taverna-workbench-renderers-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.renderers.Renderer @@ -0,0 +1,7 @@ +net.sf.taverna.t2.renderers.impl.AdvancedImageRenderer +net.sf.taverna.t2.renderers.impl.HexBinaryRenderer +net.sf.taverna.t2.renderers.impl.TextRenderer +net.sf.taverna.t2.renderers.impl.TextRtfRenderer +net.sf.taverna.t2.renderers.impl.TextXMLRenderer + + http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context-osgi.xml ---------------------------------------------------------------------- diff --git a/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context-osgi.xml b/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context-osgi.xml new file mode 100644 index 0000000..436426a --- /dev/null +++ b/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context-osgi.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:beans="http://www.springframework.org/schema/beans" + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/osgi + http://www.springframework.org/schema/osgi/spring-osgi.xsd"> + + <service ref="AdvancedImageRenderer" interface="net.sf.taverna.t2.renderers.Renderer" /> + <service ref="HexBinaryRenderer" interface="net.sf.taverna.t2.renderers.Renderer" /> + <service ref="TextRenderer" interface="net.sf.taverna.t2.renderers.Renderer" /> + <service ref="TextRtfRenderer" interface="net.sf.taverna.t2.renderers.Renderer" /> + <service ref="TextXMLRenderer" interface="net.sf.taverna.t2.renderers.Renderer" /> + + <service ref="RendererRegistry" interface="net.sf.taverna.t2.renderers.RendererRegistry" /> + + <list id="renderers" interface="net.sf.taverna.t2.renderers.Renderer" cardinality="0..N" /> + +</beans:beans> http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context.xml ---------------------------------------------------------------------- diff --git a/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context.xml b/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context.xml new file mode 100644 index 0000000..a041c98 --- /dev/null +++ b/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd"> + + <bean id="AdvancedImageRenderer" class="net.sf.taverna.t2.renderers.impl.AdvancedImageRenderer" /> + <bean id="HexBinaryRenderer" class="net.sf.taverna.t2.renderers.impl.HexBinaryRenderer" /> + <bean id="TextRenderer" class="net.sf.taverna.t2.renderers.impl.TextRenderer" /> + <bean id="TextRtfRenderer" class="net.sf.taverna.t2.renderers.impl.TextRtfRenderer" /> + <bean id="TextXMLRenderer" class="net.sf.taverna.t2.renderers.impl.TextXMLRenderer" /> + + <bean id="RendererRegistry" class="net.sf.taverna.t2.renderers.impl.RendererRegistryImpl"> + <property name="renderers" ref="renderers" /> + </bean> + + +</beans> http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-renderers-impl/src/test/java/net/sf/taverna/t2/renderers/TestRendererSPI.java ---------------------------------------------------------------------- diff --git a/taverna-workbench-renderers-impl/src/test/java/net/sf/taverna/t2/renderers/TestRendererSPI.java b/taverna-workbench-renderers-impl/src/test/java/net/sf/taverna/t2/renderers/TestRendererSPI.java new file mode 100644 index 0000000..ece7cf5 --- /dev/null +++ b/taverna-workbench-renderers-impl/src/test/java/net/sf/taverna/t2/renderers/TestRendererSPI.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * 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.renderers; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.HashSet; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + + +@SuppressWarnings("unused") +public class TestRendererSPI { + + private static final String TEST_NS = "testNS"; + + @Test + public void doNothing() { + //do nothing for the moment + } + +// @Test +// public void getAllRenderers() { +// RendererRegistry rendererRegistry = new RendererRegistry(); +// assertEquals(rendererRegistry.getInstances().size(), 10); +// } +// +// @Test +// public void checkTextHtmlMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException { +// String mimeType = "text/html"; +// String html = "<HTML><HEAD></HEAD><BODY>hello</BODY></HTML>"; +// EntityIdentifier entityIdentifier = facade.register(html, "utf-8"); +// RendererRegistry rendererRegistry = new RendererRegistry(); +// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType); +// assertEquals(renderersForMimeType.size(),2); +// assertEquals(renderersForMimeType.get(0).getClass().getSimpleName(), "TextRenderer"); +// assertEquals(renderersForMimeType.get(1).getClass().getSimpleName(), "TextHtmlRenderer"); +// assertTrue(renderersForMimeType.get(0).canHandle("text/html")); +// } +// +// @Test +// public void checkURLMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException { +// String mimeType = "text/x-taverna-web-url.text"; +// String url = "http://google.com"; +// EntityIdentifier entityIdentifier = facade.register(url); +// RendererRegistry rendererRegistry = new RendererRegistry(); +// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType); +// assertEquals(renderersForMimeType.size(),2); +// assertEquals(renderersForMimeType.get(0).getClass().getSimpleName(), "TextRenderer"); +// assertEquals(renderersForMimeType.get(1).getClass().getSimpleName(), "TextTavernaWebUrlRenderer"); +// assertTrue(renderersForMimeType.get(1).canHandle("text/x-taverna-web-url.text")); +// } +// +// @Test +// public void checkJMolMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException { +// String mimeType ="chemical/x-pdb"; +// String jmol = "jmol"; +// EntityIdentifier entityIdentifier = facade.register(jmol); +// RendererRegistry rendererRegistry = new RendererRegistry(); +// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType); +// assertEquals(renderersForMimeType.size(), 1); +// assertEquals(renderersForMimeType.get(0).getClass().getSimpleName(), "JMolRenderer"); +// assertTrue(renderersForMimeType.get(0).canHandle("chemical/x-mdl-molfile")); +// assertTrue(renderersForMimeType.get(0).canHandle("chemical/x-cml")); +// } +// +// @Test +// public void checkSeqVistaMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException { +// String mimeType ="chemical/x-swissprot"; +// String type = "seqvista"; +// EntityIdentifier entityIdentifier = facade.register(type); +// RendererRegistry rendererRegistry = new RendererRegistry(); +// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType); +// assertEquals(renderersForMimeType.size(), 1); +// assertEquals(renderersForMimeType.get(0).getClass().getSimpleName(), "SeqVistaRenderer"); +// assertTrue(renderersForMimeType.get(0).canHandle("chemical/x-embl-dl-nucleotide")); +// assertTrue(renderersForMimeType.get(0).canHandle("chemical/x-fasta")); +// } +// +// @Test +// public void checkSVGMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException { +// String mimeType ="image/svg+xml"; +// String type = "SVG"; +// EntityIdentifier entityIdentifier = facade.register(type); +// RendererRegistry rendererRegistry = new RendererRegistry(); +// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType); +// assertEquals(renderersForMimeType.size(), 2); +// assertEquals(renderersForMimeType.get(1).getClass().getSimpleName(), "SVGRenderer"); +// } +// +// @Test +// public void checkTextMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException { +// String mimeType ="text/text"; +// String type = "text"; +// EntityIdentifier entityIdentifier = facade.register(type); +// RendererRegistry rendererRegistry = new RendererRegistry(); +// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType); +// assertEquals(renderersForMimeType.size(), 1); +// assertEquals(renderersForMimeType.get(0).getClass().getSimpleName(), "TextRenderer"); +// } +// +// @Test +// public void checkTextRtfMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException { +// String mimeType ="text/rtf"; +// String type = "textRTF"; +// EntityIdentifier entityIdentifier = facade.register(type); +// RendererRegistry rendererRegistry = new RendererRegistry(); +// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType); +// assertEquals(renderersForMimeType.size(), 2); +// assertEquals(renderersForMimeType.get(1).getClass().getSimpleName(), "TextRtfRenderer"); +// } +// +// @Test +// public void checkTextXMLMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException { +// String mimeType ="text/xml"; +// String type = "textXML"; +// EntityIdentifier entityIdentifier = facade.register(type); +// RendererRegistry rendererRegistry = new RendererRegistry(); +// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType); +// assertEquals(renderersForMimeType.size(), 2); +// assertEquals(renderersForMimeType.get(1).getClass().getSimpleName(), "TextXMLRenderer"); +// } +// +// @Before +// public void setDataManager() { +// // dManager = new FileDataManager("testNS", +// // new HashSet<LocationalContext>(), new File("/tmp/fish")); +// dManager = new InMemoryDataManager(TEST_NS, +// new HashSet<LocationalContext>()); +// facade = new DataFacade(dManager); +// } + +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-report-impl/pom.xml ---------------------------------------------------------------------- diff --git a/taverna-workbench-report-impl/pom.xml b/taverna-workbench-report-impl/pom.xml new file mode 100644 index 0000000..c0e72bb --- /dev/null +++ b/taverna-workbench-report-impl/pom.xml @@ -0,0 +1,40 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <artifactId>ui-impl</artifactId> + <groupId>net.sf.taverna.t2</groupId> + <version>2.0-SNAPSHOT</version> + </parent> + <groupId>net.sf.taverna.t2.ui-impl</groupId> + <artifactId>report-impl</artifactId> + <packaging>bundle</packaging> + <name>Reporting Implementation</name> + <dependencies> + <dependency> + <groupId>net.sf.taverna.t2.core</groupId> + <artifactId>workflowmodel-api</artifactId> + <version>${t2.core.version}</version> + </dependency> + <dependency> + <groupId>net.sf.taverna.t2.ui-api</groupId> + <artifactId>report-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>net.sf.taverna.t2.ui-api</groupId> + <artifactId>file-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>net.sf.taverna.t2.ui-api</groupId> + <artifactId>edits-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>uk.org.taverna.configuration</groupId> + <artifactId>taverna-configuration-api</artifactId> + <version>${taverna.configuration.version}</version> + </dependency> + </dependencies> +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/config/impl/ReportManagerConfigurationImpl.java ---------------------------------------------------------------------- diff --git a/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/config/impl/ReportManagerConfigurationImpl.java b/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/config/impl/ReportManagerConfigurationImpl.java new file mode 100644 index 0000000..b5986b5 --- /dev/null +++ b/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/config/impl/ReportManagerConfigurationImpl.java @@ -0,0 +1,71 @@ +/** + * + */ +package net.sf.taverna.t2.workbench.report.config.impl; + +import java.util.HashMap; +import java.util.Map; + +import uk.org.taverna.configuration.AbstractConfigurable; +import uk.org.taverna.configuration.ConfigurationManager; + +import net.sf.taverna.t2.workbench.report.config.ReportManagerConfiguration; +import net.sf.taverna.t2.workflowmodel.health.RemoteHealthChecker; + +/** + * @author alanrw + * + */ +public final class ReportManagerConfigurationImpl extends AbstractConfigurable implements ReportManagerConfiguration { + + private static final int DEFAULT_TIMEOUT = 10; + + private Map<String, String> defaultPropertyMap; + + public ReportManagerConfigurationImpl(ConfigurationManager configurationManager) { + super(configurationManager); + } + + public String getCategory() { + return "general"; + } + + public Map<String, String> getDefaultPropertyMap() { + + if (defaultPropertyMap == null) { + defaultPropertyMap = new HashMap<String, String>(); + defaultPropertyMap.put(TIMEOUT, Integer.toString(DEFAULT_TIMEOUT)); + defaultPropertyMap.put(ON_EDIT, QUICK_CHECK); + defaultPropertyMap.put(ON_OPEN, QUICK_CHECK); + defaultPropertyMap.put(BEFORE_RUN, FULL_CHECK); + defaultPropertyMap.put(QUERY_BEFORE_RUN, ERRORS_OR_WARNINGS); + defaultPropertyMap.put(REPORT_EXPIRATION, Integer.toString(DEFAULT_REPORT_EXPIRATION)); + } + return defaultPropertyMap; + } + + public String getDisplayName() { + return "Validation report"; + } + + public String getFilePrefix() { + return "ReportManager"; + } + + public String getUUID() { + return "F86378E5-0EC4-4DE9-8A55-6098595413DC"; + } + + @Override + public void applySettings() { + RemoteHealthChecker.setTimeoutInSeconds(Integer.parseInt(this.getProperty(TIMEOUT))); + } + + public void setProperty(String key, String value) { + super.setProperty(key, value); + if (key.equals(TIMEOUT)) { + applySettings(); + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/impl/ReportManagerImpl.java ---------------------------------------------------------------------- diff --git a/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/impl/ReportManagerImpl.java b/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/impl/ReportManagerImpl.java new file mode 100644 index 0000000..825efee --- /dev/null +++ b/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/impl/ReportManagerImpl.java @@ -0,0 +1,564 @@ +/** + * + */ +package net.sf.taverna.t2.workbench.report.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; + +import net.sf.taverna.t2.lang.observer.MultiCaster; +import net.sf.taverna.t2.lang.observer.Observable; +import net.sf.taverna.t2.lang.observer.Observer; +import net.sf.taverna.t2.visit.HierarchyTraverser; +import net.sf.taverna.t2.visit.VisitKind; +import net.sf.taverna.t2.visit.VisitReport; +import net.sf.taverna.t2.visit.VisitReport.Status; +import net.sf.taverna.t2.visit.Visitor; +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.ClosedDataflowEvent; +import net.sf.taverna.t2.workbench.file.events.FileManagerEvent; +import net.sf.taverna.t2.workbench.file.events.SetCurrentDataflowEvent; +import net.sf.taverna.t2.workbench.report.DataflowReportEvent; +import net.sf.taverna.t2.workbench.report.FailedEntityKind; +import net.sf.taverna.t2.workbench.report.IncompleteDataflowKind; +import net.sf.taverna.t2.workbench.report.InvalidDataflowKind; +import net.sf.taverna.t2.workbench.report.ReportManager; +import net.sf.taverna.t2.workbench.report.ReportManagerEvent; +import net.sf.taverna.t2.workbench.report.UnresolvedOutputKind; +import net.sf.taverna.t2.workbench.report.UnsatisfiedEntityKind; +import net.sf.taverna.t2.workbench.report.config.ReportManagerConfiguration; +import net.sf.taverna.t2.workflowmodel.Dataflow; +import net.sf.taverna.t2.workflowmodel.DataflowValidationReport; +import net.sf.taverna.t2.workflowmodel.Processor; + +import org.apache.log4j.Logger; + +/** + * @author Alan R Williams + * + */ +public class ReportManagerImpl implements Observable<ReportManagerEvent>, ReportManager { + + private static final long MAX_AGE_OUTDATED_MILLIS = 1 * 60 * 60 * 1000; // 1 hour + private static Logger logger = Logger.getLogger(ReportManagerImpl.class); + + private ReportManagerConfiguration reportManagerConfiguration; + private HierarchyTraverser traverser = null; + private Map<Dataflow, Map<Object, Set<VisitReport>>> reportMap = Collections + .synchronizedMap(new WeakHashMap<Dataflow, Map<Object, Set<VisitReport>>>());; + private Map<Dataflow, Map<Object, Status>> statusMap = Collections + .synchronizedMap(new WeakHashMap<Dataflow, Map<Object, Status>>()); + private Map<Dataflow, Map<Object, String>> summaryMap = Collections + .synchronizedMap(new WeakHashMap<Dataflow, Map<Object, String>>()); + private Map<Dataflow, Long> lastCheckedMap = Collections + .synchronizedMap(new WeakHashMap<Dataflow, Long>()); + private Map<Dataflow, Long> lastFullCheckedMap = Collections + .synchronizedMap(new WeakHashMap<Dataflow, Long>()); + private Map<Dataflow, String> lastFullCheckedDataflowIdMap = Collections + .synchronizedMap(new WeakHashMap<Dataflow, String>()); + + private EditManager editManager; + private FileManager fileManager; + + // private Set<Visitor<?>> visitors; + + protected ReportManagerImpl(EditManager editManager, FileManager fileManager, + Set<Visitor<?>> visitors, ReportManagerConfiguration reportManagerConfiguration) + throws IllegalStateException { + this.editManager = editManager; + this.fileManager = fileManager; + this.reportManagerConfiguration = reportManagerConfiguration; + // this.visitors = visitors; + traverser = new HierarchyTraverser(visitors); + ReportManagerFileObserver fileObserver = new ReportManagerFileObserver(); + fileManager.addObserver(fileObserver); + addEditObserver(); + reportManagerConfiguration.applySettings(); + } + + private void addEditObserver() { + synchronized (editManager) { + List<Observer<EditManagerEvent>> currentObservers = editManager.getObservers(); + for (Observer<EditManagerEvent> o : currentObservers) { + editManager.removeObserver(o); + } + editManager.addObserver(new ReportManagerEditObserver()); + for (Observer<EditManagerEvent> o : currentObservers) { + editManager.addObserver(o); + } + } + } + + /* + * (non-Javadoc) + * + * @see + * net.sf.taverna.t2.workbench.report.ReportManagerI#updateReport(net.sf.taverna.t2.workflowmodel + * .Dataflow, boolean, boolean) + */ + @Override + public void updateReport(Dataflow d, boolean includeTimeConsuming, boolean remember) { + Set<VisitReport> oldTimeConsumingReports = null; + long time = System.currentTimeMillis(); + long expiration = Integer.parseInt(reportManagerConfiguration + .getProperty(ReportManagerConfiguration.REPORT_EXPIRATION)) * 60 * 1000; + if (remember && !includeTimeConsuming + && ((expiration == 0) || ((time - getLastFullCheckedTime(d)) < expiration))) { + oldTimeConsumingReports = getTimeConsumingReports(d); + } + Map<Object, Set<VisitReport>> reportsEntry = new HashMap<Object, Set<VisitReport>>(); + Map<Object, Status> statusEntry = new HashMap<Object, Status>(); + Map<Object, String> summaryEntry = new HashMap<Object, String>(); + reportMap.put(d, reportsEntry); + statusMap.put(d, statusEntry); + summaryMap.put(d, summaryEntry); + validateDataflow(d, reportsEntry, statusEntry, summaryEntry); + + Set<VisitReport> newReports = new HashSet<VisitReport>(); + traverser.traverse(d, new ArrayList<Object>(), newReports, includeTimeConsuming); + for (VisitReport vr : newReports) { + addReport(reportsEntry, statusEntry, summaryEntry, vr); + } + if (oldTimeConsumingReports != null) { + for (VisitReport vr : oldTimeConsumingReports) { + addReport(reportsEntry, statusEntry, summaryEntry, vr); + } + } + time = System.currentTimeMillis(); + lastCheckedMap.put(d, time); + if (includeTimeConsuming) { + lastFullCheckedMap.put(d, time); + lastFullCheckedDataflowIdMap.put(d, d.getIdentifier()); + } + multiCaster.notify(new DataflowReportEvent(d)); + } + + private void updateObjectReportInternal(Dataflow d, Object o) { + Map<Object, Set<VisitReport>> reportsEntry = reportMap.get(d); + Map<Object, Status> statusEntry = statusMap.get(d); + Map<Object, String> summaryEntry = summaryMap.get(d); + if (reportsEntry == null) { + logger.error("Attempt to update reports on an object in a dataflow that has not been checked"); + reportsEntry = new HashMap<Object, Set<VisitReport>>(); + statusEntry = new HashMap<Object, Status>(); + summaryEntry = new HashMap<Object, String>(); + reportMap.put(d, reportsEntry); + statusMap.put(d, statusEntry); + summaryMap.put(d, summaryEntry); + } else { + reportsEntry.remove(o); + statusEntry.remove(o); + summaryEntry.remove(o); + } + // Assume o is directly inside d + List<Object> ancestry = new ArrayList<Object>(); + ancestry.add(d); + Set<VisitReport> newReports = new HashSet<VisitReport>(); + traverser.traverse(o, ancestry, newReports, true); + for (VisitReport vr : newReports) { + addReport(reportsEntry, statusEntry, summaryEntry, vr); + } + } + + /* + * (non-Javadoc) + * + * @see + * net.sf.taverna.t2.workbench.report.ReportManagerI#updateObjectSetReport(net.sf.taverna.t2 + * .workflowmodel.Dataflow, java.util.Set) + */ + @Override + public void updateObjectSetReport(Dataflow d, Set<Object> objects) { + for (Object o : objects) { + updateObjectReportInternal(d, o); + } + multiCaster.notify(new DataflowReportEvent(d)); + } + + /* + * (non-Javadoc) + * + * @see net.sf.taverna.t2.workbench.report.ReportManagerI#updateObjectReport(net.sf.taverna.t2. + * workflowmodel.Dataflow, java.lang.Object) + */ + @Override + public void updateObjectReport(Dataflow d, Object o) { + updateObjectReportInternal(d, o); + multiCaster.notify(new DataflowReportEvent(d)); + } + + private Set<VisitReport> getTimeConsumingReports(Dataflow d) { + Set<VisitReport> result = new HashSet<VisitReport>(); + Map<Object, Set<VisitReport>> currentReports = getReports(d); + if (currentReports != null) { + for (Object o : currentReports.keySet()) { + for (VisitReport vr : currentReports.get(o)) { + if (vr.wasTimeConsuming()) { + result.add(vr); + } + } + } + } + return result; + } + + private void removeReport(Dataflow d) { + reportMap.remove(d); + statusMap.remove(d); + summaryMap.remove(d); + } + + private void addReport(Map<Object, Set<VisitReport>> reports, Map<Object, Status> statusEntry, + Map<Object, String> summaryEntry, VisitReport newReport) { + if (newReport.getCheckTime() == 0) { + newReport.setCheckTime(System.currentTimeMillis()); + } + Object subject = newReport.getSubject(); + Set<VisitReport> currentReports = reports.get(subject); + Status newReportStatus = newReport.getStatus(); + if (currentReports == null) { + currentReports = new HashSet<VisitReport>(); + reports.put(subject, currentReports); + statusEntry.put(subject, newReportStatus); + summaryEntry.put(subject, newReport.getMessage()); + } else { + Status currentStatus = statusEntry.get(subject); + if (currentStatus.compareTo(newReportStatus) < 0) { + statusEntry.put(subject, newReportStatus); + summaryEntry.put(subject, newReport.getMessage()); + } else if (currentStatus.compareTo(newReportStatus) == 0) { + if (currentStatus.equals(Status.WARNING)) { + summaryEntry.put(subject, "Multiple warnings"); + } else if (currentStatus.equals(Status.SEVERE)) { + summaryEntry.put(subject, "Multiple errors"); + } + } + } + currentReports.add(newReport); + } + + private void validateDataflow(Dataflow d, Map<Object, Set<VisitReport>> reportsEntry, + Map<Object, Status> statusEntry, Map<Object, String> summaryEntry) { + DataflowValidationReport validationReport = d.checkValidity(); + if (validationReport.isWorkflowIncomplete()) { + addReport(reportsEntry, statusEntry, summaryEntry, new VisitReport( + IncompleteDataflowKind.getInstance(), d, "Incomplete workflow", + IncompleteDataflowKind.INCOMPLETE_DATAFLOW, VisitReport.Status.SEVERE)); + } else if (!validationReport.isValid()) { + addReport(reportsEntry, statusEntry, summaryEntry, + new VisitReport(InvalidDataflowKind.getInstance(), d, "Invalid workflow", + InvalidDataflowKind.INVALID_DATAFLOW, VisitReport.Status.SEVERE)); + } + fillInReport(reportsEntry, statusEntry, summaryEntry, validationReport); + } + + private void fillInReport(Map<Object, Set<VisitReport>> reportsEntry, + Map<Object, Status> statusEntry, Map<Object, String> summaryEntry, + DataflowValidationReport report) { + for (Object o : report.getUnresolvedOutputs()) { + addReport(reportsEntry, statusEntry, summaryEntry, + new VisitReport(UnresolvedOutputKind.getInstance(), o, + "Invalid workflow output", UnresolvedOutputKind.OUTPUT, + VisitReport.Status.SEVERE)); + } + for (Object o : report.getFailedEntities()) { + addReport(reportsEntry, statusEntry, summaryEntry, + new VisitReport(FailedEntityKind.getInstance(), o, + "Mismatch of input list depths", FailedEntityKind.FAILED_ENTITY, + VisitReport.Status.SEVERE)); + } + for (Object o : report.getUnsatisfiedEntities()) { + addReport(reportsEntry, statusEntry, summaryEntry, new VisitReport( + UnsatisfiedEntityKind.getInstance(), o, "Unknown prior list depth", + UnsatisfiedEntityKind.UNSATISFIED_ENTITY, VisitReport.Status.SEVERE)); + } + // for (DataflowValidationReport subReport : report.getInvalidDataflows().values()) { + // fillInReport(descriptionMap, subReport); + // } + } + + /* + * (non-Javadoc) + * + * @see + * net.sf.taverna.t2.workbench.report.ReportManagerI#getReports(net.sf.taverna.t2.workflowmodel + * .Dataflow, java.lang.Object) + */ + @Override + public Set<VisitReport> getReports(Dataflow d, Object object) { + Set<VisitReport> result = new HashSet<VisitReport>(); + Map<Object, Set<VisitReport>> objectReports = reportMap.get(d); + if (objectReports != null) { + Set<Object> objects = new HashSet<Object>(); + objects.add(object); + if (object instanceof Processor) { + objects.addAll(((Processor) object).getActivityList()); + } + for (Object o : objects) { + if (objectReports.containsKey(o)) { + result.addAll(objectReports.get(o)); + } + } + } + return result; + } + + /* + * (non-Javadoc) + * + * @see + * net.sf.taverna.t2.workbench.report.ReportManagerI#getReports(net.sf.taverna.t2.workflowmodel + * .Dataflow) + */ + @Override + public Map<Object, Set<VisitReport>> getReports(Dataflow d) { + return reportMap.get(d); + } + + /* + * (non-Javadoc) + * + * @see net.sf.taverna.t2.workbench.report.ReportManagerI#isStructurallySound(net.sf.taverna.t2. + * workflowmodel.Dataflow) + */ + @Override + public boolean isStructurallySound(Dataflow d) { + Map<Object, Set<VisitReport>> objectReports = reportMap.get(d); + if (objectReports == null) { + return false; + } + for (Set<VisitReport> visitReportSet : objectReports.values()) { + for (VisitReport vr : visitReportSet) { + if (vr.getStatus().equals(Status.SEVERE)) { + VisitKind vk = vr.getKind(); + if ((vk instanceof IncompleteDataflowKind) + || (vk instanceof InvalidDataflowKind) + || (vk instanceof UnresolvedOutputKind) + || (vk instanceof FailedEntityKind) + || (vk instanceof UnsatisfiedEntityKind)) { + return false; + } + } + } + } + return true; + } + + /* + * (non-Javadoc) + * + * @see + * net.sf.taverna.t2.workbench.report.ReportManagerI#getStatus(net.sf.taverna.t2.workflowmodel + * .Dataflow) + */ + @Override + public Status getStatus(Dataflow d) { + Map<Object, Set<VisitReport>> objectReports = reportMap.get(d); + if (objectReports == null) { + return Status.OK; + } + Status currentStatus = Status.OK; + for (Set<VisitReport> visitReportSet : objectReports.values()) { + for (VisitReport vr : visitReportSet) { + Status status = vr.getStatus(); + if (status.compareTo(currentStatus) > 0) { + currentStatus = status; + } + if (currentStatus.equals(Status.SEVERE)) { + return currentStatus; + } + } + } + return currentStatus; + } + + /* + * (non-Javadoc) + * + * @see + * net.sf.taverna.t2.workbench.report.ReportManagerI#getStatus(net.sf.taverna.t2.workflowmodel + * .Dataflow, java.lang.Object) + */ + @Override + public Status getStatus(Dataflow d, Object object) { + Status result = Status.OK; + Map<Object, Status> statusEntry = statusMap.get(d); + if (statusEntry != null) { + Status value = statusEntry.get(object); + if (value != null) { + result = value; + } + } + return result; + } + + /* + * (non-Javadoc) + * + * @see net.sf.taverna.t2.workbench.report.ReportManagerI#getSummaryMessage(net.sf.taverna.t2. + * workflowmodel.Dataflow, java.lang.Object) + */ + @Override + public String getSummaryMessage(Dataflow d, Object object) { + String result = null; + if (!getStatus(d, object).equals(Status.OK)) { + Map<Object, String> summaryEntry = summaryMap.get(d); + if (summaryEntry != null) { + result = summaryEntry.get(object); + } + } + return result; + } + + /* + * (non-Javadoc) + * + * @see net.sf.taverna.t2.workbench.report.ReportManagerI#getLastCheckedTime(net.sf.taverna.t2. + * workflowmodel.Dataflow) + */ + @Override + public long getLastCheckedTime(Dataflow d) { + Long l = lastCheckedMap.get(d); + if (l == null) { + return 0; + } else { + return l.longValue(); + } + } + + /* + * (non-Javadoc) + * + * @see + * net.sf.taverna.t2.workbench.report.ReportManagerI#getLastFullCheckedTime(net.sf.taverna.t2 + * .workflowmodel.Dataflow) + */ + @Override + public long getLastFullCheckedTime(Dataflow d) { + Long l = lastFullCheckedMap.get(d); + if (l == null) { + return 0; + } else { + return l.longValue(); + } + } + + /** + * @author alanrw + * + */ + public class ReportManagerFileObserver implements Observer<FileManagerEvent> { + + public void notify(Observable<FileManagerEvent> sender, FileManagerEvent message) + throws Exception { + String onOpen = reportManagerConfiguration.getProperty( + ReportManagerConfiguration.ON_OPEN); + if (message instanceof ClosedDataflowEvent) { + ReportManagerImpl.this.removeReport(((ClosedDataflowEvent) message).getDataflow()); + } else if (message instanceof SetCurrentDataflowEvent) { + Dataflow dataflow = ((SetCurrentDataflowEvent) message).getDataflow(); + if (!reportMap.containsKey(dataflow)) { + if (!onOpen.equals(ReportManagerConfiguration.NO_CHECK)) { + updateReport(dataflow, + onOpen.equals(ReportManagerConfiguration.FULL_CHECK), true); + } else { + ReportManagerImpl.this.multiCaster + .notify(new DataflowReportEvent(dataflow)); + } + } else { + ReportManagerImpl.this.multiCaster.notify(new DataflowReportEvent(dataflow)); + } + } + } + + } + + private MultiCaster<ReportManagerEvent> multiCaster = new MultiCaster<ReportManagerEvent>(this); + + /* + * (non-Javadoc) + * + * @see + * net.sf.taverna.t2.workbench.report.ReportManagerI#addObserver(net.sf.taverna.t2.lang.observer + * .Observer) + */ + @Override + public void addObserver(Observer<ReportManagerEvent> observer) { + multiCaster.addObserver(observer); + } + + /* + * (non-Javadoc) + * + * @see net.sf.taverna.t2.workbench.report.ReportManagerI#getObservers() + */ + @Override + public List<Observer<ReportManagerEvent>> getObservers() { + return multiCaster.getObservers(); + } + + /* + * (non-Javadoc) + * + * @see + * net.sf.taverna.t2.workbench.report.ReportManagerI#removeObserver(net.sf.taverna.t2.lang.observer + * .Observer) + */ + @Override + public void removeObserver(Observer<ReportManagerEvent> observer) { + multiCaster.removeObserver(observer); + } + + /* + * (non-Javadoc) + * + * @see net.sf.taverna.t2.workbench.report.ReportManagerI#isReportOutdated(net.sf.taverna.t2. + * workflowmodel.Dataflow) + */ + @Override + public boolean isReportOutdated(Dataflow dataflow) { + String lastCheckedId = lastFullCheckedDataflowIdMap.get(dataflow); + Long lastCheck = lastFullCheckedMap.get(dataflow); + if (lastCheckedId == null || lastCheck == null) { + // Unknown, so outdated + return true; + } + if (!lastCheckedId.equals(dataflow.getIdentifier())) { + // Workflow changed, so outdaeted + return true; + } + long now = System.currentTimeMillis(); + long age = now - lastCheck; + // Outdated if it is older than the maximum + return age > MAX_AGE_OUTDATED_MILLIS; + } + + public class ReportManagerEditObserver implements Observer<EditManagerEvent> { + public void notify(Observable<EditManagerEvent> sender, EditManagerEvent message) + throws Exception { + String onEdit = reportManagerConfiguration + .getProperty(ReportManagerConfiguration.ON_EDIT); + Dataflow dataflow = fileManager.getCurrentDataflow(); + if (message instanceof AbstractDataflowEditEvent) { + AbstractDataflowEditEvent adee = (AbstractDataflowEditEvent) message; + if (adee.getDataFlow().equals(dataflow)) { + if (onEdit.equals(ReportManagerConfiguration.QUICK_CHECK)) { + updateReport(dataflow, false, true); + } else if (onEdit.equals(ReportManagerConfiguration.FULL_CHECK)) { + updateReport(dataflow, true, true); + } + } + } + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context-osgi.xml ---------------------------------------------------------------------- diff --git a/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context-osgi.xml b/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context-osgi.xml new file mode 100644 index 0000000..31c7432 --- /dev/null +++ b/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context-osgi.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:beans="http://www.springframework.org/schema/beans" + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/osgi + http://www.springframework.org/schema/osgi/spring-osgi.xsd"> + + <!-- <service ref="ProcessorFragilityChecker" interface="net.sf.taverna.t2.visit.fragility.FragilityChecker" /> --> + + <!-- <service ref="FragilityCheck" interface="net.sf.taverna.t2.visit.VisitKind" /> --> + + <service ref="ReportManagerImpl" interface="net.sf.taverna.t2.workbench.report.ReportManager" /> + + <service ref="ReportManagerConfiguration" interface="net.sf.taverna.t2.workbench.report.config.ReportManagerConfiguration" /> + + <reference id="editManager" interface="net.sf.taverna.t2.workbench.edits.EditManager" /> + <reference id="fileManager" interface="net.sf.taverna.t2.workbench.file.FileManager" /> + <reference id="configurationManager" interface="uk.org.taverna.configuration.ConfigurationManager" /> + + <set id="visitors" interface="net.sf.taverna.t2.visit.Visitor" cardinality="0..N" /> + +</beans:beans> http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context.xml ---------------------------------------------------------------------- diff --git a/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context.xml b/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context.xml new file mode 100644 index 0000000..966d50d --- /dev/null +++ b/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd"> + + <!-- <bean id="ProcessorFragilityChecker" class="net.sf.taverna.t2.visit.fragility.impl.ProcessorFragilityChecker" /> --> + + <!-- <bean id="FragilityCheck" class="net.sf.taverna.t2.visit.fragility.impl.FragilityCheck" /> --> + + <bean id="ReportManagerImpl" class="net.sf.taverna.t2.workbench.report.impl.ReportManagerImpl"> + <constructor-arg ref="editManager" /> + <constructor-arg ref="fileManager" /> + <constructor-arg ref="visitors" /> + <constructor-arg ref="ReportManagerConfiguration"/> + </bean> + + <bean id="ReportManagerConfiguration" class="net.sf.taverna.t2.workbench.report.config.impl.ReportManagerConfigurationImpl"> + <constructor-arg ref="configurationManager"/> + </bean> + +</beans> http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-selection-impl/pom.xml ---------------------------------------------------------------------- diff --git a/taverna-workbench-selection-impl/pom.xml b/taverna-workbench-selection-impl/pom.xml new file mode 100644 index 0000000..cb6cbcb --- /dev/null +++ b/taverna-workbench-selection-impl/pom.xml @@ -0,0 +1,35 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>net.sf.taverna.t2</groupId> + <artifactId>ui-impl</artifactId> + <version>2.0-SNAPSHOT</version> + </parent> + <groupId>net.sf.taverna.t2.ui-impl</groupId> + <artifactId>selection-impl</artifactId> + <packaging>bundle</packaging> + <name>Selection Implementation</name> + <dependencies> + <dependency> + <groupId>net.sf.taverna.t2.ui-api</groupId> + <artifactId>edits-api</artifactId> + <version>${t2.ui.api.version}</version> + </dependency> + <dependency> + <groupId>net.sf.taverna.t2.ui-api</groupId> + <artifactId>file-api</artifactId> + <version>${t2.ui.api.version}</version> + </dependency> + <dependency> + <groupId>net.sf.taverna.t2.ui-api</groupId> + <artifactId>selection-api</artifactId> + <version>${t2.ui.api.version}</version> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.compendium</artifactId> + <version>${osgi.core.version}</version> + </dependency> + </dependencies> +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/DataflowSelectionModelImpl.java ---------------------------------------------------------------------- diff --git a/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/DataflowSelectionModelImpl.java b/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/DataflowSelectionModelImpl.java new file mode 100644 index 0000000..09d6f71 --- /dev/null +++ b/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/DataflowSelectionModelImpl.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * 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.selection.impl; + +import static net.sf.taverna.t2.workbench.selection.events.DataflowSelectionMessage.Type.ADDED; +import static net.sf.taverna.t2.workbench.selection.events.DataflowSelectionMessage.Type.REMOVED; + +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import net.sf.taverna.t2.lang.observer.MultiCaster; +import net.sf.taverna.t2.lang.observer.Observer; +import net.sf.taverna.t2.workbench.selection.DataflowSelectionModel; +import net.sf.taverna.t2.workbench.selection.events.DataflowSelectionMessage; + +/** + * Default implementation of a <code>DataflowSelectionModel</code>. + * + * @author David Withers + */ +public class DataflowSelectionModelImpl implements DataflowSelectionModel { + private MultiCaster<DataflowSelectionMessage> multiCaster; + private Set<Object> selection = new TreeSet<>(new Comparator<Object>() { + @Override + public int compare(Object o1, Object o2) { + if (o1 == o2) + return 0; + return o1.hashCode() - o2.hashCode(); + } + }); + + /** + * Constructs a new instance of DataflowSelectionModelImpl. + */ + public DataflowSelectionModelImpl() { + multiCaster = new MultiCaster<>(this); + } + + @Override + public void addSelection(Object element) { + if (element != null) { + if (!selection.contains(element)) { + clearSelection(); + selection.add(element); + multiCaster.notify(new DataflowSelectionMessage(ADDED, element)); + } + } + } + + @Override + public void clearSelection() { + for (Object element : new HashSet<>(selection)) + removeSelection(element); + } + + @Override + public Set<Object> getSelection() { + return new HashSet<>(selection); + } + + @Override + public void removeSelection(Object element) { + if (element != null && selection.remove(element)) + multiCaster.notify(new DataflowSelectionMessage(REMOVED, element)); + } + + @Override + public void setSelection(Set<Object> elements) { + if (elements == null) { + clearSelection(); + return; + } + Set<Object> newSelection = new HashSet<>(elements); + for (Object element : new HashSet<>(selection)) + if (!newSelection.remove(element)) + removeSelection(element); + for (Object element : newSelection) + addSelection(element); + } + + @Override + public void addObserver(Observer<DataflowSelectionMessage> observer) { + multiCaster.addObserver(observer); + } + + @Override + public List<Observer<DataflowSelectionMessage>> getObservers() { + return multiCaster.getObservers(); + } + + @Override + public void removeObserver(Observer<DataflowSelectionMessage> observer) { + multiCaster.removeObserver(observer); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/SelectionManagerImpl.java ---------------------------------------------------------------------- diff --git a/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/SelectionManagerImpl.java b/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/SelectionManagerImpl.java new file mode 100644 index 0000000..2e86f1a --- /dev/null +++ b/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/SelectionManagerImpl.java @@ -0,0 +1,367 @@ +/******************************************************************************* + * 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.selection.impl; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import net.sf.taverna.t2.lang.observer.MultiCaster; +import net.sf.taverna.t2.lang.observer.Observable; +import net.sf.taverna.t2.lang.observer.Observer; +import net.sf.taverna.t2.workbench.edits.CompoundEdit; +import net.sf.taverna.t2.workbench.edits.Edit; +import net.sf.taverna.t2.workbench.edits.EditManager; +import net.sf.taverna.t2.workbench.edits.EditManager.DataFlowUndoEvent; +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.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.SetCurrentDataflowEvent; +import net.sf.taverna.t2.workbench.selection.DataflowSelectionModel; +import net.sf.taverna.t2.workbench.selection.SelectionManager; +import net.sf.taverna.t2.workbench.selection.events.DataflowSelectionMessage; +import net.sf.taverna.t2.workbench.selection.events.PerspectiveSelectionEvent; +import net.sf.taverna.t2.workbench.selection.events.ProfileSelectionEvent; +import net.sf.taverna.t2.workbench.selection.events.SelectionManagerEvent; +import net.sf.taverna.t2.workbench.selection.events.WorkflowBundleSelectionEvent; +import net.sf.taverna.t2.workbench.selection.events.WorkflowRunSelectionEvent; +import net.sf.taverna.t2.workbench.selection.events.WorkflowSelectionEvent; +import net.sf.taverna.t2.workbench.ui.zaria.PerspectiveSPI; +import net.sf.taverna.t2.workflow.edits.AddChildEdit; + +import org.apache.log4j.Logger; + +import uk.org.taverna.scufl2.api.container.WorkflowBundle; +import uk.org.taverna.scufl2.api.core.Processor; +import uk.org.taverna.scufl2.api.core.Workflow; +import uk.org.taverna.scufl2.api.port.InputWorkflowPort; +import uk.org.taverna.scufl2.api.port.OutputWorkflowPort; +import uk.org.taverna.scufl2.api.profiles.Profile; + +/** + * Implementation of the {@link SelectionManager}. + * + * @author David Withers + */ +public class SelectionManagerImpl implements SelectionManager { + private static final String RESULTS_PERSPECTIVE_ID = "net.sf.taverna.t2.ui.perspectives.results.ResultsPerspective"; + + private static final String DESIGN_PERSPECTIVE_ID = "net.sf.taverna.t2.ui.perspectives.design.DesignPerspective"; + + private static final Logger logger = Logger.getLogger(SelectionManagerImpl.class); + + private WorkflowBundle selectedWorkflowBundle; + private Map<WorkflowBundle, DataflowSelectionModel> workflowSelectionModels = new IdentityHashMap<>(); + private Map<WorkflowBundle, Workflow> selectedWorkflows = new IdentityHashMap<>(); + private Map<WorkflowBundle, Profile> selectedProfiles = new IdentityHashMap<>(); + private String selectedWorkflowRun; + private Map<String, DataflowSelectionModel> workflowRunSelectionModels = new HashMap<>(); + private PerspectiveSPI selectedPerspective; + private MultiCaster<SelectionManagerEvent> observers = new MultiCaster<>(this); + private FileManager fileManager; + private List<PerspectiveSPI> perspectives; + + @Override + public DataflowSelectionModel getDataflowSelectionModel(WorkflowBundle dataflow) { + DataflowSelectionModel selectionModel; + synchronized (workflowSelectionModels) { + selectionModel = workflowSelectionModels.get(dataflow); + if (selectionModel == null) { + selectionModel = new DataflowSelectionModelImpl(); + workflowSelectionModels.put(dataflow, selectionModel); + } + } + return selectionModel; + } + + @Override + public WorkflowBundle getSelectedWorkflowBundle() { + return selectedWorkflowBundle; + } + + @Override + public void setSelectedWorkflowBundle(WorkflowBundle workflowBundle) { + setSelectedWorkflowBundle(workflowBundle, true); + } + + private void setSelectedWorkflowBundle(WorkflowBundle workflowBundle, boolean notifyFileManager) { + if (workflowBundle == null || workflowBundle == selectedWorkflowBundle) + return; + if (notifyFileManager) { + fileManager.setCurrentDataflow(workflowBundle); + return; + } + if (selectedWorkflows.get(workflowBundle) == null) + selectedWorkflows.put(workflowBundle, + workflowBundle.getMainWorkflow()); + if (selectedProfiles.get(workflowBundle) == null) + selectedProfiles.put(workflowBundle, + workflowBundle.getMainProfile()); + SelectionManagerEvent selectionManagerEvent = new WorkflowBundleSelectionEvent( + selectedWorkflowBundle, workflowBundle); + selectedWorkflowBundle = workflowBundle; + notify(selectionManagerEvent); + selectDesignPerspective(); + } + + private void removeWorkflowBundle(WorkflowBundle dataflow) { + synchronized (workflowSelectionModels) { + DataflowSelectionModel selectionModel = workflowSelectionModels.remove(dataflow); + if (selectionModel != null) + for (Observer<DataflowSelectionMessage> observer : selectionModel.getObservers()) + selectionModel.removeObserver(observer); + } + synchronized (selectedWorkflows) { + selectedWorkflows.remove(dataflow); + } + synchronized (selectedProfiles) { + selectedProfiles.remove(dataflow); + } + } + + @Override + public Workflow getSelectedWorkflow() { + return selectedWorkflows.get(selectedWorkflowBundle); + } + + @Override + public void setSelectedWorkflow(Workflow workflow) { + if (workflow != null) { + Workflow selectedWorkflow = selectedWorkflows.get(workflow + .getParent()); + if (selectedWorkflow != workflow) { + SelectionManagerEvent selectionManagerEvent = new WorkflowSelectionEvent( + selectedWorkflow, workflow); + selectedWorkflows.put(workflow.getParent(), workflow); + notify(selectionManagerEvent); + } + } + } + + @Override + public Profile getSelectedProfile() { + return selectedProfiles.get(selectedWorkflowBundle); + } + + @Override + public void setSelectedProfile(Profile profile) { + if (profile != null) { + Profile selectedProfile = selectedProfiles.get(profile.getParent()); + if (selectedProfile != profile) { + SelectionManagerEvent selectionManagerEvent = new ProfileSelectionEvent( + selectedProfile, profile); + selectedProfiles.put(profile.getParent(), profile); + notify(selectionManagerEvent); + } + } + } + + @Override + public String getSelectedWorkflowRun() { + return selectedWorkflowRun; + } + + @Override + public void setSelectedWorkflowRun(String workflowRun) { + if ((selectedWorkflowRun == null && workflowRun != null) + || !selectedWorkflowRun.equals(workflowRun)) { + SelectionManagerEvent selectionManagerEvent = new WorkflowRunSelectionEvent( + selectedWorkflowRun, workflowRun); + selectedWorkflowRun = workflowRun; + notify(selectionManagerEvent); + selectResultsPerspective(); + } + } + + @Override + public DataflowSelectionModel getWorkflowRunSelectionModel(String workflowRun) { + DataflowSelectionModel selectionModel; + synchronized (workflowRunSelectionModels) { + selectionModel = workflowRunSelectionModels.get(workflowRun); + if (selectionModel == null) { + selectionModel = new DataflowSelectionModelImpl(); + workflowRunSelectionModels.put(workflowRun, selectionModel); + } + } + return selectionModel; + } + + @SuppressWarnings("unused") + private void removeWorkflowRun(String workflowRun) { + synchronized (workflowRunSelectionModels) { + DataflowSelectionModel selectionModel = workflowRunSelectionModels + .remove(workflowRun); + if (selectionModel != null) + for (Observer<DataflowSelectionMessage> observer : selectionModel + .getObservers()) + selectionModel.removeObserver(observer); + } + } + + @Override + public PerspectiveSPI getSelectedPerspective() { + return selectedPerspective; + } + + @Override + public void setSelectedPerspective(PerspectiveSPI perspective) { + if (selectedPerspective != perspective) { + SelectionManagerEvent selectionManagerEvent = new PerspectiveSelectionEvent( + selectedPerspective, perspective); + selectedPerspective = perspective; + notify(selectionManagerEvent); + } + } + + private void selectDesignPerspective() { + for (PerspectiveSPI perspective : perspectives) + if (DESIGN_PERSPECTIVE_ID.equals(perspective.getID())) { + setSelectedPerspective(perspective); + break; + } + } + + private void selectResultsPerspective() { + for (PerspectiveSPI perspective : perspectives) + if (RESULTS_PERSPECTIVE_ID.equals(perspective.getID())) { + setSelectedPerspective(perspective); + break; + } + } + + @Override + public void addObserver(Observer<SelectionManagerEvent> observer) { + synchronized (observers) { + WorkflowBundle selectedWorkflowBundle = getSelectedWorkflowBundle(); + Workflow selectedWorkflow = getSelectedWorkflow(); + Profile selectedProfile = getSelectedProfile(); + String selectedWorkflowRun = getSelectedWorkflowRun(); + PerspectiveSPI selectedPerspective = getSelectedPerspective(); + try { + if (selectedWorkflowBundle != null) + observer.notify(this, new WorkflowBundleSelectionEvent( + null, selectedWorkflowBundle)); + if (selectedWorkflow != null) + observer.notify(this, new WorkflowSelectionEvent(null, + selectedWorkflow)); + if (selectedProfile != null) + observer.notify(this, new ProfileSelectionEvent(null, + selectedProfile)); + if (selectedWorkflowRun != null) + observer.notify(this, new WorkflowRunSelectionEvent(null, + selectedWorkflowRun)); + if (selectedPerspective != null) + observer.notify(this, new PerspectiveSelectionEvent(null, + selectedPerspective)); + } catch (Exception e) { + logger.warn("Could not notify " + observer, e); + } + observers.addObserver(observer); + } + } + + @Override + public void removeObserver(Observer<SelectionManagerEvent> observer) { + observers.removeObserver(observer); + } + + @Override + public List<Observer<SelectionManagerEvent>> getObservers() { + return observers.getObservers(); + } + + public void setFileManager(FileManager fileManager) { + this.fileManager = fileManager; + setSelectedWorkflowBundle(fileManager.getCurrentDataflow()); + fileManager.addObserver(new FileManagerObserver()); + } + + public void setEditManager(EditManager editManager) { + editManager.addObserver(new EditManagerObserver()); + } + + public void setPerspectives(List<PerspectiveSPI> perspectives) { + this.perspectives = perspectives; + } + + public class FileManagerObserver implements Observer<FileManagerEvent> { + @Override + public void notify(Observable<FileManagerEvent> sender, + FileManagerEvent message) throws Exception { + if (message instanceof ClosedDataflowEvent) { + WorkflowBundle workflowBundle = ((ClosedDataflowEvent) message).getDataflow(); + removeWorkflowBundle(workflowBundle); + } else if (message instanceof OpenedDataflowEvent) { + WorkflowBundle workflowBundle = ((OpenedDataflowEvent) message).getDataflow(); + setSelectedWorkflowBundle(workflowBundle, false); + } else if (message instanceof SetCurrentDataflowEvent) { + WorkflowBundle workflowBundle = ((SetCurrentDataflowEvent) message).getDataflow(); + setSelectedWorkflowBundle(workflowBundle, false); + } + } + } + + private class EditManagerObserver implements Observer<EditManagerEvent> { + @Override + public void notify(Observable<EditManagerEvent> sender, EditManagerEvent message) + throws Exception { + Edit<?> edit = message.getEdit(); + considerEdit(edit, message instanceof DataFlowUndoEvent); + } + + private void considerEdit(Edit<?> edit, boolean undoing) { + if (edit instanceof CompoundEdit) { + CompoundEdit compound = (CompoundEdit) edit; + for (Edit<?> e : compound.getChildEdits()) + considerEdit(e, undoing); + } else if (edit instanceof AddChildEdit + && edit.getSubject() instanceof Workflow) { + Workflow subject = (Workflow) edit.getSubject(); + DataflowSelectionModel selectionModel = getDataflowSelectionModel(subject + .getParent()); + Object child = ((AddChildEdit<?>) edit).getChild(); + if (child instanceof Processor + || child instanceof InputWorkflowPort + || child instanceof OutputWorkflowPort) { + if (undoing + && selectionModel.getSelection().contains(child)) + selectionModel.clearSelection(); + else { + Set<Object> selection = new HashSet<>(); + selection.add(child); + selectionModel.setSelection(selection); + } + } + } + } + } + + private void notify(SelectionManagerEvent event) { + synchronized (observers) { + observers.notify(event); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context-osgi.xml ---------------------------------------------------------------------- diff --git a/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context-osgi.xml b/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context-osgi.xml new file mode 100644 index 0000000..19faa00 --- /dev/null +++ b/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context-osgi.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:beans="http://www.springframework.org/schema/beans" + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/osgi + http://www.springframework.org/schema/osgi/spring-osgi.xsd"> + + <service ref="selectionManager" interface="net.sf.taverna.t2.workbench.selection.SelectionManager" /> + + <reference id="editManager" interface="net.sf.taverna.t2.workbench.edits.EditManager" /> + <reference id="fileManager" interface="net.sf.taverna.t2.workbench.file.FileManager" /> + <!-- <reference id="menuManager" interface="net.sf.taverna.t2.ui.menu.MenuManager" /> --> + + <list id="perspectives" interface="net.sf.taverna.t2.workbench.ui.zaria.PerspectiveSPI" cardinality="0..N" /> + +</beans:beans> http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context.xml ---------------------------------------------------------------------- diff --git a/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context.xml b/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context.xml new file mode 100644 index 0000000..84bbff1 --- /dev/null +++ b/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd"> + + <bean id="selectionManager" class="net.sf.taverna.t2.workbench.selection.impl.SelectionManagerImpl" > + <property name="fileManager" ref="fileManager"/> + <property name="editManager" ref="editManager"/> + <property name="perspectives" ref="perspectives"/> + </bean> + +</beans> http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-update-manager/pom.xml ---------------------------------------------------------------------- diff --git a/taverna-workbench-update-manager/pom.xml b/taverna-workbench-update-manager/pom.xml new file mode 100644 index 0000000..c2f2003 --- /dev/null +++ b/taverna-workbench-update-manager/pom.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>net.sf.taverna.t2</groupId> + <artifactId>ui-impl</artifactId> + <version>2.0-SNAPSHOT</version> + </parent> + <groupId>net.sf.taverna.t2.ui-impl</groupId> + <artifactId>update-manager</artifactId> + <version>2.0.1-SNAPSHOT</version> + <packaging>bundle</packaging> + <name>Taverna Workbench Update Manager</name> + <dependencies> + <dependency> + <groupId>net.sf.taverna.t2.ui-api</groupId> + <artifactId>menu-api</artifactId> + <version>${t2.ui.api.version}</version> + </dependency> + <dependency> + <groupId>uk.org.taverna.commons</groupId> + <artifactId>taverna-update-api</artifactId> + <version>${taverna.commons.version}</version> + </dependency> + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/UpdateManagerView.java ---------------------------------------------------------------------- diff --git a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/UpdateManagerView.java b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/UpdateManagerView.java new file mode 100644 index 0000000..6b70101 --- /dev/null +++ b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/UpdateManagerView.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (C) 2013 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.update.impl; + +import java.awt.GridBagLayout; + +import javax.swing.JPanel; + +import uk.org.taverna.commons.update.UpdateManager; + +/** + * @author David Withers + */ +@SuppressWarnings({ "serial", "unused" }) +public class UpdateManagerView extends JPanel { + + private UpdateManager updateManager; + + public UpdateManagerView(UpdateManager updateManager) { + this.updateManager = updateManager; + initialize(); + } + + private void initialize() { + setLayout(new GridBagLayout()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/menu/UpdateMenuAction.java ---------------------------------------------------------------------- diff --git a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/menu/UpdateMenuAction.java b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/menu/UpdateMenuAction.java new file mode 100644 index 0000000..2c1459b --- /dev/null +++ b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/menu/UpdateMenuAction.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (C) 2013 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.update.impl.menu; + +import static javax.swing.JOptionPane.YES_OPTION; +import static javax.swing.JOptionPane.showConfirmDialog; +import static javax.swing.JOptionPane.showMessageDialog; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.net.URI; + +import javax.swing.AbstractAction; +import javax.swing.Action; + +import net.sf.taverna.t2.ui.menu.AbstractMenuAction; + +import org.apache.log4j.Logger; + +import uk.org.taverna.commons.update.UpdateException; +import uk.org.taverna.commons.update.UpdateManager; + +public class UpdateMenuAction extends AbstractMenuAction { + private static final Logger logger = Logger.getLogger(UpdateMenuAction.class); + private static final URI ADVANCED_MENU_URI = URI + .create("http://taverna.sf.net/2008/t2workbench/menu#advanced"); + + private UpdateManager updateManager; + + public UpdateMenuAction() { + super(ADVANCED_MENU_URI, 1000); + } + + @SuppressWarnings("serial") + @Override + protected Action createAction() { + return new AbstractAction("Check for updates") { + @Override + public void actionPerformed(ActionEvent e) { + findUpdates(); + } + }; + } + + public void setUpdateManager(UpdateManager updateManager) { + this.updateManager = updateManager; + } + + private void findUpdates() { + Component parent = null; + try { + if (!areUpdatesAvailable()) { + showMessageDialog(null, "No update available"); + return; + } + if (showConfirmDialog(parent, "Update available. Update Now?") != YES_OPTION) + return; + applyUpdates(); + showMessageDialog(parent, + "Update complete. Restart Taverna to apply update."); + } catch (UpdateException ex) { + showMessageDialog(parent, "Update failed: " + ex.getMessage()); + logger.warn("Update failed", ex); + } + } + + protected boolean areUpdatesAvailable() throws UpdateException { + return updateManager.checkForUpdates(); + } + + protected void applyUpdates() throws UpdateException { + updateManager.update(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/PluginMenuAction.java ---------------------------------------------------------------------- diff --git a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/PluginMenuAction.java b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/PluginMenuAction.java new file mode 100644 index 0000000..e6b4695 --- /dev/null +++ b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/PluginMenuAction.java @@ -0,0 +1,52 @@ +package net.sf.taverna.t2.workbench.updatemanager; + +import static java.awt.event.KeyEvent.VK_F12; +import static javax.swing.KeyStroke.getKeyStroke; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.net.URI; + +import javax.swing.AbstractAction; +import javax.swing.Action; + +import net.sf.taverna.t2.ui.menu.AbstractMenuAction; + +public class PluginMenuAction extends AbstractMenuAction { + private static final String UPDATES_AND_PLUGINS = "Updates and plugins"; + + @SuppressWarnings("serial") + protected class SoftwareUpdates extends AbstractAction { + public SoftwareUpdates() { + super(UPDATES_AND_PLUGINS, null/*UpdatesAvailableIcon.updateRecommendedIcon*/); + putValue(ACCELERATOR_KEY, getKeyStroke(VK_F12, 0)); + } + + @Override + public void actionPerformed(ActionEvent e) { + @SuppressWarnings("unused") + Component parent = null; + if (e.getSource() instanceof Component) { + parent = (Component) e.getSource(); + } + //FIXME this does nothing! + //final PluginManagerFrame pluginManagerUI = new PluginManagerFrame( + // PluginManager.getInstance()); + //if (parent != null) { + // pluginManagerUI.setLocationRelativeTo(parent); + //} + //pluginManagerUI.setVisible(true); + } + } + + public PluginMenuAction() { + super(URI.create("http://taverna.sf.net/2008/t2workbench/menu#advanced"), + 100); + } + + @Override + protected Action createAction() { + //return new SoftwareUpdates(); + return null; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesAvailableMenuAction.java ---------------------------------------------------------------------- diff --git a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesAvailableMenuAction.java b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesAvailableMenuAction.java new file mode 100644 index 0000000..e2611be --- /dev/null +++ b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesAvailableMenuAction.java @@ -0,0 +1,19 @@ +package net.sf.taverna.t2.workbench.updatemanager; + +import static net.sf.taverna.t2.workbench.updatemanager.UpdatesToolbarSection.UPDATES_SECTION; + +import java.awt.Component; + +import net.sf.taverna.t2.ui.menu.AbstractMenuCustom; + +public class UpdatesAvailableMenuAction extends AbstractMenuCustom { + public UpdatesAvailableMenuAction() { + super(UPDATES_SECTION, 10); + } + + @Override + protected Component createCustomComponent() { + //return new UpdatesAvailableIcon(); + return null; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesToolbarSection.java ---------------------------------------------------------------------- diff --git a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesToolbarSection.java b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesToolbarSection.java new file mode 100644 index 0000000..b16d614 --- /dev/null +++ b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesToolbarSection.java @@ -0,0 +1,16 @@ +package net.sf.taverna.t2.workbench.updatemanager; + +import static net.sf.taverna.t2.ui.menu.DefaultToolBar.DEFAULT_TOOL_BAR; + +import java.net.URI; + +import net.sf.taverna.t2.ui.menu.AbstractMenuSection; + +public class UpdatesToolbarSection extends AbstractMenuSection { + public static final URI UPDATES_SECTION = URI + .create("http://taverna.sf.net/2008/t2workbench/toolbar#updatesSection"); + + public UpdatesToolbarSection() { + super(DEFAULT_TOOL_BAR, 10000, UPDATES_SECTION); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-update-manager/src/main/resources/META-INF/spring/update-manager-context-osgi.xml ---------------------------------------------------------------------- diff --git a/taverna-workbench-update-manager/src/main/resources/META-INF/spring/update-manager-context-osgi.xml b/taverna-workbench-update-manager/src/main/resources/META-INF/spring/update-manager-context-osgi.xml new file mode 100644 index 0000000..ea637dd --- /dev/null +++ b/taverna-workbench-update-manager/src/main/resources/META-INF/spring/update-manager-context-osgi.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans:beans xmlns="http://www.springframework.org/schema/osgi" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/osgi + http://www.springframework.org/schema/osgi/spring-osgi.xsd"> + + <service ref="UpdateMenuAction" auto-export="interfaces" /> + + <reference id="updateManager" interface="uk.org.taverna.commons.update.UpdateManager" /> + +</beans:beans>