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:17 UTC
[03/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/SearchTabContentPanel.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/SearchTabContentPanel.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/SearchTabContentPanel.java
new file mode 100644
index 0000000..b583491
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/SearchTabContentPanel.java
@@ -0,0 +1,450 @@
+/*******************************************************************************
+ * 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.text.ParseException;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Vector;
+
+import javax.swing.BorderFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.SwingUtilities;
+
+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.SearchEngine;
+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
+ */
+public class SearchTabContentPanel extends JPanel implements ActionListener {
+ // CONSTANTS
+ private final static int SEARCH_HISTORY_LENGTH = 50;
+ private final static int SEARCH_FAVOURITES_LENGTH = 30;
+ protected final static String SEARCH_FROM_FAVOURITES = "searchFromFavourites";
+ protected final static String SEARCH_FROM_HISTORY = "searchFromHistory";
+ protected final static String ADD_FAVOURITE_SEARCH_INSTANCE = "addFavouriteSearchInstance";
+ protected final static String REMOVE_FAVOURITE_SEARCH_INSTANCE = "removeFavouriteSearchInstance";
+
+ private final MainComponent pluginMainComponent;
+ private final MyExperimentClient myExperimentClient;
+ private final Logger logger;
+
+ // COMPONENTS
+ private JSplitPane spMainSplitPane;
+ private SearchOptionsPanel jpSearchOptions;
+ private JPanel jpFavouriteSearches;
+ private JPanel jpSearchHistory;
+ private SearchResultsPanel jpSearchResults;
+ private final ImageIcon iconFavourite = new ImageIcon(MyExperimentPerspective.getLocalResourceURL("favourite_icon"));
+ private final ImageIcon iconRemove = new ImageIcon(MyExperimentPerspective.getLocalResourceURL("destroy_icon"));
+
+ // Data storage
+ private QuerySearchInstance siPreviousSearch;
+ private LinkedList<QuerySearchInstance> llFavouriteSearches;
+ private LinkedList<QuerySearchInstance> llSearchHistory;
+
+ // Search components
+ private final SearchEngine searchEngine; // The search engine for executing keyword query searches
+ private final Vector<Long> vCurrentSearchThreadID; // This will keep ID of the current search thread (there will only be one such thread)
+
+ public SearchTabContentPanel(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 the favourite searches
+ String strFavouriteSearches = (String) myExperimentClient.getSettings().get(MyExperimentClient.INI_FAVOURITE_SEARCHES);
+ if (strFavouriteSearches != null) {
+ Object oFavouriteSearches = Base64.decodeToObject(strFavouriteSearches);
+ this.llFavouriteSearches = (LinkedList<QuerySearchInstance>) oFavouriteSearches;
+ } else {
+ this.llFavouriteSearches = new LinkedList<QuerySearchInstance>();
+ }
+
+ // initialise the search history
+ String strSearchHistory = (String) myExperimentClient.getSettings().get(MyExperimentClient.INI_SEARCH_HISTORY);
+ if (strSearchHistory != null) {
+ Object oSearchHistory = Base64.decodeToObject(strSearchHistory);
+ this.llSearchHistory = (LinkedList<QuerySearchInstance>) oSearchHistory;
+ } else {
+ this.llSearchHistory = new LinkedList<QuerySearchInstance>();
+ }
+
+ this.initialiseUI();
+ this.updateFavouriteSearches();
+ this.updateSearchHistory();
+
+ // initialise the search engine
+ vCurrentSearchThreadID = new Vector<Long>(1);
+ vCurrentSearchThreadID.add(null); // this is just a placeholder, so that it's possible to update this value instead of adding new ones later
+ this.searchEngine = new SearchEngine(vCurrentSearchThreadID, false, jpSearchResults, pluginMainComponent, myExperimentClient, logger);
+
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ // THIS MIGHT NOT BE NEEDED AS THE SEARCH OPTIONS BOX NOW
+ // SETS THE MINIMUM SIZE OF THE SIDEBAR PROPERLY
+ spMainSplitPane.setDividerLocation(390);
+ spMainSplitPane.setOneTouchExpandable(true);
+ spMainSplitPane.setDoubleBuffered(true);
+ }
+ });
+ }
+
+ private void initialiseUI() {
+ // create search options panel
+ jpSearchOptions = new SearchOptionsPanel(this, this.pluginMainComponent, this.myExperimentClient, this.logger);
+ jpSearchOptions.setMaximumSize(new Dimension(1024, 0)); // HACK: this is to make sure that search options box won't be stretched
+
+ // create favourite searches panel
+ jpFavouriteSearches = new JPanel();
+ jpFavouriteSearches.setMaximumSize(new Dimension(1024, 0)); // HACK: this is to make sure that favourite searches box won't be stretched
+ jpFavouriteSearches.setLayout(new GridBagLayout());
+ jpFavouriteSearches.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), " Favourite Searches "), BorderFactory.createEmptyBorder(0, 5, 5, 5)));
+
+ // create search history panel
+ jpSearchHistory = new JPanel();
+ jpSearchHistory.setMaximumSize(new Dimension(1024, 0)); // HACK: this is to make sure that search history box won't be stretched
+ jpSearchHistory.setLayout(new GridBagLayout());
+ jpSearchHistory.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), " Search History "), BorderFactory.createEmptyBorder(0, 5, 5, 5)));
+
+ // create the search sidebar
+ JPanel jpSearchSidebar = new JPanel();
+ jpSearchSidebar.setLayout(new GridBagLayout());
+
+ GridBagConstraints gbConstraints = new GridBagConstraints();
+ gbConstraints.anchor = GridBagConstraints.NORTHWEST;
+ gbConstraints.fill = GridBagConstraints.BOTH;
+ gbConstraints.weightx = 1;
+ gbConstraints.gridx = 0;
+
+ gbConstraints.gridy = 0;
+ jpSearchSidebar.add(jpSearchOptions, gbConstraints);
+
+ gbConstraints.gridy = 1;
+ jpSearchSidebar.add(jpFavouriteSearches, gbConstraints);
+
+ gbConstraints.gridy = 2;
+ jpSearchSidebar.add(jpSearchHistory, gbConstraints);
+
+ JPanel jpSidebarContainer = new JPanel();
+ jpSidebarContainer.setLayout(new BorderLayout());
+ jpSidebarContainer.add(jpSearchSidebar, BorderLayout.NORTH);
+
+ // wrap sidebar in a scroll pane
+ JScrollPane spSearchSidebar = new JScrollPane(jpSidebarContainer);
+ spSearchSidebar.getVerticalScrollBar().setUnitIncrement(ResourcePreviewBrowser.PREFERRED_SCROLL);
+ spSearchSidebar.setMinimumSize(new Dimension(jpSidebarContainer.getMinimumSize().width + 20, 0));
+
+ // create panel for search results
+ this.jpSearchResults = new SearchResultsPanel(this, pluginMainComponent, myExperimentClient, logger);
+
+ spMainSplitPane = new JSplitPane();
+ spMainSplitPane.setLeftComponent(spSearchSidebar);
+ spMainSplitPane.setRightComponent(jpSearchResults);
+
+ // PUT EVERYTHING TOGETHER
+ this.setLayout(new BorderLayout());
+ this.add(spMainSplitPane);
+ }
+
+ private void addToSearchListQueue(LinkedList<QuerySearchInstance> searchInstanceList, QuerySearchInstance searchInstanceToAdd, int queueSize) {
+ // check if such entry is already in the list
+ int iDuplicateIdx = searchInstanceList.indexOf(searchInstanceToAdd);
+
+ // only do the following if the new search instance list OR current instance is not the same
+ // as the last one in the list
+ if (searchInstanceList.size() == 0
+ || iDuplicateIdx != searchInstanceList.size() - 1) {
+ // if the current item is already in the list, remove it (then re-add at the end of the list)
+ if (iDuplicateIdx >= 0)
+ searchInstanceList.remove(iDuplicateIdx);
+
+ // we want to keep the history size constant, therefore when it reaches a certain
+ // size, oldest element needs to be removed
+ if (searchInstanceList.size() >= queueSize)
+ searchInstanceList.remove();
+
+ // in either case, add the new element to the tail of the search history
+ searchInstanceList.offer(searchInstanceToAdd);
+ }
+ }
+
+ private void addToFavouriteSearches(QuerySearchInstance searchInstance) {
+ this.addToSearchListQueue(this.llFavouriteSearches, searchInstance, SEARCH_FAVOURITES_LENGTH);
+ Collections.sort(this.llFavouriteSearches);
+ }
+
+ // the method to update search history listing
+ protected void updateFavouriteSearches() {
+ this.jpFavouriteSearches.removeAll();
+
+ if (this.llFavouriteSearches.size() == 0) {
+ GridBagConstraints c = new GridBagConstraints();
+ c.weightx = 1.0;
+ c.anchor = GridBagConstraints.WEST;
+ this.jpFavouriteSearches.add(Util.generateNoneTextLabel("No favourite searches"), c);
+ } else {
+ for (int i = this.llFavouriteSearches.size() - 1; i >= 0; i--) {
+ addEntryToSearchListingPanel(this.llFavouriteSearches, i, SEARCH_FROM_FAVOURITES, this.jpFavouriteSearches, this.iconRemove, REMOVE_FAVOURITE_SEARCH_INSTANCE, "<html>Click to remove from your local favourite searches.<br>"
+ + "(This will not affect your myExperiment profile settings.)</html>");
+ }
+ }
+
+ this.jpFavouriteSearches.repaint();
+ this.jpFavouriteSearches.revalidate();
+ }
+
+ private void addToSearchHistory(QuerySearchInstance searchInstance) {
+ this.addToSearchListQueue(this.llSearchHistory, searchInstance, SEARCH_HISTORY_LENGTH);
+ }
+
+ // the method to update search history listing
+ protected void updateSearchHistory() {
+ this.jpSearchHistory.removeAll();
+
+ if (this.llSearchHistory.size() == 0) {
+ GridBagConstraints c = new GridBagConstraints();
+ c.weightx = 1.0;
+ c.anchor = GridBagConstraints.WEST;
+ this.jpSearchHistory.add(Util.generateNoneTextLabel(SearchResultsPanel.NO_SEARCHES_STATUS), c);
+ } else {
+ for (int i = this.llSearchHistory.size() - 1; i >= 0; i--) {
+ addEntryToSearchListingPanel(this.llSearchHistory, i, SEARCH_FROM_HISTORY, this.jpSearchHistory, this.iconFavourite, ADD_FAVOURITE_SEARCH_INSTANCE, "<html>Click to add to your local favourite"
+ + " searches - these will be available every time you use Taverna.<br>(This will not affect your"
+ + " myExperiment profile settings.)</html>");
+ }
+ }
+
+ this.jpSearchHistory.repaint();
+ this.jpSearchHistory.revalidate();
+
+ // also update search history in History tab
+ if (this.pluginMainComponent.getHistoryBrowser() != null) {
+ this.pluginMainComponent.getHistoryBrowser().refreshSearchHistory();
+ }
+ }
+
+ private void addEntryToSearchListingPanel(List<QuerySearchInstance> searchInstanceList, int iIndex, String searchAction, JPanel panelToPopulate, ImageIcon entryIcon, String iconAction, String iconActionTooltip) {
+ // labels with search query and search settings
+ JClickableLabel jclCurrentEntryLabel = new JClickableLabel(searchInstanceList.get(iIndex).getSearchQuery(), searchAction
+ + ":" + iIndex, this, WorkbenchIcons.findIcon, SwingUtilities.LEFT, searchInstanceList.get(iIndex).toString());
+ JLabel jlCurrentEntrySettings = new JLabel(searchInstanceList.get(iIndex).detailsAsString());
+ jlCurrentEntrySettings.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0));
+
+ // grouping search details and search settings together
+ JPanel jpCurentEntryDetails = new JPanel();
+ jpCurentEntryDetails.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.anchor = GridBagConstraints.WEST;
+ jpCurentEntryDetails.add(jclCurrentEntryLabel, c);
+ c.weightx = 1.0;
+ jpCurentEntryDetails.add(jlCurrentEntrySettings, c);
+
+ // creating a "button" to add current item to favourites
+ JClickableLabel jclFavourite = new JClickableLabel("", iconAction + ":"
+ + iIndex, this, entryIcon, SwingUtilities.LEFT, iconActionTooltip);
+ jclFavourite.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0));
+
+ // putting all pieces of current item together
+ JPanel jpCurrentEntry = new JPanel();
+ jpCurrentEntry.setLayout(new GridBagLayout());
+
+ c.anchor = GridBagConstraints.WEST;
+ c.weightx = 1.0;
+ jpCurrentEntry.add(jpCurentEntryDetails, c);
+
+ c.anchor = GridBagConstraints.WEST;
+ c.weightx = 0;
+ jpCurrentEntry.add(jclFavourite, c);
+
+ // adding current item to the history list
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1.0;
+ c.gridx = 0;
+ c.gridy = GridBagConstraints.RELATIVE;
+ panelToPopulate.add(jpCurrentEntry, c);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource().equals(this.jpSearchOptions.bSearch)) {
+ // "Search" button was clicked
+
+ // if no search query is specified, display error message
+ if (jpSearchOptions.getSearchQuery().length() == 0) {
+ javax.swing.JOptionPane.showMessageDialog(null, "Search query is empty. Please specify your search query and try again.", "Error", JOptionPane.WARNING_MESSAGE);
+ jpSearchOptions.focusSearchQueryField();
+ } else {
+ // will ensure that if the value in the search result limit editor
+ // is invalid, it is processed properly
+ try {
+ this.jpSearchOptions.jsResultLimit.commitEdit();
+ } catch (ParseException ex) {
+ JOptionPane.showMessageDialog(null, "Invalid search result limit value. This should be an\n"
+ + "integer in the range of "
+ + SearchOptionsPanel.SEARCH_RESULT_LIMIT_MIN
+ + ".."
+ + SearchOptionsPanel.SEARCH_RESULT_LIMIT_MAX, "MyExperiment Plugin - Error", JOptionPane.WARNING_MESSAGE);
+ this.jpSearchOptions.tfResultLimitTextField.selectAll();
+ this.jpSearchOptions.tfResultLimitTextField.requestFocusInWindow();
+ return;
+ }
+
+ // all fine, settings present - store the settings..
+ siPreviousSearch = new SearchEngine.QuerySearchInstance(jpSearchOptions.getSearchQuery(), jpSearchOptions.getResultCountLimit(), jpSearchOptions.getSearchWorkflows(), jpSearchOptions.getSearchFiles(), jpSearchOptions.getSearchPacks(), jpSearchOptions.getSearchUsers(), jpSearchOptions.getSearchGroups());
+
+ // .. and execute the query
+ this.jpSearchOptions.focusSearchQueryField();
+ this.runSearch();
+ }
+ } else if (e.getSource() instanceof JClickableLabel) {
+ if (e.getActionCommand().startsWith(SEARCH_FROM_HISTORY)
+ || e.getActionCommand().startsWith(SEARCH_FROM_FAVOURITES)) {
+ // the part of the action command that is following the prefix is the ID in the search history / favourites storage;
+ // this search instance is removed from history and will be re-added at the top of it when search is launched
+ int iEntryID = Integer.parseInt(e.getActionCommand().substring(e.getActionCommand().indexOf(":") + 1));
+ final QuerySearchInstance si = (e.getActionCommand().startsWith(SEARCH_FROM_HISTORY) ? this.llSearchHistory.remove(iEntryID) : this.llFavouriteSearches.get(iEntryID)); // in case of favourites, no need to remove the entry
+
+ // re-set search options in the settings box and re-run the search
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ jpSearchOptions.setSearchQuery(si.getSearchQuery());
+ jpSearchOptions.setSearchAllResourceTypes(false); // reset the 'all resource types'
+ jpSearchOptions.setSearchWorkflows(si.getSearchWorkflows());
+ jpSearchOptions.setSearchFiles(si.getSearchFiles());
+ jpSearchOptions.setSearchPacks(si.getSearchPacks());
+ jpSearchOptions.setSearchUsers(si.getSearchUsers());
+ jpSearchOptions.setSearchGroups(si.getSearchGroups());
+ jpSearchOptions.setResultCountLimit(si.getResultCountLimit());
+
+ // set this as the 'latest' search
+ siPreviousSearch = si;
+
+ // run the search (and update the search history)
+ runSearch();
+ }
+ });
+ } else if (e.getActionCommand().startsWith(ADD_FAVOURITE_SEARCH_INSTANCE)) {
+ // get the ID of the entry in the history listing first; then fetch the instance itself
+ int iHistID = Integer.parseInt(e.getActionCommand().substring(e.getActionCommand().indexOf(":") + 1));
+ final QuerySearchInstance si = this.llSearchHistory.get(iHistID);
+
+ // add item to favourites and re-draw the panel
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ addToFavouriteSearches(si);
+ updateFavouriteSearches();
+ }
+ });
+ } else if (e.getActionCommand().startsWith(REMOVE_FAVOURITE_SEARCH_INSTANCE)) {
+ // get the ID of the entry in the favourite searches listing first; then remove the instance with that ID from the list
+ int iFavouriteID = Integer.parseInt(e.getActionCommand().substring(e.getActionCommand().indexOf(":") + 1));
+ this.llFavouriteSearches.remove(iFavouriteID);
+
+ // item removed from favourites - re-draw the panel now
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ updateFavouriteSearches();
+ }
+ });
+ }
+ } else if (e.getSource().equals(this.jpSearchResults.bRefresh)) {
+ // "Refresh" button clicked; disable clearing results and re-run previous search
+ this.jpSearchResults.bClear.setEnabled(false);
+ this.rerunLastSearch();
+ } else if (e.getSource().equals(this.jpSearchResults.bClear)) {
+ // "Clear" button clicked - clear last search and disable re-running it
+ siPreviousSearch = null;
+ vCurrentSearchThreadID.set(0, null);
+ this.jpSearchResults.clear();
+ this.jpSearchResults.setStatus(SearchResultsPanel.NO_SEARCHES_STATUS);
+ this.jpSearchResults.bClear.setEnabled(false);
+ this.jpSearchResults.bRefresh.setEnabled(false);
+ }
+ }
+
+ // search history will get updated by default
+ private void runSearch() {
+ runSearch(true);
+ }
+
+ // makes preparations and runs the current search
+ // (has an option not to update the search history)
+ private void runSearch(boolean bUpdateHistory) {
+ if (bUpdateHistory) {
+ // add current search to search history ..
+ this.addToSearchHistory(siPreviousSearch);
+
+ // .. update the search history box ..
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ updateSearchHistory();
+ }
+ });
+ }
+
+ // ..and run the query
+ this.searchEngine.searchAndPopulateResults(siPreviousSearch);
+ }
+
+ // re-executes the search for the most recent query
+ // (if searches have already been done before or were not cleared)
+ public void rerunLastSearch() {
+ if (this.siPreviousSearch != null) {
+ runSearch();
+ }
+ }
+
+ public SearchResultsPanel getSearchResultPanel() {
+ return (this.jpSearchResults);
+ }
+
+ public LinkedList<QuerySearchInstance> getSearchFavouritesList() {
+ return (this.llFavouriteSearches);
+ }
+
+ public LinkedList<QuerySearchInstance> getSearchHistory() {
+ return (this.llSearchHistory);
+ }
+
+}
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/StyledHTMLEditorKit.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/StyledHTMLEditorKit.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/StyledHTMLEditorKit.java
new file mode 100644
index 0000000..2a2302a
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/StyledHTMLEditorKit.java
@@ -0,0 +1,19 @@
+package net.sf.taverna.t2.ui.perspectives.myexperiment;
+
+import javax.swing.text.html.HTMLEditorKit;
+import javax.swing.text.html.StyleSheet;
+
+public class StyledHTMLEditorKit extends HTMLEditorKit {
+
+ private final StyleSheet styleSheet;
+
+ public StyledHTMLEditorKit(StyleSheet styleSheet) {
+ this.styleSheet = styleSheet;
+ }
+
+ @Override
+ public StyleSheet getStyleSheet() {
+ return styleSheet;
+ }
+
+}
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/TagBrowserTabContentPanel.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/TagBrowserTabContentPanel.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/TagBrowserTabContentPanel.java
new file mode 100644
index 0000000..eca9ab0
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/TagBrowserTabContentPanel.java
@@ -0,0 +1,226 @@
+// Copyright (C) 2008 The University of Manchester, University of Southampton
+// and Cardiff University
+package net.sf.taverna.t2.ui.perspectives.myexperiment;
+
+import java.awt.BorderLayout;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.Vector;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.JSplitPane;
+import javax.swing.SwingUtilities;
+
+import org.apache.log4j.Logger;
+
+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.SearchEngine;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Tag;
+
+/*
+ * @author Jiten Bhagat
+ */
+public class TagBrowserTabContentPanel extends JPanel implements ActionListener {
+ // CONSTANTS
+ private static final double TAG_CLOUD_BALANCE = 0.35;
+ private static final double TAG_SIDEBAR_BALANCE = 0.4;
+ private static final int TAG_SEARCH_HISTORY_LENGTH = 50;
+
+ private MainComponent pluginMainComponent;
+ private MyExperimentClient myExperimentClient;
+ private Logger logger;
+
+ // COMPONENTS
+ private JSplitPane spMainSplitPane;
+ private JSplitPane spTagCloudSplitPane;
+ private TagCloudPanel jpMyTags;
+ private TagCloudPanel jpAllTags;
+ private SearchResultsPanel jpTagSearchResults;
+ private JButton bLoginToSeeMyTags;
+ private JPanel jpLoginToSeeMyTags;
+
+ // STORAGE
+ // last tag for which the search has been made
+ private String strCurrentTagCommand;
+ private ArrayList<Tag> lTagSearchHistory;
+
+ // Search components
+ private SearchEngine searchEngine; // The search engine for executing keyword
+ // query searches
+ private Vector<Long> vCurrentSearchThreadID; // This will keep ID of the
+
+ // current search thread (there
+ // will only be one such thread)
+
+ @SuppressWarnings("unchecked")
+ public TagBrowserTabContentPanel(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;
+
+ // no tag searches have been done yet
+ this.strCurrentTagCommand = null;
+
+ // initialise the tag search history
+ String strTagSearchHistory = (String) myExperimentClient.getSettings().get(MyExperimentClient.INI_TAG_SEARCH_HISTORY);
+ if (strTagSearchHistory != null) {
+ Object oTagSearchHistory = Base64.decodeToObject(strTagSearchHistory);
+ this.lTagSearchHistory = (ArrayList<Tag>) oTagSearchHistory;
+ } else {
+ this.lTagSearchHistory = new ArrayList<Tag>();
+ }
+
+ this.initialiseUI();
+
+ // initialise the search engine
+ vCurrentSearchThreadID = new Vector<Long>(1);
+ vCurrentSearchThreadID.add(null); // this is just a placeholder, so that
+ // it's possible to update this value
+ // instead of adding new ones later
+ this.searchEngine = new SearchEngine(vCurrentSearchThreadID, true, jpTagSearchResults, pluginMainComponent, myExperimentClient, logger);
+
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ spTagCloudSplitPane.setDividerLocation(TAG_CLOUD_BALANCE);
+ spMainSplitPane.setDividerLocation(TAG_SIDEBAR_BALANCE);
+ spMainSplitPane.setOneTouchExpandable(true);
+ spMainSplitPane.setDoubleBuffered(true);
+ }
+ });
+ }
+
+ private void initialiseUI() {
+ // This panel will be used when the user is not logged in - i.e. when can't
+ // show "My Tags";
+ // log-in button will be shown instead
+ this.bLoginToSeeMyTags = new JButton("Login to see your tags", new ImageIcon(MyExperimentPerspective.getLocalResourceURL("login_icon")));
+ this.bLoginToSeeMyTags.addActionListener(this);
+
+ this.jpLoginToSeeMyTags = new JPanel();
+ this.jpLoginToSeeMyTags.setLayout(new GridBagLayout());
+ this.jpLoginToSeeMyTags.add(this.bLoginToSeeMyTags);
+
+ // Create the tag clouds
+ this.jpMyTags = new TagCloudPanel("My Tags", TagCloudPanel.TAGCLOUD_TYPE_USER, this, pluginMainComponent, myExperimentClient, logger);
+ this.jpAllTags = new TagCloudPanel("All Tags", TagCloudPanel.TAGCLOUD_TYPE_GENERAL, this, pluginMainComponent, myExperimentClient, logger);
+
+ // add the two tag clouds to the left-hand side sidebar
+ this.spTagCloudSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+ this.spTagCloudSplitPane.setTopComponent(this.myExperimentClient.isLoggedIn() ? jpMyTags : jpLoginToSeeMyTags);
+ this.spTagCloudSplitPane.setBottomComponent(jpAllTags);
+
+ // create panel for tag search results
+ this.jpTagSearchResults = new SearchResultsPanel(this, pluginMainComponent, myExperimentClient, logger);
+
+ this.spMainSplitPane = new JSplitPane();
+ this.spMainSplitPane.setLeftComponent(spTagCloudSplitPane);
+ this.spMainSplitPane.setRightComponent(this.jpTagSearchResults);
+
+ this.setLayout(new BorderLayout());
+ this.add(this.spMainSplitPane, BorderLayout.CENTER);
+ }
+
+ // this helper is called when the user logs in / out to swap the
+ // view accordingly; 'refresh' on "My Tags" panel should be called
+ // immediately after changing the view
+ public void setMyTagsShown(boolean bShow) {
+ if (bShow) {
+ this.spTagCloudSplitPane.setTopComponent(this.jpMyTags);
+ } else {
+ this.spTagCloudSplitPane.setTopComponent(this.jpLoginToSeeMyTags);
+ }
+
+ // in either case apply element balance again
+ this.spTagCloudSplitPane.setDividerLocation(TAG_CLOUD_BALANCE);
+ }
+
+ public void refresh() {
+ if (this.myExperimentClient.isLoggedIn()) {
+ // "My Tags" are only accessible when the user has logged in
+ this.jpMyTags.refresh();
+ }
+ this.jpAllTags.refresh();
+ }
+
+ // re-executes the search for the most recent tag
+ // (if tag searches have already been done before)
+ public void rerunLastTagSearch() {
+ if (this.strCurrentTagCommand != null) {
+ this.actionPerformed(new ActionEvent(this.jpAllTags, 0, this.strCurrentTagCommand));
+ }
+ }
+
+ public TagCloudPanel getMyTagPanel() {
+ return (this.jpMyTags);
+ }
+
+ public TagCloudPanel getAllTagPanel() {
+ return (this.jpAllTags);
+ }
+
+ public SearchResultsPanel getTagSearchResultPanel() {
+ return (this.jpTagSearchResults);
+ }
+
+ public ArrayList<Tag> getTagSearchHistory() {
+ return (this.lTagSearchHistory);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource().equals(this.jpTagSearchResults.bRefresh)) {
+ // disable clearing results and re-run last tag search
+ this.getTagSearchResultPanel().bClear.setEnabled(false);
+ this.rerunLastTagSearch();
+ } else if (e.getSource().equals(this.jpTagSearchResults.bClear)) {
+ // clear last search and disable re-running it
+ this.strCurrentTagCommand = null;
+ vCurrentSearchThreadID.set(0, null);
+ this.getTagSearchResultPanel().clear();
+ this.getTagSearchResultPanel().setStatus(SearchResultsPanel.NO_SEARCHES_STATUS);
+ this.getTagSearchResultPanel().bClear.setEnabled(false);
+ this.getTagSearchResultPanel().bRefresh.setEnabled(false);
+ } else if (e.getSource() instanceof JClickableLabel
+ || e.getSource() instanceof TagCloudPanel) {
+ // one of the tags was clicked as a hyperlink in any TagCloudPanel
+ // (in Resource Preview Browser or in Tag Browser tab) or as a
+ // JClickableLabel
+ if (e.getActionCommand().startsWith("tag:")) {
+ // record the tag search command and run the search
+ this.strCurrentTagCommand = e.getActionCommand();
+ this.searchEngine.searchAndPopulateResults(strCurrentTagCommand);
+
+ // update tag search history making sure that:
+ // - there's only one occurrence of this tag in the history;
+ // - if this tag was in the history before, it is moved to the 'top'
+ // now;
+ // - predefined history size is not exceeded
+ Tag t = Tag.instantiateTagFromActionCommand(strCurrentTagCommand);
+ this.lTagSearchHistory.remove(t);
+ this.lTagSearchHistory.add(t);
+ if (this.lTagSearchHistory.size() > TAG_SEARCH_HISTORY_LENGTH)
+ this.lTagSearchHistory.remove(0);
+
+ // now update the tag search history panel in 'History' tab
+ if (this.pluginMainComponent.getHistoryBrowser() != null) {
+ this.pluginMainComponent.getHistoryBrowser().refreshTagSearchHistory();
+ }
+ }
+ } else if (e.getSource().equals(this.bLoginToSeeMyTags)) {
+ // set the return "link"
+ this.pluginMainComponent.getMyStuffTab().cTabContentComponentToSwitchToAfterLogin = this;
+
+ // switch to login tab
+ this.pluginMainComponent.getMainTabs().setSelectedComponent(this.pluginMainComponent.getMyStuffTab());
+ }
+ }
+
+}
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/TagCloudPanel.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/TagCloudPanel.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/TagCloudPanel.java
new file mode 100644
index 0000000..b03fd8f
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/TagCloudPanel.java
@@ -0,0 +1,342 @@
+/*******************************************************************************
+ * 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.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSlider;
+import javax.swing.JTextPane;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
+
+import org.apache.log4j.Logger;
+
+import net.sf.taverna.t2.lang.ui.ShadedLabel;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.MyExperimentClient;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.Tag;
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.TagCloud;
+import net.sf.taverna.t2.workbench.icons.WorkbenchIcons;
+
+/**
+ * @author Sergejs Aleksejevs, Jiten Bhagat
+ */
+public class TagCloudPanel extends JPanel implements ChangeListener, ItemListener, ActionListener, HyperlinkListener {
+ // CONSTANTS
+ private static final int TAGCLOUD_MAX_FONTSIZE = 36;
+ private static final int TAGCLOUD_MIN_FONTSIZE = 12;
+ private static final int TAGCLOUD_DEFAULT_MAX_SIZE = 350;
+ private static final int TAGCLOUD_DEFAULT_DISPLAY_SIZE = 50;
+
+ public static final int TAGCLOUD_TYPE_GENERAL = 0;
+ public static final int TAGCLOUD_TYPE_USER = 1;
+ public static final int TAGCLOUD_TYPE_RESOURCE_PREVIEW = 2;
+
+ private MainComponent pluginMainComponent;
+ private MyExperimentClient myExperimentClient;
+ private Logger logger;
+
+ // COMPONENTS
+ private String strTitle;
+ private int iType;
+ private ShadedLabel lCloudTitle;
+ private JSlider jsCloudSizeSlider;
+ private JCheckBox cbShowAllTags;
+ private JButton bRefresh;
+ private JTextPane tpTagCloudBody;
+
+ private ActionListener clickHandler;
+ private TagCloud tcData = new TagCloud();
+ private boolean bUserTagCloudSliderValueNeverSet = true;
+
+ public TagCloudPanel(String title, int iTagCloudType, ActionListener clickHandler, MainComponent component, MyExperimentClient client, Logger logger) {
+ super();
+
+ // set parameters and the main variables to ensure access to myExperiment,
+ // logger and the parent component
+ this.strTitle = title;
+ this.iType = iTagCloudType;
+ this.clickHandler = clickHandler;
+ this.pluginMainComponent = component;
+ this.myExperimentClient = client;
+ this.logger = logger;
+
+ initialiseUI();
+ }
+
+ private void initialiseUI() {
+ // set the title of the tag cloud
+ lCloudTitle = new ShadedLabel(this.strTitle, ShadedLabel.BLUE);
+
+ // create the tag cloud controls panel
+ // (all controls will be created anyway, but if that's a resource
+ // preview tag cloud, make sure that these controls are not displayed)
+ JPanel jpCloudControlsPanel = new JPanel();
+ jpCloudControlsPanel.setLayout(new BoxLayout(jpCloudControlsPanel, BoxLayout.LINE_AXIS));
+ this.jsCloudSizeSlider = new JSlider(1, TAGCLOUD_DEFAULT_MAX_SIZE, TAGCLOUD_DEFAULT_DISPLAY_SIZE);
+ this.cbShowAllTags = new JCheckBox("All tags", false);
+ this.bRefresh = new JButton("Refresh", WorkbenchIcons.refreshIcon);
+
+ if (this.iType != TagCloudPanel.TAGCLOUD_TYPE_RESOURCE_PREVIEW) {
+ this.jsCloudSizeSlider.addChangeListener(this);
+ this.jsCloudSizeSlider.setToolTipText("Drag the slider to select how big the tag cloud should be, or check the \"All tags\" box to get the full tag cloud.");
+ jpCloudControlsPanel.add(this.jsCloudSizeSlider);
+
+ this.cbShowAllTags.addItemListener(this);
+ jpCloudControlsPanel.add(this.cbShowAllTags);
+
+ this.bRefresh.addActionListener(this);
+ this.bRefresh.setToolTipText("Click this button to refresh the Tag Cloud");
+ jpCloudControlsPanel.add(this.bRefresh);
+ }
+
+ // tag cloud header panel which which contains controls
+ JPanel jpCloudHeader = new JPanel(new BorderLayout());
+ jpCloudHeader.add(jpCloudControlsPanel, BorderLayout.CENTER);
+ jpCloudHeader.setBorder(BorderFactory.createEtchedBorder());
+
+ // body of the tag cloud with the actual tags
+ this.tpTagCloudBody = new JTextPane();
+ this.tpTagCloudBody.setBorder(BorderFactory.createEmptyBorder());
+ this.tpTagCloudBody.setEditable(false);
+ this.tpTagCloudBody.setContentType("text/html");
+ this.tpTagCloudBody.addHyperlinkListener(this);
+
+ JScrollPane spTagCloudBody = new JScrollPane(this.tpTagCloudBody, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ spTagCloudBody.setBorder(BorderFactory.createEmptyBorder());
+ spTagCloudBody.setOpaque(true);
+
+ // PUT EVERYTHING TOGETHER
+ JPanel jpTagCloudContentWithControls = new JPanel();
+ jpTagCloudContentWithControls.setLayout(new BorderLayout());
+ jpTagCloudContentWithControls.add(spTagCloudBody, BorderLayout.CENTER);
+ if (this.iType != TagCloudPanel.TAGCLOUD_TYPE_RESOURCE_PREVIEW) {
+ jpTagCloudContentWithControls.add(jpCloudHeader, BorderLayout.NORTH);
+ }
+
+ this.setLayout(new BorderLayout());
+ if (this.iType != TagCloudPanel.TAGCLOUD_TYPE_RESOURCE_PREVIEW) {
+ this.add(lCloudTitle, BorderLayout.NORTH);
+ }
+ this.add(jpTagCloudContentWithControls, BorderLayout.CENTER);
+ this.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2), BorderFactory.createEtchedBorder()));
+ }
+
+ public void refresh() {
+ this.lCloudTitle.setText(strTitle
+ + " <span style='color: gray;'>(Loading...)</span>");
+
+ // Make call to myExperiment API in a different thread
+ // (then use SwingUtilities.invokeLater to update the UI when ready).
+ new Thread("Get '" + this.strTitle + "' tag cloud data") {
+ public void run() {
+ logger.debug("Getting '" + strTitle + "' tag cloud data");
+
+ try {
+ int size = -1;
+ if (!cbShowAllTags.isSelected()) {
+ size = jsCloudSizeSlider.getValue();
+ }
+
+ // based on the type of the tag cloud, different data needs to be
+ // fetched
+ switch (iType) {
+ case TagCloudPanel.TAGCLOUD_TYPE_GENERAL:
+ tcData = myExperimentClient.getGeneralTagCloud(size);
+ break;
+
+ case TagCloudPanel.TAGCLOUD_TYPE_USER:
+ tcData = myExperimentClient.getUserTagCloud(myExperimentClient.getCurrentUser(), size);
+ break;
+
+ case TagCloudPanel.TAGCLOUD_TYPE_RESOURCE_PREVIEW:
+ // fetch tag counts for tags that are already pre-set
+ myExperimentClient.convertTagListIntoTagCloudData(tcData.getTags());
+ break;
+
+ default:
+ // unknown type of tag cloud; show no data
+ tcData = new TagCloud();
+ break;
+ }
+
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ repopulate();
+ }
+ });
+ } catch (Exception ex) {
+ logger.error("Failed to get tag cloud data from myExperiment", ex);
+ }
+ }
+ }.start();
+ }
+
+ public void repopulate() {
+ logger.debug("Building '" + this.strTitle + "' tag cloud...");
+
+ try {
+ this.jsCloudSizeSlider.removeChangeListener(this);
+ if (this.iType == TAGCLOUD_TYPE_USER) {
+ jsCloudSizeSlider.setMinimum(1);
+ jsCloudSizeSlider.setMaximum(myExperimentClient.getCurrentUser().getTags().size());
+ if (bUserTagCloudSliderValueNeverSet) {
+ // this is the first load of the cloud, show all user tags
+ jsCloudSizeSlider.setValue(jsCloudSizeSlider.getMaximum());
+ bUserTagCloudSliderValueNeverSet = false;
+ } else {
+ // not the first load, test if the position of the slider is still
+ // within the scope
+ // (put that back to maximum if exceeds)
+ if (jsCloudSizeSlider.getValue() > jsCloudSizeSlider.getMaximum()
+ || this.cbShowAllTags.isSelected())
+ jsCloudSizeSlider.setValue(jsCloudSizeSlider.getMaximum());
+ }
+ } else {
+ // if "All tags" check box is ticked, set the slider max to the max no
+ // of tags
+ // (this will be the total number of tags available from myExperiment);
+ // if "All tags" was never checked before, max position of the slider
+ // will
+ // stay at predefined default value (because the total number of tags is
+ // not known yet)
+ if (this.cbShowAllTags.isSelected()) {
+ int size = this.tcData.getTags().size();
+ this.jsCloudSizeSlider.setMaximum(size);
+ this.jsCloudSizeSlider.setValue(size);
+ }
+ }
+ this.jsCloudSizeSlider.addChangeListener(this);
+
+ // For tag cloud font size calculations
+ int iMaxCount = this.tcData.getMaxTagCount();
+
+ StringBuffer content = new StringBuffer();
+
+ if (this.tcData.getTags().size() > 0) {
+ content.append("<div class='outer'>");
+ content.append("<br>");
+ content.append("<div class='tag_cloud'>");
+
+ for (Tag t : this.tcData.getTags()) {
+ // Normalise count and use it to obtain a font size value.
+ // Also chops off based on min and max.
+ int fontSize = (int) (((double) t.getCount() / ((double) iMaxCount / 3)) * TAGCLOUD_MAX_FONTSIZE);
+ if (fontSize < TAGCLOUD_MIN_FONTSIZE) {
+ fontSize = TAGCLOUD_MIN_FONTSIZE;
+ }
+ if (fontSize > TAGCLOUD_MAX_FONTSIZE) {
+ fontSize = TAGCLOUD_MAX_FONTSIZE;
+ }
+
+ content.append("<a style='font-size: " + fontSize + "pt;' href='tag:"
+ + t.getTagName() + "'>" + t.getTagName() + "</a>");
+ content.append(" ");
+ }
+
+ content.append("<br>");
+ content.append("</div>");
+ content.append("</div>");
+ } else {
+ content.append("<br>");
+ content.append("<span style='color: gray; font-weight: italic;'> No tags to display</span>");
+ }
+
+ HTMLEditorKit kit = new StyledHTMLEditorKit(pluginMainComponent.getStyleSheet());
+ HTMLDocument doc = (HTMLDocument) (kit.createDefaultDocument());
+ doc.insertAfterStart(doc.getRootElements()[0].getElement(0), content.toString());
+
+ this.tpTagCloudBody.setEditorKit(kit);
+ this.tpTagCloudBody.setDocument(doc);
+ } catch (Exception e) {
+ logger.error("Failed to populate tag cloud", e);
+ }
+
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ lCloudTitle.setText(strTitle
+ + " <span style='color: gray;'>(currently showing "
+ + tcData.getTags().size() + ")</span>");
+ revalidate();
+ }
+ });
+ }
+
+ /**
+ * Helper method to get hold of the tag cloud data. Needed to be able to set
+ * tag cloud data when using this for resource preview (when tag fetching is
+ * not required).
+ */
+ public TagCloud getTagCloudData() {
+ return this.tcData;
+ }
+
+ public void stateChanged(ChangeEvent e) {
+ if (e.getSource().equals(this.jsCloudSizeSlider)) {
+ // cloud size slider was dragged to a new place and the drag event
+ // has finished; refresh the tag cloud with the newly selected tag count
+ if (!this.jsCloudSizeSlider.getValueIsAdjusting()) {
+ this.cbShowAllTags.removeItemListener(this);
+ this.cbShowAllTags.setSelected(false);
+ this.cbShowAllTags.addItemListener(this);
+
+ this.refresh();
+ }
+ }
+ }
+
+ public void itemStateChanged(ItemEvent e) {
+ if (e.getItemSelectable().equals(this.cbShowAllTags)) {
+ // "Show all" clicked - need to refresh with all tags being displayed
+ this.refresh();
+ }
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource().equals(this.bRefresh)) {
+ // refresh button clicked on the cloud controls panel -
+ // simply refresh the cloud with the same parameters
+ this.refresh();
+ }
+ }
+
+ public void hyperlinkUpdate(HyperlinkEvent e) {
+ if (e.getSource().equals(this.tpTagCloudBody)
+ && e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
+ // one of the tags was clicked, but click processing is off-loaded to
+ // 'clickHandler'
+ this.clickHandler.actionPerformed(new ActionEvent(this, (this.getClass().getName() + e.getDescription()).hashCode(), e.getDescription()));
+ }
+ }
+}
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/TestJFrameForLocalLaunch.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/TestJFrameForLocalLaunch.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/TestJFrameForLocalLaunch.java
new file mode 100644
index 0000000..15dd3a4
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/TestJFrameForLocalLaunch.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (C) 2009 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their respective
+ * authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.ui.perspectives.myexperiment;
+
+import java.awt.Dimension;
+import javax.swing.JFrame;
+
+public class TestJFrameForLocalLaunch {
+
+ /**
+ * This is a simple test class for launching myExperiment perspective
+ * from outside Taverna. At some point it will be not usable anymore,
+ * when proper integration of myExperiment plugin is made.
+ *
+ * @author Sergejs Aleksejevs
+ */
+ public static void main(String[] args)
+ {
+ JFrame frame = new JFrame("myExperiment Perspective Test");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+ frame.setMinimumSize(new Dimension(1000, 700));
+ frame.setLocation(300, 150);
+ frame.getContentPane().add(new net.sf.taverna.t2.ui.perspectives.myexperiment.MainComponent(null, null));
+
+ frame.pack();
+ frame.setVisible(true);
+ }
+
+}
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/UploadWorkflowDialog.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/UploadWorkflowDialog.java b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/UploadWorkflowDialog.java
new file mode 100644
index 0000000..ed47183
--- /dev/null
+++ b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/UploadWorkflowDialog.java
@@ -0,0 +1,849 @@
+/*******************************************************************************
+ * 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.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JRootPane;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.event.CaretEvent;
+import javax.swing.event.CaretListener;
+
+import net.sf.taverna.t2.ui.perspectives.myexperiment.model.License;
+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.ServerResponse;
+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.file.FileManager;
+import net.sf.taverna.t2.workbench.file.impl.actions.SaveWorkflowAsAction;
+import net.sf.taverna.t2.workbench.helper.HelpEnabledDialog;
+import net.sf.taverna.t2.workbench.icons.WorkbenchIcons;
+import net.sf.taverna.t2.workflowmodel.Dataflow;
+
+import org.apache.log4j.Logger;
+
+/**
+ * @author Emmanuel Tagarira, Sergejs Aleksejevs
+ */
+public class UploadWorkflowDialog extends HelpEnabledDialog implements ActionListener,
+ CaretListener, ComponentListener, KeyListener, FocusListener {
+ // components for accessing application's main elements
+ private final MainComponent pluginMainComponent = MainComponent.MAIN_COMPONENT;
+ private final MyExperimentClient myExperimentClient = MainComponent.MY_EXPERIMENT_CLIENT;
+ private final Logger logger = MainComponent.LOGGER;
+
+ // COMPONENTS
+ private JTextArea taDescription;
+ private JTextField tfTitle;
+ private JButton bUpload;
+ private JButton bCancel;
+ private JLabel lStatusMessage;
+ private JComboBox jcbLicences;
+ private JComboBox jcbSharingPermissions;
+ private String licence;
+ private String sharing;
+
+ // STORAGE
+ private File localWorkflowFile; // the local workflow file to be uploaded
+ private Resource updateResource; // the workflow resource that is to be
+ // updated
+ private File uploadFile; // THE UPLOAD FILE
+
+ private String strDescription = null;
+ private String strTitle = null;
+ private boolean bUploadingSuccessful = false;
+
+ // misc.
+ private int gridYPositionForStatusLabel;
+ private JRadioButton rbSelectLocalFile;
+ private JRadioButton rbSelectOpenWorkflow;
+ private JButton bSelectFile;
+ private JComboBox jcbOpenWorkflows;
+ private final JLabel selectedFileLabel = new JLabel("no wokflow file selected");
+ private boolean uploadWorkflowFromLocalFile;
+ JFileChooser jfsSelectFile = new JFileChooser();
+
+ private boolean userRequestedWorkflowUpload;
+ private final FileManager fileManager;
+
+ public UploadWorkflowDialog(JFrame parent, boolean doUpload, FileManager fileManager) {
+ super(parent, "Upload workflow to myExperiment", true);
+ this.fileManager = fileManager;
+ initVarsAndUI(doUpload, null);
+ }
+
+ public UploadWorkflowDialog(JFrame parent, boolean doUpload, Resource resource,
+ FileManager fileManager) {
+ super(parent, (doUpload ? "Upload new workflow version" : "Update workflow information"),
+ true);
+ this.fileManager = fileManager;
+ initVarsAndUI(doUpload, resource);
+ }
+
+ private void initVarsAndUI(boolean doUpload, Resource resource) {
+ // set the resource for which the comment is being added
+ this.updateResource = resource;
+ this.userRequestedWorkflowUpload = doUpload;
+
+ // set options of the 'add comment' dialog box
+ this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+
+ initialiseUI();
+ this.setMinimumSize(new Dimension(525, 375));
+ }
+
+ private JPanel createSelectSource() {
+ // create radio buttons
+ ButtonGroup radioButtons = new ButtonGroup();
+ rbSelectOpenWorkflow = new JRadioButton("Already Opened Workflow");
+ rbSelectOpenWorkflow.addFocusListener(this);
+ rbSelectLocalFile = new JRadioButton("Select Local File");
+ rbSelectLocalFile.addFocusListener(this);
+ radioButtons.add(rbSelectOpenWorkflow);
+ rbSelectOpenWorkflow.setSelected(true);
+ radioButtons.add(rbSelectLocalFile);
+
+ // create the source panel and add items
+ JPanel source = new JPanel(new GridBagLayout());
+ source.setBorder(BorderFactory.createTitledBorder("Workflow source"));
+
+ GridBagConstraints c = new GridBagConstraints();
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.gridy = 0;
+ c.gridx = 0;
+ c.gridwidth = 1;
+ c.weightx = 1;
+ c.insets = new Insets(3, 0, 3, 0);
+ c.fill = GridBagConstraints.BOTH;
+
+ // add info label
+ // JLabel info = new
+ // JLabel("Upload a workflow you would like to upload:");
+ // source.add(info, c);
+
+ // add open workflow radio button
+ c.gridy++;
+ source.add(rbSelectOpenWorkflow, c);
+ c.gridx = 1;
+ c.gridwidth = 2;
+ createDropdown();
+ source.add(jcbOpenWorkflows, c);
+
+ // add local file radio button
+ c.gridwidth = 1;
+ c.gridy++;
+ c.gridx = 0;
+ source.add(rbSelectLocalFile, c);
+ c.gridx = 1;
+ source.add(selectedFileLabel, c);
+ bSelectFile = new JButton(WorkbenchIcons.openIcon);
+ bSelectFile.addActionListener(this);
+ bSelectFile.setToolTipText("Select the file you would like to upload to myExperiment");
+ c.gridx = 2;
+ source.add(bSelectFile, c);
+
+ return source;
+ }
+
+ private void createDropdown() {
+ List<DataflowSelection> openDataflows = new ArrayList<DataflowSelection>();
+
+ int currentlyOpenedIndex = 0;
+ boolean foundIndex = false;
+
+ for (Dataflow df : fileManager.getOpenDataflows()) {
+ Object source = fileManager.getDataflowSource(df);
+
+ String name = "";
+ boolean getLocalName = source instanceof InputStream;
+ if (source != null)
+ name = (getLocalName ? df.getLocalName() : source.toString());
+
+ if (df.equals(fileManager.getCurrentDataflow())) {
+ name = "<html><body>" + name + " - " + " <i>(current)</i></body></html>";
+ foundIndex = true;
+ }
+
+ openDataflows.add(new DataflowSelection(df, name));
+ if (!foundIndex)
+ currentlyOpenedIndex++;
+ }
+
+ jcbOpenWorkflows = new JComboBox(openDataflows.toArray());
+ jcbOpenWorkflows.setSelectedIndex(currentlyOpenedIndex);
+ }
+
+ private JPanel createMetadataPanel() {
+ Insets fieldInset = new Insets(0, 5, 4, 5);
+ Insets labelInset = new Insets(3, 5, 4, 5);
+
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.weightx = 1;
+ c.gridy = 0;
+ c.anchor = GridBagConstraints.WEST;
+ c.gridwidth = 2;
+ c.fill = GridBagConstraints.HORIZONTAL;
+
+ JPanel metaPanel = new JPanel(new GridBagLayout());
+ metaPanel.setBorder(BorderFactory.createTitledBorder("Workflow information"));
+
+ // title
+ JLabel lTitle = new JLabel("Workflow title:");
+ c.insets = labelInset;
+ c.gridy++;
+ metaPanel.add(lTitle, c);
+
+ this.tfTitle = new JTextField();
+ if (this.updateResource != null)
+ this.tfTitle.setText(this.updateResource.getTitle());
+ c.gridy++;
+ c.insets = fieldInset;
+ metaPanel.add(this.tfTitle, c);
+
+ // description
+ JLabel lDescription = new JLabel("Workflow description:");
+ c.gridy++;
+ c.insets = labelInset;
+ metaPanel.add(lDescription, c);
+
+ this.taDescription = new JTextArea(5, 35);
+ this.taDescription.setLineWrap(true);
+ this.taDescription.setWrapStyleWord(true);
+ if (this.updateResource != null)
+ this.taDescription.setText(this.updateResource.getDescription());
+
+ JScrollPane spDescription = new JScrollPane(this.taDescription);
+ c.gridy++;
+ c.insets = fieldInset;
+ metaPanel.add(spDescription, c);
+
+ // licences
+ String[] licenseText = new String[License.SUPPORTED_TYPES.length];
+ for (int x = 0; x < License.SUPPORTED_TYPES.length; x++)
+ licenseText[x] = License.getInstance(License.SUPPORTED_TYPES[x]).getText();
+
+ jcbLicences = new JComboBox(licenseText);
+ String defaultLicenseText = License.getInstance(License.DEFAULT_LICENSE)
+ .getText();
+ jcbLicences.setSelectedItem(defaultLicenseText);
+
+ if (this.updateResource != null) { // adding a new workflow
+ Workflow wf = (Workflow) this.updateResource;
+ String wfText = wf.getLicense().getText();
+ for (int x = 0; x < licenseText.length; x++)
+ if (wfText.equals(licenseText[x])) {
+ jcbLicences.setSelectedIndex(x);
+ break;
+ }
+ }
+
+ jcbLicences.addActionListener(this);
+ jcbLicences.setEditable(false);
+
+ JLabel lLicense = new JLabel("Please select the licence to apply:");
+ c.gridy++;
+ c.insets = labelInset;
+ metaPanel.add(lLicense, c);
+
+ c.gridy++;
+ c.insets = fieldInset;
+ metaPanel.add(jcbLicences, c);
+
+ // sharing - options: private / view / download
+ String[] permissions = { "This workflow is private.",
+ "Anyone can view, but noone can download.",
+ "Anyone can view, and anyone can download" };
+
+ this.jcbSharingPermissions = new JComboBox(permissions);
+
+ jcbSharingPermissions.addActionListener(this);
+ jcbSharingPermissions.setEditable(false);
+
+ JLabel jSharing = new JLabel("Please select your sharing permissions:");
+ c.gridy++;
+ c.insets = labelInset;
+ metaPanel.add(jSharing, c);
+
+ c.gridy++;
+ c.insets = fieldInset;
+ metaPanel.add(jcbSharingPermissions, c);
+
+ return metaPanel;
+ }
+
+ private void initialiseUI() {
+ // get content pane
+ Container contentPane = this.getContentPane();
+
+ Insets fieldInset = new Insets(3, 5, 3, 5);
+
+ // set up layout
+ contentPane.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 0;
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.gridwidth = 2;
+ c.fill = GridBagConstraints.HORIZONTAL;
+
+ // ADD ALL COMPONENTS
+ // source for workflow to upload
+ if (userRequestedWorkflowUpload) {
+ c.insets = fieldInset;
+ contentPane.add(createSelectSource(), c);
+ c.gridy++;
+ }
+
+ // create metadata panel
+ contentPane.add(createMetadataPanel(), c);
+
+ // buttons
+ this.bUpload = new JButton(userRequestedWorkflowUpload ? "Upload Workflow"
+ : "Update Workflow");
+ this.bUpload.setDefaultCapable(true);
+ this.getRootPane().setDefaultButton(this.bUpload);
+ this.bUpload.addActionListener(this);
+ this.bUpload.addKeyListener(this);
+
+ c.gridy++;
+ c.anchor = GridBagConstraints.EAST;
+ c.gridwidth = 1;
+ c.fill = GridBagConstraints.NONE;
+ c.weightx = 0.5;
+ c.insets = new Insets(10, 5, 10, 5);
+ contentPane.add(bUpload, c);
+
+ this.bCancel = new JButton("Cancel");
+ this.bCancel.setPreferredSize(this.bUpload.getPreferredSize());
+ this.bCancel.addActionListener(this);
+ c.gridx = 1;
+ c.anchor = GridBagConstraints.WEST;
+ c.weightx = 0.5;
+ contentPane.add(bCancel, c);
+
+ this.pack();
+ this.addComponentListener(this);
+
+ gridYPositionForStatusLabel = c.gridy;
+ }
+
+ /**
+ * Opens up a modal dialog where the user can enter the comment text. Window
+ * is simply closed if 'Cancel' button is pressed; on pressing 'Post
+ * Comment' button the window will turn into 'waiting' state, post the
+ * comment and return the resulting XML document (which would contain the
+ * newly added comment) back to the caller.
+ *
+ * @return String value of the non-empty comment text to be sent to
+ * myExperiment or null if action was cancelled.
+ */
+ public boolean launchUploadDialogAndPostIfRequired() {
+ // makes the 'add comment' dialog visible, then waits until it is
+ // closed;
+ // control returns to this method when the dialog window is disposed
+ this.setVisible(true);
+ return (bUploadingSuccessful);
+ }
+
+ private File performSourceCheck() {
+ if (!rbSelectLocalFile.isSelected() && !rbSelectOpenWorkflow.isSelected()) { // it
+ // is
+ // logicall
+ // impossible
+ // to
+ // get
+ // this
+ // message,
+ // have
+ // it
+ // JUST
+ // IN
+ // CASE
+ JOptionPane.showConfirmDialog(this,
+ "You have not selected a source for you workflow.\n"
+ + "Please select a source and try again.", "Select Workflow Source",
+ JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE);
+ return null;
+ }
+
+ if (rbSelectOpenWorkflow.isSelected()) { // user requested to use a flow
+ // currently open in t2
+ Dataflow dataflowToUpload = ((DataflowSelection) jcbOpenWorkflows.getSelectedItem())
+ .getDataflow();
+ SaveWorkflowAsAction saveAction = new SaveWorkflowAsAction(fileManager);
+
+ boolean skipPrompt = false;
+ if (fileManager.isDataflowChanged(dataflowToUpload)) { // if flow
+ // has
+ // changed, prompt
+ // user to save
+ JOptionPane.showConfirmDialog(this, "The workflow you are trying to upload has\n"
+ + "changed since the last time it was saved.\n\n"
+ + "Please save your file to proceed...", "Save Workflow",
+ JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE);
+ saveAction.saveDataflow(this, dataflowToUpload);
+ skipPrompt = true;
+ }
+
+ File dataflowFile = (File) fileManager.getDataflowSource(dataflowToUpload);
+ if (dataflowFile == null && !skipPrompt) {
+ JOptionPane.showConfirmDialog(this, "You cannot upload an empty workflow.\n"
+ + "Please select a different workflow before\n"
+ + "you attempt the upload again.", "Upload Error",
+ JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE);
+ return null;
+ } else
+ return dataflowFile;
+
+ } else { // user wants to use local file
+ if (localWorkflowFile == null) {
+ JOptionPane.showConfirmDialog(this, "You have not selected a file to upload.\n"
+ + "Please select a file and try again.", "Select Workflow Source",
+ JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE);
+ return null;
+ }
+
+ return localWorkflowFile;
+ }
+ }
+
+ private void getMetadata() {
+ // get sharing permission
+ switch (this.jcbSharingPermissions.getSelectedIndex()) {
+ case 0:
+ this.sharing = "private";
+ break;
+ case 1:
+ this.sharing = "view";
+ break;
+ case 2:
+ this.sharing = "download";
+ break;
+ }
+
+ // get licence
+ this.licence = License.SUPPORTED_TYPES[this.jcbLicences.getSelectedIndex()];
+
+ // get title
+ this.strTitle = this.tfTitle.getText();
+ this.strTitle = this.strTitle.trim();
+
+ // get description
+ this.strDescription = this.taDescription.getText();
+ this.strDescription = this.strDescription.trim();
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource().equals(this.bUpload)) { // * *** *** *** * UPLOAD
+ // BUTTON *
+ // *** *** *** *
+ // perform source check returns a file if attaining the source was
+ // successful
+ if (userRequestedWorkflowUpload) {
+ uploadFile = performSourceCheck();
+ if (uploadFile == null)
+ return;
+ }
+
+ // collect and put the metadata values in their respectable vars
+ getMetadata();
+
+ // if the description or the title are empty, prompt the user to
+ // confirm
+ // the upload
+ boolean proceedWithUpload = false;
+ if ((this.strDescription.length() == 0) && (this.strTitle.length() == 0)) {
+ String strInfo = "The workflow 'title' field and the 'description' field\n"
+ + "(or both) are empty. Any metadata found within the\n"
+ + "workflow will be used instead. Do you wish to proceed?";
+ int confirm = JOptionPane.showConfirmDialog(this, strInfo, "Empty fields",
+ JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE);
+ if (confirm == JOptionPane.YES_OPTION)
+ proceedWithUpload = true;
+ } else
+ proceedWithUpload = true;
+
+ if (proceedWithUpload) {
+ // the window will stay visible, but should turn into 'waiting'
+ // state
+ final JRootPane rootPane = this.getRootPane();
+ final Container contentPane = this.getContentPane();
+ contentPane.remove(this.bUpload);
+ contentPane.remove(this.bCancel);
+ if (this.lStatusMessage != null)
+ contentPane.remove(this.lStatusMessage);
+ this.taDescription.setEditable(false);
+
+ final GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = gridYPositionForStatusLabel;
+ c.gridwidth = 2;
+ c.anchor = GridBagConstraints.CENTER;
+ c.fill = GridBagConstraints.NONE;
+ c.insets = new Insets(10, 5, 10, 5);
+ lStatusMessage = new JLabel((updateResource == null ? "Uploading" : "Updating")
+ + " your workflow...", new ImageIcon(
+ MyExperimentPerspective.getLocalResourceURL("spinner")),
+ SwingConstants.CENTER);
+ contentPane.add(lStatusMessage, c);
+
+ // disable the (X) button (ideally, would need to remove it, but
+ // there's
+ // no way to do this)
+ this.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
+
+ // revalidate the window
+ this.pack();
+ this.validate();
+ this.repaint();
+
+ new Thread("Posting workflow") {
+ boolean formatRecognized = false;
+
+ @Override
+ public void run() {
+ String workflowFileContent = "";
+ if (userRequestedWorkflowUpload) {
+ if (uploadFile != null) {
+ try {
+ BufferedReader reader = new BufferedReader(new FileReader(
+ uploadFile));
+ String line;
+
+ String scuflSchemaDef = "xmlns:s=\"http://org.embl.ebi.escience/xscufl/0.1alpha\"";
+ String t2flowSchemaDef = "xmlns=\"http://taverna.sf.net/2008/xml/t2flow\"";
+
+ while ((line = reader.readLine()) != null) {
+ if (!formatRecognized
+ && (line.contains(scuflSchemaDef) || line
+ .contains(t2flowSchemaDef)))
+ formatRecognized = true;
+
+ workflowFileContent += line + "\n";
+ }
+ } catch (Exception e) {
+ lStatusMessage = new JLabel("Error occurred:" + e.getMessage(),
+ new ImageIcon(MyExperimentPerspective
+ .getLocalResourceURL("failure_icon")),
+ SwingConstants.LEFT);
+ logger.error(e.getCause() + "\n" + e.getMessage());
+ }
+ }
+ }
+
+ // *** POST THE WORKFLOW ***
+ final ServerResponse response;
+
+ if ((userRequestedWorkflowUpload && formatRecognized)
+ || !userRequestedWorkflowUpload) {
+ if (updateResource == null) // upload a new workflow
+ response = myExperimentClient.postWorkflow(workflowFileContent,
+ Util.stripAllHTML(strTitle),
+ Util.stripAllHTML(strDescription), licence, sharing);
+ else
+ // edit existing workflow
+ response = myExperimentClient.updateWorkflowVersionOrMetadata(
+ updateResource, workflowFileContent,
+ Util.stripAllHTML(strTitle),
+ Util.stripAllHTML(strDescription), licence, sharing);
+
+ bUploadingSuccessful = (response.getResponseCode() == HttpURLConnection.HTTP_OK);
+ } else {
+ bUploadingSuccessful = false;
+ response = null;
+ }
+
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ // *** REACT TO POSTING RESULT ***
+ if (bUploadingSuccessful) {
+ // workflow uploaded successfully
+ setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+
+ // disable all fields in dialog
+ tfTitle.setEnabled(false);
+ taDescription.setEnabled(false);
+ jcbLicences.setEnabled(false);
+ jcbSharingPermissions.setEnabled(false);
+ if (userRequestedWorkflowUpload) {
+ rbSelectOpenWorkflow.setEnabled(false);
+ rbSelectLocalFile.setEnabled(false);
+ selectedFileLabel.setEnabled(false);
+ bSelectFile.setEnabled(false);
+ jcbOpenWorkflows.setEnabled(false);
+ }
+ contentPane.remove(lStatusMessage);
+
+ c.insets = new Insets(10, 5, 5, 5);
+ lStatusMessage = new JLabel("Your workflow was successfully "
+ + (updateResource == null ? "uploaded." : "updated."),
+ new ImageIcon(MyExperimentPerspective
+ .getLocalResourceURL("success_icon")),
+ SwingConstants.LEFT);
+ contentPane.add(lStatusMessage, c);
+
+ bCancel.setText("OK");
+ bCancel.setDefaultCapable(true);
+ rootPane.setDefaultButton(bCancel);
+ c.insets = new Insets(5, 5, 10, 5);
+ c.gridy++;
+ contentPane.add(bCancel, c);
+
+ pack();
+ bCancel.requestFocusInWindow();
+
+ // update uploaded 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
+ MainComponent.MAIN_COMPONENT.getHistoryBrowser()
+ .getUploadedItemsHistoryList().remove(updateResource);
+ MainComponent.MAIN_COMPONENT.getHistoryBrowser()
+ .getUploadedItemsHistoryList().add(updateResource);
+ if (MainComponent.MAIN_COMPONENT.getHistoryBrowser()
+ .getUploadedItemsHistoryList().size() > HistoryBrowserTabContentPanel.UPLOADED_ITEMS_HISTORY_LENGTH) {
+ MainComponent.MAIN_COMPONENT.getHistoryBrowser()
+ .getUploadedItemsHistoryList().remove(0);
+ }
+
+ // now update the uploaded items history
+ // panel in 'History'
+ // tab
+ if (MainComponent.MAIN_COMPONENT.getHistoryBrowser() != null) {
+ MainComponent.MAIN_COMPONENT
+ .getHistoryBrowser()
+ .refreshHistoryBox(
+ HistoryBrowserTabContentPanel.UPLOADED_ITEMS_HISTORY);
+ }
+
+ } else {
+ // posting wasn't successful, notify the
+ // user
+ // and provide an option to close window or
+ // start again
+ setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+ taDescription.setEditable(true);
+ contentPane.remove(lStatusMessage);
+
+ c.insets = new Insets(10, 5, 5, 5);
+
+ String msg;
+ if (!formatRecognized)
+ msg = "Error occured: Invalid Taverna workflow.";
+ else
+ msg = "An error occured while processing your request.";
+
+ lStatusMessage = new JLabel(msg, new ImageIcon(
+ MyExperimentPerspective
+ .getLocalResourceURL("failure_icon")),
+ SwingConstants.LEFT);
+ contentPane.add(lStatusMessage, c);
+
+ bUpload.setText("Try again");
+ bUpload.setToolTipText("Please review your workflow or myExperiment base URL");
+ c.anchor = GridBagConstraints.EAST;
+ c.insets = new Insets(5, 5, 10, 5);
+ c.gridwidth = 1;
+ c.weightx = 0.5;
+ c.gridx = 0;
+ c.gridy++;
+ contentPane.add(bUpload, c);
+ rootPane.setDefaultButton(bUpload);
+
+ c.anchor = GridBagConstraints.WEST;
+ c.gridx = 1;
+ bCancel.setPreferredSize(bUpload.getPreferredSize());
+ contentPane.add(bCancel, c);
+
+ pack();
+ validate();
+ repaint();
+ }
+ }
+ });
+ }
+ }.start();
+ } // if proceedWithUpload
+ } else if (e.getSource().equals(this.bCancel)) { // * CANCEL BUTTON *
+ // cleanup the input fields if it wasn't posted successfully +
+ // simply
+ // close and destroy the window
+ if (!this.bUploadingSuccessful) {
+ this.strDescription = null;
+ this.tfTitle = null;
+ }
+ this.dispose();
+ } else if (e.getSource().equals(bSelectFile)) {// * SELECT FILE BUTTON *
+ // *
+ if (jfsSelectFile.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
+ localWorkflowFile = jfsSelectFile.getSelectedFile();
+
+ if (localWorkflowFile != null) {
+ selectedFileLabel.setText(localWorkflowFile.getAbsolutePath());
+ selectedFileLabel.setEnabled(true);
+ }
+ pack();
+ }
+ }
+ }
+
+ public void keyPressed(KeyEvent e) {
+ // if TAB was pressed in the text field (title), need to move keyboard
+ // focus
+ if (e.getSource().equals(this.tfTitle) || e.getSource().equals(this.taDescription)) {
+ if (e.getKeyCode() == KeyEvent.VK_TAB) {
+ if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) == KeyEvent.SHIFT_DOWN_MASK) {
+ // SHIFT + TAB move focus backwards
+ ((Component) e.getSource()).transferFocusBackward();
+ } else {
+ // TAB moves focus forward
+ ((Component) e.getSource()).transferFocus();
+ }
+ e.consume();
+ }
+ }
+ }
+
+ public void focusGained(FocusEvent e) {
+ if (e.getSource().equals(rbSelectLocalFile)) {
+ uploadWorkflowFromLocalFile = true;
+ bSelectFile.setEnabled(uploadWorkflowFromLocalFile);
+ jcbOpenWorkflows.setEnabled(!uploadWorkflowFromLocalFile);
+
+ if (localWorkflowFile != null) {
+ selectedFileLabel.setEnabled(uploadWorkflowFromLocalFile);
+ selectedFileLabel.setText(localWorkflowFile.getAbsolutePath());
+ pack();
+ } else
+ selectedFileLabel.setEnabled(!uploadWorkflowFromLocalFile);
+
+ } else if (e.getSource().equals(rbSelectOpenWorkflow)) {
+ uploadWorkflowFromLocalFile = false;
+ selectedFileLabel.setEnabled(uploadWorkflowFromLocalFile);
+ bSelectFile.setEnabled(uploadWorkflowFromLocalFile);
+ jcbOpenWorkflows.setEnabled(!uploadWorkflowFromLocalFile);
+ }
+ }
+
+ public void componentShown(ComponentEvent e) {
+ // center this dialog box within the preview browser window
+ if (updateResource == null) // upload has been pressed from the MAIN
+ // perspective window
+ Util.centerComponentWithinAnother(this.pluginMainComponent, this);
+ else
+ // upload pressed from resource preview window
+ Util.centerComponentWithinAnother(this.pluginMainComponent.getPreviewBrowser(), this);
+ }
+
+ public void focusLost(FocusEvent e) {
+ // not in use
+ }
+
+ public void caretUpdate(CaretEvent e) {
+ // not in use
+ }
+
+ public void componentHidden(ComponentEvent e) {
+ // not in use
+ }
+
+ public void componentMoved(ComponentEvent e) {
+ // not in use
+ }
+
+ public void keyReleased(KeyEvent e) {
+ // not in use
+ }
+
+ public void keyTyped(KeyEvent e) {
+ // not in use
+ }
+
+ public void componentResized(ComponentEvent e) {
+ // not in use
+ }
+
+ private class DataflowSelection {
+ private final Dataflow dataflow;
+ private final String name;
+
+ public DataflowSelection(Dataflow dataflow, String name) {
+ this.dataflow = dataflow;
+ this.name = name;
+ }
+
+ public Dataflow getDataflow() {
+ return dataflow;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+
+}
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/model/Base64$InputStream.class
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/model/Base64$InputStream.class b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/model/Base64$InputStream.class
new file mode 100644
index 0000000..a1a5f82
Binary files /dev/null and b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/model/Base64$InputStream.class differ
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/model/Base64$OutputStream.class
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/model/Base64$OutputStream.class b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/model/Base64$OutputStream.class
new file mode 100644
index 0000000..e754656
Binary files /dev/null and b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/model/Base64$OutputStream.class differ
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/model/Base64.class
----------------------------------------------------------------------
diff --git a/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/model/Base64.class b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/model/Base64.class
new file mode 100644
index 0000000..84fcee9
Binary files /dev/null and b/taverna-perspective-myexperiment/src/main/java/net/sf/taverna/t2/ui/perspectives/myexperiment/model/Base64.class differ