You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/03/20 15:22:18 UTC
[04/51] [abbrv] [partial] incubator-taverna-workbench git commit:
taverna-workbench-* -> taverna-*
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/ResourcePreviewFactory.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/ResourcePreviewFactory.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/ResourcePreviewFactory.java
new file mode 100644
index 0000000..128cfd3
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/ResourcePreviewFactory.java
@@ -0,0 +1,1359 @@
+/*******************************************************************************
+ * Copyright (C) 2009 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.ui.perspectives.myexperiment;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.Rectangle;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTable;
+import javax.swing.JTextPane;
+import javax.swing.ScrollPaneConstants;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.event.HyperlinkListener;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
+
+import net.sf.taverna.t2.lang.ui.DialogTextArea;
+import net.sf.taverna.t2.lang.ui.ShadedLabel;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Comment;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.File;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Group;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.MyExperimentClient;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Pack;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.PackItem;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Resource;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Tag;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.User;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Util;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Workflow;
+
+import org.apache.log4j.Logger;
+import org.jdom.Document;
+
+/**
+ * @author Sergejs Aleksejevs
+ */
+public class ResourcePreviewFactory {
+ // CONSTANTS
+ private static final int PREFERRED_LOWER_TABBED_PANE_HEIGHT = 250; // used for
+ // all
+ // tabbed
+ // views
+ // inside
+ // preview
+ // for
+ // every
+ // resource
+ // type
+
+ private final MainComponent pluginMainComponent;
+ private final MyExperimentClient myExperimentClient;
+ private final Logger logger;
+
+ // icons which are used in several places in the preview factory
+ private final ImageIcon iconWorkflow;
+ private final ImageIcon iconFile;
+ private final ImageIcon iconPack;
+ private final ImageIcon iconUser;
+ private final ImageIcon iconGroup;
+
+ public ResourcePreviewFactory(MainComponent component, MyExperimentClient client, Logger logger) {
+ super();
+
+ // set main variables to ensure access to myExperiment, logger and the
+ // parent component
+ this.pluginMainComponent = component;
+ this.myExperimentClient = client;
+ this.logger = logger;
+
+ // set up the icons
+ iconWorkflow = new ImageIcon(MyExperimentPerspective.getLocalIconURL(Resource.WORKFLOW));
+ iconFile = new ImageIcon(MyExperimentPerspective.getLocalIconURL(Resource.FILE));
+ iconPack = new ImageIcon(MyExperimentPerspective.getLocalIconURL(Resource.PACK));
+ iconUser = new ImageIcon(MyExperimentPerspective.getLocalIconURL(Resource.USER));
+ iconGroup = new ImageIcon(MyExperimentPerspective.getLocalIconURL(Resource.GROUP));
+ }
+
+ // main worker method - generates the content to be shown in the preview;
+ // responsible for parsing the preview action request, fetching data and
+ // generating all the content (via helpers)
+ public ResourcePreviewContent createPreview(String action, EventListener eventHandler) {
+ JPanel panelToPopulate = new JPanel();
+
+ // === PREPROCESSING ===
+
+ // return error message if the action string isn't actually a request for
+ // preview
+ if (!action.startsWith("preview:")) {
+ this.logger.error("Bad preview request: \"" + action + "\"");
+ panelToPopulate.add(new JLabel("An error has occurred."));
+ Resource r = new Resource();
+ r.setItemType(Resource.UNEXPECTED_TYPE);
+ r.setTitle("Bad preview request");
+ r.setURI(action);
+ return (new ResourcePreviewContent(r, panelToPopulate));
+ }
+
+ // parse the action string - we are now sure that it starts with a
+ // 'preview:'
+ action = action.substring(action.indexOf(":") + 1); // remove "preview:"
+ int iType = Integer.parseInt(action.substring(0, action.indexOf(":"))); // get
+ // type
+ action = action.substring(action.indexOf(":") + 1); // remove type
+ String strURI = action; // get URI
+
+ // === FETCHING RESOURCE DATA ===
+ Document doc = null;
+ try {
+ // the resource type is known at this point, hence can use specialist
+ // method
+ // that only fetches required metadata for (individual for each resource
+ // type)
+ doc = this.myExperimentClient.getResource(iType, strURI, Resource.REQUEST_FULL_PREVIEW);
+ } catch (Exception e) {
+ logger.error("Error while fetching resource data from myExperiment to generate a preview.\nResource type: "
+ + Resource.getResourceTypeName(iType)
+ + "\nResource URI: "
+ + strURI
+ + "\nException: " + e);
+ }
+
+ // === GENERATING PREVIEW ===
+ Resource resource = null;
+ switch (iType) {
+ case Resource.WORKFLOW:
+ Workflow w = Workflow.buildFromXML(doc, this.logger);
+ resource = w;
+ this.generateWorkflowPreviewContent(w, panelToPopulate, eventHandler);
+ break;
+
+ case Resource.FILE:
+ File f = File.buildFromXML(doc, this.logger);
+ resource = f;
+ this.generateFilePreviewContent(f, panelToPopulate, eventHandler);
+ break;
+
+ case Resource.PACK:
+ Pack p = Pack.buildFromXML(doc, this.myExperimentClient, this.logger);
+ resource = p;
+ this.generatePackPreviewContent(p, panelToPopulate, eventHandler);
+ break;
+
+ case Resource.USER:
+ User u = User.buildFromXML(doc, logger);
+ resource = u;
+ this.generateUserPreviewContent(u, panelToPopulate, eventHandler);
+ break;
+
+ case Resource.GROUP:
+ Group g = Group.buildFromXML(doc, logger);
+ resource = g;
+ this.generateGroupPreviewContent(g, panelToPopulate, eventHandler);
+ break;
+
+ default:
+ // unexpected resource type - can't generate preview
+ this.logger.error("Failed generating preview. Reason: unknown resource type - \""
+ + Resource.getResourceTypeName(iType) + "\"");
+ panelToPopulate.add(new JLabel("Cannot generate preview for unknown resource types."));
+ Resource r = new Resource();
+ r.setItemType(iType);
+ r.setTitle("Error: unknown resource type");
+ r.setURI(strURI);
+ return (new ResourcePreviewContent(r, panelToPopulate));
+ }
+
+ // format output data
+ return (new ResourcePreviewContent(resource, panelToPopulate));
+ }
+
+ private void generateWorkflowPreviewContent(Workflow w, JPanel panelToPopulate, EventListener eventHandler) {
+ if (w != null) {
+ try {
+ StringBuffer content = new StringBuffer();
+ content.append("<div class='outer'>");
+ content.append("<div class='workflow'>");
+
+ content.append("<br>");
+
+ content.append("<p class='title'>");
+ content.append("Workflow Entry: <a href='preview:" + Resource.WORKFLOW
+ + ":" + w.getURI() + "'>" + w.getTitle() + "</a> (version "
+ + w.getVersion() + ")");
+ content.append("</p>");
+
+ content.append("<br>");
+
+ content.append("<p class='info'>");
+ content.append("<b>Type:</b> " + w.getVisibleType() + "<br><br>");
+ content.append("<b>Uploader:</b> <a href='preview:" + Resource.USER
+ + ":" + w.getUploader().getURI() + "'>" + w.getUploader().getName()
+ + "</a><br>");
+ content.append("<b>Created at: </b> " + w.getCreatedAt() + "<br>");
+ content.append("<b>License: </b> <a href='"
+ + w.getLicense().getLink()
+ + "'>"
+ + w.getLicense().getText()
+ + "</a>"
+ + " <img src='"
+ + MyExperimentPerspective.getLocalResourceURL("external_link_small_icon")
+ + "' />");
+ content.append("</p>");
+
+ content.append("<br>");
+
+ content.append("<a href='" + w.getPreview() + "'>");
+ content.append("<img class='preview' src='" + w.getThumbnailBig()
+ + "'></img>");
+ content.append("</a>");
+
+ content.append("<br>");
+ content.append("<br>");
+
+ if (!w.getDescription().equals("")) {
+ content.append("<p class='desc'>");
+ content.append("<br>");
+ content.append(Util.stripHTML(w.getDescription()));
+ content.append("<br>");
+ content.append("</p>");
+ } else {
+ content.append("<span class='none_text'>No description</span>");
+ }
+
+ content.append("<br>");
+ content.append("</div>");
+ content.append("</div>");
+
+ HTMLEditorKit kit = new StyledHTMLEditorKit(pluginMainComponent.getStyleSheet());
+ HTMLDocument doc = (HTMLDocument) (kit.createDefaultDocument());
+ doc.insertAfterStart(doc.getRootElements()[0].getElement(0), content.toString());
+
+ // === Now render user's items as Swing components ===
+ // .. TABS for components, tags, comments, credits, attributions ..
+ JScrollPane spComponentsTab = createWorkflowComponentPreviewTab(w);
+ JScrollPane spTagsTab = createTagPreviewTab(w.getTags());
+ JScrollPane spCommentsTab = createCommentsPreviewTab(w.getComments());
+ JScrollPane spCreditsTab = createCreditsPreviewTab(w.getCredits());
+ JScrollPane spAttributionsTab = createAttributionsPreviewTab(w.getAttributions());
+
+ // .. ASSEMBLE ALL TABS together
+ JTabbedPane tpTabbedView = new JTabbedPane();
+ tpTabbedView.add("Components", spComponentsTab);
+ tpTabbedView.add("Tags (" + w.getTags().size() + ")", spTagsTab);
+ tpTabbedView.add("Comments (" + w.getComments().size() + ")", spCommentsTab);
+ tpTabbedView.addTab("Credits (" + w.getCredits().size() + ")", spCreditsTab);
+ tpTabbedView.addTab("Attributions (" + w.getAttributions().size() + ")", spAttributionsTab);
+
+ // PUT EVERYTHING TOGETHER
+ JTextPane tpWorkflowPreview = new JTextPane();
+ tpWorkflowPreview.setEditable(false);
+ tpWorkflowPreview.setEditorKit(kit);
+ tpWorkflowPreview.setDocument(doc);
+ tpWorkflowPreview.addHyperlinkListener((HyperlinkListener) eventHandler);
+
+ JPanel jpFullWorkflowPreview = wrapTextPaneAndTabbedViewIntoFullPreview(tpWorkflowPreview, tpTabbedView);
+
+ // POPULATE THE GIVEN PANEL
+ panelToPopulate.setLayout(new BorderLayout());
+ panelToPopulate.add(jpFullWorkflowPreview, BorderLayout.CENTER);
+
+ // this.statusLabel.setText("Workflow information found. Last fetched: "
+ // + new Date().toString());
+
+ // this.clearButton.setEnabled(true);
+ // this.refreshButton.setEnabled(true);
+ // this.loadButton.setEnabled(true);
+ // this.importButton.setEnabled(true);
+ } catch (Exception e) {
+ logger.error("Failed to populate Workflow Preview pane", e);
+ }
+ } else {
+ // statusLabel.setText("Could not find information for workflow ID: " +
+ // currentWorkflowId);
+ // clearContentTextPane();
+ // disableButtons();
+ }
+ }
+
+ private void generateFilePreviewContent(File f, JPanel panelToPopulate, EventListener eventHandler) {
+ if (f != null) {
+ try {
+ StringBuffer content = new StringBuffer();
+ content.append("<div class='outer'>");
+ content.append("<div class='file'>");
+
+ content.append("<br>");
+
+ content.append("<p class='title'>");
+ content.append("File: <a href='preview:" + Resource.FILE + ":"
+ + f.getURI() + "'>" + f.getTitle() + "</a>");
+ content.append("</p>");
+
+ content.append("<br>");
+
+ content.append("<p class='info'>");
+ content.append("<b>Type:</b> " + f.getVisibleType() + "<br>");
+ content.append("<b>Filename:</b> " + f.getFilename() + "<br><br>");
+ content.append("<b>Uploader:</b> <a href='preview:" + Resource.USER
+ + ":" + f.getUploader().getURI() + "'>" + f.getUploader().getName()
+ + "</a><br>");
+ content.append("<b>Created at: </b> " + f.getCreatedAt() + "<br>");
+ content.append("<b>Last updated at: </b> " + f.getUpdatedAt() + "<br>");
+ content.append("<b>License: </b> <a href='"
+ + f.getLicense().getLink()
+ + "'>"
+ + f.getLicense().getText()
+ + "</a>"
+ + " <img src='"
+ + MyExperimentPerspective.getLocalResourceURL("external_link_small_icon")
+ + "' />");
+ content.append("</p>");
+
+ content.append("<br>");
+
+ if (!f.getDescription().equals("")) {
+ content.append("<p class='desc'>");
+ content.append("<br>");
+ content.append(Util.stripHTML(f.getDescription()));
+ content.append("<br>");
+ content.append("</p>");
+ } else {
+ content.append("<span class='none_text'>No description</span>");
+ }
+
+ content.append("<br>");
+ content.append("</div>");
+ content.append("</div>");
+
+ HTMLEditorKit kit = new StyledHTMLEditorKit(pluginMainComponent.getStyleSheet());
+ HTMLDocument doc = (HTMLDocument) (kit.createDefaultDocument());
+ doc.insertAfterStart(doc.getRootElements()[0].getElement(0), content.toString());
+
+ // === Now render group's items as Swing components ===
+ // TABS FOR file's tags, credits, etc
+ JScrollPane spTagsTab = createTagPreviewTab(f.getTags());
+ JScrollPane spCommentsTab = createCommentsPreviewTab(f.getComments());
+ JScrollPane spCreditsTab = createCreditsPreviewTab(f.getCredits());
+ JScrollPane spAttributionsTab = createAttributionsPreviewTab(f.getAttributions());
+
+ // ASSEMBLE tabs into tabbed view
+ JTabbedPane tpTabbedView = new JTabbedPane();
+ tpTabbedView.add("Tags (" + f.getTags().size() + ")", spTagsTab);
+ tpTabbedView.add("Comments (" + f.getComments().size() + ")", spCommentsTab);
+ tpTabbedView.add("Credits (" + f.getCredits().size() + ")", spCreditsTab);
+ tpTabbedView.add("Attributions (" + f.getAttributions().size() + ")", spAttributionsTab);
+
+ // PUT EVERYTHING TOGETHER
+ JTextPane tpFilePreview = new JTextPane();
+ tpFilePreview.setEditable(false);
+ tpFilePreview.setEditorKit(kit);
+ tpFilePreview.setDocument(doc);
+ tpFilePreview.addHyperlinkListener((HyperlinkListener) eventHandler);
+
+ JPanel jpFullFilePreview = new JPanel();
+ jpFullFilePreview.setBackground(Color.WHITE); // white background for
+ // the whole file preview
+ // panel
+ jpFullFilePreview.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.gridx = GridBagConstraints.REMAINDER;
+ c.gridy = 0;
+ c.weighty = 0; // will not change size when the window is resized
+ jpFullFilePreview.add(tpFilePreview, c);
+
+ c.gridx = GridBagConstraints.REMAINDER;
+ c.gridy = 1;
+ c.weighty = 1; // will grow in size when the window is resized..
+ c.fill = GridBagConstraints.VERTICAL; // ..and fill all available space
+ // vertically
+ c.insets = new Insets(20, 0, 5, 0); // a bit of margin at the top &
+ // bottom
+ jpFullFilePreview.add(tpTabbedView, c);
+
+ // POPULATE THE GIVEN PANEL
+ panelToPopulate.setLayout(new BorderLayout());
+ panelToPopulate.add(jpFullFilePreview, BorderLayout.CENTER);
+
+ // this.statusLabel.setText("File information found. Last fetched: " +
+ // new Date().toString());
+
+ // this.clearButton.setEnabled(true);
+ // this.refreshButton.setEnabled(true);
+ // this.loadButton.setEnabled(true);
+ // this.importButton.setEnabled(true);
+ } catch (Exception e) {
+ logger.error("Failed to populate File Preview pane", e);
+ }
+ } else {
+ // statusLabel.setText("Could not find information for file ID: " +
+ // currentFileId);
+ // clearContentTextPane();
+ // disableButtons();
+ }
+ }
+
+ private void generatePackPreviewContent(Pack p, JPanel panelToPopulate, EventListener eventHandler) {
+ if (p != null) {
+ try {
+ // === Render pack details in HTML format ===
+ StringBuffer content = new StringBuffer();
+ content.append("<div class='outer'>");
+ content.append("<div class='pack'>");
+
+ content.append("<br>");
+
+ content.append("<p class='title'>");
+ content.append("Pack: <a href='preview:" + Resource.PACK + ":"
+ + p.getURI() + "'>" + p.getTitle() + "</a>");
+ content.append("</p>");
+
+ content.append("<br>");
+
+ content.append("<p class='info'>");
+ content.append("<b>Creator:</b> <a href='preview:" + Resource.USER
+ + ":" + p.getCreator().getURI() + "'>" + p.getCreator().getName()
+ + "</a><br>");
+ content.append("<b>Created at: </b> " + p.getCreatedAt() + "<br>");
+ content.append("<b>Last updated at: </b> " + p.getUpdatedAt() + "<br>");
+ content.append("</p>");
+
+ content.append("<br>");
+
+ if (!p.getDescription().equals("")) {
+ content.append("<p class='desc'>");
+ content.append("<br>");
+ content.append(Util.stripHTML(p.getDescription()));
+ content.append("<br>");
+ content.append("<br>");
+ content.append("</p>");
+ } else {
+ content.append("<span class='none_text'>No description</span>");
+ }
+
+ content.append("<br>");
+ content.append("</div>");
+ content.append("</div>");
+
+ HTMLEditorKit kit = new StyledHTMLEditorKit(pluginMainComponent.getStyleSheet());
+ HTMLDocument doc = (HTMLDocument) (kit.createDefaultDocument());
+ doc.insertAfterStart(doc.getRootElements()[0].getElement(0), content.toString());
+
+ // === Now render group's items as Swing components ===
+ // TABS FOR pack items, tags, etc
+ JScrollPane spPackItemsTab = createPackItemPreviewTab(p);
+ JScrollPane spTagsTab = createTagPreviewTab(p.getTags());
+ JScrollPane spCommentsTab = createCommentsPreviewTab(p.getComments());
+
+ // ASSEMBLE tabs into tabbed view
+ JTabbedPane tpTabbedView = new JTabbedPane();
+ tpTabbedView.addTab("Pack Items (" + p.getItemCount() + ")", spPackItemsTab);
+ tpTabbedView.add("Tags (" + p.getTags().size() + ")", spTagsTab);
+ tpTabbedView.add("Comments (" + p.getComments().size() + ")", spCommentsTab);
+
+ // PUT EVERYTHING TOGETHER
+ JTextPane tpPackPreview = new JTextPane();
+ tpPackPreview.setEditable(false);
+ tpPackPreview.setEditorKit(kit);
+ tpPackPreview.setDocument(doc);
+ tpPackPreview.addHyperlinkListener((HyperlinkListener) eventHandler);
+
+ JPanel jpFullPackPreview = new JPanel();
+ jpFullPackPreview.setBackground(Color.WHITE); // white background for
+ // the whole pack preview
+ // panel
+ jpFullPackPreview.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.gridx = GridBagConstraints.REMAINDER;
+ c.gridy = 0;
+ c.weighty = 0; // will not change size when the window is resized
+ jpFullPackPreview.add(tpPackPreview, c);
+
+ c.gridx = GridBagConstraints.REMAINDER;
+ c.gridy = 1;
+ c.weighty = 1; // will grow in size when the window is resized..
+ c.fill = GridBagConstraints.VERTICAL; // ..and fill all available space
+ // vertically
+ c.insets = new Insets(20, 0, 5, 0); // a bit of margin at the top &
+ // bottom
+ jpFullPackPreview.add(tpTabbedView, c);
+
+ // POPULATE THE GIVEN PANEL
+ panelToPopulate.setLayout(new BorderLayout());
+ panelToPopulate.add(jpFullPackPreview, BorderLayout.CENTER);
+
+ // this.statusLabel.setText("Pack information found. Last fetched: " +
+ // new Date().toString());
+
+ // this.clearButton.setEnabled(true);
+ // this.refreshButton.setEnabled(true);
+ // this.loadButton.setEnabled(true);
+ // this.importButton.setEnabled(true);
+ } catch (Exception e) {
+ logger.error("Failed to populate Pack Preview pane", e);
+ }
+ } else {
+ // statusLabel.setText("Could not find information for pack ID: " +
+ // currentPackId);
+ // clearContentTextPane();
+ // disableButtons();
+ }
+ }
+
+ private void generateUserPreviewContent(User u, JPanel panelToPopulate, EventListener eventHandler) {
+ if (u != null) {
+ try {
+ // === Render user details in HTML format ===
+ StringBuffer content = new StringBuffer();
+ content.append("<div class='outer'>");
+ content.append("<div class='user'>");
+
+ content.append("<br>");
+
+ content.append("<p class='name'>");
+ content.append("User: <a href=preview:" + Resource.USER + ":"
+ + u.getURI() + "'>" + u.getName() + "</a>");
+ content.append("</p>");
+
+ content.append("<br>");
+
+ content.append("<p class='info'>");
+ String strLocation;
+ if (u.getCity().length() == 0 && u.getCountry().length() == 0)
+ strLocation = "<span class='none_text'>Not specified</span>";
+ else
+ strLocation = u.getCity()
+ + (u.getCity().length() == 0 || u.getCountry().length() == 0 ? "" : ", ")
+ + u.getCountry();
+ content.append("<b>Location:</b> " + strLocation + "<br>");
+ content.append("<b>Joined at: </b> " + u.getCreatedAt() + "<br>");
+ content.append("<b>Last seen at: </b> " + u.getUpdatedAt() + "<br>");
+ content.append("</p>");
+
+ content.append("<br>");
+
+ content.append("<a href='" + u.getAvatarResource() + "'>");
+ content.append("<img class='avatar' src='" + u.getAvatarResource()
+ + "'></img>");
+ content.append("</a>");
+
+ content.append("<br>");
+ content.append("<br>");
+
+ if (!u.getDescription().equals("")) {
+ // HACK: the way JAVA renders html causes styling not to be inherited;
+ // hence need to
+ // remove any nested <p> or <div> tags to get a proper layout
+ content.append("<p class='desc'>"
+ + Util.stripHTML(u.getDescription()) + "<br><br></p>");
+ } else {
+ content.append("<span class='none_text'>No description</span>");
+ }
+
+ content.append("<p class='contact_details_header'>Contact Details</p>");
+ content.append("<p class='contact_details'>");
+ content.append("<b>Email: </b>"
+ + (u.getEmail().length() == 0 ? "<span class='none_text'>Not specified</span>" : u.getEmail())
+ + "<br>");
+ content.append("<b>Website: </b>"
+ + (u.getWebsite().length() == 0 ? "<span class='none_text'>Not specified</span>" : u.getWebsite()));
+ content.append("</p>");
+
+ content.append("</div>");
+ content.append("</div>");
+
+ HTMLEditorKit kit = new StyledHTMLEditorKit(pluginMainComponent.getStyleSheet());
+ HTMLDocument doc = (HTMLDocument) (kit.createDefaultDocument());
+ doc.insertAfterStart(doc.getRootElements()[0].getElement(0), content.toString());
+
+ // === Now render user's items as Swing components ===
+ // .. WORKFLOWS ..
+ JPanel jpWorkflowsTabContent = new JPanel();
+ jpWorkflowsTabContent.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
+ jpWorkflowsTabContent.setLayout(new BoxLayout(jpWorkflowsTabContent, BoxLayout.Y_AXIS));
+
+ // iterate through all workflows and add all to the panel
+ Iterator<HashMap<String, String>> iWorkflows = u.getWorkflows().iterator();
+ while (iWorkflows.hasNext()) {
+ HashMap<String, String> hmCurWF = iWorkflows.next();
+ jpWorkflowsTabContent.add(new JClickableLabel(hmCurWF.get("name"), "preview:"
+ + Resource.WORKFLOW + ":" + hmCurWF.get("uri"), pluginMainComponent.getPreviewBrowser(), this.iconWorkflow));
+ }
+
+ // .. FILES ..
+ JPanel jpFilesTabContent = new JPanel();
+ jpFilesTabContent.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
+ jpFilesTabContent.setLayout(new BoxLayout(jpFilesTabContent, BoxLayout.Y_AXIS));
+
+ // iterate through all files and add all to the panel
+ Iterator<HashMap<String, String>> iFiles = u.getFiles().iterator();
+ while (iFiles.hasNext()) {
+ HashMap<String, String> hmCurFile = iFiles.next();
+ jpFilesTabContent.add(new JClickableLabel(hmCurFile.get("name"), "preview:"
+ + Resource.FILE + ":" + hmCurFile.get("uri"), pluginMainComponent.getPreviewBrowser(), this.iconFile));
+ }
+
+ // .. PACKS ..
+ JPanel jpPacksTabContent = new JPanel();
+ jpPacksTabContent.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
+ jpPacksTabContent.setLayout(new BoxLayout(jpPacksTabContent, BoxLayout.Y_AXIS));
+
+ // iterate through all packs and add all to the panel
+ Iterator<HashMap<String, String>> iPacks = u.getPacks().iterator();
+ while (iPacks.hasNext()) {
+ HashMap<String, String> hmCurPack = iPacks.next();
+ jpPacksTabContent.add(new JClickableLabel(hmCurPack.get("name"), "preview:"
+ + Resource.PACK + ":" + hmCurPack.get("uri"), pluginMainComponent.getPreviewBrowser(), this.iconPack));
+ }
+
+ // .. FRIENDS ..
+ JPanel jpFriendsTabContent = new JPanel();
+ jpFriendsTabContent.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
+ jpFriendsTabContent.setLayout(new BoxLayout(jpFriendsTabContent, BoxLayout.Y_AXIS));
+
+ // iterate through all friends and add all to the panel
+ Iterator<HashMap<String, String>> iFriends = u.getFriends().iterator();
+ while (iFriends.hasNext()) {
+ HashMap<String, String> hmCurFriend = iFriends.next();
+ jpFriendsTabContent.add(new JClickableLabel(hmCurFriend.get("name"), "preview:"
+ + Resource.USER + ":" + hmCurFriend.get("uri"), pluginMainComponent.getPreviewBrowser(), this.iconUser));
+ }
+
+ // .. GROUPS ..
+ JPanel jpGroupsTabContent = new JPanel();
+ jpGroupsTabContent.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
+ jpGroupsTabContent.setLayout(new BoxLayout(jpGroupsTabContent, BoxLayout.Y_AXIS));
+
+ // iterate through all groups and add all to the panel
+ Iterator<HashMap<String, String>> iGroups = u.getGroups().iterator();
+ while (iGroups.hasNext()) {
+ HashMap<String, String> hmCurGroup = iGroups.next();
+ jpGroupsTabContent.add(new JClickableLabel(hmCurGroup.get("name"), "preview:"
+ + Resource.GROUP + ":" + hmCurGroup.get("uri"), pluginMainComponent.getPreviewBrowser(), this.iconGroup));
+ }
+
+ // .. WRAP EVERY TAB content into it's own scroll pane ..
+ Dimension dPreferredTabSize = new Dimension(ResourcePreviewBrowser.PREFERRED_WIDTH - 50, PREFERRED_LOWER_TABBED_PANE_HEIGHT);
+
+ JScrollPane spWorkflowsTab = new JScrollPane(jpWorkflowsTabContent);
+ spWorkflowsTab.setBorder(BorderFactory.createEmptyBorder());
+ spWorkflowsTab.setPreferredSize(dPreferredTabSize);
+ spWorkflowsTab.getVerticalScrollBar().setUnitIncrement(ResourcePreviewBrowser.PREFERRED_SCROLL);
+
+ JScrollPane spFilesTab = new JScrollPane(jpFilesTabContent);
+ spFilesTab.setBorder(BorderFactory.createEmptyBorder());
+ spFilesTab.setPreferredSize(dPreferredTabSize);
+ spFilesTab.getVerticalScrollBar().setUnitIncrement(ResourcePreviewBrowser.PREFERRED_SCROLL);
+
+ JScrollPane spPacksTab = new JScrollPane(jpPacksTabContent);
+ spPacksTab.setBorder(BorderFactory.createEmptyBorder());
+ spPacksTab.setPreferredSize(dPreferredTabSize);
+ spPacksTab.getVerticalScrollBar().setUnitIncrement(ResourcePreviewBrowser.PREFERRED_SCROLL);
+
+ JScrollPane spFriendsTab = new JScrollPane(jpFriendsTabContent);
+ spFriendsTab.setBorder(BorderFactory.createEmptyBorder());
+ spFriendsTab.setPreferredSize(dPreferredTabSize);
+ spFriendsTab.getVerticalScrollBar().setUnitIncrement(ResourcePreviewBrowser.PREFERRED_SCROLL);
+
+ JScrollPane spGroupsTab = new JScrollPane(jpGroupsTabContent);
+ spGroupsTab.setBorder(BorderFactory.createEmptyBorder());
+ spGroupsTab.setPreferredSize(dPreferredTabSize);
+ spGroupsTab.getVerticalScrollBar().setUnitIncrement(ResourcePreviewBrowser.PREFERRED_SCROLL);
+
+ // .. ASSEMBLE ALL TABS together
+ JTabbedPane tpTabbedItems = new JTabbedPane();
+ tpTabbedItems.addTab("Workflows (" + u.getWorkflows().size() + ")", spWorkflowsTab);
+ tpTabbedItems.addTab("Files (" + u.getFiles().size() + ")", spFilesTab);
+ tpTabbedItems.addTab("Packs (" + u.getPacks().size() + ")", spPacksTab);
+ tpTabbedItems.addTab("Friends (" + u.getFriends().size() + ")", spFriendsTab);
+ tpTabbedItems.addTab("Groups (" + u.getGroups().size() + ")", spGroupsTab);
+
+ // === PUT EVERYTHING TOGETHER ===
+ JTextPane tpUserPreview = new JTextPane();
+ tpUserPreview.setEditable(false);
+ tpUserPreview.setEditorKit(kit);
+ tpUserPreview.setDocument(doc);
+ tpUserPreview.addHyperlinkListener((HyperlinkListener) eventHandler);
+
+ JPanel jpFullUserPreview = new JPanel();
+ jpFullUserPreview.setBackground(Color.WHITE); // white background for
+ // the whole user preview
+ // panel
+ jpFullUserPreview.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.gridx = GridBagConstraints.REMAINDER;
+ c.gridy = 0;
+ c.weighty = 0; // will not change size when the window is resized
+ jpFullUserPreview.add(tpUserPreview, c);
+
+ c.gridx = GridBagConstraints.REMAINDER;
+ c.gridy = 1;
+ c.weighty = 1; // will grow in size when the window is resized..
+ c.fill = GridBagConstraints.VERTICAL; // ..and fill all available space
+ // vertically
+ c.insets = new Insets(20, 0, 5, 0); // a bit of margin at the top &
+ // bottom
+ jpFullUserPreview.add(tpTabbedItems, c);
+
+ // POPULATE THE GIVEN PANEL
+ panelToPopulate.setLayout(new BorderLayout());
+ panelToPopulate.add(jpFullUserPreview, BorderLayout.CENTER);
+
+ // this.statusLabel.setText("User information found. Last fetched: " +
+ // new Date().toString());
+
+ // this.clearButton.setEnabled(true);
+ // this.refreshButton.setEnabled(true);
+ // this.loadButton.setEnabled(true);
+ // this.importButton.setEnabled(true);
+ } catch (Exception e) {
+ logger.error("Failed to populate Workflow Preview pane", e);
+ }
+ } else {
+ // statusLabel.setText("Could not find information for workflow ID: " +
+ // currentWorkflowId);
+ // clearContentTextPane();
+ // disableButtons();
+ }
+ }
+
+ private void generateGroupPreviewContent(Group g, JPanel panelToPopulate, EventListener eventHandler) {
+ if (g != null) {
+ try {
+ // === Render group details in HTML format ===
+ StringBuffer content = new StringBuffer();
+ content.append("<div class='outer'>");
+ content.append("<div class='group'>");
+
+ content.append("<br>");
+
+ content.append("<p class='title'>");
+ content.append("Group: <a href='preview:" + Resource.GROUP + ":"
+ + g.getURI() + "'>" + g.getTitle() + "</a>");
+ content.append("</p>");
+
+ content.append("<br>");
+
+ content.append("<p class='info'>");
+ content.append("<b>Administrator:</b> <a href='preview:"
+ + Resource.USER + ":" + g.getAdmin().getURI() + "'>"
+ + g.getAdmin().getName() + "</a><br>");
+ content.append("<b>Created at: </b> " + g.getCreatedAt() + "<br>");
+ content.append("</p>");
+
+ content.append("<br>");
+
+ if (!g.getDescription().equals("")) {
+ content.append("<p class='desc'>");
+ content.append("<br>");
+ content.append(Util.stripHTML(g.getDescription()));
+ content.append("<br>");
+ content.append("</p>");
+ } else {
+ content.append("<span class='none_text'>No description</span>");
+ }
+
+ content.append("<br>");
+ content.append("</div>");
+ content.append("</div>");
+
+ HTMLEditorKit kit = new StyledHTMLEditorKit(pluginMainComponent.getStyleSheet());
+ HTMLDocument doc = (HTMLDocument) (kit.createDefaultDocument());
+ doc.insertAfterStart(doc.getRootElements()[0].getElement(0), content.toString());
+
+ // === Now render group's items as Swing components ===
+
+ // .. MEMBERS ..
+ JPanel jpMembersTabContent = createStandardTabContentPanel();
+
+ // iterate through all shared items and add all to the panel
+ Iterator<User> iMembers = g.getMembers().iterator();
+ while (iMembers.hasNext()) {
+ User uCurMember = iMembers.next();
+ jpMembersTabContent.add(new JClickableLabel(uCurMember.getName(), "preview:"
+ + uCurMember.getItemType() + ":" + uCurMember.getURI(), pluginMainComponent.getPreviewBrowser(), new ImageIcon(MyExperimentPerspective.getLocalIconURL(uCurMember.getItemType()))));
+ }
+
+ // wrap into a standard scroll pane
+ JScrollPane spMembersTabContent = wrapPreviewTabContentIntoScrollPane(jpMembersTabContent);
+
+ // .. SHARED ITEMS ..
+ JPanel jpSharedItemsTabContent = createStandardTabContentPanel();
+
+ // iterate through all shared items and add all to the panel
+ Iterator<Resource> iSharedItems = g.getSharedItems().iterator();
+ while (iSharedItems.hasNext()) {
+ Resource rCurItem = iSharedItems.next();
+ jpSharedItemsTabContent.add(new JClickableLabel(rCurItem.getTitle(), "preview:"
+ + rCurItem.getItemType() + ":" + rCurItem.getURI(), pluginMainComponent.getPreviewBrowser(), new ImageIcon(MyExperimentPerspective.getLocalIconURL(rCurItem.getItemType()))));
+ }
+
+ // wrap into a standard scroll pane
+ JScrollPane spSharedItemsTabContent = wrapPreviewTabContentIntoScrollPane(jpSharedItemsTabContent);
+
+ // .. TAGS, COMMENTS ..
+ JScrollPane spTagsTabContent = createTagPreviewTab(g.getTags());
+ JScrollPane spCommentsTab = createCommentsPreviewTab(g.getComments());
+
+ // ASSEMBLE tabs together
+ JTabbedPane tpTabbedItems = new JTabbedPane();
+ tpTabbedItems.addTab("Members (" + g.getMemberCount() + ")", spMembersTabContent);
+ tpTabbedItems.addTab("Shared Items (" + g.getSharedItemCount() + ")", spSharedItemsTabContent);
+ tpTabbedItems.addTab("Tags (" + g.getTags().size() + ")", spTagsTabContent);
+ tpTabbedItems.addTab("Comments (" + g.getComments().size() + ")", spCommentsTab);
+
+ // PUT EVERYTHING TOGETHER
+ JTextPane tpGroupPreview = new JTextPane();
+ tpGroupPreview.setEditable(false);
+ tpGroupPreview.setEditorKit(kit);
+ tpGroupPreview.setDocument(doc);
+ tpGroupPreview.addHyperlinkListener((HyperlinkListener) eventHandler);
+
+ JPanel jpFullGroupPreview = new JPanel();
+ jpFullGroupPreview.setBackground(Color.WHITE); // white background for
+ // the whole group
+ // preview panel
+ jpFullGroupPreview.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.gridx = GridBagConstraints.REMAINDER;
+ c.gridy = 0;
+ c.weighty = 0; // will not change size when the window is resized
+ jpFullGroupPreview.add(tpGroupPreview, c);
+
+ c.gridx = GridBagConstraints.REMAINDER;
+ c.gridy = 1;
+ c.weighty = 1; // will grow in size when the window is resized..
+ c.fill = GridBagConstraints.VERTICAL; // ..and fill all available space
+ // vertically
+ c.insets = new Insets(20, 0, 5, 0); // a bit of margin at the top &
+ // bottom
+ jpFullGroupPreview.add(tpTabbedItems, c);
+
+ // POPULATE THE GIVEN PANEL
+ panelToPopulate.setLayout(new BorderLayout());
+ panelToPopulate.add(jpFullGroupPreview, BorderLayout.CENTER);
+
+ // this.statusLabel.setText("Group information found. Last fetched: " +
+ // new Date().toString());
+
+ // this.clearButton.setEnabled(true);
+ // this.refreshButton.setEnabled(true);
+ // this.loadButton.setEnabled(true);
+ // this.importButton.setEnabled(true);
+ } catch (Exception e) {
+ logger.error("Failed to populate Group Preview pane", e);
+ }
+ } else {
+ // statusLabel.setText("Could not find information for group ID: " +
+ // currentGroupId);
+ // clearContentTextPane();
+ // disableButtons();
+ }
+ }
+
+ // *** Helper methods follow that generate particular reusable pieces of the
+ // previews ***
+
+ private JScrollPane createWorkflowComponentPreviewTab(Workflow w) {
+ final JPanel jpWorkflowComponentsTabContent = createStandardTabContentPanel();
+
+ if (!w.isTavernaWorkflow()) {
+ // can only display components for Taverna 1 workflows at the moment
+ JLabel lNotSupported = new JLabel("<html>This is a "
+ + w.getVisibleType()
+ + " workflow;<br>myExperiment can only display Taverna workflow components at the moment.</html>");
+ lNotSupported.setFont(lNotSupported.getFont().deriveFont(Font.ITALIC));
+ lNotSupported.setForeground(Color.GRAY);
+ jpWorkflowComponentsTabContent.add(lNotSupported);
+ } else if (!w.isDownloadAllowed()) {
+ // can display components for workflow of this type, but current user is
+ // not
+ // allowed to download this workflow - and, hence, to view its components
+ JLabel lNotAuthorized = new JLabel("You are not authorised to download this workflow, "
+ + "and hence component preview is not available.");
+ lNotAuthorized.setFont(lNotAuthorized.getFont().deriveFont(Font.ITALIC));
+ lNotAuthorized.setForeground(Color.GRAY);
+ jpWorkflowComponentsTabContent.add(lNotAuthorized);
+ } else {
+ // can display the components
+
+ // storage for table column names
+ Vector<String> vColumnNames = new Vector<String>();
+
+ // ** inputs **
+ vColumnNames.clear();
+ vColumnNames.addAll(Arrays.asList(new String[] { "Name", "Description" }));
+
+ Vector<Vector<String>> vInputsData = new Vector<Vector<String>>();
+ ArrayList<HashMap<String, String>> inputs = w.getComponents().get("inputs");
+ if (inputs != null) {
+ for (HashMap<String, String> curInput : inputs) {
+ Vector<String> vCurData = new Vector<String>();
+ vCurData.add(curInput.get("name"));
+ vCurData.add(curInput.get("description"));
+
+ vInputsData.add(vCurData);
+ }
+ }
+
+ JTable jtInputs = new JTable(vInputsData, vColumnNames);
+ jtInputs.getColumnModel().getColumn(0).setPreferredWidth(100);
+ jtInputs.getTableHeader().setFont(jtInputs.getTableHeader().getFont().deriveFont(Font.BOLD));
+ JPanel jpInputs = new JPanel();
+ jpInputs.setLayout(new BorderLayout());
+ jpInputs.add(jtInputs.getTableHeader(), BorderLayout.NORTH);
+ jpInputs.add(jtInputs, BorderLayout.CENTER);
+
+ JPanel jpInputsWithTitle = new JPanel();
+ jpInputsWithTitle.setBorder(BorderFactory.createEtchedBorder());
+ jpInputsWithTitle.setLayout(new BorderLayout());
+ jpInputsWithTitle.add(new ShadedLabel("Workflow input ports ("
+ + vInputsData.size() + ")", ShadedLabel.BLUE, true), BorderLayout.NORTH);
+ if (vInputsData.size() > 0) {
+ jpInputsWithTitle.add(jpInputs, BorderLayout.CENTER);
+ }
+
+ // ** processors **
+ vColumnNames.clear();
+ vColumnNames.addAll(Arrays.asList(new String[] { "Name", "Type", "Description" }));
+
+ Vector<Vector<String>> vProcessorsData = new Vector<Vector<String>>();
+ ArrayList<HashMap<String, String>> processors = w.getComponents().get("processors");
+ if (processors != null) {
+ for (HashMap<String, String> curProcessor : processors) {
+ Vector<String> vCurData = new Vector<String>();
+ vCurData.add(curProcessor.get("name"));
+ vCurData.add(curProcessor.get("type"));
+ vCurData.add(curProcessor.get("description"));
+
+ vProcessorsData.add(vCurData);
+ }
+ }
+
+ JTable jtProcessors = new JTable(vProcessorsData, vColumnNames);
+ jtProcessors.getTableHeader().setFont(jtProcessors.getTableHeader().getFont().deriveFont(Font.BOLD));
+ JPanel jpProcessors = new JPanel();
+ jpProcessors.setLayout(new BorderLayout());
+ jpProcessors.add(jtProcessors.getTableHeader(), BorderLayout.NORTH);
+ jpProcessors.add(jtProcessors, BorderLayout.CENTER);
+
+ JPanel jpProcessorsWithTitle = new JPanel();
+ jpProcessorsWithTitle.setBorder(BorderFactory.createEtchedBorder());
+ jpProcessorsWithTitle.setLayout(new BorderLayout());
+ jpProcessorsWithTitle.add(new ShadedLabel("Services ("
+ + vProcessorsData.size() + ")", ShadedLabel.BLUE, true), BorderLayout.NORTH);
+ if (vProcessorsData.size() > 0) {
+ jpProcessorsWithTitle.add(jpProcessors, BorderLayout.CENTER);
+ }
+
+ // ** links **
+ vColumnNames.clear();
+ vColumnNames.addAll(Arrays.asList(new String[] { "Source", "Sink" }));
+
+ Vector<Vector<String>> vLinksData = new Vector<Vector<String>>();
+ ArrayList<HashMap<String, String>> links = w.getComponents().get("links");
+ if (links != null) {
+ for (HashMap<String, String> curLink : links) {
+ Vector<String> vCurData = new Vector<String>();
+ vCurData.add(curLink.get("source"));
+ vCurData.add(curLink.get("sink"));
+
+ vLinksData.add(vCurData);
+ }
+ }
+
+ JTable jtLinks = new JTable(vLinksData, vColumnNames);
+ jtLinks.getColumnModel().getColumn(0).setPreferredWidth(100);
+ jtLinks.getTableHeader().setFont(jtLinks.getTableHeader().getFont().deriveFont(Font.BOLD));
+ JPanel jpLinks = new JPanel();
+ jpLinks.setLayout(new BorderLayout());
+ jpLinks.add(jtLinks.getTableHeader(), BorderLayout.NORTH);
+ jpLinks.add(jtLinks, BorderLayout.CENTER);
+
+ JPanel jpLinksWithTitle = new JPanel();
+ jpLinksWithTitle.setBorder(BorderFactory.createEtchedBorder());
+ jpLinksWithTitle.setLayout(new BorderLayout());
+ jpLinksWithTitle.add(new ShadedLabel("Links (" + vLinksData.size() + ")", ShadedLabel.BLUE, true), BorderLayout.NORTH);
+ if (vLinksData.size() > 0) {
+ jpLinksWithTitle.add(jpLinks, BorderLayout.CENTER);
+ }
+
+ // ** outputs **
+ vColumnNames.clear();
+ vColumnNames.addAll(Arrays.asList(new String[] { "Name", "Description" }));
+
+ Vector<Vector<String>> vOutputsData = new Vector<Vector<String>>();
+ ArrayList<HashMap<String, String>> outputs = w.getComponents().get("outputs");
+ if (outputs != null) {
+ for (HashMap<String, String> curOutput : outputs) {
+ Vector<String> vCurData = new Vector<String>();
+ vCurData.add(curOutput.get("name"));
+ vCurData.add(curOutput.get("description"));
+
+ vOutputsData.add(vCurData);
+ }
+ }
+
+ JTable jtOutputs = new JTable(vOutputsData, vColumnNames);
+ jtOutputs.getColumnModel().getColumn(0).setPreferredWidth(100);
+ jtOutputs.getTableHeader().setFont(jtOutputs.getTableHeader().getFont().deriveFont(Font.BOLD));
+ JPanel jpOutputs = new JPanel();
+ jpOutputs.setLayout(new BorderLayout());
+ jpOutputs.add(jtOutputs.getTableHeader(), BorderLayout.NORTH);
+ jpOutputs.add(jtOutputs, BorderLayout.CENTER);
+
+ JPanel jpOutputsWithTitle = new JPanel();
+ jpOutputsWithTitle.setBorder(BorderFactory.createEtchedBorder());
+ jpOutputsWithTitle.setLayout(new BorderLayout());
+ jpOutputsWithTitle.add(new ShadedLabel("Workflow output ports ("
+ + vOutputsData.size() + ")", ShadedLabel.BLUE, true), BorderLayout.NORTH);
+ if (vOutputsData.size() > 0) {
+ jpOutputsWithTitle.add(jpOutputs, BorderLayout.CENTER);
+ }
+
+ // PUT EVERYTHING TOGETHER
+ jpWorkflowComponentsTabContent.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.gridx = 0;
+ c.gridy = GridBagConstraints.RELATIVE;
+ c.weightx = 1.0;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.NORTH;
+ jpWorkflowComponentsTabContent.add(jpInputsWithTitle, c);
+
+ c.insets = new Insets(10, 0, 0, 0);
+ jpWorkflowComponentsTabContent.add(jpProcessorsWithTitle, c);
+
+ jpWorkflowComponentsTabContent.add(jpLinksWithTitle, c);
+
+ c.weighty = 1.0; // ONLY FOR THE LAST ELEMENT
+ jpWorkflowComponentsTabContent.add(jpOutputsWithTitle, c);
+ }
+
+ return (wrapPreviewTabContentIntoScrollPane(jpWorkflowComponentsTabContent));
+ }
+
+ private JScrollPane createPackItemPreviewTab(Pack p) {
+ JPanel jpPackItemsTabContent = createStandardTabContentPanel();
+ GridBagConstraints c = new GridBagConstraints();
+ jpPackItemsTabContent.setLayout(new GridBagLayout());
+ c.anchor = GridBagConstraints.NORTHWEST;
+
+ // iterate through all internal and external items and add all to the panel
+ if (p.getItems().size() > 0) {
+ int iCnt = 0;
+ boolean bNoCommentForPrevItem = false;
+
+ for (PackItem piCurItem : p.getItems()) {
+ c.gridx = 0;
+ c.gridy = 3 * iCnt;
+ c.weightx = 1.0;
+ c.insets = (bNoCommentForPrevItem ? new Insets(7, 0, 0, 0) : new Insets(0, 0, 0, 0));
+ c.fill = GridBagConstraints.NONE;
+ // item data is stored differently whether the item is internal or
+ // external
+ if (piCurItem.isInternalItem()) {
+ jpPackItemsTabContent.add(new JClickableLabel(piCurItem.getItem().getTitle(), "preview:"
+ + piCurItem.getItem().getItemType()
+ + ":"
+ + piCurItem.getItem().getURI(), pluginMainComponent.getPreviewBrowser(), new ImageIcon(MyExperimentPerspective.getLocalIconURL(piCurItem.getItem().getItemType()))), c);
+ } else {
+ jpPackItemsTabContent.add(new JClickableLabel(piCurItem.getTitle(), piCurItem.getLink(), // link should open up directly in the web
+ // browser
+ pluginMainComponent.getPreviewBrowser(), new ImageIcon(MyExperimentPerspective.getLocalIconURL(piCurItem.getItemType())), SwingConstants.LEFT, piCurItem.getTitle()
+ + " (link: " + piCurItem.getLink() + ")"), c);
+ }
+
+ // prepare comment before populating the metadata
+ String strComment = Util.stripAllHTML(piCurItem.getComment());
+ bNoCommentForPrevItem = (strComment == null || strComment.length() == 0);
+
+ // add metadata to the item ..
+ // .. who and when added the item ..
+ JPanel jpWhoAddedTheItem = new JPanel();
+ jpWhoAddedTheItem.setLayout(new GridBagLayout());
+ GridBagConstraints c1 = new GridBagConstraints();
+ c1.anchor = GridBagConstraints.NORTHWEST;
+ jpWhoAddedTheItem.setBorder(BorderFactory.createEmptyBorder());
+ jpWhoAddedTheItem.add(new JLabel("Added by "), c1);
+ jpWhoAddedTheItem.add(new JClickableLabel(piCurItem.getUserWhoAddedTheItem().getName(), "preview:"
+ + Resource.USER + ":" + piCurItem.getUserWhoAddedTheItem().getURI(), pluginMainComponent.getPreviewBrowser()), c1);
+
+ String strAddedOnDate = MyExperimentClient.formatDate(piCurItem.getCreatedAt());
+ c1.weightx = 1.0;
+ jpWhoAddedTheItem.add(new JLabel(" [" + strAddedOnDate + "]"), c1);
+
+ c.gridx = 0;
+ c.gridy = 3 * iCnt + 1;
+ c.insets = new Insets(0, 25, 0, 0);
+ c.weightx = 1.0;
+ if (bNoCommentForPrevItem && (iCnt + 1 == p.getItems().size()))
+ c.weighty = 1.0;
+ jpPackItemsTabContent.add(jpWhoAddedTheItem, c);
+
+ // .. and the comment
+ if (!bNoCommentForPrevItem) {
+ c.gridx = 0;
+ c.gridy = 3 * iCnt + 2;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.insets = new Insets(0, 25, 7, 25);
+ c.weightx = 1.0;
+ if (iCnt + 1 == p.getItems().size())
+ c.weighty = 1.0; // only if this is the comment for the last item,
+ // shift all items to the top of the panel
+
+ DialogTextArea taCommentText = new DialogTextArea("Comment: "
+ + strComment);
+ taCommentText.setOpaque(false);
+ taCommentText.setEditable(false);
+ taCommentText.setLineWrap(true);
+ taCommentText.setWrapStyleWord(true);
+ jpPackItemsTabContent.add(taCommentText, c);
+ }
+
+ // update the item counter
+ iCnt++;
+ }
+ } else {
+ c.weighty = 1.0;
+ c.weightx = 1.0;
+ jpPackItemsTabContent.add(Util.generateNoneTextLabel("None"), c);
+ }
+
+ return (wrapPreviewTabContentIntoScrollPane(jpPackItemsTabContent));
+ }
+
+ private JScrollPane createTagPreviewTab(List<Tag> lTags) {
+ TagCloudPanel jpTagTabContent = new TagCloudPanel("Resource tag cloud", TagCloudPanel.TAGCLOUD_TYPE_RESOURCE_PREVIEW, pluginMainComponent.getPreviewBrowser(), pluginMainComponent, myExperimentClient, logger);
+ jpTagTabContent.getTagCloudData().clear();
+ jpTagTabContent.getTagCloudData().addAll(lTags);
+ jpTagTabContent.refresh();
+
+ // tag cloud panel itself already has a scroll pane in it; hence the outer
+ // scroll pane
+ // is only used for consistency across the user interface (contents of all
+ // tabs in the
+ // preview window are scroll panes); the preferred size of the tag cloud
+ // panel should
+ // still be adjusted accordingly to the preferred size of the outer scroll
+ // pane
+ JScrollPane spTagTabContent = wrapPreviewTabContentIntoScrollPane(jpTagTabContent);
+ spTagTabContent.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ spTagTabContent.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
+
+ jpTagTabContent.setPreferredSize(spTagTabContent.getPreferredSize());
+
+ return (spTagTabContent);
+ }
+
+ private JScrollPane createCommentsPreviewTab(List<Comment> comments) {
+ final List<Comment> lComments = comments;
+ final JPanel jpCommentsTabContent = createStandardTabContentPanel();
+
+ if (lComments.size() > 0) {
+ final GridBagConstraints c = new GridBagConstraints();
+ jpCommentsTabContent.setLayout(new GridBagLayout());
+ c.anchor = GridBagConstraints.NORTHWEST;
+
+ // a placeholder for comments while they are loading
+ JLabel lLoading = new JLabel("Loading comments...", new ImageIcon(MyExperimentPerspective.getLocalResourceURL("spinner")), SwingConstants.LEFT);
+ lLoading.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 10));
+ c.weightx = 1.0;
+ c.weighty = 1.0;
+ jpCommentsTabContent.add(lLoading, c);
+
+ new Thread("Load comments for preview") {
+ @Override
+ public void run() {
+ myExperimentClient.updateCommentListWithExtraData(lComments);
+
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ // remove 'loading...' placeholder
+ jpCommentsTabContent.removeAll();
+
+ int iCnt = 0;
+ for (Comment comment : lComments) {
+ c.gridx = 0;
+ c.gridy = 2 * iCnt;
+ c.weightx = 0;
+ c.weighty = 0;
+ c.gridwidth = 1;
+ JClickableLabel lCommentAuthor = new JClickableLabel(comment.getUser().getName(), "preview:"
+ + comment.getUser().getItemType()
+ + ":"
+ + comment.getUser().getURI(), pluginMainComponent.getPreviewBrowser(), iconUser);
+ jpCommentsTabContent.add(lCommentAuthor, c);
+
+ c.gridx = 1;
+ c.gridy = 2 * iCnt;
+ c.weightx = 1.0;
+ String strCommentDate = MyExperimentClient.formatDate(comment.getCreatedAt());
+ JLabel lCommentDate = new JLabel(" - [" + strCommentDate + "]");
+ lCommentDate.setBorder(lCommentAuthor.getBorder());
+ jpCommentsTabContent.add(lCommentDate, c);
+
+ c.gridx = 0;
+ c.gridy = 2 * iCnt + 1;
+ c.weightx = 1.0;
+ c.gridwidth = 2;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ if (iCnt + 1 == lComments.size())
+ c.weighty = 1.0;
+
+ DialogTextArea taCommentText = new DialogTextArea(Util.stripAllHTML(comment.getComment()));
+ taCommentText.setBorder(BorderFactory.createEmptyBorder(0, 25, 10, 25));
+ taCommentText.setOpaque(false);
+ taCommentText.setEditable(false);
+ taCommentText.setLineWrap(true);
+ taCommentText.setWrapStyleWord(true);
+ jpCommentsTabContent.add(taCommentText, c);
+
+ iCnt++;
+ }
+
+ jpCommentsTabContent.validate();
+ jpCommentsTabContent.repaint();
+
+ // this will ensure that even if there are many comments,
+ // the comment panel is still shown starting at the top comment
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ jpCommentsTabContent.scrollRectToVisible(new Rectangle());
+ }
+ });
+ }
+ });
+ }
+ }.start();
+ } else {
+ jpCommentsTabContent.add(Util.generateNoneTextLabel("None"));
+ }
+
+ JScrollPane spCommentsTabContent = wrapPreviewTabContentIntoScrollPane(jpCommentsTabContent);
+ spCommentsTabContent.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
+ return (spCommentsTabContent);
+ }
+
+ private JScrollPane createCreditsPreviewTab(List<Resource> lCreditedUsersOrGroups) {
+ JPanel jpCreditsTabContent = createStandardTabContentPanel();
+
+ if (lCreditedUsersOrGroups.size() > 0) {
+ for (Resource r : lCreditedUsersOrGroups) {
+ jpCreditsTabContent.add(new JClickableLabel(r.getTitle(), "preview:"
+ + r.getItemType() + ":" + r.getURI(), pluginMainComponent.getPreviewBrowser(), new ImageIcon(MyExperimentPerspective.getLocalIconURL(r.getItemType()))));
+ }
+ } else {
+ jpCreditsTabContent.add(Util.generateNoneTextLabel("None"));
+ }
+
+ return (wrapPreviewTabContentIntoScrollPane(jpCreditsTabContent));
+ }
+
+ private JScrollPane createAttributionsPreviewTab(List<Resource> lAttributions) {
+ JPanel jpAttributionsTabContent = createStandardTabContentPanel();
+
+ if (lAttributions.size() > 0) {
+ for (Resource r : lAttributions) {
+ jpAttributionsTabContent.add(new JClickableLabel(r.getTitle(), "preview:"
+ + r.getItemType() + ":" + r.getURI(), pluginMainComponent.getPreviewBrowser(), new ImageIcon(MyExperimentPerspective.getLocalIconURL(r.getItemType()))));
+ }
+ } else {
+ jpAttributionsTabContent.add(Util.generateNoneTextLabel("None"));
+ }
+
+ return (wrapPreviewTabContentIntoScrollPane(jpAttributionsTabContent));
+ }
+
+ /**
+ * A standard starting point for all preview window tabs.
+ */
+ private JPanel createStandardTabContentPanel() {
+ JPanel jpTabContentPanel = new JPanel();
+ jpTabContentPanel.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
+ jpTabContentPanel.setLayout(new BoxLayout(jpTabContentPanel, BoxLayout.Y_AXIS));
+
+ return (jpTabContentPanel);
+ }
+
+ private JScrollPane wrapPreviewTabContentIntoScrollPane(JPanel jpTabContentPanel) {
+ // WRAPS TAB CONTENT into it's own SCROLL PANE ..
+ Dimension dPreferredTabSize = new Dimension(ResourcePreviewBrowser.PREFERRED_WIDTH - 50, PREFERRED_LOWER_TABBED_PANE_HEIGHT);
+
+ JScrollPane spTabContent = new JScrollPane(jpTabContentPanel);
+ spTabContent.setBorder(BorderFactory.createEmptyBorder());
+ spTabContent.setPreferredSize(dPreferredTabSize);
+ spTabContent.getVerticalScrollBar().setUnitIncrement(ResourcePreviewBrowser.PREFERRED_SCROLL);
+
+ return (spTabContent);
+ }
+
+ private JPanel wrapTextPaneAndTabbedViewIntoFullPreview(JTextPane tpHTMLPreview, JTabbedPane tpTabbedView) {
+ // WRAPS HTML JTextPane PREVIEW AND A JTabbedPane WITH DETAILS INTO A SINGLE
+ // PREVIEW PANEL
+ JPanel jpFullPreview = new JPanel();
+ jpFullPreview.setBackground(Color.WHITE); // white background for the whole
+ // preview panel
+ jpFullPreview.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.gridx = GridBagConstraints.REMAINDER;
+ c.gridy = 0;
+ c.weighty = 0; // will not change size when the window is resized
+ jpFullPreview.add(tpHTMLPreview, c);
+
+ c.gridx = GridBagConstraints.REMAINDER;
+ c.gridy = 1;
+ c.weighty = 1; // will grow in size when the window is resized..
+ c.fill = GridBagConstraints.VERTICAL; // ..and fill all available space
+ // vertically
+ c.insets = new Insets(20, 0, 5, 0); // a bit of margin at the top & bottom
+ jpFullPreview.add(tpTabbedView, c);
+
+ return (jpFullPreview);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/SearchOptionsPanel.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/SearchOptionsPanel.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/SearchOptionsPanel.java
new file mode 100644
index 0000000..b2fd9f5
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/SearchOptionsPanel.java
@@ -0,0 +1,317 @@
+/*******************************************************************************
+ * Copyright (C) 2009 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.ui.perspectives.myexperiment;
+
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSpinner;
+import javax.swing.JTextField;
+import javax.swing.SpinnerNumberModel;
+
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.MyExperimentClient;
+import net.sf.taverna.t2.workbench.icons.WorkbenchIcons;
+
+import org.apache.log4j.Logger;
+
+/**
+ * @author Sergejs Aleksejevs, Emmanuel Tagarira
+ */
+public class SearchOptionsPanel extends JPanel implements ItemListener, KeyListener {
+ // CONSTANTS
+ protected static final int SEARCH_RESULT_LIMIT_MIN = 1;
+ protected static final int SEARCH_RESULT_LIMIT_INIT = 20;
+ protected static final int SEARCH_RESULT_LIMIT_MAX = 100;
+
+ private final MainComponent pluginMainComponent;
+ private final MyExperimentClient myExperimentClient;
+ private final Logger logger;
+ private final ActionListener clickHandler;
+
+ // COMPONENTS
+ protected JButton bSearch;
+ private JTextField tfSearchQuery;
+ private JCheckBox cbSearchAllTypes;
+ private JCheckBox cbWorkflows;
+ private JCheckBox cbFiles;
+ private JCheckBox cbPacks;
+ private JCheckBox cbUsers;
+ private JCheckBox cbGroups;
+ protected JSpinner jsResultLimit;
+ protected JTextField tfResultLimitTextField;
+
+ // Data
+ ArrayList<JCheckBox> alDataTypeCheckboxes;
+
+ public SearchOptionsPanel(ActionListener actionListener, MainComponent component, MyExperimentClient client, Logger logger) {
+ super();
+
+ // set main variables to ensure access to myExperiment, logger and the parent component
+ this.pluginMainComponent = component;
+ this.myExperimentClient = client;
+ this.logger = logger;
+ this.clickHandler = actionListener;
+
+ this.initialiseUI();
+
+ // this will hold the collection of all checkboxes that correspond to data types (will be used in item event handling)
+ alDataTypeCheckboxes = new ArrayList<JCheckBox>(Arrays.asList(new JCheckBox[] { cbWorkflows, cbFiles, cbPacks, cbUsers, cbGroups }));
+ }
+
+ private void initialiseUI() {
+ this.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), " Search Settings "), BorderFactory.createEmptyBorder(5, 5, 5, 5)));
+
+ this.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.gridx = 0;
+ c.gridy = 0;
+ c.anchor = GridBagConstraints.WEST;
+ this.add(new JLabel("Query"), c);
+
+ c.gridx = 0;
+ c.gridy = 1;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1.0;
+ tfSearchQuery = new JTextField();
+ tfSearchQuery.setToolTipText("<html>Tips for creating search queries:<br>1) Use wildcards to make more "
+ + "flexible queries. Asterisk (<b>*</b>) matches any zero or more<br> characters (e.g. "
+ + "<b><i>Seq*</i></b> would match <b><i>Sequence</i></b>), question mark (<b>?</b>) matches any single<br>"
+ + " character (e.g. <b><i>Tave?na</i></b> would match <b><i>Taverna</i></b>).<br>"
+ + "2) Enclose the <b><i>\"search query\"</i></b> in double quotes to make exact phrase matching, otherwise<br>"
+ + " items that contain any (or all) words in the <b><i>search query</i></b> will be found.</html>");
+ tfSearchQuery.addKeyListener(this);
+ this.add(tfSearchQuery, c);
+
+ c.gridx = 4;
+ c.gridy = 1;
+ c.gridwidth = 1;
+ c.fill = GridBagConstraints.NONE;
+ c.weightx = 0;
+ c.insets = new Insets(0, 5, 0, 0);
+ bSearch = new JButton("Search", WorkbenchIcons.searchIcon);
+ bSearch.addActionListener(this.clickHandler);
+ bSearch.addKeyListener(this);
+ this.add(bSearch, c);
+
+ c.gridx = 0;
+ c.gridy = 2;
+ c.insets = new Insets(10, 0, 3, 0);
+ this.add(new JLabel("Search for..."), c);
+
+ c.gridx = 0;
+ c.gridy = 3;
+ c.gridwidth = 2;
+ c.insets = new Insets(0, 0, 0, 0);
+ cbSearchAllTypes = new JCheckBox("all resource types", true);
+ cbSearchAllTypes.addItemListener(this);
+ cbSearchAllTypes.addKeyListener(this);
+ this.add(cbSearchAllTypes, c);
+
+ c.gridx = 0;
+ c.gridy = 4;
+ c.gridwidth = 1;
+ c.ipady = 0;
+ cbWorkflows = new JCheckBox("workflows", true);
+ cbWorkflows.addItemListener(this);
+ cbWorkflows.addKeyListener(this);
+ this.add(cbWorkflows, c);
+
+ c.gridx = 0;
+ c.gridy = 5;
+ cbFiles = new JCheckBox("files", true);
+ cbFiles.addItemListener(this);
+ cbFiles.addKeyListener(this);
+ this.add(cbFiles, c);
+
+ c.gridx = 0;
+ c.gridy = 6;
+ cbPacks = new JCheckBox("packs", true);
+ cbPacks.addItemListener(this);
+ cbPacks.addKeyListener(this);
+ this.add(cbPacks, c);
+
+ c.gridx = 1;
+ c.gridy = 4;
+ cbUsers = new JCheckBox("users", true);
+ cbUsers.addItemListener(this);
+ cbUsers.addKeyListener(this);
+ this.add(cbUsers, c);
+
+ c.gridx = 1;
+ c.gridy = 5;
+ cbGroups = new JCheckBox("groups", true);
+ cbGroups.addItemListener(this);
+ cbGroups.addKeyListener(this);
+ this.add(cbGroups, c);
+
+ c.gridx = 3;
+ c.gridy = 2;
+ c.insets = new Insets(10, 25, 3, 0);
+ JLabel jlResultLimit = new JLabel("Result limit");
+ this.add(jlResultLimit, c);
+
+ c.gridx = 3;
+ c.gridy = 3;
+ c.insets = new Insets(0, 25, 0, 0);
+ jsResultLimit = new JSpinner(new SpinnerNumberModel(SEARCH_RESULT_LIMIT_INIT, SEARCH_RESULT_LIMIT_MIN, SEARCH_RESULT_LIMIT_MAX, 1));
+ jsResultLimit.setPreferredSize(new Dimension(jlResultLimit.getPreferredSize().width, jsResultLimit.getPreferredSize().height));
+ this.add(jsResultLimit, c);
+
+ // adding KeyListener to JSpinner directly doesn't make sense; need to attach KeyListener to the text field that is associated with spinner
+ tfResultLimitTextField = ((JSpinner.DefaultEditor) this.jsResultLimit.getEditor()).getTextField();
+ tfResultLimitTextField.addKeyListener(this);
+ }
+
+ public String getSearchQuery() {
+ return (this.tfSearchQuery.getText());
+ }
+
+ public void setSearchQuery(String strSearchQuery) {
+ this.tfSearchQuery.setText(strSearchQuery);
+ }
+
+ public void focusSearchQueryField() {
+ this.tfSearchQuery.selectAll();
+ this.tfSearchQuery.requestFocusInWindow();
+ }
+
+ public void setSearchAllResourceTypes(boolean bSearchAllTypes) {
+ this.cbSearchAllTypes.setSelected(bSearchAllTypes);
+ }
+
+ public boolean getSearchWorkflows() {
+ return (this.cbWorkflows.isSelected());
+ }
+
+ public void setSearchWorkflows(boolean bSearchWorkflows) {
+ this.cbWorkflows.setSelected(bSearchWorkflows);
+ }
+
+ public boolean getSearchFiles() {
+ return (this.cbFiles.isSelected());
+ }
+
+ public void setSearchFiles(boolean bSearchFiles) {
+ this.cbFiles.setSelected(bSearchFiles);
+ }
+
+ public boolean getSearchPacks() {
+ return (this.cbPacks.isSelected());
+ }
+
+ public void setSearchPacks(boolean bSearchPacks) {
+ this.cbPacks.setSelected(bSearchPacks);
+ }
+
+ public boolean getSearchUsers() {
+ return (this.cbUsers.isSelected());
+ }
+
+ public void setSearchUsers(boolean bSearchUsers) {
+ this.cbUsers.setSelected(bSearchUsers);
+ }
+
+ public boolean getSearchGroups() {
+ return (this.cbGroups.isSelected());
+ }
+
+ public void setSearchGroups(boolean bSearchGroups) {
+ this.cbGroups.setSelected(bSearchGroups);
+ }
+
+ public int getResultCountLimit() {
+ // JSpinner handles value validation itself, so there is no need to
+ // make our own validation too
+ return (Integer.parseInt(this.jsResultLimit.getValue().toString()));
+ }
+
+ public void setResultCountLimit(int iLimit) {
+ this.jsResultLimit.setValue(iLimit);
+ }
+
+ // this monitors all checkbox clicks and selects / deselects other checkboxes which are relevant
+ public void itemStateChanged(ItemEvent e) {
+ if (e.getItemSelectable().equals(this.cbSearchAllTypes)) {
+ // "all resource types" clicked - need to select / deselect all data type checkboxes accordingly
+ for (JCheckBox cb : this.alDataTypeCheckboxes) {
+ cb.removeItemListener(this);
+ cb.setSelected(this.cbSearchAllTypes.isSelected());
+ cb.addItemListener(this);
+ }
+
+ // also, enable / disable the search button
+ this.bSearch.setEnabled(this.cbSearchAllTypes.isSelected());
+ } else if (this.alDataTypeCheckboxes.contains(e.getItemSelectable())) {
+ // one of the checkboxes for data types was clicked (e.g. workflows, files, etc);
+ // need to calculate how many of those are currently selected
+ int iSelectedCnt = 0;
+ for (JCheckBox cb : this.alDataTypeCheckboxes) {
+ if (cb.isSelected())
+ iSelectedCnt++;
+ }
+
+ // if all are selected, tick "search all types" checkbox; uncheck otherwise
+ this.cbSearchAllTypes.removeItemListener(this);
+ this.cbSearchAllTypes.setSelected(iSelectedCnt == this.alDataTypeCheckboxes.size());
+ this.cbSearchAllTypes.addItemListener(this);
+
+ // enable search button if at least one data type is selected; disable otherwise
+ this.bSearch.setEnabled(iSelectedCnt > 0);
+ }
+ }
+
+ public void keyPressed(KeyEvent e) {
+ // ENTER pressed - start search by simulating "search" button click
+ // (only do this if the "search" button was active at that moment)
+ if (e.getKeyCode() == KeyEvent.VK_ENTER
+ && this.bSearch.isEnabled()
+ && (Arrays.asList(new JComponent[] { this.tfSearchQuery, this.bSearch, this.cbSearchAllTypes, this.tfResultLimitTextField }).contains(e.getSource()) || this.alDataTypeCheckboxes.contains(e.getSource()))) {
+ this.clickHandler.actionPerformed(new ActionEvent(this.bSearch, 0, ""));
+ }
+ }
+
+ public void keyReleased(KeyEvent e) {
+ // do nothing
+ }
+
+ public void keyTyped(KeyEvent e) {
+ // do nothing
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/SearchResultsPanel.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/SearchResultsPanel.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/SearchResultsPanel.java
new file mode 100644
index 0000000..dbc3b36
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/SearchResultsPanel.java
@@ -0,0 +1,201 @@
+/*******************************************************************************
+ * Copyright (C) 2009 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.ui.perspectives.myexperiment;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.MyExperimentClient;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Resource;
+import net.sf.taverna.t2.workbench.icons.WorkbenchIcons;
+
+import org.apache.log4j.Logger;
+
+/**
+ * @author Sergejs Aleksejevs
+ */
+public class SearchResultsPanel extends JPanel
+{
+ // CONSTANTS
+ public static final String NO_SEARCHES_STATUS = "No searches have been done so far";
+
+
+ private MainComponent pluginMainComponent;
+ private MyExperimentClient myExperimentClient;
+ private Logger logger;
+
+ // COMPONENTS
+ private JLabel lStatusLabel;
+ public JButton bRefresh;
+ public JButton bClear;
+ private JPanel jpResultsBody;
+ private ActionListener alClickHandler;
+
+ // result data store
+ boolean bNoSearchesMadeYet;
+ String strCurrentSearchTerm;
+ HashMap<Integer, ArrayList<Resource>> hmSearchResults;
+
+
+ public SearchResultsPanel(ActionListener buttonClickHandler, MainComponent component, MyExperimentClient client, Logger logger)
+ {
+ super();
+
+ // set main variables to ensure access to myExperiment, logger and the parent component
+ this.pluginMainComponent = component;
+ this.myExperimentClient = client;
+ this.logger = logger;
+ this.alClickHandler = buttonClickHandler;
+
+ // initialise the result data collection to an empty one, just in case
+ // someone calls refresh() before setting the real result data
+ bNoSearchesMadeYet = true;
+ hmSearchResults = new HashMap<Integer, ArrayList<Resource>>();
+
+ this.initialiseUI();
+ }
+
+
+
+ private void initialiseUI()
+ {
+ // label to hold the status of search (e.g. result query + count, etc)
+ this.lStatusLabel = new JLabel(NO_SEARCHES_STATUS);
+ this.lStatusLabel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0)); // a bit of padding on the left
+
+ // control buttons for the search results panel
+ JPanel jpButtonsPanel = new JPanel();
+ jpButtonsPanel.setLayout(new BoxLayout(jpButtonsPanel, BoxLayout.LINE_AXIS));
+ this.bClear = new JButton("Clear", WorkbenchIcons.deleteIcon);
+ this.bClear.addActionListener(this.alClickHandler);
+ this.bClear.setToolTipText("Click this button to clear the search results");
+ this.bClear.setEnabled(false);
+ jpButtonsPanel.add(this.bClear);
+ this.bRefresh = new JButton("Refresh", WorkbenchIcons.refreshIcon);
+ this.bRefresh.addActionListener(this.alClickHandler);
+ this.bRefresh.setToolTipText("Click this button to refresh the search results");
+ this.bRefresh.setEnabled(false);
+ jpButtonsPanel.add(this.bRefresh);
+
+ // status panel containing the status label and control buttons
+ JPanel jpStatusPanel = new JPanel(new BorderLayout());
+ jpStatusPanel.setBorder(BorderFactory.createEtchedBorder());
+ jpStatusPanel.add(this.lStatusLabel, BorderLayout.CENTER);
+ jpStatusPanel.add(jpButtonsPanel, BorderLayout.EAST);
+
+ // create empty panel for the main search result content
+ this.jpResultsBody = new JPanel();
+ jpResultsBody.setLayout(new BorderLayout());
+
+ // PUT EVERYTHING TOGETHER
+ this.setLayout(new BorderLayout());
+ this.add(jpStatusPanel, BorderLayout.NORTH);
+ this.add(this.jpResultsBody, BorderLayout.CENTER);
+
+ // tabbed results view is missing from this method - this is
+ // because if no results will be found in a particular category,
+ // that tab will not be displayed (hence the results view will
+ // need to be generated every time dynamically)
+ }
+
+
+ public void setCurrentSearchTerm(String strSearchTerm)
+ {
+ this.strCurrentSearchTerm = strSearchTerm;
+ }
+
+ public String getCurrentSearchTerm()
+ {
+ return (this.strCurrentSearchTerm);
+ }
+
+
+ public void setSearchResultsData(HashMap<Integer, ArrayList<Resource>> hmResults)
+ {
+ this.bNoSearchesMadeYet = false;
+ this.hmSearchResults = hmResults;
+ }
+
+
+ public void setStatus(String status)
+ {
+ this.lStatusLabel.setText(status);
+ }
+
+ public void refresh()
+ {
+ // remove all items from the main results content panel
+ this.jpResultsBody.removeAll();
+
+ if (!this.bNoSearchesMadeYet) // this will be true if the result collection was never assigned to this result panel
+ {
+ ArrayList<Integer> alResourceTypes = new ArrayList<Integer>(this.hmSearchResults.keySet());
+ Collections.sort(alResourceTypes); // this will ensure that the tabs are always in the correct order
+ if(alResourceTypes.isEmpty()) {
+ this.jpResultsBody.add(new JLabel("No items to display"), BorderLayout.NORTH);
+ this.repaint();
+ }
+ else {
+ JTabbedPane tpResults = new JTabbedPane();
+
+ for(int iType : alResourceTypes)
+ {
+ // HACK: for now all item types are suitably turned into plural by simply appending "s"
+ String strTabLabel = Resource.getResourceTypeName(iType) + "s (" + this.hmSearchResults.get(iType).size() + ")";
+
+ ResourceListPanel jpTabContents = new ResourceListPanel(pluginMainComponent, myExperimentClient, logger);
+ jpTabContents.setListItems(this.hmSearchResults.get(iType));
+
+ JScrollPane spTabContents = new JScrollPane(jpTabContents);
+ spTabContents.getVerticalScrollBar().setUnitIncrement(ResourcePreviewBrowser.PREFERRED_SCROLL);
+
+ tpResults.add(strTabLabel, spTabContents);
+ }
+
+ this.jpResultsBody.add(tpResults, BorderLayout.CENTER);
+ this.bClear.setEnabled(true);
+ this.bRefresh.setEnabled(true);
+ }
+ }
+
+ this.revalidate();
+ }
+
+
+ public void clear()
+ {
+ // remove all items from the main results content panel
+ this.jpResultsBody.removeAll();
+ this.repaint();
+ this.revalidate();
+ }
+
+}