You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/02/23 11:22:36 UTC

[13/51] [partial] incubator-taverna-workbench git commit: Revert "temporarily empty repository"

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/search/ServiceFilteringSettings.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/search/ServiceFilteringSettings.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/search/ServiceFilteringSettings.java
new file mode 100644
index 0000000..76d4eca
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/search/ServiceFilteringSettings.java
@@ -0,0 +1,184 @@
+package net.sf.taverna.biocatalogue.model.search;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.tree.TreePath;
+
+import net.sf.taverna.biocatalogue.model.Util;
+import net.sf.taverna.biocatalogue.ui.filtertree.FilterTreeNode;
+import net.sf.taverna.biocatalogue.ui.tristatetree.JTriStateTree;
+
+/**
+ * This class provides functionality to deal with service filtering settings.
+ * Particularly used to save the current state of the filtering tree as a
+ * favourite filter.
+ * 
+ * Instances of this class hold all necessary information to restore the
+ * filtering state at a later point.
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public class ServiceFilteringSettings implements Comparable<ServiceFilteringSettings>, Serializable
+{
+  private static final long serialVersionUID = -5706169924295062628L;
+  
+  private String filterName;
+  private int filteringCriteriaNumber;
+  private List<TreePath> filterTreeRootsOfCheckedPaths;
+  
+  
+  
+  /**
+   * Stores current filtering selection in the provided JTriStateTree
+   * instance into the instance of this class.
+   * 
+   * @param filterTree The JTriStateTree instance to get the current selection from.
+   */
+  public ServiceFilteringSettings(JTriStateTree filterTree)
+  {
+    this(null, filterTree);
+  }
+  
+  
+  /**
+   * Stores current filtering selection in the provided JTriStateTree
+   * instance into the instance of this class.
+   * 
+   * @param filterName The name to associate with this filter.
+   * @param filterTree The JTriStateTree instance to get the current selection from.
+   */
+  @SuppressWarnings("unchecked")
+  public ServiceFilteringSettings(String filterName, JTriStateTree filterTree)
+  {
+    this.filterName = filterName;
+    
+    this.filteringCriteriaNumber = filterTree.getLeavesOfCheckedPaths().size();
+    
+    // a deep copy of the data from the filter tree is created, so that the data stored in this instance
+    // is fully independent of the filter tree itself; therefore local copy of this data may be modified
+    // as needed and will not affect the main filter (and vice versa) 
+    this.filterTreeRootsOfCheckedPaths = (List<TreePath>)Util.deepCopy(filterTree.getRootsOfCheckedPaths());
+  }
+  
+  
+  /**
+   * Analyses the filter tree and produces part of the request URL containing settings regarding filters.
+   */
+  @SuppressWarnings("unchecked")
+  public Map<String,String[]> getFilteringURLParameters()
+  {
+    // analyse filter tree to get checked elements 
+    Map<String,HashSet<String>> selections = new HashMap<String,HashSet<String>>(); 
+    
+    // cycle through the deepest selected nodes;
+    // NB! the CheckboxTree acts in a way that if A contains B,C --
+    // 1) if only B is checked, tp.getLastPathComponent() will be B;
+    // 2) if both B,C are checked, tp.getLastPathComponent() will be A;
+    for (TreePath selectedRootNodePath : getFilterTreeRootsOfCheckedPaths()) {
+      FilterTreeNode selectedNode = (FilterTreeNode)selectedRootNodePath.getLastPathComponent();
+      
+      // identify affected nodes
+      HashSet<FilterTreeNode> affectedNodes = new HashSet<FilterTreeNode>();
+      if (selectedNode.isFilterCategory()) {
+        // case as in example 2) -- need to "extract" nodes that are one level deeper
+        for (Enumeration children = selectedNode.children(); children.hasMoreElements(); ) {
+          affectedNodes.add((FilterTreeNode)children.nextElement());
+        }
+      }
+      else {
+        // case as in example 1)
+        affectedNodes.add(selectedNode);
+      }
+      
+      // walk through the identified collection of nodes and build the data structure with URL values
+      for (FilterTreeNode node : affectedNodes) {
+        if (selections.containsKey(node.getType())) {
+          selections.get(node.getType()).add(node.getUrlValue());
+        }
+        else {
+          HashSet<String> newSet = new HashSet<String>();
+          newSet.add(node.getUrlValue());
+          
+          selections.put(node.getType(), newSet);
+        }
+      }
+    }
+    
+    
+    // now use the constructed set of data to build the map of filtering URL parameters
+    Map<String,String[]> filterUrlParameters = new HashMap<String,String[]>();
+    for(String key : selections.keySet())
+    {
+      List<String> categoryValues = new ArrayList<String>();
+      for (String value : selections.get(key)) {
+        categoryValues.add(value);
+      }
+      
+      filterUrlParameters.put(key, categoryValues.toArray(new String[0]));
+    }
+    
+    return (filterUrlParameters);
+  }
+  
+  
+  // *** Getters ***
+  
+  public String getFilterName() {
+    return (this.filterName == null || filterName.length() == 0 ? "untitled filter" : this.filterName);
+  }
+  
+  public List<TreePath> getFilterTreeRootsOfCheckedPaths() {
+    return filterTreeRootsOfCheckedPaths;
+  }
+  
+  /**
+   * @return Number of filtering criteria within the current filter.
+   */
+  public int getNumberOfFilteringCriteria() {
+    return filteringCriteriaNumber;
+  }
+  
+  // *** End of getters ***
+  
+  
+  public boolean equals(Object other)
+  {
+    if (other instanceof ServiceFilteringSettings)
+    {
+      ServiceFilteringSettings o = (ServiceFilteringSettings)other;
+      return (this.filterName.equals(o.filterName) &&
+              this.filterTreeRootsOfCheckedPaths.equals(o.filterTreeRootsOfCheckedPaths));
+    }
+    else {
+      return false;
+    }
+  }
+  
+  
+  public int compareTo(ServiceFilteringSettings other)
+  {
+    int iOrdering = this.filterName.compareTo(other.filterName);
+    if (iOrdering == 0) {
+      iOrdering = this.getNumberOfFilteringCriteria() - other.getNumberOfFilteringCriteria();
+    }
+    
+    // inverse order, as the traversal of lists in the favourite filters panel is
+    // done this way round
+    return (-1 * iOrdering);
+  }
+  
+  
+  public String toString() {
+    return ("Filter: '" + getFilterName() + "' [" + detailsAsString() + "]");
+  }
+  
+  public String detailsAsString() {
+    return (getNumberOfFilteringCriteria() + " filtering criteria");
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/AnnotationBean.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/AnnotationBean.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/AnnotationBean.java
new file mode 100644
index 0000000..81ce849
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/AnnotationBean.java
@@ -0,0 +1,52 @@
+package net.sf.taverna.biocatalogue.test;
+
+
+public class AnnotationBean
+{
+  public AnnotationBean() { }
+  
+  public String self;
+  private int version;
+  private String created;
+  public Annotatable annotatable;
+  private Source source;
+  private Attribute attribute;
+  private Value value;
+  
+  
+  public static class Annotatable
+  {
+    private Annotatable() { }
+    
+    private String name;
+    public String resource;
+    private String type;
+  }
+  
+  public static class Source
+  {
+    private Source() { }
+    
+    private String name;
+    private String resource;
+    private String type;
+  }
+  
+  public static class Attribute
+  {
+    private Attribute() { }
+    
+    private String name;
+    private String resource;
+    private String identifier;
+  }
+  
+  public static class Value
+  {
+    private Value() { }
+    
+    private String resource;
+    private String type;
+    private String content;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/DrawDefaultIconTest.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/DrawDefaultIconTest.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/DrawDefaultIconTest.java
new file mode 100644
index 0000000..1bec9e6
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/DrawDefaultIconTest.java
@@ -0,0 +1,38 @@
+package net.sf.taverna.biocatalogue.test;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.image.BufferedImage;
+
+import javax.swing.ImageIcon;
+import javax.swing.JOptionPane;
+
+public class DrawDefaultIconTest {
+
+  /**
+   * @param args
+   */
+  public static void main(String[] args)
+  {
+    int w = 16;
+    int h = 16;
+    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+    GraphicsDevice gd = ge.getDefaultScreenDevice();
+    GraphicsConfiguration gc = gd.getDefaultConfiguration();
+    
+    BufferedImage image = gc.createCompatibleImage(w, h, BufferedImage.TYPE_INT_ARGB);
+    Graphics2D g = image.createGraphics();
+    g.setColor(Color.RED);
+    g.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER));
+    g.drawLine(4, 4, 12, 12);
+    g.drawLine(12, 4, 4, 12);
+    g.dispose();
+    
+    JOptionPane.showMessageDialog(null, new ImageIcon(image)); 
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/GSONTest.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/GSONTest.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/GSONTest.java
new file mode 100644
index 0000000..eba01d6
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/GSONTest.java
@@ -0,0 +1,19 @@
+package net.sf.taverna.biocatalogue.test;
+
+import com.google.gson.Gson;
+
+public class GSONTest
+{
+
+  public static void main(String[] args) throws Exception
+  {
+    String json = "[{\"annotatable\":{\"name\":\"IndexerService\",\"resource\":\"http://sandbox.biocatalogue.org/services/2158\",\"type\":\"Service\"},\"self\":\"http://sandbox.biocatalogue.org/annotations/47473\",\"value\":{\"resource\":\"http://sandbox.biocatalogue.org/tags/indexing\",\"type\":\"Tag\",\"content\":\"indexing\"},\"version\":1,\"created\":\"2010-01-13T09:24:04Z\",\"source\":{\"name\":\"Marco Roos\",\"resource\":\"http://sandbox.biocatalogue.org/users/48\",\"type\":\"User\"},\"attribute\":{\"name\":\"Tag\",\"resource\":\"http://sandbox.biocatalogue.org/annotation_attributes/2\",\"identifier\":\"http://www.biocatalogue.org/attribute#Category\"}}]";
+    
+    Gson gson = new Gson();
+    AnnotationBean[] a = gson.fromJson(json, AnnotationBean[].class);
+    
+    System.out.println("Self URL: " + a[0].self);
+    System.out.println("Annotatable resource: " + a[0].annotatable.resource);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/GSONTest_exportingJSON.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/GSONTest_exportingJSON.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/GSONTest_exportingJSON.java
new file mode 100644
index 0000000..6e63ebb
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/GSONTest_exportingJSON.java
@@ -0,0 +1,30 @@
+package net.sf.taverna.biocatalogue.test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.sf.taverna.biocatalogue.model.connectivity.BeanForPOSTToFilteredIndex;
+
+import com.google.gson.Gson;
+
+public class GSONTest_exportingJSON
+{
+
+  /**
+   * @param args
+   */
+  public static void main(String[] args)
+  {
+    Map<String, String[]> m = new HashMap<String, String[]>();
+    m.put("a", new String[] {"b","c"});
+    m.put("d", new String[] {"e","f"});
+    
+    BeanForPOSTToFilteredIndex b = new BeanForPOSTToFilteredIndex();
+    b.filters = m;
+    
+    Gson gson = new Gson();
+    System.out.println(gson.toJson(b));
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/GSONTest_forSoapOperationsIndex.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/GSONTest_forSoapOperationsIndex.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/GSONTest_forSoapOperationsIndex.java
new file mode 100644
index 0000000..30035f7
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/GSONTest_forSoapOperationsIndex.java
@@ -0,0 +1,27 @@
+package net.sf.taverna.biocatalogue.test;
+
+import net.sf.taverna.biocatalogue.model.Resource;
+import net.sf.taverna.biocatalogue.model.connectivity.BeansForJSONLiteAPI;
+import net.sf.taverna.biocatalogue.model.connectivity.BioCatalogueClient;
+
+public class GSONTest_forSoapOperationsIndex
+{
+
+  /**
+   * @param args
+   * @throws Exception
+   */
+  public static void main(String[] args) throws Exception
+  {
+    BioCatalogueClient client = BioCatalogueClient.getInstance(); 
+    
+    String url = BioCatalogueClient.API_SOAP_OPERATIONS_URL;
+//    url = Util.appendURLParameter(url, "q", "blast");
+    BeansForJSONLiteAPI.ResourceIndex soapOpIndex = client.getBioCatalogueResourceLiteIndex(Resource.TYPE.SOAPOperation, url);
+    
+    System.out.println("result count: " + soapOpIndex.getResources().length + "\n\n");
+//    System.out.println(soapOpIndex.soap_operations[1].getName() + "\n" + soapOpIndex.soap_operations[1].getURL() + "\n\n");
+    
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/JWaitDialogTest.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/JWaitDialogTest.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/JWaitDialogTest.java
new file mode 100644
index 0000000..2aed586
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/JWaitDialogTest.java
@@ -0,0 +1,36 @@
+package net.sf.taverna.biocatalogue.test;
+
+import net.sf.taverna.biocatalogue.ui.JWaitDialog;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.MainComponent;
+
+public class JWaitDialogTest
+{
+
+  public static void main(String[] args)
+  {
+    System.out.println("start test");
+    
+    final JWaitDialog jwd = new JWaitDialog(MainComponent.dummyOwnerJFrame, "Old title", "Please wait... Please wait... Please wait... Please wait...");
+    
+    // NB! Background process must be started before the modal dialog box
+    //     is made visible - otherwise processing freezes.
+    new Thread("testing delayed update of JWaitDialog")
+    {
+      public void run()
+      {
+        // wait for some time
+        try { Thread.sleep(3000); }
+        catch (InterruptedException e) { /* do nothing */ }
+        
+        // update the dialog
+        jwd.setTitle("New title");
+        jwd.waitFinished("Great, all done!");
+        
+        System.out.println("end test");
+      }
+    }.start();
+    
+    jwd.setVisible(true);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/LinkedListEqualsTest.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/LinkedListEqualsTest.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/LinkedListEqualsTest.java
new file mode 100644
index 0000000..6f252bd
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/LinkedListEqualsTest.java
@@ -0,0 +1,25 @@
+package net.sf.taverna.biocatalogue.test;
+
+import java.util.LinkedList;
+
+public class LinkedListEqualsTest
+{
+  public static void main(String[] args)
+  {
+    LinkedList l = new LinkedList();
+    
+    String a = new String("test1");
+    String b = new String("test2");
+    
+    System.out.println(a == b);
+    System.out.println(a.equals(b));
+    
+    l.add(a);
+    l.add(b);
+    
+    System.out.println(l);
+    System.out.println(l.indexOf(a));
+    System.out.println(l.indexOf(b));
+    
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestAPICaller.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestAPICaller.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestAPICaller.java
new file mode 100644
index 0000000..a48a996
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestAPICaller.java
@@ -0,0 +1,241 @@
+package net.sf.taverna.biocatalogue.test;
+
+import javax.swing.JFrame;
+import java.awt.Dimension;
+import javax.swing.JPanel;
+import java.awt.BorderLayout;
+import javax.swing.JTextField;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JOptionPane;
+import javax.swing.JTextPane;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+
+import net.sf.taverna.biocatalogue.model.connectivity.BioCatalogueClient;
+
+import java.awt.GridBagLayout;
+import java.awt.GridBagConstraints;
+import java.awt.Insets;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+/**
+ * @author Sergejs Aleksejevs
+ */
+public class TestAPICaller extends JFrame implements ActionListener {
+
+	private JPanel jContentPane = null;
+	private JTextField tfURL = null;
+	private JButton bSubmitRequest = null;
+	private JButton bClear = null;
+	private JScrollPane spOutputPane = null;
+	private JTextPane tpOutputPane = null;
+
+	/**
+	 * This method initializes 
+	 * 
+	 */
+	public TestAPICaller() {
+		super();
+		initialize();
+	}
+
+	/**
+	 * This method initializes this
+	 * 
+	 */
+	private void initialize() {
+        this.setSize(new Dimension(515, 321));
+        this.setTitle("Test Service Catalogue API Caller");
+        this.setContentPane(getJContentPane());
+		
+        this.bSubmitRequest.setDefaultCapable(true);
+        this.getRootPane().setDefaultButton(bSubmitRequest);
+	}
+
+	/**
+	 * This method initializes jContentPane	
+	 * 	
+	 * @return javax.swing.JPanel	
+	 */
+	private JPanel getJContentPane() {
+		if (jContentPane == null) {
+			GridBagConstraints gridBagConstraints3 = new GridBagConstraints();
+			gridBagConstraints3.fill = GridBagConstraints.BOTH;
+			gridBagConstraints3.gridwidth = 2;
+			gridBagConstraints3.gridx = 0;
+			gridBagConstraints3.gridy = 2;
+			gridBagConstraints3.ipadx = 459;
+			gridBagConstraints3.ipady = 182;
+			gridBagConstraints3.weightx = 1.0;
+			gridBagConstraints3.weighty = 1.0;
+			gridBagConstraints3.insets = new Insets(4, 12, 9, 12);
+			GridBagConstraints gridBagConstraints2 = new GridBagConstraints();
+			gridBagConstraints2.fill = GridBagConstraints.HORIZONTAL;
+			gridBagConstraints2.gridy = 1;
+			gridBagConstraints2.ipadx = 0;
+			gridBagConstraints2.ipady = 0;
+			gridBagConstraints2.insets = new Insets(0, 5, 7, 12);
+			gridBagConstraints2.weightx = 0.5;
+			gridBagConstraints2.gridx = 1;
+			GridBagConstraints gridBagConstraints1 = new GridBagConstraints();
+			gridBagConstraints1.fill = GridBagConstraints.HORIZONTAL;
+			gridBagConstraints1.gridy = 1;
+			gridBagConstraints1.ipadx = 0;
+			gridBagConstraints1.ipady = 0;
+			gridBagConstraints1.insets = new Insets(0, 12, 7, 5);
+			gridBagConstraints1.weightx = 0.5;
+			gridBagConstraints1.gridx = 0;
+			GridBagConstraints gridBagConstraints = new GridBagConstraints();
+			gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
+			gridBagConstraints.gridwidth = 2;
+			gridBagConstraints.gridx = 0;
+			gridBagConstraints.gridy = 0;
+			gridBagConstraints.ipadx = 466;
+			gridBagConstraints.weightx = 1.0;
+			gridBagConstraints.ipady = 3;
+			gridBagConstraints.insets = new Insets(13, 12, 8, 12);
+			jContentPane = new JPanel();
+			jContentPane.setLayout(new GridBagLayout());
+			jContentPane.add(getTfURL(), gridBagConstraints);
+			jContentPane.add(getBSubmitRequest(), gridBagConstraints1);
+			jContentPane.add(getBClear(), gridBagConstraints2);
+			jContentPane.add(getSpOutputPane(), gridBagConstraints3);
+		}
+		return jContentPane;
+	}
+
+	/**
+	 * This method initializes tfURL	
+	 * 	
+	 * @return javax.swing.JTextField	
+	 */
+	private JTextField getTfURL() {
+		if (tfURL == null) {
+			tfURL = new JTextField();
+			tfURL.setText(BioCatalogueClient.DEFAULT_API_SANDBOX_BASE_URL);
+		}
+		return tfURL;
+	}
+
+	/**
+	 * This method initializes tfSubmitRequest	
+	 * 	
+	 * @return javax.swing.JButton	
+	 */
+	private JButton getBSubmitRequest() {
+		if (bSubmitRequest == null) {
+			bSubmitRequest = new JButton();
+			bSubmitRequest.setText("Submit Request");
+			bSubmitRequest.addActionListener(this);
+		}
+		return bSubmitRequest;
+	}
+	
+	
+	/**
+	 * This method initializes bClear	
+	 * 	
+	 * @return javax.swing.JButton	
+	 */
+	private JButton getBClear() {
+		if (bClear == null) {
+			bClear = new JButton();
+			bClear.setText("Clear Output");
+			bClear.addActionListener(this);
+		}
+		return bClear;
+	}
+	
+	
+	/**
+	 * This method initializes tpOutputPane	
+	 * 	
+	 * @return javax.swing.JTextPane	
+	 */
+	private JTextPane getTpOutputPane() {
+		if (tpOutputPane == null) {
+			tpOutputPane = new JTextPane();
+			tpOutputPane.setContentType("text/plain");
+		}
+		return tpOutputPane;
+	}
+	
+
+	/**
+	 * This method initializes spOutputPane	
+	 * 	
+	 * @return javax.swing.JScrollPane	
+	 */
+	private JScrollPane getSpOutputPane() {
+		if (spOutputPane == null) {
+			spOutputPane = new JScrollPane();
+			spOutputPane.setViewportView(getTpOutputPane());
+		}
+		return spOutputPane;
+	}
+
+	
+	// ACTION LISTENER
+	
+	public void actionPerformed(ActionEvent e) {
+		if (e.getSource().equals(bSubmitRequest)) {
+			tfURL.selectAll();
+			
+			// call the actual test method
+			runBioCatalogueAPITest(tfURL.getText());
+		}
+		else if (e.getSource().equals(bClear)) {
+			this.tpOutputPane.setText("");
+		}
+		
+	}
+
+
+	// ACTUAL TEST CLASS
+	
+	private void runBioCatalogueAPITest(String url) {
+		final String urlFinal = url;
+		new Thread("making request") {
+  		public void run() {
+  		  tpOutputPane.setText("Initialising Service Catalogue client...");
+  		  BioCatalogueClient client = null;
+        try {
+          client = BioCatalogueClient.getInstance();
+        }
+        catch (Exception e) {
+          e.printStackTrace();
+        }
+        
+    		final StringBuilder text = new StringBuilder();
+    		try {
+    		  tpOutputPane.setText("Sending request...");
+    		  BufferedReader br = new BufferedReader(new InputStreamReader(client.doBioCatalogueGET(urlFinal).getResponseStream()));
+    		  String str = "";
+    		  
+    		  while ((str = br.readLine()) != null) {
+    		    text.append(str + "\n");
+    		  }
+    		  
+    		  br.close();
+    		}
+    		catch (Exception e) {
+    		  text.append(e);
+    		}
+    		
+    		SwingUtilities.invokeLater(new Runnable() {
+    		  public void run() {
+    		    tpOutputPane.setText(text.toString());
+    		  }
+    		});
+  		}
+		}.start();
+		
+	}
+
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestDoubleUsageOfSameSwingElement.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestDoubleUsageOfSameSwingElement.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestDoubleUsageOfSameSwingElement.java
new file mode 100644
index 0000000..e5ad39c
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestDoubleUsageOfSameSwingElement.java
@@ -0,0 +1,32 @@
+package net.sf.taverna.biocatalogue.test;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+
+public class TestDoubleUsageOfSameSwingElement extends JFrame
+{
+  private String text = "abc";
+  boolean bLowerCase = true;
+  
+  public TestDoubleUsageOfSameSwingElement()
+  {
+    final JButton bBtn = new JButton(text);
+    bBtn.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        bLowerCase = !bLowerCase;
+        bBtn.setText(bLowerCase ? text.toLowerCase() : text.toUpperCase());
+      }
+    });
+    
+    this.setLayout(new BorderLayout());
+    this.add(bBtn, BorderLayout.WEST);
+    this.add(bBtn, BorderLayout.EAST);
+    
+    this.pack();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestUtilURLHandling.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestUtilURLHandling.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestUtilURLHandling.java
new file mode 100644
index 0000000..71a6ca7
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestUtilURLHandling.java
@@ -0,0 +1,87 @@
+package net.sf.taverna.biocatalogue.test;
+
+import net.sf.taverna.biocatalogue.model.Util;
+
+public class TestUtilURLHandling
+{
+  public static void main(String[] args)
+  {
+    String url1 = "http://sandbox.biocatalogue.org/search";
+    String url2 = "http://sandbox.biocatalogue.org/search?";
+    String url3 = "http://sandbox.biocatalogue.org/search?q=";
+    String url4 = "http://sandbox.biocatalogue.org/search?q=franck";
+    String url5 = "http://sandbox.biocatalogue.org/services?tag=%5Bbiology%5D";
+    String url6 = "http://sandbox.biocatalogue.org/services?tag=%5B%3Chttp%3A%2F%2Fwww.mygrid.org.uk%2Fontology%23DDBJ%3E%5D";
+    
+    
+    System.out.println("----------------------------");
+    System.out.println("Extracting URL parameters:\n");
+    
+    
+    System.out.println(url1 + "\nParameter map:\n" + Util.extractURLParameters(url1));
+    System.out.println("Reconstructed query string from parameter map: " + Util.constructURLQueryString(Util.extractURLParameters(url1)) + "\n");
+    
+    
+    System.out.println(url2 + "\nParameter map:\n" + Util.extractURLParameters(url2));
+    System.out.println("Reconstructed query string from parameter map: " + Util.constructURLQueryString(Util.extractURLParameters(url2)) + "\n");
+    
+    
+    System.out.println(url3 + "\nParameter map:\n" + Util.extractURLParameters(url3));
+    System.out.println("Reconstructed query string from parameter map: " + Util.constructURLQueryString(Util.extractURLParameters(url3)) + "\n");
+    
+    
+    System.out.println(url4 + "\nParameter map:\n" + Util.extractURLParameters(url4));
+    System.out.println("Reconstructed query string from parameter map: " + Util.constructURLQueryString(Util.extractURLParameters(url4)) + "\n");
+    
+    
+    System.out.println(url5 + "\nParameter map:\n" + Util.extractURLParameters(url5));
+    System.out.println("Reconstructed query string from parameter map: " + Util.constructURLQueryString(Util.extractURLParameters(url5)) + "\n");
+    
+    
+    System.out.println("\n\n----------------------------");
+    System.out.println("Adding parameters:\n");
+    
+    String newUrl = Util.appendURLParameter(url1, "testParam", "testValue");
+    System.out.println(url1 + "\n" + newUrl + "\n");
+    
+    newUrl = Util.appendURLParameter(url2, "testParam", "testValue");
+    System.out.println(url2 + "\n" + newUrl + "\n");
+    
+    newUrl = Util.appendURLParameter(url3, "testParam", "testValue");
+    System.out.println(url3 + "\n" + newUrl + "\n");
+    
+    newUrl = Util.appendURLParameter(url4, "testParam", "testValue");
+    System.out.println(url4 + "\n" + newUrl + "\n");
+    
+    newUrl = Util.appendURLParameter(url5, "testParam", "testValue");
+    System.out.println(url5 + "\n" + newUrl + "\n");
+    
+    
+    System.out.println("\n\n----------------------------");
+    System.out.println("Getting parameter values:\n");
+    
+    System.out.println("Value of '" + "testParam" + "' in the URL: " + url1 + " -- " + Util.extractURLParameter(url1, "testParam"));
+    System.out.println("Value of '" + "testParam" + "' in the URL: " + url2 + " -- " + Util.extractURLParameter(url2, "testParam"));
+    System.out.println("Value of '" + "q" + "' in the URL: " + url3 + " -- " + Util.extractURLParameter(url3, "q"));
+    System.out.println("Value of '" + "q" + "' in the URL: " + url4 + " -- " + Util.extractURLParameter(url4, "q"));
+    System.out.println("Value of '" + "tag" + "' in the URL: " + url5 + " -- " + Util.extractURLParameter(url5, "tag"));
+    
+    
+    System.out.println("\n\n----------------------------");
+    System.out.println("URL decoding:\n");
+    
+    System.out.println("Original URL: " + url6 + "\nDecoded URL: " + Util.urlDecodeQuery(url6));
+    
+    
+    System.out.println("\n\n----------------------------");
+    System.out.println("Appending a string before URL parameters:\n");
+    
+    String strToAppend = ".xml";
+    System.out.println("Appending '" + strToAppend + "' in the URL: " + url1 + " -- " + Util.appendStringBeforeParametersOfURL(url1, strToAppend));
+    System.out.println("Appending '" + strToAppend + "' in the URL: " + url2 + " -- " + Util.appendStringBeforeParametersOfURL(url2, strToAppend));
+    System.out.println("Appending '" + strToAppend + "' in the URL: " + url3 + " -- " + Util.appendStringBeforeParametersOfURL(url3, strToAppend));
+    System.out.println("Appending '" + strToAppend + "' in the URL: " + url4 + " -- " + Util.appendStringBeforeParametersOfURL(url4, strToAppend));
+    System.out.println("Appending '" + strToAppend + "' in the URL: " + url5 + " -- " + Util.appendStringBeforeParametersOfURL(url5, strToAppend));
+    System.out.println("Appending '" + strToAppend + "' in the URL: " + url6 + " -- " + Util.appendStringBeforeParametersOfURL(url6, strToAppend));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestXHTMLRenderer.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestXHTMLRenderer.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestXHTMLRenderer.java
new file mode 100644
index 0000000..a50254e
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/TestXHTMLRenderer.java
@@ -0,0 +1,42 @@
+package net.sf.taverna.biocatalogue.test;
+
+import java.awt.Container;
+import java.io.File;
+
+import javax.swing.JFrame;
+
+import org.xhtmlrenderer.simple.FSScrollPane;
+import org.xhtmlrenderer.simple.XHTMLPanel;
+
+public class TestXHTMLRenderer extends JFrame {
+  public TestXHTMLRenderer() {
+    try {
+      init();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+  
+  public void init() throws Exception {
+    Container contentPane = this.getContentPane();
+    
+    XHTMLPanel panel = new XHTMLPanel();
+    panel.getSharedContext().getTextRenderer().setSmoothingThreshold(0); // Anti-aliasing for all font sizes
+    panel.setDocument(new File("c:\\Temp\\MyExperiment\\T2 BioCatalogue Plugin\\BioCatalogue Plugin\\resources\\test.html"));
+    
+    FSScrollPane scroll = new FSScrollPane(panel);
+    contentPane.add(scroll);
+    
+    this.setTitle("XHTML rendered test");
+    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+    this.pack();
+    this.setSize(1024, 768);
+  }
+  
+  
+  public static void main(String[] args) {
+    JFrame f = new TestXHTMLRenderer();
+    f.setVisible(true);
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/WrappableJLabelTest.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/WrappableJLabelTest.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/WrappableJLabelTest.java
new file mode 100644
index 0000000..22afbd4
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/WrappableJLabelTest.java
@@ -0,0 +1,35 @@
+package net.sf.taverna.biocatalogue.test;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+public class WrappableJLabelTest extends JFrame
+{
+  public WrappableJLabelTest() {
+    
+    // depending on the LayoutManager of the container, JLabel may
+    // be resized or simply "cut off" on the edges - e.g. FlowLayout
+    // cuts it off, BorderLayout does the resizing
+    JPanel jpTestPanel = new JPanel(new BorderLayout());
+    jpTestPanel.add(new JLabel("<html><span color=\"red\">a very long</span> text that <b>is just</b> " +
+        "showing how the whole thing looks - will it wrap text or not; this " +
+    "is the question</html>"), BorderLayout.CENTER);
+    
+    this.getContentPane().add(jpTestPanel);
+    
+    this.pack();
+  }
+  
+  public static void main(String[] args)
+  {
+    WrappableJLabelTest f = new WrappableJLabelTest();
+    f.setLocationRelativeTo(null);
+    f.setPreferredSize(new Dimension(400, 300));
+    f.setVisible(true);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/XStreamTest.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/XStreamTest.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/XStreamTest.java
new file mode 100644
index 0000000..edc1d5a
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/test/XStreamTest.java
@@ -0,0 +1,32 @@
+package net.sf.taverna.biocatalogue.test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.DomDriver;
+
+import net.sf.taverna.biocatalogue.model.SoapOperationIdentity;
+
+
+public class XStreamTest
+{
+
+  public static void main(String[] args)
+  {
+    List<SoapOperationIdentity> processors = new ArrayList<SoapOperationIdentity>();
+    processors.add(new SoapOperationIdentity("http://www.test.com/test.wsdl", "aa", null));
+    processors.add(new SoapOperationIdentity("http://www.example.com/example.wsdl", "bb", null));
+    
+    XStream xstream = new XStream(new DomDriver());
+    String xml = xstream.toXML(processors);
+    
+    System.out.println(xml);
+    
+    List<SoapOperationIdentity> processorsFromXML = (List<SoapOperationIdentity>)xstream.fromXML(xml);
+    System.out.println("\n\n");
+    System.out.println(processorsFromXML.get(0).getWsdlLocation() + " - " + processorsFromXML.get(0).getOperationName());
+    System.out.println(processorsFromXML.get(1).getWsdlLocation() + " - " + processorsFromXML.get(1).getOperationName());
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/BioCatalogueExplorationTab.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/BioCatalogueExplorationTab.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/BioCatalogueExplorationTab.java
new file mode 100644
index 0000000..d3f452d
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/BioCatalogueExplorationTab.java
@@ -0,0 +1,131 @@
+package net.sf.taverna.biocatalogue.ui;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+
+import javax.swing.BorderFactory;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.LayoutFocusTraversalPolicy;
+
+import net.sf.taverna.biocatalogue.model.connectivity.BioCatalogueClient;
+import net.sf.taverna.biocatalogue.ui.search_results.SearchResultsMainPanel;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.MainComponent;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.MainComponentFactory;
+
+import org.apache.log4j.Logger;
+
+
+/**
+ * 
+ * @author Sergejs Aleksejevs
+ */
+@SuppressWarnings("serial")
+public class BioCatalogueExplorationTab extends JPanel implements HasDefaultFocusCapability
+{
+  private final MainComponent pluginPerspectiveMainComponent;
+  private final BioCatalogueClient client;
+  private final Logger logger;
+  
+  
+  // COMPONENTS
+  private BioCatalogueExplorationTab thisPanel;
+  
+  private SearchOptionsPanel searchOptionsPanel;
+  private SearchResultsMainPanel tabbedSearchResultsPanel;
+  
+  
+  public BioCatalogueExplorationTab()
+  {
+    this.thisPanel = this;
+    
+    this.pluginPerspectiveMainComponent = MainComponentFactory.getSharedInstance();
+    this.client = BioCatalogueClient.getInstance();
+    this.logger = Logger.getLogger(this.getClass());
+    
+    initialiseUI();
+    
+    // this is to make sure that search will get focused when this tab is opened
+    // -- is a workaround to a bug in JVM
+    setFocusCycleRoot(true);
+    setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() {
+      public Component getDefaultComponent(Container cont) {
+          return (thisPanel.getDefaultComponent());
+      }
+    });
+  }
+  
+  
+  private void initialiseUI()
+  {
+    this.tabbedSearchResultsPanel = new SearchResultsMainPanel();
+    this.searchOptionsPanel = new SearchOptionsPanel(tabbedSearchResultsPanel);
+    
+    
+    this.setLayout(new GridBagLayout());
+    GridBagConstraints c = new GridBagConstraints();
+    
+    c.gridx = 0;
+    c.gridy = 0;
+    c.weightx = 0.0;
+    c.anchor = GridBagConstraints.WEST;
+    c.insets = new Insets(3,10,3,10);
+    String baseString= "<html><b>Using service catalogue at </b>" + client.getBaseURL() + "</html>";
+    this.add(new JLabel(baseString), c);
+
+    
+    c.gridx = 1;
+    c.gridy = 0;
+    c.weightx = 0.1;
+    c.fill = GridBagConstraints.HORIZONTAL;
+    c.anchor = GridBagConstraints.EAST;
+    c.insets = new Insets(3,30,3,10);
+    
+    this.add(searchOptionsPanel, c);
+    
+    c.insets = new Insets(0,0,0,0);
+    c.gridy++;
+    c.gridx = 0;
+    c.gridwidth = 2;
+    c.weightx = c.weighty = 1.0;
+    c.fill = GridBagConstraints.BOTH;
+    c.anchor = GridBagConstraints.CENTER;
+    this.add(tabbedSearchResultsPanel, c);
+    
+    this.setBorder(BorderFactory.createEmptyBorder(20, 10, 10, 10));
+  }
+  
+  
+  public SearchResultsMainPanel getTabbedSearchResultsPanel() {
+    return tabbedSearchResultsPanel;
+  }
+  
+  
+  
+  // *** Callbacks for HasDefaultFocusCapability interface ***
+  
+  public void focusDefaultComponent() {
+    this.searchOptionsPanel.focusDefaultComponent();
+  }
+  
+  public Component getDefaultComponent() {
+    return (this.searchOptionsPanel.getDefaultComponent());
+  }
+  
+  // *********************************************************
+  
+  
+  public static void main(String[] args) {
+    JFrame f = new JFrame();
+    f.getContentPane().add(new BioCatalogueExplorationTab());
+    f.setSize(1000, 800);
+    f.setLocationRelativeTo(null);
+    
+    f.setVisible(true);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/HasDefaultFocusCapability.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/HasDefaultFocusCapability.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/HasDefaultFocusCapability.java
new file mode 100644
index 0000000..d8915d5
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/HasDefaultFocusCapability.java
@@ -0,0 +1,15 @@
+package net.sf.taverna.biocatalogue.ui;
+
+import java.awt.Component;
+
+/**
+ * Indicates that the class which implements this interface will focus default
+ * component (as if the component represented by that class was activated).
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public interface HasDefaultFocusCapability
+{
+  public void focusDefaultComponent();
+  public Component getDefaultComponent();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/JClickableLabel.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/JClickableLabel.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/JClickableLabel.java
new file mode 100644
index 0000000..0cc9246
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/JClickableLabel.java
@@ -0,0 +1,172 @@
+package net.sf.taverna.biocatalogue.ui;
+
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.EventListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.JLabel;
+import javax.swing.SwingUtilities;
+
+/**
+ * @author Sergejs Aleksejevs
+ */
+@SuppressWarnings("serial")
+public class JClickableLabel extends JLabel implements MouseListener
+{
+  /**
+   * Default height of the JClickableLabel - calculated based on 16-pixel
+   * standard square icon and 3-pixel thick padding on top / bottom of element.
+   */
+  public static final int DEFAULT_HEIGHT = 22;
+  
+  public static final Color DEFAULT_REGULAR_FOREGROUND_COLOR = Color.BLUE;
+  public static final Color DEFAULT_HOVER_FOREGROUND_COLOR = new Color(133, 53, 53);
+  
+  
+  // This will hold the data which is relevant to processing the 'click' event on this label
+  private final String strData;
+  
+  // This will hold a reference to ResourcePreviewBrowser instance that is supposed to process the clicks
+  // on JClickableLabels
+  private ActionListener clickHandler;
+  
+  
+  private Color REGULAR_FOREGROUND_COLOR = DEFAULT_REGULAR_FOREGROUND_COLOR;
+  private Color HOVER_FOREGROUND_COLOR = DEFAULT_HOVER_FOREGROUND_COLOR;
+  
+  
+  public JClickableLabel(String strLabel, String strDataForAction, EventListener eventHandler)
+  {
+    this(strLabel, strDataForAction, eventHandler, null);
+  }
+  
+  public JClickableLabel(String strLabel, String strDataForAction, EventListener eventHandler, Icon icon)
+  {
+    this(strLabel, strDataForAction, eventHandler, icon, SwingUtilities.LEFT);
+  }
+  
+  public JClickableLabel(String strLabel, String strDataForAction, EventListener eventHandler, Icon icon, int horizontalAlignment)
+  {
+    this(strLabel, strDataForAction, eventHandler, icon, horizontalAlignment, null);
+  }
+  
+  /**
+   * 
+   * @param strLabel Textual label that will be visible in the UI.
+   * @param strDataForAction Data that will be passed to eventHandler when click on the label is made.
+   * @param eventHandler ActionListener that will process clicks on this label.
+   * @param icon Icon to display in the label.
+   * @param horizontalAlignment This is one of SwingConstants: LEFT, CENTER, RIGHT, LEADING or TRAILING
+   * @param strTooltip Tooltip to show over the label - if none is provided (e.g. null value), the strLabel will be used as a tooltip.
+   */
+  public JClickableLabel(String strLabel, String strDataForAction, EventListener eventHandler, Icon icon, int horizontalAlignment, String strTooltip)
+  {
+    super(strLabel, icon, horizontalAlignment);
+    
+    this.strData = strDataForAction;
+    this.clickHandler = (ActionListener)eventHandler;
+    
+    // empty border at the top and bottom will simulate "line-spacing"
+    // (this is only needed when an icon is displayed)
+    if (icon != null) {
+      this.setBorder(BorderFactory.createEmptyBorder(3, 0, 3, 0));
+    }
+    
+    // the tooltip for now only shows the full label text
+    this.setToolTipText(strTooltip == null ? strLabel : strTooltip);
+    this.setForeground(REGULAR_FOREGROUND_COLOR);
+    this.addMouseListener(this);
+  }
+  
+  
+  public void setRegularForegroundColor(Color regularForegroundColor)
+  {
+    REGULAR_FOREGROUND_COLOR = regularForegroundColor;
+    
+    // apply the new foreground color immediately
+    this.setForeground(REGULAR_FOREGROUND_COLOR);
+  }
+
+  public Color getRegularForegroundColor() {
+    return REGULAR_FOREGROUND_COLOR;
+  }
+  
+  
+  public void setHoverForegroundColor(Color hoverForegroundColor)
+  {
+    // will be applied the next time mouse hovers over this label
+    HOVER_FOREGROUND_COLOR = hoverForegroundColor;
+  }
+
+  public Color getHoverForegroundColor() {
+    return HOVER_FOREGROUND_COLOR;
+  }
+  
+  
+  /**
+   * @return The "hidden" string value that is normally sent as an <code>ActionCommand</code>
+   *         within <code>ActionEvent</code> when JClickableLabel is clicked.
+   */
+  public String getData() {
+    return (this.strData);
+  }
+  
+  
+  /**
+   * @return String value of the label that this JClickableLabel would have in the UI.
+   */
+  public String toString() {
+    return (this.getText());
+  }
+  
+  
+  /* This class extends JLabel, so it can't extend MouseAdapter;
+   * therefore, empty methods will be added for not useful callbacks
+   * from the MouseListener interface.
+   */
+  public void mouseClicked(MouseEvent e) 
+  {
+    // call 'actionPerformed' method on the clickHandler instance that was supplied
+    // on creation of the JClickableLabel instance
+    this.clickHandler.actionPerformed(new ActionEvent(this, e.getID(), this.strData));
+  }
+  
+  public void mouseEntered(MouseEvent e) 
+  {
+    this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)) ;
+    this.setForeground(HOVER_FOREGROUND_COLOR);
+  }
+  
+  public void mouseExited(MouseEvent e) 
+  {
+    this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)) ;
+    this.setForeground(REGULAR_FOREGROUND_COLOR);
+  }
+  
+  public void mousePressed(MouseEvent e) 
+  {
+    // do nothing
+  }
+  
+  public void mouseReleased(MouseEvent e) 
+  {
+    // do nothing
+  }
+  
+  
+  /**
+   * @return A dummy instance of JClickable label - only intended to
+   *         represent an object of this class; doesn't have a click handler,
+   *         so a click on it will result in a <code>NullPointerException</code>.
+   */
+  public static JClickableLabel getDummyInstance() {
+    return (new JClickableLabel("dummy", "", null));
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/JWaitDialog.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/JWaitDialog.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/JWaitDialog.java
new file mode 100644
index 0000000..526066b
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/JWaitDialog.java
@@ -0,0 +1,234 @@
+package net.sf.taverna.biocatalogue.ui;
+
+import java.awt.BorderLayout;
+//import java.awt.Dimension;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import javax.swing.BorderFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.UIManager;
+
+import net.sf.taverna.biocatalogue.model.ResourceManager;
+import net.sf.taverna.t2.workbench.MainWindow;
+
+/**
+ * Creates a modal non-resizable dialog window.
+ * 
+ * Intended to be used for operations that consume some
+ * time, but the user must wait for them to complete before
+ * proceeding.
+ * 
+ * Initially the dialog shows a specified string message or
+ * component and a "loader" bar - dynamic GIF image that
+ * displays "activity" going on. At this stage the window
+ * cannot be closed.
+ * 
+ * When the operation completes, the caller notifies the dialog
+ * that it has finished, provides a new message / component to
+ * display and allows the dialog to be closed.
+ * 
+ * If the operation doesn't complete within the specified time,
+ * a timeout occurs and the dialog windows lets to close itself.
+ * 
+ * @author Sergejs Aleksejevs
+ */
+@SuppressWarnings("serial")
+public class JWaitDialog extends JDialog
+{
+  private static final int DEFAULT_TIMEOUT = 10000;
+  private static final ImageIcon LOADER_ICON = ResourceManager.getImageIcon(ResourceManager.BAR_LOADER_ORANGE);
+  
+  private JPanel jpInformationPanel;
+  private JLabel jlLoaderIcon;
+  
+  private JButton bOK;
+  private JPanel jpOKButton;
+  
+  private Timer timeoutTimer;
+  private boolean hasTimedOut;
+  
+  
+  /**
+   * Creates a new Wait Dialog with no parent and default timeout on
+   * operation - <code>JWaitDialog.DEFAULT_TIMEOUT</code>.
+   * 
+   * @param dialogTitle Title to set for the dialog window.
+   * @param waitMessage Text to be displayed in the body of this dialog while
+   *                    the user waits.
+   */
+  public JWaitDialog(String dialogTitle, String waitMessage) {
+    this(null, dialogTitle, new JLabel(waitMessage, JLabel.CENTER), DEFAULT_TIMEOUT);
+  }
+  
+  
+  /**
+   * Creates a new Wait Dialog with specified parent and default timeout on
+   * operation - <code>JWaitDialog.DEFAULT_TIMEOUT</code>.
+   * 
+   * @param owner Specified JFrame is set as an owner for this Wait Dialog.
+   * @param dialogTitle Title to set for the dialog window.
+   * @param waitMessage Text to be displayed in the body of this dialog while
+   *                    the user waits.
+   */
+  public JWaitDialog(JFrame owner, String dialogTitle, String waitMessage) {
+    this(owner, dialogTitle, new JLabel(waitMessage, JLabel.CENTER), DEFAULT_TIMEOUT);
+  }
+  
+  
+  /**
+   * Creates a new Wait Dialog with specified parent and timeout on
+   * operation.
+   * 
+   * @param owner Specified JFrame is set as an owner for this Wait Dialog.
+   * @param dialogTitle Title to set for the dialog window.
+   * @param waitMessage Text to be displayed in the body of this dialog while
+   *                    the user waits.
+   * @param timeoutMillis Duration of the timeout on the operation - after this
+   *                      time has passed the window will notify of the timeout
+   *                      and allow to close itself. Value of 0 indicates that the timeout will never occur.
+   */
+  public JWaitDialog(JFrame owner, String dialogTitle, String waitMessage, int timeoutMillis) {
+    this(owner, dialogTitle, new JLabel(waitMessage, JLabel.CENTER), timeoutMillis);
+  }
+  
+  
+  /**
+   * Creates a new Wait Dialog with parent JFrame.
+   * 
+   * @param owner Specified JFrame is set as an owner for this Wait Dialog.
+   * @param dialogTitle Title to set for the dialog window.
+   * @param waitInformationComponent Component to be shown in the body of this
+   *                    dialog windows while the user waits for an operation to complete.
+   * @param timeoutMillis Duration of the timeout on the operation - after this
+   *                      time has passed the window will notify of the timeout
+   *                      and allow to close itself. Value of 0 indicates that the timeout will never occur.
+   */
+  public JWaitDialog(JFrame owner, String dialogTitle, JComponent waitInformationComponent, int timeoutMillis)
+  {
+    super(owner);
+    this.setModal(true);
+    this.setTitle(dialogTitle);
+    
+    // this will show the wait message to the user
+    jpInformationPanel = new JPanel(new GridLayout());
+    jpInformationPanel.add(waitInformationComponent);
+    jpInformationPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 10, 20));
+    
+    // some graphical indication that the loading activity is going on
+    jlLoaderIcon = new JLabel(LOADER_ICON);
+    jlLoaderIcon.setBorder(BorderFactory.createEmptyBorder(0, 20, 20, 20));
+    
+    // put components into the dialog box
+    this.getContentPane().setLayout(new BorderLayout());
+    this.getContentPane().add(jpInformationPanel, BorderLayout.CENTER);
+    this.getContentPane().add(jlLoaderIcon, BorderLayout.SOUTH);
+
+    this.pack();
+    // Set the height of the dialog not to be more than 500; the message is in the scroll pane so that should be OK
+    this.setSize(new Dimension(this.getPreferredSize().width, this.getPreferredSize().height > 500 ? 500 : this.getPreferredSize().height));
+    //    this.setResizable(false);
+    this.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
+    
+    // center this window within the main Taverna Workbench window
+    this.setLocationRelativeTo(MainWindow.getMainWindow());
+    
+    
+    // start the timer - on timeout it will produce the
+    // timeout message and allow to close the window
+    hasTimedOut = false;
+    if (timeoutMillis > 0)
+    {
+      timeoutTimer = new Timer();
+      timeoutTimer.schedule(
+          new TimerTask() {
+            public void run() {
+              waitFinished(new JLabel("<html><center>The operation did not complete within the " +
+              		                    "allocated time.</center></html>",
+              		                    UIManager.getIcon("OptionPane.warningIcon"), JLabel.CENTER));
+              hasTimedOut = true;
+            }
+          },
+          timeoutMillis);
+    }
+  }
+  
+  
+  public void waitFinished(String resultMessage) {
+    waitFinished(new JLabel(resultMessage, JLabel.CENTER));
+  }
+  
+  public void waitFinished(JComponent resultInformationComponent)
+  {
+    // this prevents the real response to be set after the
+    // timeout message was already displayed
+    if (!hasTimedOut)
+    {
+      // first of all stop the timeout timer: if this
+      // method was called by the application explicitly, not on
+      // timeout, we don't want the timeout message to appear after that
+      if (timeoutTimer != null) { timeoutTimer.cancel(); }
+      
+      // change the information component
+      jpInformationPanel.removeAll();
+      jpInformationPanel.add(resultInformationComponent);
+      
+      // the OK button will allow closing the window
+      bOK = new JButton("OK");
+      //bOK.setPreferredSize(new Dimension(LOADER_ICON.getIconWidth(), (int) (1.5 * LOADER_ICON.getIconHeight())));
+      bOK.addActionListener(new ActionListener() {
+        public void actionPerformed(ActionEvent e) {
+          // just remove the window
+          dispose();
+        }
+      });
+      bOK.addKeyListener(new KeyAdapter() {
+        public void keyPressed(KeyEvent e) {
+          if (e.getKeyCode() == KeyEvent.VK_ENTER) {
+            // a fallback mechanism - default button doesn't work for some reason
+            // when the button is added into the dialog not in the constructor
+            bOK.doClick();
+          }
+        }
+      });
+      bOK.setDefaultCapable(true);
+      this.getRootPane().setDefaultButton(bOK);
+      
+      // wrap OK button into a panel to add empty borders
+      jpOKButton = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
+      jpOKButton.add(bOK);
+      jpOKButton.setBorder(BorderFactory.createEmptyBorder(0, 20, 20 - (bOK.getPreferredSize().height - LOADER_ICON.getIconHeight()), 20));
+      
+      
+      // add OK button instead of the loader icon 
+      this.getContentPane().remove(jlLoaderIcon);
+      this.getContentPane().add(jpOKButton, BorderLayout.SOUTH);
+      this.bOK.requestFocusInWindow();
+      
+      // re-enable (X) button in the title bar
+      this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+      
+      // update the size of this window - as the inner sizes of components have
+      // been likely to change; then center the dialog box within its parent
+      this.pack();
+      // Set the height of the dialog not to be more than 500; the message is in the scroll pane so that should be OK
+      this.setSize(new Dimension(this.getPreferredSize().width, this.getPreferredSize().height > 500 ? 500 : this.getPreferredSize().height));
+      this.setLocationRelativeTo(MainWindow.getMainWindow());
+    }
+  }
+  
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/SearchOptionsPanel.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/SearchOptionsPanel.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/SearchOptionsPanel.java
new file mode 100644
index 0000000..b0d9d26
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/SearchOptionsPanel.java
@@ -0,0 +1,167 @@
+package net.sf.taverna.biocatalogue.ui;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.util.Arrays;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.event.CaretEvent;
+import javax.swing.event.CaretListener;
+
+import net.sf.taverna.biocatalogue.model.BioCataloguePluginConstants;
+import net.sf.taverna.biocatalogue.model.ResourceManager;
+import net.sf.taverna.biocatalogue.model.Resource.TYPE;
+import net.sf.taverna.biocatalogue.model.search.SearchOptions;
+import net.sf.taverna.biocatalogue.ui.search_results.SearchResultsMainPanel;
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+
+
+/**
+ * 
+ * @author Sergejs Aleksejevs
+ */
+@SuppressWarnings("serial")
+public class SearchOptionsPanel extends JPanel implements HasDefaultFocusCapability
+{
+  // COMPONENTS
+  private SearchOptionsPanel thisPanel;
+  
+private JTextField tfSearchQuery;
+  private JButton bSearch;
+  
+  private final SearchResultsMainPanel tabbedSearchResultsPanel;
+  
+  
+  public SearchOptionsPanel(SearchResultsMainPanel tabbedSearchResultsPanel)
+  {
+    super();
+    this.thisPanel = this;
+    this.tabbedSearchResultsPanel = tabbedSearchResultsPanel;
+    
+    this.initialiseUI();
+  }
+  
+  
+  private void initialiseUI()
+  {
+    this.setLayout(new GridBagLayout());
+    GridBagConstraints c = new GridBagConstraints();
+    
+    c.gridx = 0;
+    c.gridy = 0;
+    c.weightx = 0.0;
+    c.fill = GridBagConstraints.NONE;
+    
+    
+    this.tfSearchQuery = new JTextField(30);
+    this.tfSearchQuery.setToolTipText(
+        "<html>&nbsp;Tips for creating search queries:<br>" +
+        "&nbsp;1) Use wildcards to make more flexible queries. Asterisk (<b>*</b>) matches any zero or more<br>" +
+        "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;characters (e.g. <b><i>Seq*</i></b> would match <b><i>Sequence</i></b>), question mark (<b>?</b>) matches any single<br>" +
+        "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;character (e.g. <b><i>Bla?t</i></b> would match <b><i>Blast</i></b>).<br>" +
+        "&nbsp;2) Enclose the <b><i>\"search query\"</i></b> in double quotes to make exact phrase matching, otherwise<br>" +
+        "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;items that contain any (or all) words in the <b><i>search query</i></b> will be found.</html>");
+    
+    this.tfSearchQuery.addFocusListener(new FocusListener() {
+      public void focusGained(FocusEvent e) {
+        tfSearchQuery.selectAll();
+      }
+      public void focusLost(FocusEvent e) { /* do nothing */ }
+    });
+    this.tfSearchQuery.addKeyListener(new KeyAdapter() {
+      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 && bSearch.isEnabled()) {    
+          bSearch.doClick();
+        }
+      }
+    });
+    JButton jbClearSearch = new DeselectingButton(new AbstractAction("Clear") {
+
+		@Override
+		public void actionPerformed(ActionEvent e) {
+			tfSearchQuery.setText("");
+			clearSearch();
+		}}, "");
+    jbClearSearch.setIcon(ResourceManager.getImageIcon(ResourceManager.CLEAR_ICON));
+    
+    this.add(jbClearSearch, c);
+    
+    c.gridx++;
+    c.fill = GridBagConstraints.HORIZONTAL;
+    c.weightx = 0.1;
+    this.add(tfSearchQuery, c);
+    
+    
+    // --- Search button ---
+    
+    c.gridx++;
+    c.weightx = 0;
+    c.fill = GridBagConstraints.NONE;
+    c.anchor = GridBagConstraints.EAST;
+    this.bSearch = new DeselectingButton("Search",
+    		new ActionListener() {
+        public void actionPerformed(ActionEvent e) {
+          if (getSearchQuery().length() == 0) {
+            clearSearch();
+          }
+          else {
+            // search query available - collect data about the current search and execute it
+            tabbedSearchResultsPanel.startNewSearch(thisPanel.getState());
+          }
+        }
+      },
+      tfSearchQuery.getToolTipText());
+    this.bSearch.setIcon(ResourceManager.getImageIcon(ResourceManager.SEARCH_ICON));
+    this.add(bSearch, c);
+    
+}
+   
+  private void clearSearch() {
+	  tabbedSearchResultsPanel.clearSearch();
+      thisPanel.focusDefaultComponent();
+  }
+  
+  /**
+   * Saves the current state of the search options into a single {@link SearchOptions} object.
+   */
+  public SearchOptions getState() {
+    return (new SearchOptions(getSearchQuery(), Arrays.asList(TYPE.values())));
+  }
+  
+  
+  // *** GETTERS AND SETTERS ***
+  
+  public String getSearchQuery() {
+    return (this.tfSearchQuery.getText().trim());
+  }
+  public void setSearchQuery(String strSearchQuery) {
+    this.tfSearchQuery.setText(strSearchQuery);
+  }
+   
+  
+  // *** Callbacks for HasDefaultFocusCapability interface ***
+  
+  public void focusDefaultComponent() {
+    this.tfSearchQuery.selectAll();
+    this.tfSearchQuery.requestFocusInWindow();
+  }
+  
+  public Component getDefaultComponent() {
+    return(this.tfSearchQuery);
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/filtertree/FilterTreeNode.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/filtertree/FilterTreeNode.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/filtertree/FilterTreeNode.java
new file mode 100644
index 0000000..fedd553
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/filtertree/FilterTreeNode.java
@@ -0,0 +1,91 @@
+package net.sf.taverna.biocatalogue.ui.filtertree;
+
+import net.sf.taverna.biocatalogue.ui.tristatetree.TriStateTreeNode;
+
+/**
+ * This class allows storing two pieces of data relevant to content filtering
+ * within the node of a tree. These values are kept hidden from the user and
+ * are only used when the filtering is about to happen.
+ * 
+ * @author Sergejs Aleksejevs
+ */
+@SuppressWarnings("serial")
+public class FilterTreeNode extends TriStateTreeNode
+{
+  private String type; 
+  private String urlValue;
+  final private boolean isFilterCategory;
+  
+  
+  /**
+   * This constructor is useful for root nodes, which need not have filter type / value.
+   */
+  public FilterTreeNode(Object userObject) {
+    super(userObject);
+    
+    this.isFilterCategory = true;
+  }
+  
+  
+  /**
+   * @param userObject As in the superclass (DefaultMutableTreeNode) - the object which represents the node in the UI
+   * @param filterType Type of the filter - e.g. 'Service Categories' --> "cat"; 'Service Types' --> "t"
+   * @param filterUrlValue Value that should be added to the URL to perform the filtering operation
+   */
+  public FilterTreeNode(Object userObject, String filterType, String filterUrlValue) {
+    super(userObject);
+    
+    this.setType(filterType);
+    this.setUrlValue(filterUrlValue);
+    this.isFilterCategory = false;
+  }
+  
+  
+  public void setType(String type) {
+    this.type = type;
+  }
+  
+  public String getType() {
+    return type;
+  }
+  
+  public void setUrlValue(String urlValue) {
+    this.urlValue = urlValue;
+  }
+  
+  
+  public String getUrlValue() {
+    return urlValue;
+  }
+  
+  /**
+   * @return True if and only if this node is one of the "root" filter categories (not to be mixed with root of the filter tree).
+   */
+  public boolean isFilterCategory() {
+    return isFilterCategory;
+  }
+  
+  
+  /**
+   * @return <code>true</code> if the current {@link FilterTreeNode} represents a tag with a namespace
+   *         (i.e. an ontological term), whose full tag name looks like:
+   *         <code>< http://example.namespace.com#tag_display_name ></code>
+   */
+  public boolean isTagWithNamespaceNode() {
+    return (this.getType() != null && this.getType().contains("tag") && this.getUrlValue().contains("#") &&
+            this.getUrlValue().startsWith("<") && this.getUrlValue().endsWith(">"));
+  }
+  
+  
+  /**
+   * Static wrapper for {@link FilterTreeNode#isTagWithNamespaceNode()}
+   *  
+   * @param filterType
+   * @param filterUrlValue
+   * @return
+   */
+  public static boolean isTagWithNamespaceNode(String filterType, String filterUrlValue) {
+    return (new FilterTreeNode("test_user_object", filterType, filterUrlValue).isTagWithNamespaceNode());
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/filtertree/FilterTreePane.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/filtertree/FilterTreePane.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/filtertree/FilterTreePane.java
new file mode 100644
index 0000000..75a80ea
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/filtertree/FilterTreePane.java
@@ -0,0 +1,348 @@
+package net.sf.taverna.biocatalogue.ui.filtertree;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JToolBar;
+import javax.swing.SwingUtilities;
+
+import net.sf.taverna.biocatalogue.model.BioCataloguePluginConstants;
+import net.sf.taverna.biocatalogue.model.Resource.TYPE;
+import net.sf.taverna.biocatalogue.model.ResourceManager;
+import net.sf.taverna.biocatalogue.model.connectivity.BioCatalogueClient;
+import net.sf.taverna.biocatalogue.model.search.SearchInstance;
+import net.sf.taverna.biocatalogue.model.search.ServiceFilteringSettings;
+import net.sf.taverna.biocatalogue.ui.tristatetree.JTriStateTree;
+import net.sf.taverna.biocatalogue.ui.tristatetree.TriStateTreeCheckingListener;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.MainComponentFactory;
+import net.sf.taverna.t2.workbench.icons.WorkbenchIcons;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.log4j.Logger;
+
+import org.biocatalogue.x2009.xml.rest.Filter;
+import org.biocatalogue.x2009.xml.rest.FilterGroup;
+import org.biocatalogue.x2009.xml.rest.FilterType;
+import org.biocatalogue.x2009.xml.rest.Filters;
+
+/**
+ * 
+ * @author Sergejs Aleksejevs
+ */
+@SuppressWarnings("serial")
+public class FilterTreePane extends JPanel implements TriStateTreeCheckingListener
+{
+  private TYPE resourceType;
+  private String filtersURL;
+  private BioCatalogueClient client;
+  private Logger logger;
+  
+  private FilterTreePane thisPanel;
+  
+  private JToolBar tbFilterTreeToolbar;
+  
+  private JPanel jpFilters = null;
+  private JFilterTree filterTree;  // tree component to display filter selections
+  private Filters filtersRoot;     // last filters element which was received from the API
+
+  
+  
+  public FilterTreePane(TYPE resourceType)
+  {
+    this.thisPanel = this;
+    
+    this.resourceType = resourceType;
+    this.filtersURL = resourceType.getAPIResourceCollectionFiltersURL();
+    this.client = BioCatalogueClient.getInstance();
+    this.logger = Logger.getLogger(this.getClass());
+    
+    initialiseUI();
+    loadFiltersAndBuildTheTree();
+  }
+  
+  
+  private void initialiseUI()
+  {
+    jpFilters = new JPanel();
+    jpFilters.setBackground(Color.WHITE);
+    
+    JScrollPane spFilters = new JScrollPane(jpFilters);
+    spFilters.setMinimumSize(new Dimension(235,0));
+    spFilters.setPreferredSize(new Dimension(300,0));
+    spFilters.getVerticalScrollBar().setUnitIncrement(BioCataloguePluginConstants.DEFAULT_SCROLL);
+    
+    
+    tbFilterTreeToolbar = createTreeActionToolbar();
+    resetTreeActionToolbar();
+    
+    this.setLayout(new BorderLayout());
+    this.add(tbFilterTreeToolbar, BorderLayout.NORTH);
+    this.add(spFilters, BorderLayout.CENTER);
+  }
+  
+  
+  /**
+   * @return A toolbar that replicates all actions available in the contextual menu of
+   *         the filtering tree - mainly: saving current filter, reloading filter tree,
+   *         expanding/collapsing and selecting/deselecting everything in the tree.
+   */
+private JToolBar createTreeActionToolbar()
+  {
+     
+    
+    // the actual toolbar - no actions are added to it yet: done in a separate method
+    JToolBar tbTreeActions = new JToolBar(JToolBar.HORIZONTAL);
+    tbTreeActions.setAlignmentX(RIGHT_ALIGNMENT);
+    tbTreeActions.setBorderPainted(true);
+    tbTreeActions.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+    tbTreeActions.setFloatable(false);
+    return (tbTreeActions);
+  }
+  
+  
+  /**
+   * Resets the action toolbar to the original state.
+   */
+  public void resetTreeActionToolbar()
+  {
+    
+    tbFilterTreeToolbar.removeAll();
+    tbFilterTreeToolbar.repaint();
+  }
+  
+  
+  /**
+   * This method loads filter data from API and populates the view.
+   */
+  private void loadFiltersAndBuildTheTree()
+  {
+    SwingUtilities.invokeLater(new Runnable() {
+      public void run()
+      {
+        resetTreeActionToolbar();
+        
+        jpFilters.removeAll();
+        jpFilters.setLayout(new BorderLayout());
+        jpFilters.add(new JLabel(" Loading filters..."), BorderLayout.NORTH);
+        jpFilters.add(new JLabel(ResourceManager.getImageIcon(ResourceManager.BAR_LOADER_ORANGE)), BorderLayout.CENTER);
+        thisPanel.validate();
+        thisPanel.repaint();      // validate and repaint this component to make sure that
+                                  // scroll bar around the filter tree placeholder panel disappears
+      }
+    });
+    
+    new Thread("Load filters") {
+      public void run() {
+        try {
+          // load filter data
+          filtersRoot = client.getBioCatalogueFilters(filtersURL);
+          
+          // Create root of the filter tree component
+          FilterTreeNode root = new FilterTreeNode("root");
+          
+          // populate the tree via its root element
+          for (FilterGroup fgroup : filtersRoot.getGroupList())
+          {
+            // attach filter group directly to the root node
+            FilterTreeNode fgroupNode = new FilterTreeNode("<html><span style=\"color: black; font-weight: bold;\">" + StringEscapeUtils.escapeHtml(fgroup.getName().toString()) + "</span></html>");
+            root.add(fgroupNode);
+            
+            
+            // go through all filter types in this group and add them to the tree
+            for (FilterType ftype : fgroup.getTypeList())
+            {
+              // if there's more than one filter type in the group, add the type node as another level of nesting
+              // (otherwise, attach filters inside the single type directly to the group node)
+              FilterTreeNode filterTypeNode = fgroupNode;
+              if (fgroup.getTypeList().size() > 1) {
+                filterTypeNode = new FilterTreeNode("<html><span style=\"color: black; font-weight: bold;\">" + StringEscapeUtils.escapeHtml(ftype.getName().toString()) + "</span></html>");
+                fgroupNode.add(filterTypeNode);
+              }
+              
+              // For some reason sorting the list of filters before inserting into tree
+              // messes up the tree nodes
+//              Collections.sort(ftype.getFilterList(), new Comparator<Filter>(){
+//				@Override
+//				public int compare(Filter f1, Filter f2) {
+//				    return (f1.getName().compareToIgnoreCase(f2.getName()));
+//				}           	  
+//              });
+              addFilterChildren(filterTypeNode, ftype.getUrlKey().toString(), ftype.getFilterList());
+            }
+          }
+          
+          // Create the tree view with the populated root
+          filterTree = new JFilterTree(root);
+          filterTree.setRootVisible(false);      // don't want the root to be visible; not a standard thing, so not implemented within JTriStateTree
+          filterTree.setLargeModel(true);        // potentially can have many filters!
+          filterTree.addCheckingListener(thisPanel);
+          
+                   
+          // insert the created tree view into the filters panel
+          jpFilters.removeAll();
+          jpFilters.setLayout(new GridLayout(0,1));
+          jpFilters.add(filterTree);
+          jpFilters.validate();
+          
+          
+          // add actions from the contextual menu of the filter tree into the toolbar
+          // that replicates those plus adds additional ones in this panel
+          tbFilterTreeToolbar.removeAll();
+          for (Action a : filterTree.getContextualMenuActions()) {
+            tbFilterTreeToolbar.add(a);
+          }
+          
+          
+          // enable all actions
+          filterTree.enableAllContextualMenuAction(true);
+        }
+        catch (Exception e) {
+          logger.error("Failed to load filter tree from the following URL: " + filtersURL, e);
+        }
+      }
+      
+      
+      /**
+       * Recursive method to populate a node of the filter tree with all
+       * sub-filters.
+       * 
+       * Ontological terms will be underlined.
+       * 
+       * @param root Tree node to add children to.
+       * @param filterList A list of Filters to add to "root" as children.
+       */
+      private void addFilterChildren(FilterTreeNode root, String filterCategory, List<Filter> filterList) {
+        for (Filter f : filterList) {
+        	
+					// Is this an ontological term?
+					String ontology = null;
+					if (FilterTreeNode.isTagWithNamespaceNode(filterCategory, f
+							.getUrlValue())) {
+						String nameAndNamespace = f.getUrlValue().substring(1,
+								f.getUrlValue().length() - 1);
+						String[] namePlusNamespace = nameAndNamespace
+								.split("#");
+						ontology = JFilterTree
+								.getOntologyFromNamespace(namePlusNamespace[0]);
+					}
+
+					FilterTreeNode fNode = new FilterTreeNode("<html><span color=\"black\"" /*(FilterTreeNode.isTagWithNamespaceNode(filterCategory, f.getUrlValue()) ? " style=\"text-decoration: underline;\"" : "") */ + ">" +
+                               StringEscapeUtils.escapeHtml(f.getName()) + " (" + f.getCount() + ")" + "</span>" +
+                               /*(FilterTreeNode.isTagWithNamespaceNode(filterCategory, f.getUrlValue()) ? "<span color=\"gray\">&nbsp;("+f.getCount().intValue()+")</span></html>" : "</html>"),*/
+                               (ontology != null ? "<span color=\"#3090C7\"> &lt;"+ ontology +"&gt;</span></html>" : "</html>"),
+                               filterCategory, f.getUrlValue());
+					addFilterChildren(fNode, filterCategory, f.getFilterList());
+         
+					// Insert the node into the (alphabetically) sorted children nodes
+					List<FilterTreeNode> children = Collections.list(root.children());
+					// Search for the index the new node should be inserted at
+					int index = Collections.binarySearch(children, fNode,
+							new Comparator<FilterTreeNode>() {
+								@Override
+								public int compare(FilterTreeNode o1,
+										FilterTreeNode o2) {
+									String str1 = ((String) o1.getUserObject())
+											.toString();
+									String str2 = ((String) o2.getUserObject())
+											.toString();
+									return (str1.compareToIgnoreCase(str2));
+								}
+							});
+
+					if (index < 0){ // not found - index will be equal to -insertion-point -1
+						index = -index - 1;
+					}// else node with the same name found in the array - insert it at that position
+			        root.insert(fNode, index);
+
+			        //root.add(fNode);
+        		}
+      		} 
+    	}.start();
+  	}
+  
+  
+  /**
+   * @param si Uses this SearchInstance to restore the checking
+   *           state of filtering criteria in the filter tree. 
+   */
+  public void restoreFilteringSettings(SearchInstance si) {
+    this.filterTree.restoreFilterCheckingSettings(si.getFilteringSettings().getFilterTreeRootsOfCheckedPaths());
+  }
+  
+  
+  /**
+   * Clears any selections made in the filter tree -
+   * i.e. both clears checked nodes and removes all tree path selections.
+   */
+  public void clearSelection() {
+    // filter tree may not have been initialised yet, so perform a check
+    if (this.filterTree != null)
+    {
+      // remove, then restore self as a listener - this is to avoid
+      // receiving checking state change event
+      this.filterTree.removeCheckingListener(thisPanel);
+      this.filterTree.selectAllNodes(false);
+      this.filterTree.clearSelection();
+      this.filterTree.addCheckingListener(thisPanel);
+    }
+  }
+  
+  
+  /**
+   * Collapses all expanded nodes in the filter tree.
+   */
+  public void collapseAll() {
+    // filter tree may not have been initialised yet, so perform a check
+    if (this.filterTree != null) {
+      this.filterTree.collapseAll();
+    }
+  }
+  
+  public void applyQueryString(final String queryString) {
+	    this.filtersURL = resourceType.getAPIResourceCollectionFiltersURL() + "?q=" + queryString;
+	    loadFiltersAndBuildTheTree();
+  }
+  
+  /**
+   * Used for making preferred height of the search status label
+   * the same as the height of this toolbar.
+   * 
+   * @return
+   */
+  public Dimension getTreeToolbarPreferredSize() {
+    return this.tbFilterTreeToolbar.getPreferredSize();
+  }
+  
+  
+  // *** Callback for TriStateTreeCheckingListener ***
+  
+  /**
+   * We start a new search as soon as checking state of the filter tree changes.
+   */
+  public void triStateTreeCheckingChanged(JTriStateTree source)
+  {
+    MainComponentFactory.getSharedInstance().getBioCatalogueExplorationTab().getTabbedSearchResultsPanel().
+        startNewFiltering(resourceType, new ServiceFilteringSettings(filterTree));
+  }
+
+
+public void reset() {
+    this.filtersURL = resourceType.getAPIResourceCollectionFiltersURL();
+	loadFiltersAndBuildTheTree();
+}
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/filtertree/JFilterTree.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/filtertree/JFilterTree.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/filtertree/JFilterTree.java
new file mode 100644
index 0000000..a6cc111
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/filtertree/JFilterTree.java
@@ -0,0 +1,69 @@
+package net.sf.taverna.biocatalogue.ui.filtertree;
+
+import java.awt.event.MouseEvent;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.sf.taverna.biocatalogue.ui.tristatetree.JTriStateTree;
+import net.sf.taverna.biocatalogue.ui.tristatetree.TriStateTreeNode;
+
+/**
+ * This subclass of {@link JTriStateTree} provides custom behaviour
+ * for tooltips: ontological terms will now always get a tooltip that
+ * displays the namespace for the tag, but plain text tags will still
+ * behave as before - the way it is defined in the superclass (so that
+ * the tooltip will only be shown if the tag does not fully fit into
+ * the visible part of the {@link FilterTreePane}.
+ * 
+ * @author Sergejs Aleksejevs
+ */
+@SuppressWarnings("serial")
+public class JFilterTree extends JTriStateTree
+{
+  
+  private static Map<String, String> nameSpaceToOntologyMap = new HashMap<String, String>(){
+      {
+          put("http://www.mygrid.org.uk/ontology", "mygrid-domain-ontology");
+          put("http://www.mygrid.org.uk/mygrid-moby-service", "mygrid-service-ontology");
+      }
+  };
+ 
+
+  public JFilterTree(TriStateTreeNode root) {
+    super(root);
+  }
+  
+  
+  public String getToolTipText(MouseEvent e)
+  {
+    Object correspondingObject = super.getTreeNodeObject(e);
+    if (correspondingObject != null && correspondingObject instanceof FilterTreeNode) {
+      FilterTreeNode filterNode = (FilterTreeNode) correspondingObject;
+      
+      if (filterNode.isTagWithNamespaceNode())
+      {
+        String nameAndNamespace = filterNode.getUrlValue().substring(1, filterNode.getUrlValue().length() - 1);
+        String[] namePlusNamespace = nameAndNamespace.split("#");
+        
+        return ("<html>" + namePlusNamespace[1] + " (<b>Namespace: </b>" + namePlusNamespace[0] + ")</html>");
+      }
+    }
+    
+    return super.getToolTipText(e);
+  }
+  
+  public static String getOntologyFromNamespace(String namespace){
+	  if (namespace == null){
+		  return null;
+	  }
+	  else{
+		  if (nameSpaceToOntologyMap.containsKey(namespace)){
+			  return nameSpaceToOntologyMap.get(namespace);
+		  }
+		  else{
+			  return null;
+		  }
+	  }
+  }
+  
+}