You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/02/23 11:22:34 UTC
[11/51] [partial] incubator-taverna-workbench git commit: Revert
"temporarily empty repository"
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/search_results/ServiceListCellRenderer.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/search_results/ServiceListCellRenderer.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/search_results/ServiceListCellRenderer.java
new file mode 100644
index 0000000..eafe095
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/search_results/ServiceListCellRenderer.java
@@ -0,0 +1,291 @@
+package net.sf.taverna.biocatalogue.ui.search_results;
+
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.biocatalogue.x2009.xml.rest.Location;
+import org.biocatalogue.x2009.xml.rest.ResourceLinkWithString;
+import org.biocatalogue.x2009.xml.rest.Service;
+import org.biocatalogue.x2009.xml.rest.ServiceSummary.Provider;
+
+import net.sf.taverna.biocatalogue.model.LoadingExpandedResource;
+import net.sf.taverna.biocatalogue.model.LoadingResource;
+import net.sf.taverna.biocatalogue.model.Resource;
+import net.sf.taverna.biocatalogue.model.Resource.TYPE;
+import net.sf.taverna.biocatalogue.model.ResourceManager;
+import net.sf.taverna.biocatalogue.model.Util;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.health_check.ServiceMonitoringStatusInterpreter;
+
+
+/**
+ * This list cell renderer is will display (web) Service items in the search results
+ * list box.
+ *
+ * In the collapsed state, four data items will be shown per service: status (as per monitoring data),
+ * service type (SOAP / REST), the name of the service and its description.
+ *
+ * In the expanded state, other details are added to the ones above: service categories, locations,
+ * endpoints and providers.
+ *
+ * @author Sergejs Aleksejevs
+ */
+@SuppressWarnings("serial")
+public class ServiceListCellRenderer extends ExpandableOnDemandLoadedListCellRenderer
+{
+ private JLabel jlTypeIcon;
+ private JLabel jlItemStatus;
+ private JLabel jlItemTitle;
+ private JLabel jlDescription;
+
+ private GridBagConstraints c;
+
+
+ public ServiceListCellRenderer() {
+ /* do nothing */
+ }
+
+
+ /**
+ * This entry can be in one of two states:
+ * -- containing only the name of the resource and NOT loading further details;
+ * -- containing only the name of the resource and LOADING further details.
+ *
+ * @param itemToRender
+ * @return
+ */
+ protected GridBagConstraints prepareInitiallyLoadingEntry(Object itemToRender)
+ {
+ TYPE resourceType = determineResourceType(itemToRender);
+ LoadingResource resource = (LoadingResource)itemToRender;
+
+ jlTypeIcon = new JLabel(resourceType.getIcon());
+ jlItemStatus = new JLabel(ResourceManager.getImageIcon(ResourceManager.SERVICE_STATUS_UNKNOWN_ICON));
+
+ jlItemTitle = new JLabel(Resource.getDisplayNameForResource(resource), JLabel.LEFT);
+ jlItemTitle.setForeground(Color.decode("#AD0000")); // very dark red
+ jlItemTitle.setFont(jlItemTitle.getFont().deriveFont(Font.PLAIN, jlItemTitle.getFont().getSize() + 2));
+
+ jlDescription = resource.isLoading() ? loaderBarAnimationGrey : loaderBarAnimationGreyStill;
+
+ return (arrangeLayout(false));
+ }
+
+
+ /**
+ *
+ * @param itemToRender
+ * @param expandedView <code>true</code> to indicate that this method generates the top
+ * fragment of the expanded list entry for this SOAP operation / REST method.
+ * @return
+ */
+ protected GridBagConstraints prepareLoadedEntry(Object itemToRender, boolean selected)
+ {
+ TYPE resourceType = determineResourceType(itemToRender);
+ Service service = (Service)itemToRender;;
+
+ // service type
+ if (service.getServiceTechnologyTypes() != null && service.getServiceTechnologyTypes().getTypeList().size() > 0)
+ {
+ if (service.getServiceTechnologyTypes().getTypeList().size() > 1 &&
+ !(service.getServiceTechnologyTypes().getTypeList().get(0).toString().equalsIgnoreCase("SOAP")) &&
+ service.getServiceTechnologyTypes().getTypeList().get(1).toString().equalsIgnoreCase("SOAPLAB")
+ )
+ {
+ jlTypeIcon = new JLabel(ResourceManager.getImageIcon(ResourceManager.SERVICE_TYPE_MULTITYPE_ICON));
+ }
+ else if (service.getServiceTechnologyTypes().getTypeArray(0).toString().equalsIgnoreCase("SOAP")) {
+ jlTypeIcon = new JLabel(ResourceManager.getImageIcon(ResourceManager.SERVICE_TYPE_SOAP_ICON));
+ }
+ else if (service.getServiceTechnologyTypes().getTypeArray(0).toString().equalsIgnoreCase("REST")) {
+ jlTypeIcon = new JLabel(ResourceManager.getImageIcon(ResourceManager.SERVICE_TYPE_REST_ICON));
+ }
+ }
+ else {
+ // can't tell the type - just show as a service of no particular type
+ jlTypeIcon = new JLabel(resourceType.getIcon());
+ }
+
+
+ // service status
+ jlItemStatus = new JLabel(ServiceMonitoringStatusInterpreter.getStatusIcon(service, true));
+
+ jlItemTitle = new JLabel(Resource.getDisplayNameForResource(service), JLabel.LEFT);
+ jlItemTitle.setForeground(Color.decode("#AD0000")); // very dark red
+ jlItemTitle.setFont(jlItemTitle.getFont().deriveFont(Font.PLAIN, jlItemTitle.getFont().getSize() + 2));
+
+ int descriptionMaxLength = DESCRIPTION_MAX_LENGTH_EXPANDED;
+ String strDescription = Util.stripAllHTML(service.getDescription());
+ strDescription = (strDescription == null || strDescription.length() == 0 ?
+ "<font color=\"gray\">no description</font>" :
+ StringEscapeUtils.escapeHtml(Util.ensureLineLengthWithinString(strDescription, LINE_LENGTH, false)));
+
+ if (strDescription.length() > descriptionMaxLength) {
+ strDescription = strDescription.substring(0, descriptionMaxLength) + "<font color=\"gray\">(...)</font>";
+ }
+ strDescription = "<html><b>Description: </b>" + strDescription + "</html>";
+ jlDescription = new JLabel(strDescription);
+
+ return (arrangeLayout(true));
+ }
+
+
+ /**
+ * @return Final state of the {@link GridBagConstraints} instance
+ * that was used to lay out components in the panel.
+ */
+ private GridBagConstraints arrangeLayout(boolean showActionButtons)
+ {
+ // POPULATE PANEL WITH PREPARED COMPONENTS
+ this.setLayout(new GridBagLayout());
+ c = new GridBagConstraints();
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.fill = GridBagConstraints.HORIZONTAL;
+
+ c.gridx = 0;
+ c.gridy = 0;
+ c.weightx = 0;
+ c.insets = new Insets(10, 6, 6, 3);
+ this.add(jlTypeIcon, c);
+
+ c.gridx++;
+ c.insets = new Insets(10, 3, 6, 3);
+ this.add(jlItemStatus, c);
+
+ c.gridx++;
+ c.weightx = 1.0;
+ c.insets = new Insets(10, 3, 6, 3);
+ this.add(jlItemTitle, c);
+
+ if (showActionButtons) {
+ c.gridx++;
+ c.gridheight = 3;
+ c.weightx = 0;
+ c.weighty = 1.0;
+ jlExpand = new JLabel(ResourceManager.getImageIcon(ResourceManager.FOLD_ICON));
+ this.add(jlExpand, c);
+ }
+
+ c.gridx = 2;
+ c.gridy++;
+ c.gridheight = 1;
+ c.weightx = 1.0;
+ c.weighty = 0;
+ c.insets = new Insets(3, 3, 3, 3);
+ this.add(jlDescription, c);
+
+ return (c);
+ }
+
+
+
+ protected void prepareLoadingExpandedEntry(Object itemToRender)
+ {
+ LoadingExpandedResource expandedResource = (LoadingExpandedResource) itemToRender;
+ GridBagConstraints c = prepareLoadedEntry(expandedResource.getAssociatedObj(), false);
+
+ if (expandedResource.isLoading())
+ {
+ c.gridx = 0;
+ c.gridy++;
+ c.gridwidth = 3;
+ c.anchor = GridBagConstraints.CENTER;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1.0;
+ this.add(loaderBarAnimationOrange, c);
+ }
+ else
+ {
+ // *** additional data for this Web Service operations ***
+ Service service = (Service) expandedResource.getAssociatedObj();
+
+
+ // -- categories --
+ int categoryCount = service.getSummary().getCategoryList().size();
+ String categoryString = "";
+ if (categoryCount > 0) {
+ List<String> categoryNames = new ArrayList<String>();
+ for (ResourceLinkWithString category : service.getSummary().getCategoryList()) {
+ categoryNames.add(category.getStringValue());
+ }
+ categoryString = "<html><b>" + Util.pluraliseNoun("Category", categoryCount) + ": </b>" + StringEscapeUtils.escapeHtml(Util.join(categoryNames, ", ")) + "</html>";
+ }
+ else {
+ categoryString = "<html><b>Category: </b><font color=\"gray\">unknown</font></html>";
+ }
+
+ c.gridy++;
+ this.add(new JLabel(categoryString),c);
+
+
+ // -- endpoints --
+ int endpointCount = service.getSummary().getEndpointList().size();
+ String endpointString = "";
+ if (endpointCount > 0) {
+ endpointString = "<html><b>" + Util.pluraliseNoun("Endpoint", endpointCount) + ": </b>" +
+ StringEscapeUtils.escapeHtml(Util.join(service.getSummary().getEndpointList(), ", ")) + "</html>";
+ }
+ else {
+ endpointString = "<html><b>Endpoint: </b><font color=\"gray\">unknown</font></html>";
+ }
+
+ c.gridy++;
+ this.add(new JLabel(endpointString), c);
+
+
+ // -- providers --
+ int providerCount = service.getSummary().getProviderList().size();
+ String providerString = "";
+ if (providerCount > 0) {
+ List<String> providerNames = new ArrayList<String>();
+ for (Provider serviceProvider : service.getSummary().getProviderList()) {
+ providerNames.add(serviceProvider.getName());
+ }
+ providerString = "<html><b>" + Util.pluraliseNoun("Provider", providerCount) + ": </b>" + StringEscapeUtils.escapeHtml(Util.join(providerNames, ", ")) + "</html>";
+ }
+ else {
+ providerString = "<html><b>Provider: </b><font color=\"gray\">unknown</font></html>";
+ }
+
+ c.gridy++;
+ this.add(new JLabel(providerString),c);
+
+
+ // -- locations --
+ int locationCount = service.getSummary().getLocationList().size();
+ String locationString = "";
+ List<String> locations = new ArrayList<String>();
+ if (locationCount > 0) {
+ for (Location location : service.getSummary().getLocationList()) {
+ List<String> locationNameFragments = new ArrayList<String>();
+ locationNameFragments.add(location.getCity());
+ locationNameFragments.add(location.getCountry());
+ locations.add(Util.join(locationNameFragments, ", "));
+ }
+ }
+ locationString = "<html><b>" + Util.pluraliseNoun("Location", locations.size()) + ": </b>" +
+ (locations.size() > 0 ? StringEscapeUtils.escapeHtml(Util.join(locations, "; ")) : "<font color=\"gray\">unknown</font>") +
+ "</html>";
+
+ c.gridy++;
+ c.insets = new Insets(3, 3, 12, 3);
+ this.add(new JLabel(locationString),c);
+ }
+ }
+
+
+@Override
+boolean shouldBeHidden(Object itemToRender) {
+ return false;
+}
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/JTriStateTree.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/JTriStateTree.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/JTriStateTree.java
new file mode 100644
index 0000000..304e50a
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/JTriStateTree.java
@@ -0,0 +1,631 @@
+package net.sf.taverna.biocatalogue.ui.tristatetree;
+
+import java.awt.Component;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JPopupMenu;
+import javax.swing.JTree;
+import javax.swing.SwingUtilities;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.MutableTreeNode;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
+
+import net.sf.taverna.biocatalogue.model.ResourceManager;
+import net.sf.taverna.t2.workbench.icons.WorkbenchIcons;
+
+
+/**
+ * @author Sergejs Aleksejevs
+ */
+@SuppressWarnings("serial")
+public class JTriStateTree extends JTree
+{
+ // This is used to manage location and padding of tooltips on long items
+ // that don't fit into the visible part of this tree.
+ private static final int JCHECKBOX_WIDTH = 16;
+
+ private JTriStateTree instanceOfSelf;
+ private JPopupMenu contextualMenu;
+
+ private TriStateTreeNode root;
+
+ // will enable/disable checkboxes - when disabled the selection
+ // will remain, but will appear as read-only
+ private boolean bCheckingEnabled;
+
+ private List<Action> contextualMenuActions;
+ private Action expandAllAction;
+ private Action collapseAllAction;
+ private Action selectAllAction;
+ private Action deselectAllAction;
+
+ private Set<TriStateTreeCheckingListener> checkingListeners;
+
+
+ @SuppressWarnings("serial")
+public JTriStateTree(TriStateTreeNode root)
+ {
+ super(root);
+ this.root = root;
+ this.instanceOfSelf = this;
+
+ // by default checking is allowed
+ this.bCheckingEnabled = true;
+
+ // initially, no checking listeners
+ checkingListeners = new HashSet<TriStateTreeCheckingListener>();
+
+ // initially set to show the [+]/[-] icons for expanding collapsing top-level nodes
+ this.setShowsRootHandles(true);
+
+ // use the cell rendered which understands the three states of the
+ // nodes of this tree
+ this.setCellRenderer(new TriStateCheckBoxTreeCellRenderer());
+
+
+ // create all necessary actions for the popup menu: selecting/deselecting and expanding/collapsing all nodes
+ this.selectAllAction = new AbstractAction("Select all", ResourceManager.getImageIcon(ResourceManager.SELECT_ALL_ICON))
+ {
+ // Tooltip
+ { this.putValue(SHORT_DESCRIPTION, "Select all nodes in the tree"); }
+
+ public void actionPerformed(ActionEvent e) {
+ selectAllNodes(true);
+ }
+ };
+
+ // Use the Taverna untick icon
+ this.deselectAllAction = new AbstractAction("Deselect all", ResourceManager.getImageIcon(ResourceManager.UNCHECKED_ICON))
+ {
+ // Tooltip
+ { this.putValue(SHORT_DESCRIPTION, "Deselect all nodes in the tree"); }
+
+ public void actionPerformed(ActionEvent e) {
+ selectAllNodes(false);
+ }
+ };
+
+
+// this.expandAllAction = new AbstractAction("Expand all", ResourceManager.getImageIcon(ResourceManager.EXPAND_ALL_ICON))
+ // Use the standard Taverna plus icon
+ this.expandAllAction = new AbstractAction("Expand all", WorkbenchIcons.plusIcon)
+ {
+ // Tooltip
+ { this.putValue(SHORT_DESCRIPTION, "Expand all nodes in the tree"); }
+
+ public void actionPerformed(ActionEvent e) {
+ expandAll();
+ }
+ };
+
+// this.collapseAllAction = new AbstractAction("Collapse all", ResourceManager.getImageIcon(ResourceManager.COLLAPSE_ALL_ICON))
+ // Use the standard Taverna minus icon
+ this.collapseAllAction = new AbstractAction("Collapse all", WorkbenchIcons.minusIcon)
+ {
+ // Tooltip
+ { this.putValue(SHORT_DESCRIPTION, "Collapse all expanded nodes in the tree"); }
+
+ public void actionPerformed(ActionEvent e) {
+ collapseAll();
+ }
+ };
+
+
+ // populate the popup menu with created menu items
+ contextualMenuActions = Arrays.asList(new Action[] {expandAllAction, collapseAllAction, deselectAllAction});
+
+ contextualMenu = new JPopupMenu();
+ contextualMenu.add(expandAllAction);
+ contextualMenu.add(collapseAllAction);
+ contextualMenu.add(new JPopupMenu.Separator());
+ //contextualMenu.add(selectAllAction);
+ contextualMenu.add(deselectAllAction);
+
+
+ this.addMouseListener(new MouseAdapter() {
+ // use mousePressed, not mouseClicked to make sure that
+ // quick successive clicks get processed correctly, otherwise
+ // some clicks are disregarded
+ public void mousePressed(MouseEvent e)
+ {
+ // only listen to checkbox checking requests if this is
+ // a correct type of mouse event for this
+ if (!e.isPopupTrigger() && e.getButton() == MouseEvent.BUTTON1)
+ {
+ int clickedRow = instanceOfSelf.getRowForLocation(e.getX(), e.getY());
+
+ // only make changes to node selections if checking is enabled in the tree and
+ // it was a node which was clicked, not [+]/[-] or blank space
+ if (bCheckingEnabled && clickedRow != -1)
+ {
+ Object clickedObject = instanceOfSelf.getPathForRow(clickedRow).getLastPathComponent();
+ if (clickedObject instanceof TriStateTreeNode) {
+ TriStateTreeNode node = ((TriStateTreeNode)clickedObject);
+
+ // toggle state of the clicked node + propagate the changes to
+ // the checking state of all nodes
+ node.toggleState(true);
+
+ // repaint the whole tree
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ instanceOfSelf.repaint();
+ }
+ });
+
+ // notify all listeners
+ notifyCheckingListeners();
+ }
+ }
+ }
+ else {
+ // not a checking action - instead, bring up a popup menu
+ contextualMenu.show(instanceOfSelf, e.getX(), e.getY());
+ }
+ }
+
+ public void mouseReleased(MouseEvent e)
+ {
+ if (e.isPopupTrigger()) {
+ // another way a popup menu may be called on different systems
+ contextualMenu.show(instanceOfSelf, e.getX(), e.getY());
+ }
+ }
+
+
+ /**
+ * This method enables tooltips on this instance of JTriStateTree
+ * when mouse enters its bounds. Custom tooltips will be used, but
+ * this notifies ToolTipManager that tooltips must be shown on this
+ * tree.
+ */
+ public void mouseEntered(MouseEvent e) {
+ instanceOfSelf.setToolTipText("Filter tree");
+ }
+
+ /**
+ * Removes tooltips from this JTriStateTree when mouse leaves its bounds.
+ */
+ public void mouseExited(MouseEvent e) {
+ instanceOfSelf.setToolTipText(null);
+ }
+
+ });
+
+ }
+
+
+ /**
+ * This method is used to determine tooltip location.
+ *
+ * Helps to ensure that the tooltip appears directly over the
+ * text in the row over which the mouse currently hovers.
+ */
+ public Point getToolTipLocation(MouseEvent e)
+ {
+ int iRowIndex = this.getRowForLocation(e.getX(), e.getY());
+ if (iRowIndex != -1) {
+ // mouse hovers over one of the rows - make top-left corner of
+ // the tooltip to appear over the top-left corner of that row
+ Rectangle bounds = this.getRowBounds(iRowIndex);
+ return (new Point(bounds.x + JCHECKBOX_WIDTH, bounds.y));
+ }
+ else {
+ // let ToolTipManager determine where to show the tooltip (if it will be shown)
+ return null;
+ }
+ }
+
+
+ /**
+ * Supports dynamic tooltips for the contents of this JTriStateTree -
+ * the tooltips will only be shown for those tree nodes that don't
+ * fully fit within the visible bounds of the tree.
+ *
+ * For other nodes no tooltip will be shown.
+ */
+ public String getToolTipText(MouseEvent e)
+ {
+ String strTooltip = null;
+
+ Object correspondingObject = getTreeNodeObject(e);
+ if (correspondingObject != null) {
+ // mouse is hovering over some row in the tree, not a blank space --
+ // obtain a component that is identical to the one which is currently displayed at the identified row in the tree
+ Component rendering = this.getCellRenderer().getTreeCellRendererComponent(this, correspondingObject, false, false,
+ true, this.getRowForLocation(e.getX(), e.getY()), false);
+
+ if (rendering.getPreferredSize().width + getToolTipLocation(e).x - JCHECKBOX_WIDTH > this.getVisibleRect().width) {
+ // if the component is not fully visible, the tooltip will be displayed -
+ // tooltip text matches the one for this row in the tree, will just be shown in full
+ strTooltip = correspondingObject.toString();
+ }
+ }
+
+ // return either tooltip text or 'null' if no tooltip is currently required
+ return (strTooltip);
+ }
+
+
+ /**
+ * Check whether a {@link MouseEvent} happened in such a location
+ * in the {@link JTriStateTree} that corresponds to some node or a
+ * blank space.
+ *
+ * @param e
+ * @return Object contained in the tree node that corresponds to the
+ * location of specified {@link MouseEvent} <code>e</code>;
+ * or <code>null</code> if the event happened over a blank space.
+ */
+ public Object getTreeNodeObject(MouseEvent e)
+ {
+ int iRowIndex = this.getRowForLocation(e.getX(), e.getY());
+ if (iRowIndex != -1) {
+ // mouse is hovering over some row in the tree, not a blank space
+ return (this.getPathForRow(iRowIndex).getLastPathComponent());
+ }
+
+ return (null);
+ }
+
+
+ /**
+ * @return List of the highest-level nodes of the tree that have full (not partial) selection and,
+ * therefore, act as roots of checked paths.
+ */
+ public List<TreePath> getRootsOfCheckedPaths()
+ {
+ return getRootsOfCheckedPaths(this.root);
+ }
+
+ /**
+ * A recursive version of the getCheckedRootsOfCheckedPaths().
+ * Performs all the work for a given node and returns result to
+ * the caller.
+ *
+ * @param startNode Node to start with.
+ * @return
+ */
+ private List<TreePath> getRootsOfCheckedPaths(TriStateTreeNode startNode)
+ {
+ ArrayList<TreePath> pathsToRootsOfCheckings = new ArrayList<TreePath>();
+
+ Object currentNode = null;
+ for (Enumeration e = startNode.children(); e.hasMoreElements(); )
+ {
+ currentNode = e.nextElement();
+ if (currentNode instanceof TriStateTreeNode) {
+ TriStateTreeNode curTriStateNode = (TriStateTreeNode)currentNode;
+
+ if (curTriStateNode.getState().equals(TriStateCheckBox.State.CHECKED)) {
+ pathsToRootsOfCheckings.add(new TreePath(curTriStateNode.getPath()));
+ }
+ else if (curTriStateNode.getState().equals(TriStateCheckBox.State.PARTIAL)) {
+ pathsToRootsOfCheckings.addAll(getRootsOfCheckedPaths(curTriStateNode));
+ }
+ }
+ }
+
+ return (pathsToRootsOfCheckings);
+ }
+
+
+ /**
+ * @return List of TreePath objects, where the last component in each
+ * path is the root of an unchecked path in this tree. In other
+ * words each of those last components is either an unchecked
+ * leaf node or a node, none of whose children (and itself as
+ * well) are checked.
+ */
+ public List<TreePath> getRootsOfUncheckedPaths()
+ {
+ return (getRootsOfUncheckedPaths(this.root));
+ }
+
+
+ /**
+ * Recursive worker method for <code>getRootsOfUncheckedPaths()</code>.
+ */
+ private List<TreePath> getRootsOfUncheckedPaths(TreeNode startNode)
+ {
+ List<TreePath> rootNodesOfUncheckedPaths = new ArrayList<TreePath>();
+
+ Object currentNode = null;
+ for (Enumeration e = startNode.children(); e.hasMoreElements(); )
+ {
+ currentNode = e.nextElement();
+ if (!(currentNode instanceof TriStateTreeNode) ||
+ ((TriStateTreeNode)currentNode).getState().equals(TriStateCheckBox.State.UNCHECKED))
+ {
+ rootNodesOfUncheckedPaths.add(new TreePath(((DefaultMutableTreeNode)currentNode).getPath()));
+ }
+ else {
+ rootNodesOfUncheckedPaths.addAll(getRootsOfUncheckedPaths((TreeNode)currentNode));
+ }
+ }
+
+ return (rootNodesOfUncheckedPaths);
+ }
+
+
+ /**
+ * @return List of TreePath objects, that point to all "leaf"
+ * nodes in the tree that are checked - in other words
+ * this method returns a collection of paths to all "deepest"
+ * nodes in this tree that are checked and do not have any
+ * (checked) children.
+ */
+ public List<TreePath> getLeavesOfCheckedPaths() {
+ return (getLeavesOfCheckedPaths(this.root));
+ }
+
+
+ /**
+ * Recursive worker method for {@link JTriStateTree#getLeavesOfCheckedPaths()}
+ */
+ private List<TreePath> getLeavesOfCheckedPaths(TriStateTreeNode startNode)
+ {
+ List<TreePath> leavesOfCheckedPaths = new ArrayList<TreePath>();
+
+ // this node is only relevant if it is checked itself - if not,
+ // it must be the first-level child of another node that is checked
+ // and is only considered here on the recursive pass (but will be discarded)
+ if (startNode.getState().equals(TriStateCheckBox.State.CHECKED) ||
+ startNode.getState().equals(TriStateCheckBox.State.PARTIAL))
+ {
+ // "ask" all children to do the same...
+ Object currentNode = null;
+ for (Enumeration e = startNode.children(); e.hasMoreElements(); ) {
+ currentNode = e.nextElement();
+ if (currentNode instanceof TriStateTreeNode) {
+ leavesOfCheckedPaths.addAll(getLeavesOfCheckedPaths((TriStateTreeNode)currentNode));
+ }
+ }
+
+ // ...if we have a list of leaf nodes, then this node can't be a leaf;
+ // -> but alternatively, if the list is empty, it means that this node is
+ // itself a leaf node and must be added to the result
+ if (leavesOfCheckedPaths.isEmpty()) {
+ leavesOfCheckedPaths.add(new TreePath(startNode.getPath()));
+ }
+ }
+
+ return (leavesOfCheckedPaths);
+ }
+
+
+ /**
+ * @return List of all contextual menu actions that are available for this tree.
+ */
+ public List<Action> getContextualMenuActions() {
+ return this.contextualMenuActions;
+ }
+
+
+ /**
+ * Enables or disables all actions in the contextual menu
+ * @param actionsAreEnabled
+ */
+ public void enableAllContextualMenuAction(boolean actionsAreEnabled) {
+ for (Action a : getContextualMenuActions()) {
+ a.setEnabled(actionsAreEnabled);
+ }
+ }
+
+
+ /**
+ * Selects or deselects all nodes.
+ * @param selectAll True - to select all; false - to reset all selections.
+ */
+ public void selectAllNodes(boolean selectAll) {
+ root.setState(selectAll ? TriStateCheckBox.State.CHECKED : TriStateCheckBox.State.UNCHECKED);
+ root.updateStateOfRelatedNodes();
+ this.repaint();
+
+ // even though this isn't a click in the tree, the selection has changed -
+ // notify all listeners
+ notifyCheckingListeners();
+ }
+
+
+ /**
+ * TODO - this method doesn't take into account a possibility that the
+ * filter tree might have changed
+ *
+ * @param rootsOfCheckedPaths A list of TreePath objects which represent a checking state of
+ * the nodes in this tree (as returned by <code>getRootsOfCheckedPaths()</code>).
+ *
+ * The last node of each path is the one that should have <code>TriStateCheckBox.State.CHECKED</code>
+ * state (so that last node is a root of checked path that start at that node). Related partial
+ * checkings for the UI can be computed from that by the tree checking model.
+ *
+ * Therefore, a single "real" checking per provided TreePath from <code>rootsOfCheckedPaths</code> is
+ * made.
+ */
+ public void restoreFilterCheckingSettings(List<TreePath> rootsOfCheckedPaths)
+ {
+ // start with removing all selections
+ this.selectAllNodes(false);
+
+ for (TreePath p : rootsOfCheckedPaths) {
+ restoreTreePathCheckingSettings(this.root, p);
+ }
+ }
+
+ /**
+ * A worker method for <code>restoreFilterCheckingSettings(List<TreePath> rootsOfCheckedPaths)</code>.
+ * See that method for further details.
+ *
+ * @param startNode A node of this tree.
+ * @param pathFromStartNode A TreePath object from the stored filter, where the first node must be
+ * equals to <code>startNode</code> (based on the <code>userObject</code>,
+ * but not the checking state), should the traversal of the tree result in
+ * checking the last node of this TreePath eventually - which is the goal
+ * of this method.
+ * @return True if traversal of <code>pathFromStartNode</code> succeeded and a node in this tree was checked;
+ * false if traversal couldn't find a matching node in this tree, and so no checking was made.
+ */
+ private boolean restoreTreePathCheckingSettings(TriStateTreeNode startNode, TreePath pathFromStartNode)
+ {
+ if (startNode == null || pathFromStartNode == null || pathFromStartNode.getPathCount() == 0) {
+ // no match - no data to work with
+ return (false);
+ }
+
+ // compare the "roots" - provided start node and the root of the provided path
+ // (based on the 'user object', but not the selection state)
+ if (startNode.equals(pathFromStartNode.getPathComponent(0)))
+ {
+ if (pathFromStartNode.getPathCount() == 1) {
+ // provided startNode is equals to the only node in the provided tree path -
+ // so it is the node to mark as checked; also - make sure that this selection
+ // propagates through tree
+ startNode.setState(TriStateCheckBox.State.CHECKED, true);
+
+ // we've found the required node in this path - no further search needed,
+ // so terminate this method
+ return (true);
+ }
+ else {
+ // provided startNode is equals to the first node of the provided tree path -
+ // meaning that at this stage we need to traverse all children of the startNode
+ // and look for the child that would match the next element in the provided tree path
+ //
+ // to do this, produce a new tree path from the provided one that doesn't contain
+ // the first node - then proceed recursively
+ Object[] currentPathComponents = pathFromStartNode.getPath();
+ Object[] reducedPathComponents = new Object[currentPathComponents.length - 1];
+ System.arraycopy(currentPathComponents, 1, reducedPathComponents, 0, currentPathComponents.length - 1);
+
+ Enumeration children = startNode.children();
+ while (children.hasMoreElements()) {
+ TriStateTreeNode currentChild = (TriStateTreeNode)children.nextElement();
+
+ // if recursive call succeeds, no need to iterate any further
+ if (restoreTreePathCheckingSettings(currentChild, new TreePath(reducedPathComponents))) return (true);
+ }
+ }
+ }
+
+ // the startNode doesn't match the the first element in the provided tree path
+ // or no match could be found during recursive search for the node to "check"
+ return (false);
+ }
+
+
+ /**
+ * Expands all paths in this tree.
+ */
+ public void expandAll()
+ {
+ // this simply expands all tree nodes
+ // TODO - this actually "freezes" the UI if there are many nodes in the tree
+ // some better solution to be found (e.g. expand the nodes in the model, then update UI, or similar)
+ for (int i = 0; i < getRowCount(); i++) {
+ instanceOfSelf.expandRow(i);
+ }
+ }
+
+
+ /**
+ * Collapses all paths in this tree.
+ */
+ public void collapseAll()
+ {
+ // this simply collapses all expanded nodes - this is very quick, execute just as it is
+ for (int i = getRowCount() - 1; i >= 0; i--) {
+ instanceOfSelf.collapseRow(i);
+ }
+ }
+
+
+ /**
+ * Removes all nodes in this tree that are unchecked.
+ *
+ * It doesn't iterate through *all* nodes - if some node is
+ * indeed unchecked, it removes that node and any children that
+ * it has (because unchecked node is the root of an unchecked path).
+ */
+ public void removeAllUncheckedNodes()
+ {
+ // get the tree model first - will be used to remove the nodes
+ DefaultTreeModel theTreeModel = (DefaultTreeModel)this.treeModel;
+
+ // remove unchecked nodes
+ List<TreePath> allNodesToRemove = this.getRootsOfUncheckedPaths();
+ for (TreePath p : allNodesToRemove) {
+ theTreeModel.removeNodeFromParent((MutableTreeNode)p.getLastPathComponent());
+ }
+ }
+
+
+ /**
+ * Provides access to the contextual menu of this JTriStateTree.
+ *
+ * @return Reference to the contextual menu.
+ */
+ public JPopupMenu getContextualMenu() {
+ return contextualMenu;
+ }
+
+
+ public void setCheckingEnabled(boolean bCheckingEnabled) {
+ this.bCheckingEnabled = bCheckingEnabled;
+ }
+
+ /**
+ * @return True if the current state of this JTriStateTree
+ * allows making changes to checking of checkboxes
+ * in its nodes.
+ */
+ public boolean isCheckingEnabled() {
+ return bCheckingEnabled;
+ }
+
+
+ /**
+ * @param listener New tree checking listener to register for updates
+ * to tree node selections.
+ */
+ public void addCheckingListener(TriStateTreeCheckingListener listener) {
+ if (listener != null) {
+ this.checkingListeners.add(listener);
+ }
+ }
+
+
+ /**
+ * @param listener Tree checking listener to remove.
+ */
+ public void removeCheckingListener(TriStateTreeCheckingListener listener) {
+ if (listener != null) {
+ this.checkingListeners.remove(listener);
+ }
+ }
+
+
+ /**
+ * Sends a signal to all listeners to check the state of the tree,
+ * as it has changed.
+ */
+ private void notifyCheckingListeners() {
+ for (TriStateTreeCheckingListener listener : this.checkingListeners) {
+ listener.triStateTreeCheckingChanged(instanceOfSelf);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/Swing - Tristate CheckBox.7z
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/Swing - Tristate CheckBox.7z b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/Swing - Tristate CheckBox.7z
new file mode 100644
index 0000000..8c60d87
Binary files /dev/null and b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/Swing - Tristate CheckBox.7z differ
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/Test.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/Test.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/Test.java
new file mode 100644
index 0000000..6d58db3
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/Test.java
@@ -0,0 +1,67 @@
+package net.sf.taverna.biocatalogue.ui.tristatetree;
+
+import java.awt.BorderLayout;
+
+import javax.swing.JFrame;
+import javax.swing.JScrollPane;
+
+/**
+ * @author Sergejs Aleksejevs
+ */
+public class Test extends JFrame
+{
+ public Test() {
+ this.setLayout(new BorderLayout());
+
+ this.add(new TriStateCheckBox("LOL", TriStateCheckBox.State.PARTIAL), BorderLayout.NORTH);
+
+ TriStateTreeNode root = new TriStateTreeNode("root");
+ TriStateTreeNode c1 = new TriStateTreeNode("child 1");
+ TriStateTreeNode c2 = new TriStateTreeNode("child 2");
+ TriStateTreeNode c3 = new TriStateTreeNode("child 3");
+
+ TriStateTreeNode c1_1 = new TriStateTreeNode("child 1_1");
+ TriStateTreeNode c1_2 = new TriStateTreeNode("child 1_2");
+ TriStateTreeNode c1_3 = new TriStateTreeNode("child 1_3");
+
+ TriStateTreeNode c2_1 = new TriStateTreeNode("child 2_1");
+ TriStateTreeNode c2_2 = new TriStateTreeNode("child 2_2");
+ TriStateTreeNode c2_3 = new TriStateTreeNode("child 2_3");
+
+ TriStateTreeNode c3_1 = new TriStateTreeNode("child 3_1");
+ TriStateTreeNode c3_2 = new TriStateTreeNode("child 3_2");
+ TriStateTreeNode c3_3 = new TriStateTreeNode("child 3_3");
+
+ TriStateTreeNode c1_1_1 = new TriStateTreeNode("child 1_1_1");
+ TriStateTreeNode c1_1_2 = new TriStateTreeNode("child 1_1_2");
+ TriStateTreeNode c1_1_3 = new TriStateTreeNode("child 1_1_3");
+
+ // adding second level children
+ root.add(c1); root.add(c2); root.add(c3);
+
+ // adding third-level children
+ c1.add(c1_1); c1.add(c1_2); c1.add(c1_3);
+ c2.add(c2_1); c2.add(c2_2); c2.add(c2_3);
+ c3.add(c3_1); c3.add(c3_2); c3.add(c3_3);
+
+ // adding fourth-level children
+ c1_1.add(c1_1_1); c1_1.add(c1_1_2); c1_1.add(c1_1_3);
+
+
+ // NB! important to create the tree when 'root' is already populated with children
+ JTriStateTree tree = new JTriStateTree(root);
+ tree.setRootVisible(false);
+ tree.setShowsRootHandles(true);
+ this.add(new JScrollPane(tree), BorderLayout.CENTER);
+
+ this.setDefaultCloseOperation(EXIT_ON_CLOSE);
+ this.pack();
+ }
+
+
+ public static void main(String[] args) {
+ JFrame a = new Test();
+ a.setVisible(true);
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateCheckBox.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateCheckBox.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateCheckBox.java
new file mode 100644
index 0000000..361dfc3
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateCheckBox.java
@@ -0,0 +1,172 @@
+package net.sf.taverna.biocatalogue.ui.tristatetree;
+
+/*
+ * Taken from: http://72.5.124.102/thread.jspa?threadID=721308&messageID=9955637
+ * Data webpage accessed: 07/February/2010
+ *
+ * Modified by Sergejs Aleksejevs
+ */
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+
+import javax.swing.Icon;
+import javax.swing.JCheckBox;
+import javax.swing.JToggleButton;
+import javax.swing.UIManager;
+
+public class TriStateCheckBox extends JCheckBox
+{
+ private static final long serialVersionUID = 1L;
+
+ public static enum State {
+ CHECKED, UNCHECKED, PARTIAL
+ };
+
+
+ // these colors will be used for painting the 'partial' state of the checkbox -
+ // a gradient painting will be made from top-left to bottom-right
+ private Color partialStateTopLeftColor = Color.GREEN.darker().darker().darker();
+ private Color partialStateBottomRightColor = Color.GREEN.brighter().brighter().brighter();
+
+
+ /**
+ * Creates an initially unselected check box button with no text, no icon.
+ */
+ public TriStateCheckBox() {
+ this(null, State.UNCHECKED);
+ }
+
+ /**
+ * Creates a check box with text and icon, and specifies whether or not it is initially
+ * selected.
+ *
+ * @param text
+ * The text of the check box.
+ * @param initial
+ * The initial state
+ */
+ public TriStateCheckBox(String text, State initial) {
+ super.setText(text);
+ setModel(new TriStateModel(initial));
+ setIcon(new TriStateIcon(this));
+ // some UI settings
+ setRolloverEnabled(true);
+ }
+
+ /**
+ * Set the new state to either CHECKED, PARTIAL or UNCHECKED.
+ */
+ public void setState(State state) {
+ ((TriStateModel) model).setState(state);
+ }
+
+ /**
+ * Return the current state, which is determined by the selection status of the model.
+ */
+ public State getState() {
+ return ((TriStateModel) model).getState();
+ }
+
+ public void setSelected(boolean selected) {
+ ((TriStateModel) model).setSelected(selected);
+ }
+
+ /** The model for the button */
+ private static class TriStateModel extends JToggleButton.ToggleButtonModel {
+
+ private static final long serialVersionUID = 1L;
+ protected State state;
+
+ public TriStateModel(State state) {
+ this.state = state;
+ }
+
+ public boolean isSelected() {
+ return state == State.CHECKED;
+ }
+
+ public State getState() {
+ return state;
+ }
+
+ public void setState(State state) {
+ this.state = state;
+ fireStateChanged();
+ }
+
+ public void setPressed(boolean pressed) {
+ if (pressed) {
+ switch (state) {
+ case UNCHECKED:
+ state = State.CHECKED;
+ break;
+ case PARTIAL:
+ state = State.UNCHECKED;
+ break;
+ case CHECKED:
+ state = State.PARTIAL;
+ break;
+ }
+ }
+
+ }
+
+ public void setSelected(boolean selected) {
+ if (selected) {
+ this.state = State.CHECKED;
+ } else {
+ this.state = State.UNCHECKED;
+ }
+ }
+ }
+
+ private class TriStateIcon implements Icon
+ {
+ private Icon checkBoxIcon;
+ private TriStateCheckBox triStateCheckBox;
+ public TriStateIcon(TriStateCheckBox triStateCheckBox) {
+ this.triStateCheckBox = triStateCheckBox;
+ this.checkBoxIcon = UIManager.getIcon("CheckBox.icon");
+
+ return;
+ }
+
+ public final int getIconHeight() {
+ return this.checkBoxIcon.getIconHeight();
+
+ }
+
+ public final int getIconWidth() {
+ return this.checkBoxIcon.getIconWidth();
+
+ }
+
+
+ public void paintIcon(Component c, Graphics g, int x, int y)
+ {
+ checkBoxIcon.paintIcon(triStateCheckBox, g, x, y);
+ if (triStateCheckBox.getState().equals(TriStateCheckBox.State.PARTIAL))
+ {
+ // this is changed to create the gradient paint dynamically every time;
+ // this makes sure that the gradient is relative to the actual position of the checkbox,
+ // rather than in the absolute coordinates of the parent component
+ GradientPaint gradient = new GradientPaint(x, y, partialStateTopLeftColor, x + 8, y + 8, partialStateBottomRightColor, false);
+
+ Graphics2D g2d = (Graphics2D) g;
+ g2d.setPaint(gradient);
+ final int deltaX = 2;
+ final int deltaY = 2;
+ final int xNew = x + deltaX;
+ final int yNew = y + deltaY;
+ final int width = getIconWidth() - 2*deltaX;
+ final int height = getIconHeight() - 2*deltaY;
+ g2d.fillRect(xNew, yNew, width, height);
+ }
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateCheckBoxTreeCellRenderer.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateCheckBoxTreeCellRenderer.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateCheckBoxTreeCellRenderer.java
new file mode 100644
index 0000000..dd78bf7
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateCheckBoxTreeCellRenderer.java
@@ -0,0 +1,62 @@
+package net.sf.taverna.biocatalogue.ui.tristatetree;
+
+import java.awt.Color;
+import java.awt.Component;
+
+import javax.swing.JLabel;
+import javax.swing.JTree;
+import javax.swing.border.Border;
+import javax.swing.tree.DefaultTreeCellRenderer;
+
+import net.sf.taverna.biocatalogue.model.ResourceManager;
+
+
+/**
+ * Provides a mechanism for rendering tri-state tree nodes.
+ *
+ * @author Sergejs Aleksejevs
+ */
+public class TriStateCheckBoxTreeCellRenderer extends DefaultTreeCellRenderer
+{
+ public Component getTreeCellRendererComponent(JTree tree, Object value,
+ boolean selected, boolean expanded, boolean leaf, int row,
+ boolean hasFocus)
+ {
+ Border treeNodePanelBorder = null; // will be obtained from default rendering and applied to the new one
+ Color backgroundColor = null; // likewise: will be applied to all constituents of the new rendering
+
+ // obtain the default rendering, we'll then customize it
+ Component defaultRendering = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
+
+ // it is most likely that the default rendering will be a JLabel, check just to be safe
+ if (defaultRendering instanceof JLabel)
+ {
+ JLabel defaultRenderedLabel = ((JLabel)defaultRendering);
+
+ // if this is not the case, it kind of undermines the whole purpose
+ // of using this tree cell renderer, but check just to be sure
+ if (value instanceof TriStateTreeNode) {
+ // a state value from within the TriStateTreeNode will be used to
+ // set the correct state in its rendering
+ switch (((TriStateTreeNode)value).getState()) {
+ case CHECKED:
+ if (((TriStateTreeNode)value).getPath().length > 2) {
+ // only allow CHECKED state icon for nodes that are deeper than second
+ // level in the tree - that is for any nodes that do not represent categories
+ // in the tree (root is not shown, so nodes that represent categories are
+ // effectively multiple category "roots" that have actual contents inside them)
+ defaultRenderedLabel.setIcon(ResourceManager.getImageIcon(ResourceManager.TRISTATE_CHECKBOX_CHECKED_ICON));
+ break;
+ }
+ // else -- 'fall through' to PARTIAL icon: this was a CHECKED state for the category node
+ case PARTIAL: defaultRenderedLabel.setIcon(ResourceManager.getImageIcon(ResourceManager.TRISTATE_CHECKBOX_PARTIAL_ICON)); break;
+ case UNCHECKED: defaultRenderedLabel.setIcon(ResourceManager.getImageIcon(ResourceManager.TRISTATE_CHECKBOX_UNCHECKED_ICON)); break;
+ default: defaultRenderedLabel.setIcon(null); break;
+ }
+ }
+ }
+
+ return (defaultRendering);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateTreeCheckingListener.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateTreeCheckingListener.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateTreeCheckingListener.java
new file mode 100644
index 0000000..e612e54
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateTreeCheckingListener.java
@@ -0,0 +1,12 @@
+package net.sf.taverna.biocatalogue.ui.tristatetree;
+
+/**
+ * A simple interface to enable tracking tree checking
+ * changes.
+ *
+ * @author Sergejs Aleksejevs
+ */
+public interface TriStateTreeCheckingListener
+{
+ public void triStateTreeCheckingChanged(JTriStateTree source);
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateTreeNode.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateTreeNode.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateTreeNode.java
new file mode 100644
index 0000000..248cdf8
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/ui/tristatetree/TriStateTreeNode.java
@@ -0,0 +1,246 @@
+package net.sf.taverna.biocatalogue.ui.tristatetree;
+
+import java.util.Enumeration;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreeNode;
+
+/**
+ * This class models tri-state nodes in the tree. Effectively
+ * it associates a tri-state checkbox with each tree node.
+ *
+ * Useful for partial selections of hierarchical data -
+ * partial selection of a node indicates that some of the
+ * children of that node are selected.
+ *
+ * @author Sergejs Aleksejevs
+ */
+@SuppressWarnings("serial")
+public class TriStateTreeNode extends DefaultMutableTreeNode
+{
+ private TriStateCheckBox.State state;
+
+ /**
+ * Creates a regular tree node; associated tri-state checkbox state is set to UNCHECKED.
+ *
+ * @param userObject The object this tree node will represent.
+ */
+ public TriStateTreeNode(Object userObject) {
+ this(userObject, TriStateCheckBox.State.UNCHECKED);
+ }
+
+ /**
+ * Creates a regular tree node; associated tri-state checkbox state is set to the provided <code>initialState</code> value.
+ *
+ * @param userObject The object this tree node will represent.
+ * @param initialState One of the enum values of <code>TriStateCheckBox.State</code>.
+ */
+ public TriStateTreeNode(Object userObject, TriStateCheckBox.State initialState) {
+ super(userObject);
+ this.state = initialState;
+ }
+
+
+ /**
+ * Compares based on the user object, not the state of this node.
+ */
+ public boolean equals(Object other) {
+ if (other instanceof TriStateTreeNode) {
+ return (this.userObject.equals(((TriStateTreeNode)other).userObject));
+ }
+ else {
+ return (false);
+ }
+ }
+
+
+ /**
+ * Sets the state of the current node and (optionally) propagates
+ * those changes through the tree.
+ *
+ * @param state The new state to set - value from <code>TriStateCheckBox.State</code> enum.
+ * @param propagateChangesToRelatedNodes True - to use the tree checking model to
+ * propagate changes of the state of the current tree node to the
+ * other related tree nodes (e.g. all descendants and ancestors) -
+ * up and down the tree hierarchy. False - to only update the current
+ * node and make no changes to the rest of the tree.
+ */
+ public void setState(TriStateCheckBox.State state, boolean propagateChangesToRelatedNodes)
+ {
+ this.state = state;
+
+ // check if the tree checking model should be activated
+ if (propagateChangesToRelatedNodes) {
+ updateStateOfRelatedNodes();
+ }
+ }
+
+
+ /**
+ * Sets the state of the current node.
+ *
+ * @param state The new state to set - value from <code>TriStateCheckBox.State</code> enum.
+ */
+ public void setState(TriStateCheckBox.State state) {
+ setState(state, false);
+ }
+
+
+ public TriStateCheckBox.State getState() {
+ return state;
+ }
+
+
+ /**
+ * Toggles the state of the associated tri-state checkbox.
+ * State transitions are as follows:</br>
+ * <code>
+ * TriStateCheckBox.State.CHECKED -> TriStateCheckBox.State.UNCHECKED
+ * TriStateCheckBox.State.PARTIAL -> TriStateCheckBox.State.UNCHECKED
+ * TriStateCheckBox.State.UNCHECKED -> TriStateCheckBox.State.CHECKED
+ * </code>
+ *
+ * @param propagateChangesToRelatedNodes True - to use the tree checking model to
+ * propagate changes of the state of the current tree node to the
+ * other related tree nodes (e.g. all descendants and ancestors) -
+ * up and down the tree hierarchy. False - to only update the current
+ * node and make no changes to the rest of the tree.
+ * @return The value of the new state.
+ */
+ public TriStateCheckBox.State toggleState(boolean propagateChangesToRelatedNodes)
+ {
+ if (state.equals(TriStateCheckBox.State.CHECKED) || state.equals(TriStateCheckBox.State.PARTIAL)) {
+ state = TriStateCheckBox.State.UNCHECKED;
+ }
+ else if (state.equals(TriStateCheckBox.State.UNCHECKED)) {
+ state = TriStateCheckBox.State.CHECKED;
+ }
+
+ // check if the tree checking model should be activated
+ if (propagateChangesToRelatedNodes) {
+ updateStateOfRelatedNodes();
+ }
+
+ return (state);
+ }
+
+
+ /*
+ * === The tree CHECKING MODEL ===
+ *
+ * Effectively, this defines the way the tree reacts to it's nodes
+ * being checked / unchecked. Only one model is implemented at the
+ * moment, therefore it's not extracted into a separate class, but
+ * remains to be a part of the TriStateTreeNode.
+ *
+ * Could possibly be better placed within the JTriStateTree, rather
+ * than TriStateTreeNode.
+ */
+
+ /**
+ * The entry point - must be invoked to traverse the tree and make
+ * changes to checking states of related tree nodes.
+ */
+ public void updateStateOfRelatedNodes()
+ {
+ updateStateOfAncestors(this.getParent());
+ updateStateOfDescendants(this);
+ }
+
+
+ /**
+ * Recursively visits all ancestors of the <code>parentNode</code>
+ * and decides on their checking states based on the states of their
+ * children nodes.
+ *
+ * @param parentNode Initially - parent node of the current node (i.e. the one,
+ * for which a state update has been made); then updated for
+ * recursive calls.
+ */
+ private void updateStateOfAncestors(TreeNode parentNode)
+ {
+ // reached root of the tree, do nothing - return
+ if (parentNode == null) {
+ return;
+ }
+
+ if (parentNode instanceof TriStateTreeNode) {
+ TriStateTreeNode parentTriStateNode = (TriStateTreeNode)parentNode;
+
+ // explicitly fetch children into a new enumeration - this is
+ // to make sure that we work with the same enumeration, rather
+ // than obtaining a fresh one with every reference to 'parentTriStateNode.children()'
+ Enumeration childNodes = parentTriStateNode.children();
+
+ // go through all the children and count the number of selected ones
+ int iChildrenCount = 0;
+ int iPartiallySelectedChildren = 0;
+ int iSelectedChildren = 0;
+
+ while(childNodes.hasMoreElements()) {
+ Object node = childNodes.nextElement();
+ if (node instanceof TriStateTreeNode) {
+ TriStateTreeNode currentNode = (TriStateTreeNode)node;
+ iChildrenCount++;
+ if (currentNode.getState().equals(TriStateCheckBox.State.CHECKED)) {
+ iSelectedChildren++;
+ }
+ else if (currentNode.getState().equals(TriStateCheckBox.State.PARTIAL)) {
+ iPartiallySelectedChildren++;
+ }
+ }
+ }
+
+
+ // decide on the state of the 'parentNode' based on the checking state of its children
+ if (iSelectedChildren == 0 && iPartiallySelectedChildren == 0) {
+ // no children are selected
+ parentTriStateNode.setState(TriStateCheckBox.State.UNCHECKED);
+ }
+ else if ((iSelectedChildren + iPartiallySelectedChildren) > 0 && iSelectedChildren < iChildrenCount) {
+ // some children are selected (either partially or fully)
+ parentTriStateNode.setState(TriStateCheckBox.State.PARTIAL);
+ }
+ else if (iSelectedChildren > 0 && iSelectedChildren == iChildrenCount) {
+ // all children are selected
+ parentTriStateNode.setState(TriStateCheckBox.State.CHECKED);
+ }
+
+
+ // repeat the same recursively up the hierarchy
+ updateStateOfAncestors(parentTriStateNode.getParent());
+ }
+ }
+
+ /**
+ * Recursively traverses all descendants of the <code>parentNode</code>
+ * to set their checking state to the value of the state of the <code>parentNode</code>.
+ *
+ * @param parentNode Initially - the tree node for which the state
+ * change was made; then updated for recursive calls.
+ */
+ private void updateStateOfDescendants(TriStateTreeNode parentNode)
+ {
+ // explicitly fetch children into a new enumeration - this is
+ // to make sure that we work with the same enumeration, rather
+ // than obtaining a fresh one with every reference to 'parentNode.children()'
+ Enumeration childNodes = parentNode.children();
+
+ // for all child nodes do 2 things:
+ // - set their state as that of the parent;
+ // - repeat the same recursively with their children
+ while(childNodes.hasMoreElements()) {
+ Object node = childNodes.nextElement();
+ if (node instanceof TriStateTreeNode) {
+ TriStateTreeNode currentNode = (TriStateTreeNode) node;
+ currentNode.setState(parentNode.getState());
+ currentNode.updateStateOfDescendants(currentNode);
+ }
+ }
+ }
+
+ /*
+ * === End of CHECKING MODEL implementation.
+ */
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/BioCataloguePerspective.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/BioCataloguePerspective.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/BioCataloguePerspective.java
new file mode 100644
index 0000000..ac170dc
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/BioCataloguePerspective.java
@@ -0,0 +1,70 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue;
+
+import java.io.InputStream;
+import java.net.URL;
+
+import javax.swing.ImageIcon;
+
+import net.sf.taverna.biocatalogue.model.ResourceManager;
+import net.sf.taverna.t2.workbench.ui.zaria.PerspectiveSPI;
+
+import org.jdom.Element;
+
+/**
+ * @author Sergejs Aleksejevs
+ */
+public class BioCataloguePerspective implements PerspectiveSPI
+{
+ private MainComponent perspectiveMainComponent;
+ private boolean visible = true;
+
+ public ImageIcon getButtonIcon()
+ {
+ return ResourceManager.getImageIcon(ResourceManager.FAVICON);
+ }
+
+ public InputStream getLayoutInputStream() {
+ return getClass().getResourceAsStream("biocatalogue-perspective.xml");
+ }
+
+ public String getText() {
+ return "Service Catalogue";
+ }
+
+ public boolean isVisible() {
+ return visible;
+ }
+
+ public int positionHint()
+ {
+ // this determines position of perspective in the
+ // bar with perspective buttons (currently makes it the last in
+ // the list)
+ return 40;
+ }
+
+ public void setVisible(boolean visible) {
+ this.visible = visible;
+
+ }
+
+ public void update(Element layoutElement) {
+ // TODO Auto-generated method stub
+
+ // 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;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/MainComponent.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/MainComponent.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/MainComponent.java
new file mode 100644
index 0000000..eeb1cba
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/MainComponent.java
@@ -0,0 +1,285 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.GridLayout;
+
+import javax.swing.ImageIcon;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.ToolTipManager;
+import javax.swing.border.LineBorder;
+
+import net.sf.taverna.biocatalogue.model.BioCataloguePluginConstants;
+import net.sf.taverna.biocatalogue.model.ResourceManager;
+import net.sf.taverna.biocatalogue.model.Util;
+import net.sf.taverna.biocatalogue.ui.BioCatalogueExplorationTab;
+import net.sf.taverna.t2.workbench.icons.WorkbenchIcons;
+import net.sf.taverna.t2.workbench.ui.zaria.UIComponentSPI;
+
+import org.apache.log4j.Logger;
+
+/*
+ * @author Sergejs Aleksejevs
+ */
+@SuppressWarnings("serial")
+public final class MainComponent extends JPanel implements UIComponentSPI //, ChangeListener
+{
+// private static final String windowBaseTitle = "BioCatalogue API Demo";
+// private HashMap<String, String> windowTitleMap;
+
+ private MainComponent pluginPerspectiveMainComponent;
+ private final Logger logger = Logger.getLogger(MainComponent.class);
+
+ //private JTabbedPane tpMainTabs;
+ private BioCatalogueExplorationTab jpBioCatalogueExplorationTab;
+// private BioCataloguePluginAbout jpAboutTab;
+
+ public static JFrame dummyOwnerJFrame;
+ static {
+ // this is only to have a nice icon on all Dialog boxes - can be removed at any time
+ dummyOwnerJFrame = new JFrame();
+ dummyOwnerJFrame.setIconImage(ResourceManager.getImageIcon(ResourceManager.FAVICON).getImage());
+ }
+
+
+ /**
+ * This constructor is protected, and so is only available to the classes in its package -
+ * i.e. Taverna integration classes. Other parts of the plugin must use <code>MainComponentFactory.getSharedInstance()</code>
+ * to get the shared instance of this class.
+ */
+ protected MainComponent()
+ {
+ super();
+ initialiseEnvironment();
+ initialisePerspectiveUI();
+ }
+
+
+ // *** Methods implementing UIComponentSPI interface ***
+
+ public ImageIcon getIcon() {
+ return WorkbenchIcons.databaseIcon;
+ }
+
+ @Override
+ public String getName() {
+ return "Service Catalogue Perspective Main Component";
+ }
+
+ public void onDisplay() {
+ // TODO Auto-generated method stub
+ }
+
+ public void onDispose() {
+ // TODO Auto-generated method stub
+ }
+
+ // *** End of methods implementing UIComponentSPI interface ***
+
+
+ private void initialiseEnvironment()
+ {
+ // before anything else - store a reference to self for use during
+ // initialisation of other components
+ pluginPerspectiveMainComponent = this;
+
+
+ // pre-load classes for FlyingSaucer XHTML renderer - this will make sure
+ // that the first time it is used, there will be no delay while classes
+ // are loaded by Java
+ new Thread("class pre-loading") {
+ public void run() {
+ try {
+ Class.forName("org.xhtmlrenderer.simple.FSScrollPane");
+ Class.forName("org.xhtmlrenderer.simple.XHTMLPanel");
+ }
+ catch (ClassNotFoundException e) {
+ logger.error("Problem while pre-loading classes for FlyingSaucer XHTML renderer", e);
+ }
+ }
+ }.start();
+
+
+ // determine what folder is to be used for config files
+ if (!Util.isRunningInTaverna()) {
+ // running outside Taverna, place config file and log into the user's home directory
+ BioCataloguePluginConstants.CONFIG_FILE_FOLDER =
+ new java.io.File(System.getProperty("user.home"), BioCataloguePluginConstants.CONFIG_FILE_FOLDER_WHEN_RUNNING_STANDALONE);
+ BioCataloguePluginConstants.LOG_FILE_FOLDER =
+ new java.io.File(System.getProperty("user.home"), BioCataloguePluginConstants.CONFIG_FILE_FOLDER_WHEN_RUNNING_STANDALONE);
+ }
+
+
+ // this makes sure that tooltips will stay displayed for longer than default
+ ToolTipManager.sharedInstance().setDismissDelay(BioCataloguePluginConstants.DEFAULT_TOOLTIP_DURATION);
+
+ // these components must be accessed by all other components, hence need
+ // to be initialised before any other initialisation is done
+
+// windowTitleMap = new HashMap<String,String>();
+ }
+
+ private void initialisePerspectiveUI()
+ {
+ // set the loader icon to show that the perspective is loading
+ this.setLayout(new GridLayout(1,1));
+ this.add(new JLabel(ResourceManager.getImageIcon(ResourceManager.BAR_LOADER_ORANGE)));
+
+ new Thread("Initialise Service Catalogue Perspective UI")
+ {
+ public void run() {
+ // create all tabs prior to putting them inside the tabbed pane
+ jpBioCatalogueExplorationTab = new BioCatalogueExplorationTab();
+// jpServiceFilteringTab = new ServiceFilteringTab(pluginPerspectiveMainComponent, client, logger);
+// jpSearchTab = new SearchTab(pluginPerspectiveMainComponent, client, logger);
+// jpAboutTab = new BioCataloguePluginAbout(pluginPerspectiveMainComponent, client, logger);
+
+ // create main tabs
+// tpMainTabs = new JTabbedPane();
+// tpMainTabs.add("Explore BioCatalogue", jpBioCatalogueExplorationTab);
+// tpMainTabs.add("Search", jpSearchTab);
+// tpMainTabs.add("Filter Services", jpServiceFilteringTab);
+// tpMainTabs.add("About", jpAboutTab);
+
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run()
+ {
+ // add main tabs and the status bar into the perspective
+ pluginPerspectiveMainComponent.removeAll();
+ pluginPerspectiveMainComponent.setLayout(new BorderLayout());
+ pluginPerspectiveMainComponent.setBorder(new LineBorder(Color.BLACK));
+ pluginPerspectiveMainComponent.add(jpBioCatalogueExplorationTab, BorderLayout.CENTER);
+
+ // everything is prepared -- need to focus default component on the first tab
+ // (artificially generate change event on the tabbed pane to perform focus request)
+// tpMainTabs.setSelectedIndex(1);
+// tpMainTabs.addChangeListener(pluginPerspectiveMainComponent);
+// tpMainTabs.setSelectedIndex(0);
+ }
+ });
+ }
+ }.start();
+ }
+
+ /**
+ * Determines whether the specified tab is currently active in the main tabbed pane.
+ * @param strTabClassName Class name of the tab which is tested for being active.
+ * @return True if specified tab is currently active.
+ */
+/*
+ private boolean isTabActive(String strTabClassName)
+ {
+ if (tpMainTabs == null) return (false);
+
+ // if an anonymous thread within the main tab component class will call
+ // this method, we want to store the main tab's class, rather than
+ // the full class name of the anonymous worker thread
+ String strCurSelectedTabClassName = tpMainTabs.getSelectedComponent().getClass().getName();
+
+ // get the real class name to match
+ String strBaseClassName = Util.getBaseClassName(strTabClassName);
+
+ // compare the two class names
+ return (strBaseClassName.equals(strCurSelectedTabClassName));
+ }
+ */
+
+
+ /**
+ * This method "selects" the tab represented by the component provided as a parameter.
+ *
+ * @param c Component that represents one of the tabs in the main tabbed pane.
+ * If <code>c</code> is not found within the components of the tabbed pane, nothing will happen.
+ */
+/*
+ public void setTabActive(Component c)
+ {
+ try {
+ tpMainTabs.setSelectedComponent(c);
+ }
+ catch (IllegalArgumentException e) {
+ // do nothing, can't activate component which is not in the tabbed pane
+ }
+ }
+ */
+
+
+ /**
+ * Sets title of the main perspective window for a specified tab,
+ * thus supporting different window titles for different tabs;
+ * new title will only be displayed immediately if the specified tab.
+ *
+ * @param strTabClassName Class name of the tab, for which window title should be updated.
+ * @param strTitle New title to set.
+ */
+/*
+ public void setWindowTitle(String strTabClassName, String strTitle)
+ {
+ // if an anonymous thread within the main tab component class will call
+ // this method, we want to store the main tab's class, rather than
+ // the full class name of the anonymous worker thread
+ String strBaseClassName = Util.getBaseClassName(strTabClassName);
+
+ // store the new title for for the specified tab
+ windowTitleMap.put(strBaseClassName, strTitle);
+
+ // if the specified tab is active, update window title immediately
+ if (isTabActive(strBaseClassName)) displayWindowTitle(strBaseClassName);
+ }
+ */
+
+
+ /**
+ * Displays window title that corresponds to specified tab.
+ *
+ * @param strTabClassName Class name of the tab for which the window title is to be set.
+ */
+/*
+ public void displayWindowTitle(String strTabClassName)
+ {
+ // if an anonymous thread within the main tab component class will call
+ // this method, we want to store the main tab's class, rather than
+ // the full class name of the anonymous worker thread
+ String strBaseClassName = Util.getBaseClassName(strTabClassName);
+
+ if (windowTitleMap.containsKey(strBaseClassName)) {
+ // title for specified tab found - show it
+ // TODO - disabled until this info will be shown in the status bar
+ //this.setTitle(windowBaseTitle + " :: " + windowTitleMap.get(strBaseClassName));
+ }
+ else {
+ // tab not found - display standard title
+ // TODO - disabled until this info will be shown in the status bar
+ //this.setTitle(windowBaseTitle);
+ }
+ }
+ */
+
+ // *** Getters for various components ***
+
+ /**
+ * @return Reference to the component that represents the BioCatalogue Exploration
+ * tab in the BioCatalogue Perspective.
+ */
+ public BioCatalogueExplorationTab getBioCatalogueExplorationTab() {
+ return (this.jpBioCatalogueExplorationTab);
+ }
+
+ // *** Callbacks for ChangeListener interface ***
+
+/* public void stateChanged(ChangeEvent e)
+ {
+ if (e.getSource().equals(tpMainTabs)) {
+ // will get called when selected tab changes - need to focus default component in the active tab
+ // and also set a correct window title
+ if (tpMainTabs.getSelectedComponent() instanceof HasDefaultFocusCapability) {
+ ((HasDefaultFocusCapability)tpMainTabs.getSelectedComponent()).focusDefaultComponent();
+ this.displayWindowTitle(tpMainTabs.getSelectedComponent().getClass().getName());
+ }
+ }
+ }*/
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/MainComponentFactory.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/MainComponentFactory.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/MainComponentFactory.java
new file mode 100644
index 0000000..c213600
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/MainComponentFactory.java
@@ -0,0 +1,46 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue;
+
+import javax.swing.ImageIcon;
+
+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;
+
+/**
+ * @author Sergejs Aleksejevs
+ */
+public class MainComponentFactory implements UIComponentFactorySPI
+{
+ // this is to ensure that the whole perspective is not re-created
+ // each time it is being activated in Taverna, rather it will only
+ // happen once during the execution
+ private static MainComponent mainPerspectiveComponent = null;
+
+ public static MainComponent getSharedInstance()
+ {
+ // double-check on existence of the 'mainPerspectiveComponent' ensures
+ // that it is really created only once
+ if (mainPerspectiveComponent == null) {
+ synchronized(MainComponentFactory.class) {
+ if (mainPerspectiveComponent == null) {
+ mainPerspectiveComponent = new MainComponent();
+ }
+ }
+ }
+ return (mainPerspectiveComponent);
+ }
+
+ public UIComponentSPI getComponent() {
+ return (getSharedInstance());
+ }
+
+
+ public ImageIcon getIcon() {
+ return WorkbenchIcons.databaseIcon;
+ }
+
+ public String getName() {
+ return "Service Catalogue Main Component Factory";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/MainComponentShutdownHook.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/MainComponentShutdownHook.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/MainComponentShutdownHook.java
new file mode 100644
index 0000000..6c2e844
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/MainComponentShutdownHook.java
@@ -0,0 +1,49 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue;
+
+import com.thoughtworks.xstream.XStream;
+
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.config.BioCataloguePluginConfiguration;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.service_panel.BioCatalogueServiceProvider;
+import net.sf.taverna.t2.workbench.ShutdownSPI;
+
+/**
+ * @author Sergejs Aleksejevs
+ */
+public class MainComponentShutdownHook implements ShutdownSPI
+{
+ 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()
+ {
+ // Do not save service providers in BioCatalogue's conf file - they should be saved by Taverna together with
+ // other service providers
+
+// // store services that were added to the Service Panel - both REST and SOAP
+// XStream xstream = new XStream();
+//
+// BioCataloguePluginConfiguration configuration = BioCataloguePluginConfiguration.getInstance();
+//
+// configuration.setProperty(
+// BioCataloguePluginConfiguration.SOAP_OPERATIONS_IN_SERVICE_PANEL,
+// xstream.toXML(BioCatalogueServiceProvider.getRegisteredSOAPOperations()));
+// configuration.setProperty(
+// BioCataloguePluginConfiguration.REST_METHODS_IN_SERVICE_PANEL,
+// xstream.toXML(BioCatalogueServiceProvider.getRegisteredRESTMethods()));
+//
+// // save all the plugin's configuration
+// configuration.store();
+//
+//
+// // close API operation log
+// MainComponentFactory.getSharedInstance().getBioCatalogueClient().getAPILogWriter().close();
+//
+ return true;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/8c4b365e/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/TestJFrameForLocalLaunch.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/TestJFrameForLocalLaunch.java b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/TestJFrameForLocalLaunch.java
new file mode 100644
index 0000000..28a52c7
--- /dev/null
+++ b/taverna-workbench-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/TestJFrameForLocalLaunch.java
@@ -0,0 +1,68 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+
+import javax.swing.JFrame;
+
+import net.sf.taverna.biocatalogue.model.ResourceManager;
+
+
+/**
+ * @author Sergejs Aleksejevs
+ */
+public class TestJFrameForLocalLaunch extends JFrame implements ComponentListener
+{
+ private static final int DEFAULT_POSITION_X = 225;
+ private static final int DEFAULT_POSITION_Y = 150;
+
+ private static final int DEFAULT_WIDTH = 800;
+ private static final int DEFAULT_HEIGHT = 500;
+
+
+ private TestJFrameForLocalLaunch()
+ {
+ // set window title and icon
+ this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ this.setTitle("Service Catalogue API Demo"/* TODO - windowBaseTitle */);
+ this.setIconImage(ResourceManager.getImageIcon(ResourceManager.FAVICON).getImage());
+ this.addComponentListener(this);
+
+ // get content pane
+ Container contentPane = this.getContentPane();
+ contentPane.setLayout(new BorderLayout());
+
+ // put main tabs into the content pane
+ contentPane.add(MainComponentFactory.getSharedInstance(), BorderLayout.CENTER);
+
+ this.pack();
+ }
+
+
+ // *** Callbacks for ComponentListener interface ***
+
+ public void componentResized(ComponentEvent e) { /* do nothing */ }
+ public void componentMoved(ComponentEvent e) { /* do nothing */ }
+ public void componentHidden(ComponentEvent e) { /* do nothing */ }
+ public void componentShown(ComponentEvent e) {
+ this.setLocation(DEFAULT_POSITION_X, DEFAULT_POSITION_Y);
+ }
+
+
+ /**
+ * This is a simple test class for launching BioCatalogue perspective
+ * from outside Taverna. At some point it will be not usable anymore,
+ * when proper integration of BioCatalogue plugin is made.
+ *
+ * @author Sergejs Aleksejevs
+ */
+ public static void main(String[] args)
+ {
+ TestJFrameForLocalLaunch standaloneFrame = new TestJFrameForLocalLaunch();
+ standaloneFrame.setMinimumSize(new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT));
+ standaloneFrame.setVisible(true);
+ }
+}