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:21 UTC

[07/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/HistoryBrowserTabContentPanel.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/HistoryBrowserTabContentPanel.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/HistoryBrowserTabContentPanel.java
new file mode 100644
index 0000000..3dfd2db
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/HistoryBrowserTabContentPanel.java
@@ -0,0 +1,541 @@
+/*******************************************************************************
+ * 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.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.ScrollPaneConstants;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.border.Border;
+
+import net.sf.taverna.t2.lang.ui.ShadedLabel;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Base64;
+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.ui.perspectives.myexperiment.model.Tag;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Util;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.SearchEngine.QuerySearchInstance;
+import net.sf.taverna.t2.workbench.icons.WorkbenchIcons;
+
+import org.apache.log4j.Logger;
+
+/**
+ * @author Sergejs Aleksejevs, Emmanuel Tagarira
+ */
+public class HistoryBrowserTabContentPanel extends JPanel implements ActionListener {
+  // CONSTANTS
+  public static final int DOWNLOADED_ITEMS_HISTORY_LENGTH = 50;
+  public static final int OPENED_ITEMS_HISTORY_LENGTH = 50;
+  public static final int UPLOADED_ITEMS_HISTORY_LENGTH = 50;
+  public static final int COMMENTED_ON_ITEMS_HISTORY_LENGTH = 50;
+
+  public static final int PREVIEWED_ITEMS_HISTORY = 0;
+  public static final int DOWNLOADED_ITEMS_HISTORY = 1;
+  public static final int OPENED_ITEMS_HISTORY = 2;
+  public static final int UPLOADED_ITEMS_HISTORY = 4;
+  public static final int COMMENTED_ON_ITEMS_HISTORY = 3;
+
+  private final MainComponent pluginMainComponent;
+  private final MyExperimentClient myExperimentClient;
+  private final Logger logger;
+
+  // STORAGE
+  private ArrayList<Resource> lDownloadedItems;
+  private ArrayList<Resource> lOpenedItems;
+  private ArrayList<Resource> lUploadedItems;
+  private ArrayList<Resource> lCommentedOnItems;
+
+  // COMPONENTS
+  private JPanel jpPreviewHistory;
+  private JPanel jpSearchHistory;
+  private JPanel jpTagSearchHistory;
+  private JPanel jpDownloadedItemsHistory;
+  private JPanel jpOpenedItemsHistory;
+  private JPanel jpUploadedItemsHistory;
+  private JPanel jpCommentedOnHistory;
+  private JSplitPane spMain;
+  private JClickableLabel jclPreviewHistory;
+  private JClickableLabel jclSearchHistory;
+  private JClickableLabel jclTagSearchHistory;
+  private JClickableLabel jclDownloadedItemsHistory;
+  private JClickableLabel jclOpenedItemsHistory;
+  private JClickableLabel jclUploadedItemsHistory;
+  private JClickableLabel jclCommentedOnHistory;
+  private JPanel jpPreviewHistoryBox;
+  private JPanel jpSearchHistoryBox;
+  private JPanel jpTagSearchHistoryBox;
+  private JPanel jpDownloadedItemsHistoryBox;
+  private JPanel jpOpenedItemsHistoryBox;
+  private JPanel jpUploadedItemsHistoryBox;
+  private JPanel jpCommentedOnHistoryBox;
+
+  @SuppressWarnings("unchecked")
+  public HistoryBrowserTabContentPanel(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;
+
+	// initialise downloaded items history
+	String strDownloadedItemsHistory = (String) myExperimentClient.getSettings().get(MyExperimentClient.INI_DOWNLOADED_ITEMS_HISTORY);
+	if (strDownloadedItemsHistory != null) {
+	  Object oDownloadedItemsHistory = Base64.decodeToObject(strDownloadedItemsHistory);
+	  this.lDownloadedItems = (ArrayList<Resource>) oDownloadedItemsHistory;
+	} else {
+	  this.lDownloadedItems = new ArrayList<Resource>();
+	}
+
+	// initialise opened items history
+	String strOpenedItemsHistory = (String) myExperimentClient.getSettings().get(MyExperimentClient.INI_OPENED_ITEMS_HISTORY);
+	if (strOpenedItemsHistory != null) {
+	  Object oOpenedItemsHistory = Base64.decodeToObject(strOpenedItemsHistory);
+	  this.lOpenedItems = (ArrayList<Resource>) oOpenedItemsHistory;
+	} else {
+	  this.lOpenedItems = new ArrayList<Resource>();
+	}
+
+	// initialise uploaded items history
+	String strUploadedItemsHistory = (String) myExperimentClient.getSettings().get(MyExperimentClient.INI_UPLOADED_ITEMS_HISTORY);
+	if (strUploadedItemsHistory != null) {
+	  Object oUploadedItemsHistory = Base64.decodeToObject(strUploadedItemsHistory);
+	  this.lUploadedItems = (ArrayList<Resource>) oUploadedItemsHistory;
+	} else {
+	  this.lUploadedItems = new ArrayList<Resource>();
+	}
+
+	// initialise history of the items that were commented on
+	String strCommentedItemsHistory = (String) myExperimentClient.getSettings().get(MyExperimentClient.INI_COMMENTED_ITEMS_HISTORY);
+	if (strCommentedItemsHistory != null) {
+	  Object oCommentedItemsHistory = Base64.decodeToObject(strCommentedItemsHistory);
+	  this.lCommentedOnItems = (ArrayList<Resource>) oCommentedItemsHistory;
+	} else {
+	  this.lCommentedOnItems = new ArrayList<Resource>();
+	}
+
+	this.initialiseUI();
+	this.refreshAllData();
+  }
+
+  private void confirmHistoryDelete(final int id, String strBoxTitle) {
+	if (JOptionPane.showConfirmDialog(null, "This will the "
+		+ strBoxTitle.toLowerCase() + " list.\nDo you want to proceed?", "myExperiment Plugin - Confirmation Required", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
+	  switch (id) {
+		case 1:
+		  pluginMainComponent.getPreviewBrowser().clearPreviewHistory();
+		  break;
+		case 2:
+		  pluginMainComponent.getSearchTab().getSearchHistory().clear();
+		  pluginMainComponent.getSearchTab().updateSearchHistory();
+		  break;
+		case 3:
+		  pluginMainComponent.getTagBrowserTab().getTagSearchHistory().clear();
+		  break;
+		case 4:
+		  clearDownloadedItemsHistory();
+		  break;
+		case 5:
+		  clearOpenedItemsHistory();
+		  break;
+		case 6:
+		  clearCommentedOnItemsHistory();
+		  break;
+		case 7:
+		  clearUploadedItemsHistory();
+		  break;
+	  }
+	  refreshAllData();
+	}
+  }
+
+  private JPanel addSpecifiedPanel(final int id, final String strBoxTitle, JPanel jPanel) {
+	JPanel jpTemp = new JPanel();
+	jpTemp.setLayout(new BorderLayout());
+	jpTemp.add(generateContentBox(strBoxTitle, jPanel), BorderLayout.CENTER);
+	JButton bClear = new JButton("Clear " + strBoxTitle, WorkbenchIcons.deleteIcon);
+	bClear.addActionListener(new ActionListener() {
+	  public void actionPerformed(ActionEvent e) {
+		confirmHistoryDelete(id, strBoxTitle);
+	  }
+	});
+
+	jpTemp.add(bClear, BorderLayout.SOUTH);
+	jpTemp.setMinimumSize(new Dimension(500, 0));
+	return jpTemp;
+  }
+
+  private void initialiseUI() {
+	// create helper text
+	ShadedLabel lHelper = new ShadedLabel("All history sections are local to myExperiment plugin usage."
+		+ " Detailed history of your actions on myExperiment is available in your profile on myExperiment.", ShadedLabel.BLUE);
+
+	// create all individual content holder panels
+	this.jpPreviewHistory = new JPanel();
+	this.jpTagSearchHistory = new JPanel();
+	this.jpSearchHistory = new JPanel();
+	this.jpDownloadedItemsHistory = new JPanel();
+	this.jpOpenedItemsHistory = new JPanel();
+	this.jpUploadedItemsHistory = new JPanel();
+	this.jpCommentedOnHistory = new JPanel();
+
+	// create sidebar
+	JPanel jpSidebar = new JPanel();
+	jpSidebar.setLayout(new BoxLayout(jpSidebar, BoxLayout.Y_AXIS));
+	Border border = BorderFactory.createEmptyBorder(5, 3, 10, 3);
+	jclPreviewHistory = new JClickableLabel("Previewed Items", "preview_history", this, WorkbenchIcons.editIcon, SwingConstants.LEFT, "tooltip");
+	jclPreviewHistory.setBorder(border);
+	jpSidebar.add(jclPreviewHistory);
+
+	jclSearchHistory = new JClickableLabel("Search History", "search_history", this, WorkbenchIcons.editIcon, SwingConstants.LEFT, "tooltip");
+	jclSearchHistory.setBorder(border);
+	jpSidebar.add(jclSearchHistory);
+
+	jclTagSearchHistory = new JClickableLabel("Tag Searches Made", "tag_history", this, WorkbenchIcons.editIcon, SwingConstants.LEFT, "tooltip");
+	jclTagSearchHistory.setBorder(border);
+	jpSidebar.add(jclTagSearchHistory);
+
+	jclDownloadedItemsHistory = new JClickableLabel("Downloaded Items", "downloads_history", this, WorkbenchIcons.editIcon, SwingConstants.LEFT, "tooltip");
+	jclDownloadedItemsHistory.setBorder(border);
+	jpSidebar.add(jclDownloadedItemsHistory);
+
+	jclOpenedItemsHistory = new JClickableLabel("Opened Items", "opened_history", this, WorkbenchIcons.editIcon, SwingConstants.LEFT, "tooltip");
+	jclOpenedItemsHistory.setBorder(border);
+	jpSidebar.add(jclOpenedItemsHistory);
+
+	jclUploadedItemsHistory = new JClickableLabel("Updated Items", "uploaded_history", this, WorkbenchIcons.editIcon, SwingConstants.LEFT, "tooltip");
+	jclUploadedItemsHistory.setBorder(border);
+	jpSidebar.add(jclUploadedItemsHistory);
+
+	jclCommentedOnHistory = new JClickableLabel("Items Commented On", "comments_history", this, WorkbenchIcons.editIcon, SwingConstants.LEFT, "tooltip");
+	jclCommentedOnHistory.setBorder(border);
+	jpSidebar.add(jclCommentedOnHistory);
+
+	JPanel jpSidebarContainer = new JPanel();
+	jpSidebarContainer.add(jpSidebar, BorderLayout.NORTH);
+	JScrollPane spSidebar = new JScrollPane(jpSidebarContainer);
+	spSidebar.getVerticalScrollBar().setUnitIncrement(ResourcePreviewBrowser.PREFERRED_SCROLL);
+	spSidebar.setMinimumSize(new Dimension(245, 0));
+	spSidebar.setMaximumSize(new Dimension(300, 0));
+
+	// create standard boxes for each content holder panels
+	// only one of these will hold the right hand side of spMain at any given time
+	// arg 1: is the ID, which will be used by confirmHistoryDelete() to decide
+	// how to delete the history item
+	jpPreviewHistoryBox = addSpecifiedPanel(1, "Items you have previewed", jpPreviewHistory);
+	jpSearchHistoryBox = addSpecifiedPanel(2, "Terms you have searched for", jpSearchHistory);
+	jpTagSearchHistoryBox = addSpecifiedPanel(3, "Tags searches you have made", jpTagSearchHistory);
+	jpDownloadedItemsHistoryBox = addSpecifiedPanel(4, "Items you have downloaded", jpDownloadedItemsHistory);
+	jpOpenedItemsHistoryBox = addSpecifiedPanel(5, "Workflows you have opened in Taverna", jpOpenedItemsHistory);
+	jpCommentedOnHistoryBox = addSpecifiedPanel(6, "Items you have commented on in myExperiment", jpCommentedOnHistory);
+	jpUploadedItemsHistoryBox = addSpecifiedPanel(7, "Items you have updated on myExperiment", jpUploadedItemsHistory);
+
+	// put everything together
+	spMain = new JSplitPane();
+	spMain.setLeftComponent(spSidebar);
+	spMain.setRightComponent(jpPreviewHistoryBox);
+
+	spMain.setOneTouchExpandable(true);
+	spMain.setDividerLocation(247);
+	spMain.setDoubleBuffered(true);
+
+	// spMyStuff will be the only component in the Panel
+	this.setLayout(new BorderLayout());
+	this.add(spMain);
+	this.add(lHelper, BorderLayout.NORTH);
+
+  }
+
+  public ArrayList<Resource> getDownloadedItemsHistoryList() {
+	return (this.lDownloadedItems);
+  }
+
+  public void clearDownloadedItemsHistory() {
+	this.lDownloadedItems.clear();
+  }
+
+  public ArrayList<Resource> getOpenedItemsHistoryList() {
+	return (this.lOpenedItems);
+  }
+
+  public ArrayList<Resource> getUploadedItemsHistoryList() {
+	return (this.lUploadedItems);
+  }
+
+  public void clearOpenedItemsHistory() {
+	this.lOpenedItems.clear();
+  }
+
+  public void clearUploadedItemsHistory() {
+	this.lUploadedItems.clear();
+  }
+
+  public ArrayList<Resource> getCommentedOnItemsHistoryList() {
+	return (this.lCommentedOnItems);
+  }
+
+  public void clearCommentedOnItemsHistory() {
+	this.lCommentedOnItems.clear();
+  }
+
+  /**
+   * Used to refresh all boxes at a time (for example at launch time).
+   */
+  private void refreshAllData() {
+	this.refreshHistoryBox(PREVIEWED_ITEMS_HISTORY);
+	this.refreshHistoryBox(DOWNLOADED_ITEMS_HISTORY);
+	this.refreshHistoryBox(OPENED_ITEMS_HISTORY);
+	this.refreshHistoryBox(UPLOADED_ITEMS_HISTORY);
+	this.refreshHistoryBox(COMMENTED_ON_ITEMS_HISTORY);
+	this.refreshSearchHistory();
+	this.refreshTagSearchHistory();
+  }
+
+  /**
+   * This helper can be called externally to refresh the following history
+   * boxes: previewed items history, downloaded items history, opened items
+   * history and the history of items that were commented on.
+   * 
+   * Is used inside ResourcePreviewBrowser and MainComponent every time a
+   * relevant action occurs. Also useful, when an option to 'clear preview
+   * history' is used in the Preferences window for. a particular history type.
+   */
+  public void refreshHistoryBox(int historyType) {
+	switch (historyType) {
+	  case PREVIEWED_ITEMS_HISTORY:
+		this.jpPreviewHistory.removeAll();
+		populateHistoryBox(this.pluginMainComponent.getPreviewBrowser().getPreviewHistory(), this.jpPreviewHistory, "No items were previewed yet");
+		break;
+	  case DOWNLOADED_ITEMS_HISTORY:
+		this.jpDownloadedItemsHistory.removeAll();
+		populateHistoryBox(this.lDownloadedItems, this.jpDownloadedItemsHistory, "No items were downloaded");
+		break;
+	  case OPENED_ITEMS_HISTORY:
+		this.jpOpenedItemsHistory.removeAll();
+		populateHistoryBox(this.lOpenedItems, this.jpOpenedItemsHistory, "No items were opened");
+		break;
+	  case UPLOADED_ITEMS_HISTORY:
+		this.jpUploadedItemsHistory.removeAll();
+		populateHistoryBox(this.lUploadedItems, this.jpUploadedItemsHistory, "No items were updated");
+		break;
+	  case COMMENTED_ON_ITEMS_HISTORY:
+		this.jpCommentedOnHistory.removeAll();
+		populateHistoryBox(this.lCommentedOnItems, this.jpCommentedOnHistory, "You didn't comment on any items");
+		break;
+	}
+  }
+
+  /**
+   * Retrieves history data from a relevant list and populates the specified
+   * panel with it. All listed items will be resources that can be opened by
+   * Preview Browser.
+   */
+  private void populateHistoryBox(List<Resource> lHistory, JPanel jpPanelToPopulate, String strLabelIfNoItems) {
+	if (lHistory.size() > 0) {
+	  for (int i = lHistory.size() - 1; i >= 0; i--) {
+		Resource r = lHistory.get(i);
+		if (r != null) {
+		  JClickableLabel lResource = Util.generateClickableLabelFor(r, this.pluginMainComponent.getPreviewBrowser());
+		  jpPanelToPopulate.add(lResource);
+		}
+	  }
+	} else {
+	  jpPanelToPopulate.add(Util.generateNoneTextLabel(strLabelIfNoItems));
+	}
+
+	// make sure that the component is updated after population
+	jpPanelToPopulate.revalidate();
+	jpPanelToPopulate.repaint();
+  }
+
+  /**
+   * This helper can be called externally to refresh the search history. Is used
+   * inside SearchTabContentPanel every time a new item is added to search
+   * history.
+   */
+  public void refreshSearchHistory() {
+	this.jpSearchHistory.removeAll();
+	populateSearchHistory();
+  }
+
+  /**
+   * Retrieves search history data from SearchTabContentPanel and populates the
+   * relevant panel.
+   */
+  private void populateSearchHistory() {
+	List<QuerySearchInstance> lSearchHistory = this.pluginMainComponent.getSearchTab().getSearchHistory();
+
+	// prepare layout
+	this.jpSearchHistory.setLayout(new GridBagLayout());
+	GridBagConstraints c = new GridBagConstraints();
+	c.anchor = GridBagConstraints.NORTHWEST;
+
+	if (lSearchHistory.size() > 0) {
+	  for (int i = lSearchHistory.size() - 1; i >= 0; i--) {
+		QuerySearchInstance qsiCurrent = lSearchHistory.get(i);
+		JClickableLabel jclCurrentEntryLabel = new JClickableLabel(qsiCurrent.getSearchQuery(), SearchTabContentPanel.SEARCH_FROM_HISTORY
+			+ ":" + i, this, WorkbenchIcons.findIcon, SwingUtilities.LEFT, qsiCurrent.toString());
+		JLabel jlCurrentEntrySettings = new JLabel(qsiCurrent.detailsAsString());
+		jlCurrentEntrySettings.setBorder(BorderFactory.createEmptyBorder(3, 5, 0, 0));
+
+		JPanel jpCurrentSearchHistoryEntry = new JPanel();
+		jpCurrentSearchHistoryEntry.setLayout(new GridBagLayout());
+		c.gridx = 0;
+		c.gridy = 0;
+		c.weightx = 0;
+		jpCurrentSearchHistoryEntry.add(jclCurrentEntryLabel, c);
+		c.gridx = 1;
+		c.gridy = 0;
+		c.weightx = 1.0;
+		jpCurrentSearchHistoryEntry.add(jlCurrentEntrySettings, c);
+
+		c.gridy = lSearchHistory.size() - 1 - i;
+		if (i == 0)
+		  c.weighty = 1.0;
+		this.jpSearchHistory.add(jpCurrentSearchHistoryEntry, c);
+	  }
+	} else {
+	  c.weightx = 1.0;
+	  c.weighty = 1.0;
+	  this.jpSearchHistory.add(Util.generateNoneTextLabel(SearchResultsPanel.NO_SEARCHES_STATUS), c);
+	}
+
+	// make sure that the component is updated after population
+	this.jpSearchHistory.revalidate();
+	this.jpSearchHistory.repaint();
+  }
+
+  /**
+   * This helper can be called externally to refresh the tag search history. Is
+   * used inside TagBrowserTabContentPanel every time a new tag is searched for.
+   */
+  public void refreshTagSearchHistory() {
+	this.jpTagSearchHistory.removeAll();
+	populateTagSearchHistory();
+  }
+
+  /**
+   * Retrieves tag search history data from Tag Browser and populates the
+   * relevant panel.
+   */
+  private void populateTagSearchHistory() {
+	List<Tag> lTagSearchHistory = this.pluginMainComponent.getTagBrowserTab().getTagSearchHistory();
+
+	if (lTagSearchHistory.size() > 0) {
+	  for (int i = lTagSearchHistory.size() - 1; i >= 0; i--) {
+		Tag t = lTagSearchHistory.get(i);
+		JClickableLabel lTag = new JClickableLabel(t.getTagName(), "tag:"
+			+ t.getTagName(), this, new ImageIcon(MyExperimentPerspective.getLocalIconURL(Resource.TAG)), // HACK: after deserialization t.getItemType() return "Unknown" type
+		SwingConstants.LEFT, "Tag: " + t.getTagName());
+		this.jpTagSearchHistory.add(lTag);
+	  }
+	} else {
+	  this.jpTagSearchHistory.add(Util.generateNoneTextLabel("No searches by tags have been made yet"));
+	}
+
+	// make sure that the component is updated after population
+	this.jpTagSearchHistory.revalidate();
+	this.jpTagSearchHistory.repaint();
+  }
+
+  /**
+   * @param strBoxTitle
+   *          Title of the content box.
+   * @param jpContentPanel
+   *          JPanel which will be populated with history listing.
+   * @return Prepared JPanel with a border, title and jpContentPanel wrapped
+   *         into a scroll pane.
+   */
+  private static JPanel generateContentBox(String strBoxTitle, JPanel jpContentPanel) {
+	// set layout for the content panel
+	jpContentPanel.setLayout(new BoxLayout(jpContentPanel, BoxLayout.Y_AXIS));
+
+	// wrap content panel into a standard scroll pane
+	JScrollPane spContent = new JScrollPane(jpContentPanel);
+	spContent.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
+	spContent.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
+	spContent.getVerticalScrollBar().setUnitIncrement(ResourcePreviewBrowser.PREFERRED_SCROLL);
+
+	// create the actual box stub with a border which will contain the scroll pane
+	JPanel jpBox = new JPanel();
+	jpBox.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2), BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), " "
+		+ strBoxTitle + " ")));
+
+	jpBox.setLayout(new GridBagLayout());
+	GridBagConstraints c = new GridBagConstraints();
+	c.anchor = GridBagConstraints.NORTHWEST;
+	c.fill = GridBagConstraints.BOTH;
+	c.weightx = 1.0;
+	c.weighty = 1.0;
+	jpBox.add(spContent, c);
+
+	return (jpBox);
+  }
+
+  // *** Callback for ActionListener interface ***
+  public void actionPerformed(ActionEvent e) {
+	if (e.getSource() instanceof JClickableLabel) {
+	  if (e.getActionCommand().startsWith(SearchTabContentPanel.SEARCH_FROM_HISTORY)) {
+		// open search tab and start the chosen search
+		this.pluginMainComponent.getSearchTab().actionPerformed(e);
+		this.pluginMainComponent.getMainTabs().setSelectedComponent(this.pluginMainComponent.getSearchTab());
+	  } else if (e.getActionCommand().startsWith("tag:")) {
+		// open tag browser tab and start the chosen tag search
+		this.pluginMainComponent.getTagBrowserTab().actionPerformed(e);
+		this.pluginMainComponent.getMainTabs().setSelectedComponent(this.pluginMainComponent.getTagBrowserTab());
+	  } else if (e.getActionCommand().contains("history")) {
+		if (e.getActionCommand() == "preview_history")
+		  spMain.setRightComponent(jpPreviewHistoryBox);
+		else if (e.getActionCommand() == "search_history")
+		  spMain.setRightComponent(jpSearchHistoryBox);
+		else if (e.getActionCommand() == "tag_history")
+		  spMain.setRightComponent(jpTagSearchHistoryBox);
+		else if (e.getActionCommand() == "downloads_history")
+		  spMain.setRightComponent(jpDownloadedItemsHistoryBox);
+		else if (e.getActionCommand() == "opened_history")
+		  spMain.setRightComponent(jpOpenedItemsHistoryBox);
+		else if (e.getActionCommand() == "uploaded_history")
+		  spMain.setRightComponent(jpUploadedItemsHistoryBox);
+		else if (e.getActionCommand() == "comments_history")
+		  spMain.setRightComponent(jpCommentedOnHistoryBox);
+	  }
+	}
+
+  }
+
+}

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/JClickableLabel.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/JClickableLabel.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/JClickableLabel.java
new file mode 100644
index 0000000..53f901f
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/JClickableLabel.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * 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.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;
+
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Util;
+
+/**
+ * @author Sergejs Aleksejevs, Jiten Bhagat
+ */
+
+public class JClickableLabel extends JLabel implements MouseListener
+{
+  // This will hold the data which is relevant to processing the 'click' event on this label
+  private String strData;
+  
+  // This will hold a reference to ResourcePreviewBrowser instance that is supposed to process the clicks
+  // on JClickableLabels
+  private ActionListener clickHandler;
+  
+  
+  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(Color.BLUE);
+    this.addMouseListener(this);
+  }
+  
+  
+  /* 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 'actionPerfermed' 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 ) ) ;
+  }
+  
+  public void mouseExited(MouseEvent e) 
+  {
+    this.setCursor( Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR ) ) ;
+  }
+  
+  public void mousePressed(MouseEvent e) 
+  {
+    // do nothing
+  }
+  
+  public void mouseReleased(MouseEvent 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/MainComponent.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/MainComponent.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/MainComponent.java
new file mode 100644
index 0000000..f4b6ace
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/MainComponent.java
@@ -0,0 +1,645 @@
+/*******************************************************************************
+ * 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.ActionEvent;
+import java.io.ByteArrayInputStream;
+import java.awt.Desktop;
+import java.net.URI;
+
+import javax.swing.AbstractAction;
+import javax.swing.ImageIcon;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.text.html.HTMLEditorKit;
+import javax.swing.text.html.StyleSheet;
+
+import net.sf.taverna.t2.lang.ui.ShadedLabel;
+import net.sf.taverna.t2.ui.perspectives.PerspectiveRegistry;
+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.ui.perspectives.myexperiment.model.Util;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Workflow;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.FileType;
+import net.sf.taverna.t2.workbench.file.exceptions.OpenException;
+import net.sf.taverna.t2.workbench.file.importworkflow.gui.ImportWorkflowWizard;
+import net.sf.taverna.t2.workbench.icons.WorkbenchIcons;
+import net.sf.taverna.t2.workbench.ui.zaria.PerspectiveSPI;
+import net.sf.taverna.t2.workbench.ui.zaria.UIComponentSPI;
+import net.sf.taverna.t2.workflowmodel.Dataflow;
+import net.sf.taverna.t2.workflowmodel.serialization.xml.impl.XMLSerializationConstants;
+
+import org.apache.log4j.Logger;
+
+/**
+ * @author Sergejs Aleksejevs, Emmanuel Tagarira, Jiten Bhagat
+ */
+public final class MainComponent extends JPanel implements UIComponentSPI, ChangeListener {
+	// myExperiment client, logger and the stylesheet will be made available
+	// throughout the whole perspective
+	private MyExperimentClient myExperimentClient;
+	private final Logger logger = Logger.getLogger(MainComponent.class);
+	private final StyleSheet css;
+	private final ResourcePreviewFactory previewFactory;
+	private final ResourcePreviewBrowser previewBrowser;
+
+	// components of the perspective
+	private JTabbedPane tpMainTabs;
+	private MyStuffTabContentPanel pMyStuffContainer;
+	private ExampleWorkflowsPanel pExampleWorkflows;
+	private TagBrowserTabContentPanel pTagBrowser;
+	private SearchTabContentPanel pSearchTab;
+	private HistoryBrowserTabContentPanel pHistoryBrowserTab;
+	private PluginStatusBar pStatusBar;
+	private PluginPreferencesDialog jdPreferences;
+
+	public static MainComponent MAIN_COMPONENT;
+	public static MyExperimentClient MY_EXPERIMENT_CLIENT;
+	public static Logger LOGGER;
+	private final EditManager editManager;
+	private final FileManager fileManager;
+
+	public MainComponent(EditManager editManager, FileManager fileManager) {
+		super();
+		this.editManager = editManager;
+		this.fileManager = fileManager;
+
+		// create and initialise myExperiment client
+		try {
+			this.myExperimentClient = new MyExperimentClient(logger);
+		} catch (Exception e) {
+			this.logger.error("Couldn't initialise myExperiment client");
+		}
+
+		// x, y, z ARE NOT USED ANYWHERE ELSE
+		// HACK TO BE ABLE TO GET THE REFS FROM TAVERNA'S PREFERENCE PANEL
+		// TODO: refactor code for all the other classes to utilise the class
+		// vars
+		MainComponent x = this;
+		MAIN_COMPONENT = x;
+
+		MyExperimentClient y = this.myExperimentClient;
+		MY_EXPERIMENT_CLIENT = y;
+
+		Logger z = this.logger;
+		LOGGER = z;
+
+		// components to generate and display previews
+		previewFactory = new ResourcePreviewFactory(this, myExperimentClient, logger);
+		previewBrowser = new ResourcePreviewBrowser(this, myExperimentClient, logger, fileManager);
+
+		this.css = new StyleSheet();
+		this.css.importStyleSheet(MyExperimentPerspective.getLocalResourceURL("css_stylesheet"));
+		logger.debug("Stylesheet loaded: \n" + this.css.toString());
+
+		// check if values for default tabs are set, if not - set defaults;
+		// NB! This has to be done before initialising UI
+		if (myExperimentClient.getSettings().getProperty(
+				MyExperimentClient.INI_DEFAULT_ANONYMOUS_TAB) == null)
+			myExperimentClient.getSettings().put(MyExperimentClient.INI_DEFAULT_ANONYMOUS_TAB, "3"); // SEARCH
+		if (myExperimentClient.getSettings().getProperty(
+				MyExperimentClient.INI_DEFAULT_LOGGED_IN_TAB) == null)
+			myExperimentClient.getSettings().put(MyExperimentClient.INI_DEFAULT_LOGGED_IN_TAB, "0"); // STUFF
+
+		initialisePerspectiveUI();
+
+		// HACK for a weird stylesheet bug (where the first thing to use the
+		// stylesheet doesn't actually get the styles)
+		// NB! This has to be located after all ShadedLabels were initialized to
+		// prevent bad layout in them
+		HTMLEditorKit kit = new StyledHTMLEditorKit(this.css);
+
+		// determine which shutdown operations to use
+		if (Util.isRunningInTaverna()) {
+			// register the current instance of main component with the
+			// myExperiment
+			// perspective; this will be used later on when shutdown operation
+			// needs
+			// to be performed - e.g. this aids ShutdownSPI to find the running
+			// instance of the plugin
+			for (PerspectiveSPI perspective : PerspectiveRegistry.getInstance().getPerspectives()) {
+				if (perspective.getText().equals(MyExperimentPerspective.PERSPECTIVE_NAME)) {
+					((MyExperimentPerspective) perspective).setMainComponent(this);
+					break;
+				}
+			}
+		}
+
+		// Do the rest in a separate thread to avoid hanging the GUI.
+		// Remember to use SwingUtilities.invokeLater to update the GUI
+		// directly.
+		new Thread("Data initialisation for Taverna 2 - myExperiment plugin") {
+			@Override
+			public void run() {
+				// load the data into the plugin
+				initialiseData();
+			}
+		}.start();
+
+	}
+
+	public ImageIcon getIcon() {
+		return WorkbenchIcons.databaseIcon;
+	}
+
+	@Override
+	public String getName() {
+		return "myExperiment Perspective Main Component";
+	}
+
+	public void onDisplay() {
+	}
+
+	public void onDispose() {
+	}
+
+	public MyExperimentClient getMyExperimentClient() {
+		return this.myExperimentClient;
+	}
+
+	public Logger getLogger() {
+		return this.logger;
+	}
+
+	public StyleSheet getStyleSheet() {
+		return this.css;
+	}
+
+	public PluginStatusBar getStatusBar() {
+		return this.pStatusBar;
+	}
+
+	public PluginPreferencesDialog getPreferencesDialog() {
+		return this.jdPreferences;
+	}
+
+	public ResourcePreviewFactory getPreviewFactory() {
+		return this.previewFactory;
+	}
+
+	public ResourcePreviewBrowser getPreviewBrowser() {
+		return this.previewBrowser;
+	}
+
+	public HistoryBrowserTabContentPanel getHistoryBrowser() {
+		return this.pHistoryBrowserTab;
+	}
+
+	public JTabbedPane getMainTabs() {
+		return (this.tpMainTabs);
+	}
+
+	public MyStuffTabContentPanel getMyStuffTab() {
+		return (this.pMyStuffContainer);
+	}
+
+	public ExampleWorkflowsPanel getExampleWorkflowsTab() {
+		return (this.pExampleWorkflows);
+	}
+
+	public TagBrowserTabContentPanel getTagBrowserTab() {
+		return (this.pTagBrowser);
+	}
+
+	public SearchTabContentPanel getSearchTab() {
+		return (this.pSearchTab);
+	}
+
+	private void initialisePerspectiveUI() {
+		// HACK: this is required to prevent some labels from having white
+		// non-transparent background
+		ShadedLabel testLabel = new ShadedLabel("test", ShadedLabel.BLUE);
+
+		// create instances of individual components
+		// (NB! Status bar needs to be initialised first, so that it is
+		// available to
+		// other components immediately!)
+		this.pStatusBar = new PluginStatusBar(this, myExperimentClient, logger);
+		this.pMyStuffContainer = new MyStuffTabContentPanel(this, myExperimentClient, logger, fileManager);
+		this.pExampleWorkflows = new ExampleWorkflowsPanel(this, myExperimentClient, logger);
+		this.pTagBrowser = new TagBrowserTabContentPanel(this, myExperimentClient, logger);
+		this.pSearchTab = new SearchTabContentPanel(this, myExperimentClient, logger);
+		this.pHistoryBrowserTab = new HistoryBrowserTabContentPanel(this, myExperimentClient,
+				logger);
+
+		// add the required ones into the main tabs
+		this.tpMainTabs = new JTabbedPane();
+		this.tpMainTabs.add("My Stuff", this.pMyStuffContainer);
+		// TODO: implement the starter pack
+		this.tpMainTabs.add("Starter Pack", this.pExampleWorkflows);
+		this.tpMainTabs.add("Tag Browser", this.pTagBrowser);
+		this.tpMainTabs.add("Search", this.pSearchTab);
+		this.tpMainTabs.add("Local History", this.pHistoryBrowserTab);
+
+		// add main tabs and the status bar into the perspective
+		this.setLayout(new BorderLayout());
+		this.add(this.tpMainTabs, BorderLayout.CENTER);
+		this.add(this.pStatusBar, BorderLayout.SOUTH);
+
+		// add listener to TabbedPane, so that the app "knows" when some tab was
+		// opened
+		this.tpMainTabs.addChangeListener(this);
+
+		// initialise the preferences dialog
+		/*
+		 * NB! this has to be done after all tabs were created (Preview Browser
+		 * is used as an owner of the preferences dialog because Preview Browser
+		 * is the only JFrame in the application - in Java 1.5 it is only
+		 * possible to set an icon to a JFrame and all 'children' dialog of it
+		 * get the same icon - so essentially, this is only to set the
+		 * myExperiment logo as an icon of preferences dialog.)
+		 */
+		this.jdPreferences = new PluginPreferencesDialog(this.getPreviewBrowser(), this,
+				myExperimentClient, logger);
+	}
+
+	private void initialiseData() {
+		this.logger.debug("Initialising myExperiment Perspective data");
+
+		// check if 'auto-login' is required (NB! This requires the BASE_URL to
+		// be
+		// set correctly!)
+		Object oAutoLogin = this.myExperimentClient.getSettings().get(
+				MyExperimentClient.INI_AUTO_LOGIN);
+		if (oAutoLogin != null && oAutoLogin.equals("true")) {
+			this.getStatusBar().setStatus(this.getMyStuffTab().getClass().getName(),
+					"Performing autologin");
+			this.myExperimentClient.doLoginFromStoredCredentials();
+			this.getStatusBar().setStatus(this.getMyStuffTab().getClass().getName(),
+					"Autologin finished. Fetching user data");
+		}
+
+		// NB! This should only be done if the user is logged in -
+		// otherwise this component simply doesn't exist
+		// this.pMyStuffContainer.spMyStuff.setDividerLocation(0.3);
+
+		// load data into all tabs
+		this.pMyStuffContainer.createAndInitialiseInnerComponents();
+		if (this.myExperimentClient.isLoggedIn()) {
+			// set the default tab for logged in user (e.g. as a consequence of
+			// auto-login)
+			tpMainTabs.setSelectedIndex(Integer.parseInt(myExperimentClient.getSettings()
+					.getProperty(MyExperimentClient.INI_DEFAULT_LOGGED_IN_TAB)));
+
+			// auto-login was successful - can display user tags
+			// (no need to refresh this cloud on its own, because the whole tab
+			// is refreshed immediately after)
+			this.pTagBrowser.setMyTagsShown(true);
+		} else {
+			// set the default tab for anonymous user (auto-login failed or
+			// wasn't
+			// chosen)
+			tpMainTabs.setSelectedIndex(Integer.parseInt(myExperimentClient.getSettings()
+					.getProperty(MyExperimentClient.INI_DEFAULT_ANONYMOUS_TAB)));
+		}
+
+		this.pExampleWorkflows.refresh();
+		this.pTagBrowser.refresh();
+	}
+
+	public void stateChanged(ChangeEvent e) {
+		// invoked when a tab is opened
+		if (e.getSource().equals(this.tpMainTabs)) {
+			this.getStatusBar().displayStatus(
+					this.getMainTabs().getSelectedComponent().getClass().getName());
+		}
+	}
+
+	// ************** ACTIONS ***************
+	public class PreviewResourceAction extends AbstractAction {
+		private int iResourceType = Resource.UNKNOWN;
+		private String strResourceURI = "";
+
+		public PreviewResourceAction(int iResourceType, String strResourceURI) {
+			putValue(SMALL_ICON, WorkbenchIcons.zoomIcon);
+			putValue(NAME, "Preview");
+			putValue(SHORT_DESCRIPTION,
+					"Preview this " + Resource.getResourceTypeName(iResourceType).toLowerCase()
+							+ " in the Preview Browser window");
+
+			this.iResourceType = iResourceType;
+			this.strResourceURI = strResourceURI;
+		}
+
+		public void actionPerformed(ActionEvent actionEvent) {
+			getPreviewBrowser()
+					.preview("preview:" + this.iResourceType + ":" + this.strResourceURI);
+		}
+	}
+
+	public class DownloadResourceAction extends AbstractAction {
+		private Resource resource = null;
+
+		public DownloadResourceAction(Resource resource) {
+			this(resource, true);
+		}
+
+		public DownloadResourceAction(Resource resource, boolean bShowButtonLabel) {
+			this.resource = resource;
+			String strResourceType = resource.getItemTypeName().toLowerCase();
+
+			// in either case the icon is the same; label might be displayed -
+			// based
+			// on the parameter
+			putValue(SMALL_ICON, WorkbenchIcons.saveIcon);
+			if (bShowButtonLabel)
+				putValue(NAME, "Download");
+
+			String strTooltip = "Downloading " + strResourceType + "s is currently not possible";
+			boolean bDownloadAllowed = false;
+			if (resource.isDownloadable()) {
+				if (resource.isDownloadAllowed()) {
+					strTooltip = "Download this " + strResourceType + " and store it locally";
+					bDownloadAllowed = true;
+				} else {
+					strTooltip = "You don't have permissions to download this " + strResourceType;
+				}
+			}
+
+			setEnabled(bDownloadAllowed);
+			putValue(SHORT_DESCRIPTION, strTooltip);
+		}
+
+		public void actionPerformed(ActionEvent actionEvent) {
+			try {
+				Desktop.getDesktop().browse(new URI(resource.getResource() + "/download"));
+
+				// update downloaded items history making sure that:
+				// - there's only one occurrence of this item in the history;
+				// - if this item was in the history before, it is moved to the
+				// 'top'
+				// now;
+				// - predefined history size is not exceeded
+				getHistoryBrowser().getDownloadedItemsHistoryList().remove(resource);
+				getHistoryBrowser().getDownloadedItemsHistoryList().add(resource);
+				if (getHistoryBrowser().getDownloadedItemsHistoryList().size() > HistoryBrowserTabContentPanel.DOWNLOADED_ITEMS_HISTORY_LENGTH) {
+					getHistoryBrowser().getDownloadedItemsHistoryList().remove(0);
+				}
+
+				// now update the downloaded items history panel in 'History'
+				// tab
+				if (getHistoryBrowser() != null) {
+					getHistoryBrowser().refreshHistoryBox(
+							HistoryBrowserTabContentPanel.DOWNLOADED_ITEMS_HISTORY);
+				}
+			} catch (Exception ex) {
+				logger.error("Failed while trying to open download URL in a standard browser; URL was: "
+						+ resource.getURI() + "\nException was: " + ex);
+			}
+		}
+	}
+
+	public class LoadResourceInTavernaAction extends AbstractAction {
+		private final Resource resource;
+
+		public LoadResourceInTavernaAction(Resource resource) {
+			this(resource, true);
+		}
+
+		public LoadResourceInTavernaAction(Resource resource, boolean bShowButtonLabel) {
+			this.resource = resource;
+			String strResourceType = resource.getItemTypeName().toLowerCase();
+
+			putValue(SMALL_ICON, WorkbenchIcons.openIcon);
+			if (bShowButtonLabel)
+				putValue(NAME, "Open");
+
+			boolean bLoadingAllowed = false;
+			String strTooltip = "Loading " + strResourceType
+					+ "s into Taverna Workbench is currently not possible";
+			if (resource.getItemType() == Resource.WORKFLOW) {
+				if (((Workflow) resource).isTavernaWorkflow()) {
+					if (resource.isDownloadAllowed()) {
+						// Taverna workflow and download allowed - can load in
+						// Taverna
+						bLoadingAllowed = true;
+						strTooltip = "Download and load this workflow in Design mode of Taverna Workbench";
+					} else {
+						strTooltip = "You don't have permissions to download this workflow, and thus to load into Taverna Workbench";
+					}
+				} else {
+					strTooltip = "Loading workflow of unsupported type into Taverna Workbench is not possible.";
+				}
+			}
+
+			setEnabled(bLoadingAllowed);
+			putValue(SHORT_DESCRIPTION, strTooltip);
+
+		}
+
+		public void actionPerformed(ActionEvent actionEvent) {
+			// if the preview browser window is opened, hide it beneath the main
+			// window
+			if (getPreviewBrowser().isActive())
+				getPreviewBrowser().toBack();
+
+			final String strCallerTabClassName = getMainTabs().getSelectedComponent().getClass()
+					.getName();
+			getStatusBar().setStatus(strCallerTabClassName, "Downloading and opening workflow...");
+			logger.debug("Downloading and opening workflow from URI: " + resource.getURI());
+
+			new Thread("Download and open workflow") {
+				@Override
+				public void run() {
+					try {
+						Workflow w = myExperimentClient.fetchWorkflowBinary(resource.getURI());
+						ByteArrayInputStream workflowDataInputStream = new ByteArrayInputStream(
+								w.getContent());
+
+						FileType fileTypeType = (w.isTaverna1Workflow() ? new ScuflFileType()
+								: new T2FlowFileType());
+						Dataflow openDataflow = fileManager.openDataflow(fileTypeType,
+								workflowDataInputStream);
+					} catch (Exception e) {
+						javax.swing.JOptionPane.showMessageDialog(null,
+								"An error has occurred while trying to load a workflow from myExperiment.\n\n"
+										+ e, "Error", JOptionPane.ERROR_MESSAGE);
+						logger.error(
+								"Failed to open connection to URL to download and open workflow, from myExperiment.",
+								e);
+					}
+
+					getStatusBar().setStatus(strCallerTabClassName, null);
+
+					// update opened items history making sure that:
+					// - there's only one occurrence of this item in the
+					// history;
+					// - if this item was in the history before, it is moved to
+					// the 'top'
+					// now;
+					// - predefined history size is not exceeded
+					getHistoryBrowser().getOpenedItemsHistoryList().remove(resource);
+					getHistoryBrowser().getOpenedItemsHistoryList().add(resource);
+					if (getHistoryBrowser().getOpenedItemsHistoryList().size() > HistoryBrowserTabContentPanel.OPENED_ITEMS_HISTORY_LENGTH) {
+						getHistoryBrowser().getOpenedItemsHistoryList().remove(0);
+					}
+
+					// now update the opened items history panel in 'History'
+					// tab
+					if (getHistoryBrowser() != null) {
+						getHistoryBrowser().refreshHistoryBox(
+								HistoryBrowserTabContentPanel.OPENED_ITEMS_HISTORY);
+					}
+				}
+			}.start();
+		}
+	}
+
+	public class ImportIntoTavernaAction extends AbstractAction {
+		private final Resource resource;
+		private boolean importAsNesting;
+
+		public ImportIntoTavernaAction(Resource r) {
+			this.resource = r;
+
+			String strResourceType = resource.getItemTypeName().toLowerCase();
+
+			putValue(SMALL_ICON, WorkbenchIcons.importIcon);
+			putValue(NAME, "Import");
+
+			boolean bLoadingAllowed = false;
+			String strTooltip = "Loading " + strResourceType
+					+ "s into Taverna Workbench is currently not possible";
+			if (resource.getItemType() == Resource.WORKFLOW) {
+				if (((Workflow) resource).isTavernaWorkflow()) {
+					if (resource.isDownloadAllowed()) {
+						// Taverna workflow and download allowed - can load in
+						// Taverna
+						bLoadingAllowed = true;
+						strTooltip = "Import this workflow into one that is currently open in the Design mode of Taverna Workbench";
+					} else {
+						strTooltip = "You don't have permissions to download this workflow, and thus to load into Taverna Workbench";
+					}
+				} else {
+					strTooltip = "Loading workflow of unsupported type into Taverna Workbench is not possible.";
+				}
+			}
+
+			setEnabled(bLoadingAllowed);
+			putValue(SHORT_DESCRIPTION, strTooltip);
+		}
+
+		public void actionPerformed(ActionEvent actionEvent) {
+			// if the preview browser window is opened, hide it beneath the main
+			// window
+			if (getPreviewBrowser().isActive())
+				getPreviewBrowser().toBack();
+
+			ImportWorkflowWizard importWorkflowDialog = new ImportWorkflowWizard(
+					getPreviewBrowser(), editManager, fileManager);
+
+			Workflow w;
+			try {
+				w = MY_EXPERIMENT_CLIENT.fetchWorkflowBinary(resource.getURI());
+			} catch (Exception e) {
+				JOptionPane.showMessageDialog(null, "An error has occurred "
+						+ "while trying to load a " + "workflow from myExperiment.\n\n" + e,
+						"Error", JOptionPane.ERROR_MESSAGE);
+				LOGGER.error("Failed to open connection to URL to "
+						+ "download and open workflow, from myExperiment.", e);
+				return;
+			}
+			ByteArrayInputStream workflowDataInputStream = new ByteArrayInputStream(w.getContent());
+			FileType fileTypeType = (w.isTaverna1Workflow() ? new MainComponent.ScuflFileType()
+					: new MainComponent.T2FlowFileType());
+			Dataflow toBeImported;
+			try {
+				toBeImported = fileManager.openDataflowSilently(fileTypeType,
+						workflowDataInputStream).getDataflow();
+			} catch (OpenException e) {
+				JOptionPane.showMessageDialog(null, "An error has occurred"
+						+ " while trying to load a " + "workflow from myExperiment.\n\n" + e,
+						"Error", JOptionPane.ERROR_MESSAGE);
+				LOGGER.error("Failed to" + " open connection to URL "
+						+ "to download and open workflow, from myExperiment.", e);
+				return;
+			}
+			importWorkflowDialog.setCustomSourceDataflow(toBeImported, "From myExperiment: "
+					+ resource.getTitle());
+			importWorkflowDialog.setSourceEnabled(false);
+			importWorkflowDialog.setVisible(true);
+
+			// update opened items history making sure that:
+			// - there's only one occurrence of this item in the history;
+			// - if this item was in the history before, it is moved to the
+			// 'top' now;
+			// - predefined history size is not exceeded
+			getHistoryBrowser().getOpenedItemsHistoryList().remove(resource);
+			getHistoryBrowser().getOpenedItemsHistoryList().add(resource);
+			if (getHistoryBrowser().getOpenedItemsHistoryList().size() > HistoryBrowserTabContentPanel.OPENED_ITEMS_HISTORY_LENGTH) {
+				getHistoryBrowser().getOpenedItemsHistoryList().remove(0);
+			}
+
+			// now update the opened items history panel in 'History' tab
+			if (getHistoryBrowser() != null)
+				getHistoryBrowser().refreshHistoryBox(
+						HistoryBrowserTabContentPanel.OPENED_ITEMS_HISTORY);
+		}
+
+	}
+
+	// *** FileTypes for opening workflows inside Taverna
+
+	public static class ScuflFileType extends FileType {
+
+		@Override
+		public String getDescription() {
+			return "Taverna 1 SCUFL workflow";
+		}
+
+		@Override
+		public String getExtension() {
+			return "xml";
+		}
+
+		@Override
+		public String getMimeType() {
+			return "application/vnd.taverna.scufl+xml";
+		}
+	}
+
+	public static class T2FlowFileType extends FileType {
+		@Override
+		public String getDescription() {
+			return "Taverna 2 workflow";
+		}
+
+		@Override
+		public String getExtension() {
+			return "t2flow";
+		}
+
+		@Override
+		public String getMimeType() {
+			// "application/vnd.taverna.t2flow+xml";
+			return XMLSerializationConstants.WORKFLOW_DOCUMENT_MIMETYPE;
+		}
+	}
+}

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/MainComponentFactory.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/MainComponentFactory.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/MainComponentFactory.java
new file mode 100644
index 0000000..65f8875
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/MainComponentFactory.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * 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;
+
+/**
+ * @author Sergejs Aleksejevs, Jiten Bhagat
+ */
+
+import javax.swing.ImageIcon;
+
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.icons.WorkbenchIcons;
+import net.sf.taverna.t2.workbench.ui.zaria.UIComponentFactorySPI;
+import net.sf.taverna.t2.workbench.ui.zaria.UIComponentSPI;
+
+public class MainComponentFactory implements UIComponentFactorySPI {
+
+	private EditManager editManager;
+	private FileManager fileManager;
+
+	public UIComponentSPI getComponent() {
+		return new MainComponent(editManager, fileManager);
+	}
+
+	public ImageIcon getIcon() {
+		return WorkbenchIcons.databaseIcon;
+	}
+
+	public String getName() {
+		return "myExperiment Main Component Factory";
+	}
+
+	public void setEditManager(EditManager editManager) {
+		this.editManager = editManager;
+	}
+
+	public void setFileManager(FileManager fileManager) {
+		this.fileManager = fileManager;
+	}
+
+}

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/MainComponentShutdownHook.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/MainComponentShutdownHook.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/MainComponentShutdownHook.java
new file mode 100644
index 0000000..2214d5e
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/MainComponentShutdownHook.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * 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 net.sf.taverna.t2.ui.perspectives.PerspectiveRegistry;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.MyExperimentClient;
+import net.sf.taverna.t2.workbench.ShutdownSPI;
+import net.sf.taverna.t2.workbench.ui.zaria.PerspectiveSPI;
+
+import org.apache.log4j.Logger;
+
+/**
+ * @author Sergejs Aleksejevs, Jiten Bhagat
+ */
+
+public class MainComponentShutdownHook implements ShutdownSPI {
+  private MainComponent pluginMainComponent;
+  private MyExperimentClient myExperimentClient;
+  private Logger logger;
+
+  public int positionHint() {
+	// all custom plugins are suggested to return a value of > 100;
+	// this affects when in the termination process will this plugin
+	// be shutdown;
+	return 100;
+  }
+
+  public boolean shutdown() {
+	// find instance of main component of the running myExperiment perspective
+	MainComponent mainComponent = null;
+	for (PerspectiveSPI perspective : PerspectiveRegistry.getInstance().getPerspectives()) {
+	  if (perspective instanceof MyExperimentPerspective) {		  
+		mainComponent = ((MyExperimentPerspective) perspective).getMainComponent();
+		break;
+	  }
+	}
+
+	// if myExperiment perspective wasn't initialised, no shutdown operations are required / possible
+	if (mainComponent != null) {
+	  this.setLinks(mainComponent, mainComponent.getMyExperimentClient(), mainComponent.getLogger());
+	  logger.debug("Starting shutdown operations for myExperiment plugin");
+
+	  try {
+		myExperimentClient.storeHistoryAndSettings();
+	  } catch (Exception e) {
+		logger.error("Failed while serializing myExperiment plugin settings:\n"
+			+ e);
+	  }
+
+	  logger.debug("myExperiment plugin shutdown is completed; terminated...");
+	}
+
+	// "true" means that shutdown operations are complete and Taverna can terminate
+	return true;
+  }
+
+  /**
+   * Sets up links of this class with the rest of the plugin.
+   */
+  public void setLinks(MainComponent component, MyExperimentClient client, Logger logger) {
+	this.pluginMainComponent = component;
+	this.myExperimentClient = client;
+	this.logger = logger;
+  }
+
+}

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/MyExperimentPerspective.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/MyExperimentPerspective.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/MyExperimentPerspective.java
new file mode 100644
index 0000000..1982b75
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/MyExperimentPerspective.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * 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.io.InputStream;
+import java.net.URL;
+
+import javax.swing.ImageIcon;
+
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Resource;
+import net.sf.taverna.t2.workbench.ui.zaria.PerspectiveSPI;
+
+import org.jdom.Element;
+
+/**
+ * @author Sergejs Aleksejevs, Jiten Bhagat
+ */
+public class MyExperimentPerspective implements PerspectiveSPI {
+	// CONSTANTS
+	// this is where all icons, stylesheet, etc are located
+	private static final String BASE_RESOURCE_PATH = "/net/sf/taverna/t2/ui/perspectives/myexperiment/";
+	public static final String PERSPECTIVE_NAME = "myExperiment";
+	public static final String PLUGIN_VERSION = "0.2beta";
+
+	// COMPONENTS
+	private MainComponent perspectiveMainComponent;
+	private boolean visible = true;
+
+	public ImageIcon getButtonIcon() {
+		URL iconURL = MyExperimentPerspective.getLocalResourceURL("myexp_icon16x16");
+		if (iconURL == null) {
+			return null;
+		} else {
+			return new ImageIcon(iconURL);
+		}
+	}
+
+	public InputStream getLayoutInputStream() {
+		return getClass().getResourceAsStream("myexperiment-perspective.xml");
+	}
+
+	public String getText() {
+		return PERSPECTIVE_NAME;
+	}
+
+	public boolean isVisible() {
+		return visible;
+	}
+
+	public int positionHint() {
+		// this determines position of myExperiment perspective in the
+		// bar with perspective buttons (currently makes it the last in the
+		// list)
+		return 30;
+	}
+
+	public void setVisible(boolean visible) {
+		this.visible = visible;
+
+	}
+
+	public void update(Element layoutElement) {
+		// Not sure what to do here
+	}
+
+	public void setMainComponent(MainComponent component) {
+		this.perspectiveMainComponent = component;
+	}
+
+	/**
+	 * Returns the instance of the main component of this perspective.
+	 */
+	public MainComponent getMainComponent() {
+		return this.perspectiveMainComponent;
+	}
+
+	// a single point in the plugin where all resources are referenced
+	public static URL getLocalResourceURL(String strResourceName) {
+		String strResourcePath = MyExperimentPerspective.BASE_RESOURCE_PATH;
+
+		if (strResourceName.equals("not_authorized_icon"))
+			strResourcePath += "denied.png";
+		if (strResourceName.equals("failure_icon"))
+			strResourcePath += "denied.png";
+		else if (strResourceName.equals("success_icon"))
+			strResourcePath += "tick.png";
+		else if (strResourceName.equals("spinner"))
+			strResourcePath += "ajax-loader.gif";
+		else if (strResourceName.equals("spinner_stopped"))
+			strResourcePath += "ajax-loader-still.gif";
+		else if (strResourceName.equals("external_link_small_icon"))
+			strResourcePath += "external_link_listing_small.png";
+		else if (strResourceName.equals("back_icon"))
+			strResourcePath += "arrow_left.png";
+		else if (strResourceName.equals("forward_icon"))
+			strResourcePath += "arrow_right.png";
+		else if (strResourceName.equals("refresh_icon"))
+			strResourcePath += "arrow_refresh.png";
+		else if (strResourceName.equals("favourite_icon"))
+			strResourcePath += "star.png";
+		else if (strResourceName.equals("add_favourite_icon"))
+			strResourcePath += "favourite_add.png";
+		else if (strResourceName.equals("delete_favourite_icon"))
+			strResourcePath += "favourite_delete.png";
+		else if (strResourceName.equals("destroy_icon"))
+			strResourcePath += "cross.png";
+		else if (strResourceName.equals("add_comment_icon"))
+			strResourcePath += "comment_add.png";
+		else if (strResourceName.equals("myexp_icon"))
+			strResourcePath += "myexp_icon.png";
+		else if (strResourceName.equals("myexp_icon16x16"))
+			strResourcePath += "myexp_icon16x16.png";
+		else if (strResourceName.equals("open_in_my_experiment_icon"))
+			strResourcePath += "open_in_myExperiment.png";
+		else if (strResourceName.equals("login_icon"))
+			strResourcePath += "login.png";
+		else if (strResourceName.equals("logout_icon"))
+			strResourcePath += "logout.png";
+		else if (strResourceName.equals("css_stylesheet"))
+			strResourcePath += "styles.css";
+		else {
+			throw new java.lang.IllegalArgumentException(
+					"Unknown myExperiment plugin resource requested; requested resource name was: "
+							+ strResourceName);
+		}
+
+		// no exception was thrown, therefore the supplied resource name was
+		// recognised;
+		// return the local URL of that resource
+		return (MyExperimentPerspective.class.getResource(strResourcePath));
+	}
+
+	// a single point in the plugin where all resources' icons are referenced
+	public static URL getLocalIconURL(int iResourceType) {
+		String strResourcePath = MyExperimentPerspective.BASE_RESOURCE_PATH;
+
+		switch (iResourceType) {
+		case Resource.WORKFLOW:
+			strResourcePath += "workflow.png";
+			break;
+		case Resource.FILE:
+			strResourcePath += "file.png";
+			break;
+		case Resource.PACK:
+			strResourcePath += "pack.png";
+			break;
+		case Resource.PACK_EXTERNAL_ITEM:
+			strResourcePath += "remote_resource.png";
+			break;
+		case Resource.USER:
+			strResourcePath += "user.png";
+			break;
+		case Resource.GROUP:
+			strResourcePath += "group.png";
+			break;
+		case Resource.TAG:
+			strResourcePath += "tag_blue.png";
+			break;
+		default:
+			throw new java.lang.IllegalArgumentException(
+					"Unknown myExperiment plugin resource requested; requested resource name was: "
+							+ Resource.getResourceTypeName(iResourceType));
+		}
+
+		// no exception was thrown, therefore the supplied resource name was
+		// recognised;
+		// return the local URL of that resource
+		return (MyExperimentPerspective.class.getResource(strResourcePath));
+	}
+
+}

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/MyStuffContributionsPanel.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/MyStuffContributionsPanel.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/MyStuffContributionsPanel.java
new file mode 100644
index 0000000..e7ef972
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/MyStuffContributionsPanel.java
@@ -0,0 +1,370 @@
+/*******************************************************************************
+ * 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.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+
+import net.sf.taverna.t2.lang.ui.ShadedLabel;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.File;
+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.Resource;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Workflow;
+
+import org.apache.log4j.Logger;
+import org.jdom.Document;
+import org.jdom.Element;
+
+
+/**
+ * @author Sergejs Aleksejevs, Emmanuel Tagarira, Jiten Bhagat
+ */
+public class MyStuffContributionsPanel extends JPanel implements ActionListener {
+  // CONSTANTS
+  private static final int SHADED_LABEL_HEIGHT = 20;
+  private static final int SECTION_VSPACING = 5;
+  private static final int SCROLL_PANE_PADDING = 3;
+  private static final int TOTAL_SECTION_VSPACING = SHADED_LABEL_HEIGHT
+	  + SECTION_VSPACING + SCROLL_PANE_PADDING + 5; // the last literal is to cover all paddings / margins / etc
+
+  private MainComponent pluginMainComponent;
+  private MyExperimentClient myExperimentClient;
+  private Logger logger;
+
+  // MAIN COMPONENTS of the view
+  JPanel jpMyWorkflows;
+  JPanel jpMyFiles;
+  JPanel jpMyPacks;
+
+  // HELPER COMPONENTS
+  // these are the individual content listings for 'my workfows', 'my files' and 'my packs' ..
+  ResourceListPanel jpMyWorkflowsContent = null;
+  ResourceListPanel jpMyFilesContent = null;
+  ResourceListPanel jpMyPacksContent = null;
+
+  // .. these will be wrapped into individual scroll panes to ensure correct sizes
+  JScrollPane spMyWorkflowsContent = null;
+  JScrollPane spMyFilesContent = null;
+  JScrollPane spMyPacksContent = null;
+
+  // STORAGE
+  private ArrayList<JPanel> alVisiblePanels;
+  private ArrayList<JComponent[]> alVisiblePanelsWithHelperElements;
+
+  public MyStuffContributionsPanel(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;
+
+	alVisiblePanels = new ArrayList<JPanel>();
+	alVisiblePanelsWithHelperElements = new ArrayList<JComponent[]>();
+
+	// check that settings for this panel were set correctly in the INI file
+	// (if any record is missing - assume that this section is visible)
+	// (this will ensure that these values can be used with no further validity checks
+	//  across the plugin; this is because this method will be executed at start of the plugin)
+	if (myExperimentClient.getSettings().getProperty(MyExperimentClient.INI_MY_STUFF_WORKFLOWS) == null) {
+	  myExperimentClient.getSettings().put(MyExperimentClient.INI_MY_STUFF_WORKFLOWS, new Boolean(true).toString());
+	}
+	if (myExperimentClient.getSettings().getProperty(MyExperimentClient.INI_MY_STUFF_FILES) == null) {
+	  myExperimentClient.getSettings().put(MyExperimentClient.INI_MY_STUFF_FILES, new Boolean(true).toString());
+	}
+	if (myExperimentClient.getSettings().getProperty(MyExperimentClient.INI_MY_STUFF_PACKS) == null) {
+	  myExperimentClient.getSettings().put(MyExperimentClient.INI_MY_STUFF_PACKS, new Boolean(true).toString());
+	}
+
+	// create and initialise the UI of MyStuff tab
+	initialiseUI();
+	initialiseData();
+  }
+
+  private void initialiseUI() {
+	JPanel jpMyWorkflowsContainer = new JPanel();
+	jpMyWorkflowsContainer.setBorder(BorderFactory.createEmptyBorder());
+	if (Boolean.parseBoolean(myExperimentClient.getSettings().getProperty(MyExperimentClient.INI_MY_STUFF_WORKFLOWS))) {
+	  // "My Workflows" panel
+	  jpMyWorkflowsContainer.setBorder(BorderFactory.createEtchedBorder());
+	  jpMyWorkflowsContainer.setLayout(new BorderLayout());
+
+	  ShadedLabel l0 = new ShadedLabel("My Workflows", ShadedLabel.BLUE);
+	  jpMyWorkflowsContainer.add(l0, BorderLayout.NORTH);
+
+	  jpMyWorkflows = new JPanel();
+	  jpMyWorkflows.setLayout(new BorderLayout());
+	  jpMyWorkflows.setBackground(Color.WHITE);
+	  jpMyWorkflows.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
+	  jpMyWorkflows.add(new JLabel("Loading...", new ImageIcon(MyExperimentPerspective.getLocalResourceURL("spinner")), SwingConstants.CENTER));
+
+	  jpMyWorkflowsContainer.add(jpMyWorkflows, BorderLayout.CENTER);
+	  alVisiblePanels.add(jpMyWorkflows);
+	}
+
+	JPanel jpMyFilesContainer = new JPanel();
+	if (Boolean.parseBoolean(myExperimentClient.getSettings().getProperty(MyExperimentClient.INI_MY_STUFF_FILES))) {
+	  // "My Files" panel
+	  jpMyFilesContainer.setBorder(BorderFactory.createEtchedBorder());
+	  jpMyFilesContainer.setLayout(new BorderLayout());
+
+	  ShadedLabel l1 = new ShadedLabel("My Files", ShadedLabel.BLUE);
+	  jpMyFilesContainer.add(l1, BorderLayout.NORTH);
+
+	  jpMyFiles = new JPanel();
+	  jpMyFiles.setLayout(new BorderLayout());
+	  jpMyFiles.setBackground(Color.WHITE);
+	  jpMyFiles.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
+	  jpMyFiles.add(new JLabel("Loading...", new ImageIcon(MyExperimentPerspective.getLocalResourceURL("spinner")), SwingConstants.CENTER));
+
+	  jpMyFilesContainer.add(jpMyFiles, BorderLayout.CENTER);
+	  alVisiblePanels.add(jpMyFiles);
+	}
+
+	JPanel jpMyPacksContainer = new JPanel();
+	if (Boolean.parseBoolean(myExperimentClient.getSettings().getProperty(MyExperimentClient.INI_MY_STUFF_PACKS))) {
+	  // "My Packs" panel
+	  jpMyPacksContainer.setBorder(BorderFactory.createEtchedBorder());
+	  jpMyPacksContainer.setLayout(new BorderLayout());
+
+	  ShadedLabel l2 = new ShadedLabel("My Packs", ShadedLabel.BLUE);
+	  jpMyPacksContainer.add(l2, BorderLayout.NORTH);
+
+	  jpMyPacks = new JPanel();
+	  jpMyPacks.setLayout(new BorderLayout());
+	  jpMyPacks.setBackground(Color.WHITE);
+	  jpMyPacks.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
+	  jpMyPacks.add(new JLabel("Loading...", new ImageIcon(MyExperimentPerspective.getLocalResourceURL("spinner")), SwingConstants.CENTER));
+
+	  jpMyPacksContainer.add(jpMyPacks, BorderLayout.CENTER);
+	  alVisiblePanels.add(jpMyPacks);
+	}
+
+	// ..putting everything together    
+	JPanel jpEverything = new JPanel();
+	jpEverything.setLayout(new GridBagLayout());
+
+	GridBagConstraints gbConstraints = new GridBagConstraints();
+	gbConstraints.anchor = GridBagConstraints.NORTHWEST;
+	gbConstraints.fill = GridBagConstraints.BOTH;
+	gbConstraints.gridx = 0;
+	gbConstraints.weightx = 1;
+	gbConstraints.weighty = 1;
+	int index = 0;
+
+	gbConstraints.gridy = index++;
+	jpEverything.add(jpMyWorkflowsContainer, gbConstraints);
+
+	gbConstraints.gridy = index++;
+	jpEverything.add(jpMyFilesContainer, gbConstraints);
+
+	gbConstraints.gridy = index++;
+	jpEverything.add(jpMyPacksContainer, gbConstraints);
+
+	this.setLayout(new BorderLayout());
+	this.add(jpEverything, BorderLayout.NORTH);
+  }
+
+  private void initialiseData() {
+	// Make call to myExperiment API in a different thread
+	// (then use SwingUtilities.invokeLater to update the UI when ready).
+	new Thread("Loading data about contributions of current user.") {
+	  @SuppressWarnings("unchecked")
+	  public void run() {
+		logger.debug("Loading contributions data for current user");
+
+		try {
+		  final ArrayList<Workflow> alWorkflowInstances = new ArrayList<Workflow>();
+		  if (alVisiblePanels.contains(jpMyWorkflows)) {
+			boolean anyMore = true;
+			for (int page = 1; anyMore; page++) {
+				// fetch all user workflows
+				Document doc = myExperimentClient.getUserContributions(myExperimentClient.getCurrentUser(), Resource.WORKFLOW, Resource.REQUEST_SHORT_LISTING, page);
+				if (doc != null) {
+					List<Element> foundElements = doc.getRootElement().getChildren();
+					anyMore = !foundElements.isEmpty();
+					for (Element e : foundElements) {
+						Workflow wfCurrent = Workflow.buildFromXML(e, logger);
+						alWorkflowInstances.add(wfCurrent);
+					}
+				}
+				}
+		  }
+
+		  final ArrayList<File> alFileInstances = new ArrayList<File>();
+		  if (alVisiblePanels.contains(jpMyFiles)) {
+				boolean anyMore = true;
+				for (int page = 1; anyMore; page++) {
+			// fetch all user files
+			Document doc = myExperimentClient.getUserContributions(myExperimentClient.getCurrentUser(), Resource.FILE, Resource.REQUEST_SHORT_LISTING, page);
+			if (doc != null) {
+			  List<Element> foundElements = doc.getRootElement().getChildren();
+				anyMore = !foundElements.isEmpty();
+			  for (Element e : foundElements) {
+				File fCurrent = File.buildFromXML(e, logger);
+				alFileInstances.add(fCurrent);
+			  }
+			}
+				}
+		  }
+
+		  final ArrayList<Pack> alPackInstances = new ArrayList<Pack>();
+		  if (alVisiblePanels.contains(jpMyPacks)) {
+				boolean anyMore = true;
+				for (int page = 1; anyMore; page++) {
+			// fetch all user packs
+			Document doc = myExperimentClient.getUserContributions(myExperimentClient.getCurrentUser(), Resource.PACK, Resource.REQUEST_SHORT_LISTING, page);
+			if (doc != null) {
+			  List<Element> foundElements = doc.getRootElement().getChildren();
+				anyMore = !foundElements.isEmpty();
+			  for (Element e : foundElements) {
+				Pack pCurrent = Pack.buildFromXML(e, myExperimentClient, logger);
+				alPackInstances.add(pCurrent);
+			  }
+			}
+				}
+		  }
+
+		  SwingUtilities.invokeLater(new Runnable() {
+			public void run() {
+			  // now create views for all user contributions
+			  if (alVisiblePanels.contains(jpMyWorkflows)) {
+				// .. workflows ..
+				jpMyWorkflowsContent = new ResourceListPanel(pluginMainComponent, myExperimentClient, logger);
+				jpMyWorkflowsContent.setFullSizeItemsList(false);
+				jpMyWorkflowsContent.setListItems(new ArrayList<Resource>(alWorkflowInstances));
+
+				spMyWorkflowsContent = new JScrollPane(jpMyWorkflowsContent);
+				spMyWorkflowsContent.getVerticalScrollBar().setUnitIncrement(ResourcePreviewBrowser.PREFERRED_SCROLL);
+
+				jpMyWorkflows.removeAll();
+				jpMyWorkflows.setBackground(null); // return background to default colour
+				jpMyWorkflows.setBorder(BorderFactory.createEmptyBorder()); // remove border that was added prior to loading
+				jpMyWorkflows.add(spMyWorkflowsContent);
+
+				alVisiblePanelsWithHelperElements.add(new JComponent[] { jpMyWorkflows, spMyWorkflowsContent, jpMyWorkflowsContent });
+			  }
+
+			  if (alVisiblePanels.contains(jpMyFiles)) {
+				// .. files ..
+				jpMyFilesContent = new ResourceListPanel(pluginMainComponent, myExperimentClient, logger);
+				jpMyFilesContent.setFullSizeItemsList(false);
+				jpMyFilesContent.setListItems(new ArrayList<Resource>(alFileInstances));
+
+				spMyFilesContent = new JScrollPane(jpMyFilesContent);
+				spMyFilesContent.getVerticalScrollBar().setUnitIncrement(ResourcePreviewBrowser.PREFERRED_SCROLL);
+
+				jpMyFiles.removeAll();
+				jpMyFiles.setBackground(null); // return background to default colour
+				jpMyFiles.setBorder(BorderFactory.createEmptyBorder()); // remove border that was added prior to loading
+				jpMyFiles.add(spMyFilesContent);
+
+				alVisiblePanelsWithHelperElements.add(new JComponent[] { jpMyFiles, spMyFilesContent, jpMyFilesContent });
+			  }
+
+			  if (alVisiblePanels.contains(jpMyPacks)) {
+				// .. packs ..
+				jpMyPacksContent = new ResourceListPanel(pluginMainComponent, myExperimentClient, logger);
+				jpMyPacksContent.setFullSizeItemsList(false);
+				jpMyPacksContent.setListItems(new ArrayList<Resource>(alPackInstances));
+
+				spMyPacksContent = new JScrollPane(jpMyPacksContent);
+				spMyPacksContent.getVerticalScrollBar().setUnitIncrement(ResourcePreviewBrowser.PREFERRED_SCROLL);
+
+				jpMyPacks.removeAll();
+				jpMyPacks.setBackground(null); // return background to default colour
+				jpMyPacks.setBorder(BorderFactory.createEmptyBorder()); // remove border that was added prior to loading
+				jpMyPacks.add(spMyPacksContent);
+
+				alVisiblePanelsWithHelperElements.add(new JComponent[] { jpMyPacks, spMyPacksContent, jpMyPacksContent });
+			  }
+
+			  // now work out correct sizes for each section - the goal is to maximize the usage of the space on the page
+
+			  int iFullAvailableHeight = getSize().height;
+			  ArrayList<Integer> alIndexesToScale = new ArrayList<Integer>();
+			  for (int i = 0; i < alVisiblePanelsWithHelperElements.size(); i++) {
+				JScrollPane spContent = (JScrollPane) alVisiblePanelsWithHelperElements.get(i)[1];
+				JPanel jpContent = (JPanel) alVisiblePanelsWithHelperElements.get(i)[2];
+
+				if ((jpContent.getPreferredSize().height + TOTAL_SECTION_VSPACING) < (iFullAvailableHeight / alVisiblePanels.size())) {
+				  Dimension d = jpContent.getPreferredSize();
+				  d.height += SCROLL_PANE_PADDING;
+				  spContent.setPreferredSize(d);
+
+				  iFullAvailableHeight -= (jpContent.getPreferredSize().height)
+					  + TOTAL_SECTION_VSPACING;
+				} else
+				  alIndexesToScale.add(i);
+			  }
+
+			  if (alIndexesToScale.size() > 0) {
+				Dimension d = new Dimension();
+
+				for (Integer i : alIndexesToScale) {
+				  d.height = (iFullAvailableHeight / alIndexesToScale.size())
+					  - TOTAL_SECTION_VSPACING;
+				  if (d.height > ((JPanel) alVisiblePanelsWithHelperElements.get(i)[2]).getPreferredSize().height
+					  + SCROLL_PANE_PADDING)
+					d.height = ((JPanel) alVisiblePanelsWithHelperElements.get(i)[2]).getPreferredSize().height
+						+ SCROLL_PANE_PADDING;
+
+				  JScrollPane spCurrent = (JScrollPane) alVisiblePanelsWithHelperElements.get(i)[1];
+				  spCurrent.setPreferredSize(d);
+				}
+			  }
+
+			  // report that this component has been loaded
+			  pluginMainComponent.getMyStuffTab().cdlComponentLoadingDone.countDown();
+
+			  validate();
+			  repaint();
+			}
+		  });
+		} catch (Exception ex) {
+		  logger.error("Failed to populate some panel in My Stuff tab (User's files, workflows or packs)", ex);
+		}
+	  }
+	}.start();
+  }
+
+  public void actionPerformed(ActionEvent arg0) {
+	javax.swing.JOptionPane.showMessageDialog(null, "button clicked");
+  }
+
+}