http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/ServiceTreePanel.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/ServiceTreePanel.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/ServiceTreePanel.java
new file mode 100644
index 0000000..5d24027
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/ServiceTreePanel.java
@@ -0,0 +1,192 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel;
+
+import static java.awt.datatransfer.DataFlavor.javaJVMLocalObjectMimeType;
+import static javax.swing.SwingUtilities.invokeLater;
+
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.io.IOException;
+
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.TransferHandler;
+import javax.swing.event.TreeExpansionEvent;
+import javax.swing.event.TreeWillExpandListener;
+import javax.swing.tree.ExpandVetoException;
+import javax.swing.tree.TreeCellRenderer;
+import javax.swing.tree.TreePath;
+
+import org.apache.taverna.servicedescriptions.ServiceDescription;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionRegistry;
+import org.apache.taverna.ui.menu.MenuManager;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.selection.SelectionManager;
+import 
org.apache.taverna.workbench.ui.servicepanel.menu.AddServiceProviderMenu;
+import org.apache.taverna.workbench.ui.servicepanel.tree.Filter;
+import org.apache.taverna.workbench.ui.servicepanel.tree.FilterTreeModel;
+import org.apache.taverna.workbench.ui.servicepanel.tree.FilterTreeNode;
+import org.apache.taverna.workbench.ui.servicepanel.tree.TreePanel;
+
+import org.apache.log4j.Logger;
+
+import org.apache.taverna.commons.services.ServiceRegistry;
+
+public class ServiceTreePanel extends TreePanel {
+       private static final long serialVersionUID = 6611462684296693909L;
+       private static Logger logger = Logger.getLogger(ServiceTreePanel.class);
+
+       private final ServiceDescriptionRegistry serviceDescriptionRegistry;
+       private final EditManager editManager;
+       private final MenuManager menuManager;
+       private final SelectionManager selectionManager;
+       private final ServiceRegistry serviceRegistry;
+
+       public ServiceTreePanel(FilterTreeModel treeModel,
+                       ServiceDescriptionRegistry serviceDescriptionRegistry, 
EditManager editManager,
+                       MenuManager menuManager, SelectionManager 
selectionManager, ServiceRegistry serviceRegistry) {
+               super(treeModel);
+               this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+               this.editManager = editManager;
+               this.menuManager = menuManager;
+               this.selectionManager = selectionManager;
+               this.serviceRegistry = serviceRegistry;
+               initialize();
+       }
+
+       @Override
+       protected void initialize() {
+               super.initialize();
+               tree.setDragEnabled(true);
+               tree.setTransferHandler(new ServiceTransferHandler());
+               tree.addTreeWillExpandListener(new AvoidRootCollapse());
+               tree.expandRow(0);
+
+               invokeLater(new Runnable() {
+                       @Override
+                       public void run() {
+                               tree.addMouseListener(new 
ServiceTreeClickListener(tree,
+                                               ServiceTreePanel.this, 
serviceDescriptionRegistry,
+                                               editManager, menuManager, 
selectionManager,
+                                               serviceRegistry));
+                       }
+               });
+       }
+
+       @Override
+       protected Component createExtraComponent() {
+               JComponent buttonPanel = new JPanel(new FlowLayout());
+               buttonPanel.add(new 
AddServiceProviderMenu(serviceDescriptionRegistry));
+               // buttonPanel.add(new JButton(new 
RefreshProviderRegistryAction()));
+               return buttonPanel;
+       }
+
+       @Override
+       public Filter createFilter(String text) {
+               return new ServiceFilter(text, filterTreeModel.getRoot());
+       }
+
+       @Override
+       protected TreeCellRenderer createCellRenderer() {
+               return new ServiceTreeCellRenderer();
+       }
+
+       public static class AvoidRootCollapse implements TreeWillExpandListener 
{
+               @Override
+               public void treeWillCollapse(TreeExpansionEvent event) throws 
ExpandVetoException {
+                       if (event.getPath().getPathCount() == 1)
+                               throw new ExpandVetoException(event, "Can't 
collapse root");
+               }
+
+               @Override
+               public void treeWillExpand(TreeExpansionEvent event) throws 
ExpandVetoException {
+               }
+       }
+
+       private final class ServiceTransferHandler extends TransferHandler {
+               private static final long serialVersionUID = 
4347965626386951176L;
+
+               /**
+                * Triggered when a node ie. an {@link ActivityItem} is dragged 
out of
+                * the tree. Figures out what node it is being dragged and then 
starts a
+                * drag action with it
+                */
+               @Override
+               protected Transferable createTransferable(JComponent c) {
+                       TreePath selectionPath = tree.getSelectionPath();
+                       if (selectionPath == null)
+                               return null;
+                       FilterTreeNode lastPathComponent = (FilterTreeNode) 
selectionPath
+                                       .getLastPathComponent();
+                       if (!(lastPathComponent.getUserObject() instanceof 
ServiceDescription))
+                               return null;
+                       final ServiceDescription serviceDescription = 
(ServiceDescription) lastPathComponent
+                                       .getUserObject();
+
+                       return new Transferable() {
+                               @Override
+                               public Object getTransferData(DataFlavor flavor)
+                                               throws 
UnsupportedFlavorException, IOException {
+                                       return serviceDescription;
+                               }
+
+                               @Override
+                               public DataFlavor[] getTransferDataFlavors() {
+                                       DataFlavor[] flavors = new 
DataFlavor[1];
+                                       try {
+                                               flavors[0] = 
getFlavorForClass(ServiceDescription.class);
+                                       } catch (ClassNotFoundException e) {
+                                               logger.error("Error casting 
Dataflavor", e);
+                                               flavors[0] = null;
+                                       }
+                                       return flavors;
+                               }
+
+                               @Override
+                               public boolean isDataFlavorSupported(DataFlavor 
flavor) {
+                                       DataFlavor thisFlavor = null;
+                                       try {
+                                               thisFlavor = 
getFlavorForClass(ServiceDescription.class);
+                                       } catch (ClassNotFoundException e) {
+                                               logger.error("Error casting 
Dataflavor", e);
+                                       }
+                                       return flavor.equals(thisFlavor);
+                               }
+                       };
+               }
+
+               @Override
+               public int getSourceActions(JComponent c) {
+                       return COPY_OR_MOVE;
+               }
+       }
+
+       private DataFlavor getFlavorForClass(Class<?> clazz)
+                       throws ClassNotFoundException {
+               String name = clazz.getName();
+               return new DataFlavor(javaJVMLocalObjectMimeType + ";class=" + 
clazz,
+                               name.substring(name.lastIndexOf('.') + 1),
+                               clazz.getClassLoader());
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/AddServiceProviderAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/AddServiceProviderAction.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/AddServiceProviderAction.java
new file mode 100644
index 0000000..ae1be4e
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/AddServiceProviderAction.java
@@ -0,0 +1,255 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.actions;
+
+import static java.awt.BorderLayout.CENTER;
+import static java.awt.BorderLayout.NORTH;
+import static java.awt.BorderLayout.SOUTH;
+import static java.awt.BorderLayout.WEST;
+import static java.awt.event.KeyEvent.VK_ENTER;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static org.apache.taverna.workbench.MainWindow.getMainWindow;
+import static 
org.apache.commons.beanutils.PropertyUtils.getPropertyDescriptors;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.beans.PropertyDescriptor;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import org.apache.taverna.lang.observer.Observable;
+import org.apache.taverna.lang.observer.Observer;
+import org.apache.taverna.lang.uibuilder.UIBuilder;
+import org.apache.taverna.servicedescriptions.ConfigurableServiceProvider;
+import org.apache.taverna.servicedescriptions.CustomizedConfigurePanelProvider;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionRegistry;
+import 
org.apache.taverna.servicedescriptions.CustomizedConfigurePanelProvider.CustomizedConfigureCallBack;
+import org.apache.taverna.servicedescriptions.events.ProviderErrorNotification;
+import 
org.apache.taverna.servicedescriptions.events.ServiceDescriptionProvidedEvent;
+import 
org.apache.taverna.servicedescriptions.events.ServiceDescriptionRegistryEvent;
+import org.apache.taverna.workbench.helper.HelpEnabledDialog;
+
+import org.apache.log4j.Logger;
+
+import org.apache.taverna.scufl2.api.configurations.Configuration;
+
+/**
+ * Action for adding a service provider
+ * 
+ * @author Stian Soiland-Reyes
+ * @author Alan R Williams
+ */
+@SuppressWarnings("serial")
+public class AddServiceProviderAction extends AbstractAction {
+       private static Logger logger = 
getLogger(AddServiceProviderAction.class);
+
+       // protected static Dimension DIALOG_SIZE = new Dimension(400, 300);
+
+       private ServiceDescriptionRegistry serviceDescriptionRegistry;
+
+       private final ConfigurableServiceProvider confProvider;
+       private final Component owner;
+
+       public AddServiceProviderAction(ConfigurableServiceProvider 
confProvider,
+                       Component owner) {
+               super(confProvider.getName() + "...", confProvider.getIcon());
+               this.confProvider = confProvider;
+               this.owner = owner;
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               if (confProvider instanceof CustomizedConfigurePanelProvider) {
+                       final CustomizedConfigurePanelProvider provider = 
(CustomizedConfigurePanelProvider) confProvider;
+                       provider.createCustomizedConfigurePanel(new 
CustomizedConfigureCallBack() {
+                               @Override
+                               public Configuration getTemplateConfig() {
+                                       return (Configuration) 
provider.getConfiguration().clone();
+                               }
+
+                               @Override
+                               public ServiceDescriptionRegistry 
getServiceDescriptionRegistry() {
+                                       return 
AddServiceProviderAction.this.getServiceDescriptionRegistry();
+                               }
+
+                               @Override
+                               public void 
newProviderConfiguration(Configuration providerConfig) {
+                                       addNewProvider(providerConfig);
+                               }
+                       });
+                       return;
+               }
+
+               Configuration configuration;
+               try {
+                       configuration = (Configuration) 
confProvider.getConfiguration().clone();
+               } catch (Exception ex) {
+                       throw new RuntimeException("Can't clone configuration 
bean", ex);
+               }
+               JPanel buildEditor = buildEditor(configuration);
+               String title = "Add " + confProvider.getName();
+               JDialog dialog = new HelpEnabledDialog(getMainWindow(), title, 
true, null);
+               JPanel iconPanel = new JPanel();
+               iconPanel.add(new JLabel(confProvider.getIcon()), NORTH);
+               dialog.add(iconPanel, WEST);
+               dialog.add(buildEditor, CENTER);
+               JPanel buttonPanel = new JPanel(new BorderLayout());
+               final AddProviderAction addProviderAction = new 
AddProviderAction(configuration,
+                               dialog);
+               JButton addProviderButton = new JButton(addProviderAction);
+               buttonPanel.add(addProviderButton, WEST);
+               
+               dialog.add(buttonPanel, SOUTH);
+           // When user presses "Return" key fire the action on the "Add" 
button
+               addProviderButton.addKeyListener(new KeyAdapter() {
+                       @Override
+                       public void keyPressed(KeyEvent evt) {
+                               if (evt.getKeyCode() == VK_ENTER)
+                                       addProviderAction.actionPerformed(null);
+                       }
+               });
+               dialog.getRootPane().setDefaultButton(addProviderButton);
+               
+               // dialog.setSize(buttonPanel.getPreferredSize());
+               dialog.pack();
+               dialog.setLocationRelativeTo(owner);
+//             dialog.setLocation(owner.getLocationOnScreen().x + 
owner.getWidth(),
+//                             owner.getLocationOnScreen().y + 
owner.getHeight());
+               dialog.setVisible(true);
+       }
+
+       protected void addNewProvider(Configuration configurationBean) {
+               ConfigurableServiceProvider cloned = 
(ConfigurableServiceProvider) confProvider
+                               .newInstance();
+               try {
+                       cloned.configure(configurationBean);
+                       getServiceDescriptionRegistry().addObserver(
+                                       new 
CheckAddedCorrectlyObserver(cloned));
+                       
getServiceDescriptionRegistry().addServiceDescriptionProvider(
+                                       cloned);
+               } catch (Exception ex) {
+                       logger.warn("Can't configure provider " + cloned + " 
using "
+                                       + configurationBean, ex);
+                       showMessageDialog(owner, "Can't configure service 
provider "
+                                       + cloned.getName(), "Can't add service 
provider",
+                                       ERROR_MESSAGE);
+               }
+       }
+
+       private PropertyDescriptor[] getProperties(Configuration configuration) 
{
+               // FIXME This is *so* wrong!
+               try {
+                       return getPropertyDescriptors(configuration);
+               } catch (Exception ex) {
+                       throw new RuntimeException("Can't inspect configuration 
bean", ex);
+               }
+       }
+
+       // TODO This is probably not right
+       protected JPanel buildEditor(Configuration configuration) {
+               List<String> uiBuilderConfig = new ArrayList<>();
+               int lastPreferred = 0;
+               for (PropertyDescriptor property : 
getProperties(configuration)) {
+                       if (property.isHidden() || property.isExpert())
+                               // TODO: Add support for expert properties
+                               continue;
+                       String propertySpec = property.getName() + ":name="
+                                       + property.getDisplayName();
+                       if (property.isPreferred())
+                               // Add it to the front
+                               uiBuilderConfig.add(lastPreferred++, 
propertySpec);
+                       else
+                               uiBuilderConfig.add(propertySpec);
+               }
+
+               return UIBuilder.buildEditor(configuration, uiBuilderConfig
+                               .toArray(new String[0]));
+       }
+
+       public void setServiceDescriptionRegistry(
+                       ServiceDescriptionRegistry serviceDescriptionRegistry) {
+               this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+       }
+
+       public ServiceDescriptionRegistry getServiceDescriptionRegistry() {
+               return serviceDescriptionRegistry;
+       }
+
+       public class AddProviderAction extends AbstractAction {
+               private final Configuration configurationBean;
+               private final JDialog dialog;
+
+               private AddProviderAction(Configuration configurationBean, 
JDialog dialog) {
+                       super("Add");
+                       this.configurationBean = configurationBean;
+                       this.dialog = dialog;
+               }
+
+               @Override
+               public void actionPerformed(ActionEvent e) {
+                       addNewProvider(configurationBean);
+                       dialog.setVisible(false);
+               }
+       }
+
+       public class CheckAddedCorrectlyObserver implements
+                       Observer<ServiceDescriptionRegistryEvent> {
+               private final ConfigurableServiceProvider provider;
+
+               private CheckAddedCorrectlyObserver(ConfigurableServiceProvider 
provider) {
+                       this.provider = provider;
+               }
+
+               @Override
+               public void notify(Observable<ServiceDescriptionRegistryEvent> 
sender,
+                               ServiceDescriptionRegistryEvent message) throws 
Exception {
+                       if (message instanceof ProviderErrorNotification)
+                               notify((ProviderErrorNotification) message);
+                       else if (message instanceof 
ServiceDescriptionProvidedEvent)
+                               notify((ServiceDescriptionProvidedEvent) 
message);
+               }
+
+               private void notify(ServiceDescriptionProvidedEvent 
providedMsg) {
+                       if (providedMsg.getProvider() == provider)
+                               
getServiceDescriptionRegistry().removeObserver(this);
+               }
+
+               private void notify(ProviderErrorNotification errorMsg) {
+                       if (errorMsg.getProvider() != provider)
+                               return;
+                       getServiceDescriptionRegistry().removeObserver(this);
+                       
getServiceDescriptionRegistry().removeServiceDescriptionProvider(
+                                       provider);
+//                     showMessageDialog(owner, errorMsg.getMessage(),
+//                                     "Can't add provider " + provider, 
ERROR_MESSAGE);
+               }
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/ExportServiceDescriptionsAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/ExportServiceDescriptionsAction.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/ExportServiceDescriptionsAction.java
new file mode 100644
index 0000000..2183854
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/ExportServiceDescriptionsAction.java
@@ -0,0 +1,154 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.actions;
+
+import static javax.swing.JFileChooser.APPROVE_OPTION;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.NO_OPTION;
+import static javax.swing.JOptionPane.YES_NO_CANCEL_OPTION;
+import static javax.swing.JOptionPane.YES_OPTION;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static javax.swing.JOptionPane.showMessageDialog;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.util.prefs.Preferences;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.filechooser.FileFilter;
+
+import org.apache.taverna.servicedescriptions.ServiceDescriptionRegistry;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Action to export the current service descritpions from the Service
+ * Registry to an xml file.
+ *
+ * @author Alex Nenadic
+ */
+//FIXME this file assumes we're writing out as XML
+@SuppressWarnings("serial")
+public class ExportServiceDescriptionsAction extends AbstractAction {
+       private static final String EXTENSION = ".xml";
+       private static final String EXPORT_SERVICES = "Export services to file";
+       private static final String SERVICE_EXPORT_DIR_PROPERTY = 
"serviceExportDir";
+       private Logger logger = 
Logger.getLogger(ExportServiceDescriptionsAction.class);
+       private final ServiceDescriptionRegistry serviceDescriptionRegistry;
+
+       public ExportServiceDescriptionsAction(ServiceDescriptionRegistry 
serviceDescriptionRegistry) {
+               super(EXPORT_SERVICES);
+               this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+       }
+
+       public static final boolean INHIBIT = true;
+
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               JComponent parentComponent = null;
+               if (e.getSource() instanceof JComponent)
+                       parentComponent = (JComponent) e.getSource();
+
+               if (INHIBIT) {
+                       showMessageDialog(parentComponent,
+                                       "Operation not currently working 
correctly",
+                                       "Not Implemented", ERROR_MESSAGE);
+                       return;
+               }
+
+               JFileChooser fileChooser = new JFileChooser();
+               Preferences prefs = Preferences.userNodeForPackage(getClass());
+               String curDir = prefs.get(SERVICE_EXPORT_DIR_PROPERTY,
+                               System.getProperty("user.home"));
+               fileChooser.setDialogTitle("Select file to export services to");
+
+               fileChooser.setFileFilter(new FileFilter() {
+                       @Override
+                       public boolean accept(File f) {
+                               return f.isDirectory()
+                                               || 
f.getName().toLowerCase().endsWith(EXTENSION);
+                       }
+
+                       @Override
+                       public String getDescription() {
+                               return ".xml files";
+                       }
+               });
+
+               fileChooser.setCurrentDirectory(new File(curDir));
+
+               boolean tryAgain = true;
+               while (tryAgain) {
+                       tryAgain = false;
+                       int returnVal = 
fileChooser.showSaveDialog(parentComponent);
+                       if (returnVal == APPROVE_OPTION) {
+                               prefs.put(SERVICE_EXPORT_DIR_PROPERTY, 
fileChooser.getCurrentDirectory()
+                                               .toString());
+                               File file = fileChooser.getSelectedFile();
+                               if 
(!file.getName().toLowerCase().endsWith(EXTENSION)) {
+                                       String newName = file.getName() + 
EXTENSION;
+                                       file = new File(file.getParentFile(), 
newName);
+                               }
+
+                               try {
+                                       if (file.exists()) {
+                                               String msg = "Are you sure you 
want to overwrite existing file "
+                                                               + file + "?";
+                                               int ret = 
showConfirmDialog(parentComponent, msg,
+                                                               "File already 
exists", YES_NO_CANCEL_OPTION);
+                                               if (ret == NO_OPTION) {
+                                                       tryAgain = true;
+                                                       continue;
+                                               } else if (ret != YES_OPTION) {
+                                                       logger.info("Service 
descriptions export: aborted overwrite of "
+                                                                       + 
file.getAbsolutePath());
+                                                       break;
+                                               }
+                                       }
+                                       exportServiceDescriptions(file);
+                                       break;
+                               } catch (Exception ex) {
+                                       logger.error("Service descriptions 
export: failed to export services to "
+                                                       + 
file.getAbsolutePath(), ex);
+                                       showMessageDialog(
+                                                       parentComponent,
+                                                       "Failed to export 
services to "
+                                                                       + 
file.getAbsolutePath(), "Error",
+                                                       ERROR_MESSAGE);
+                                       break;
+                               }
+                       }
+               }
+
+               if (parentComponent instanceof JButton)
+                       // lose the focus from the button after performing the 
action
+                       parentComponent.requestFocusInWindow();
+       }
+
+       private void exportServiceDescriptions(File file) {
+               // TODO: Open in separate thread to avoid hanging UI
+               
serviceDescriptionRegistry.exportCurrentServiceDescriptions(file);
+               logger.info("Service descriptions export: saved to file "
+                               + file.getAbsolutePath());
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/ImportServiceDescriptionsFromFileAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/ImportServiceDescriptionsFromFileAction.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/ImportServiceDescriptionsFromFileAction.java
new file mode 100644
index 0000000..218df0f
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/ImportServiceDescriptionsFromFileAction.java
@@ -0,0 +1,157 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.actions;
+
+import static javax.swing.JFileChooser.APPROVE_OPTION;
+import static javax.swing.JOptionPane.CANCEL_OPTION;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.QUESTION_MESSAGE;
+import static javax.swing.JOptionPane.YES_NO_CANCEL_OPTION;
+import static javax.swing.JOptionPane.YES_OPTION;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static javax.swing.JOptionPane.showOptionDialog;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.util.HashSet;
+import java.util.prefs.Preferences;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.filechooser.FileFilter;
+
+import org.apache.log4j.Logger;
+
+import org.apache.taverna.servicedescriptions.ConfigurableServiceProvider;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionProvider;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionRegistry;
+
+/**
+ * Action to import a list of service descriptions from an xml file
+ * into the Service Registry. Users have an option to completely
+ * replace the current services or just add the ones from the file
+ * to the current services.
+ *
+ * @author Alex Nenadic
+ */
+//FIXME this file assumes we're writing out as XML
+@SuppressWarnings("serial")
+public class ImportServiceDescriptionsFromFileAction extends AbstractAction{
+       private static final String EXTENSION = ".xml";
+       private static final String IMPORT_SERVICES = "Import services from 
file";
+       private static final String SERVICE_IMPORT_DIR_PROPERTY = 
"serviceImportDir";
+       private static final Logger logger = 
Logger.getLogger(ExportServiceDescriptionsAction.class);
+
+       private final ServiceDescriptionRegistry serviceDescriptionRegistry;
+
+       public ImportServiceDescriptionsFromFileAction(
+                       ServiceDescriptionRegistry serviceDescriptionRegistry) {
+               super(IMPORT_SERVICES);
+               this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+       }
+
+       private static final Object[] CHOICES = { "Add to current services",
+                       "Replace current services", "Cancel" };
+
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               JComponent parentComponent = null;
+               if (e.getSource() instanceof JComponent)
+                       parentComponent = (JComponent) e.getSource();
+
+               if (ExportServiceDescriptionsAction.INHIBIT) {
+                       showMessageDialog(parentComponent,
+                                       "Operation not currently working 
correctly",
+                                       "Not Implemented", ERROR_MESSAGE);
+                       return;
+               }
+
+               int choice = showOptionDialog(
+                               parentComponent,
+                               "Do you want to add the imported services to 
the current ones or replace the current ones?",
+                               "Import services", YES_NO_CANCEL_OPTION, 
QUESTION_MESSAGE,
+                               null, CHOICES, CHOICES[0]);
+
+               if (choice != CANCEL_OPTION) {
+                       JFileChooser fileChooser = new JFileChooser();
+                       Preferences prefs = 
Preferences.userNodeForPackage(getClass());
+                       String curDir = prefs.get(SERVICE_IMPORT_DIR_PROPERTY, 
System.getProperty("user.home"));
+
+                       fileChooser.setDialogTitle("Select file to import 
services from");
+
+                       fileChooser.setFileFilter(new FileFilter() {
+                               @Override
+                               public boolean accept(File f) {
+                                       return f.isDirectory()
+                                                       || 
f.getName().toLowerCase().endsWith(EXTENSION);
+                               }
+
+                               @Override
+                               public String getDescription() {
+                                       return EXTENSION + " files";
+                               }
+                       });
+
+                       fileChooser.setCurrentDirectory(new File(curDir));
+
+                       if (fileChooser.showOpenDialog(parentComponent) == 
APPROVE_OPTION) {
+                               prefs.put(SERVICE_IMPORT_DIR_PROPERTY, 
fileChooser
+                                               
.getCurrentDirectory().toString());
+                               File file = fileChooser.getSelectedFile();
+
+                               try {
+                                       // Did user want to replace or add 
services?
+                                       importServices(file, choice == 
YES_OPTION);
+                               } catch (Exception ex) {
+                                       logger.error(
+                                                       "Service descriptions 
import: failed to import services from "
+                                                                       + 
file.getAbsolutePath(), ex);
+                                       showMessageDialog(parentComponent,
+                                                       "Failed to import 
services from " + file.getAbsolutePath(), "Error",
+                                                       ERROR_MESSAGE);
+                               }
+                       }
+               }
+
+               if (parentComponent instanceof JButton)
+                       // lose the focus from the button after performing the 
action
+                       parentComponent.requestFocusInWindow();
+       }
+
+       private void importServices(final File file, final boolean addToCurrent)
+                       throws Exception {
+               // TODO: Open in separate thread to avoid hanging UI
+
+               if (!addToCurrent)
+                       for (ServiceDescriptionProvider provider : new 
HashSet<>(
+                                       
serviceDescriptionRegistry.getServiceDescriptionProviders()))
+                               // remove all configurable service providers
+                               if (provider instanceof 
ConfigurableServiceProvider)
+                                       serviceDescriptionRegistry
+                                                       
.removeServiceDescriptionProvider(provider);
+
+               // import all providers from the file
+               serviceDescriptionRegistry.loadServiceProviders(file);
+               serviceDescriptionRegistry.saveServiceDescriptions();
+       }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/ImportServiceDescriptionsFromURLAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/ImportServiceDescriptionsFromURLAction.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/ImportServiceDescriptionsFromURLAction.java
new file mode 100644
index 0000000..af51ce1
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/ImportServiceDescriptionsFromURLAction.java
@@ -0,0 +1,128 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.actions;
+
+import static javax.swing.JOptionPane.CANCEL_OPTION;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.QUESTION_MESSAGE;
+import static javax.swing.JOptionPane.YES_NO_CANCEL_OPTION;
+import static javax.swing.JOptionPane.YES_OPTION;
+import static javax.swing.JOptionPane.showInputDialog;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static javax.swing.JOptionPane.showOptionDialog;
+
+import java.awt.event.ActionEvent;
+import java.net.URL;
+import java.util.HashSet;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+
+import org.apache.taverna.servicedescriptions.ConfigurableServiceProvider;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionProvider;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionRegistry;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Action to import a list of service descriptions from an URL pointing
+ * to an xml file into the Service Registry. Users have an option to
+ * completely replace the current services or just add the ones from the
+ * file to the current services.
+ *
+ * @author Alex Nenadic
+ */
+@SuppressWarnings("serial")
+public class ImportServiceDescriptionsFromURLAction extends AbstractAction{
+       private static final String IMPORT_SERVICES_FROM_URL = "Import services 
from URL";
+       private static final Logger logger = 
Logger.getLogger(ExportServiceDescriptionsAction.class);
+
+       private final ServiceDescriptionRegistry serviceDescriptionRegistry;
+
+       public 
ImportServiceDescriptionsFromURLAction(ServiceDescriptionRegistry 
serviceDescriptionRegistry) {
+               super(IMPORT_SERVICES_FROM_URL);
+               this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+       }
+
+       private static final Object[] CHOICES = { "Add to current services",
+                       "Replace current services", "Cancel" };
+
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               JComponent parentComponent = null;
+               if (e.getSource() instanceof JComponent)
+                       parentComponent = (JComponent) e.getSource();
+
+               if (ExportServiceDescriptionsAction.INHIBIT) {
+                       showMessageDialog(parentComponent,
+                                       "Operation not currently working 
correctly",
+                                       "Not Implemented", ERROR_MESSAGE);
+                       return;
+               }
+
+               int choice = showOptionDialog(
+                               parentComponent,
+                               "Do you want to add the imported services to 
the current ones or replace the current ones?",
+                               "Import services", YES_NO_CANCEL_OPTION, 
QUESTION_MESSAGE,
+                               null, CHOICES, CHOICES[0]);
+
+               if (choice != CANCEL_OPTION) {
+                       final String urlString = (String) 
showInputDialog(parentComponent,
+                                       "Enter the URL of the service 
descriptions file to import",
+                                       "Service Descriptions URL", 
QUESTION_MESSAGE, null, null,
+                                       "http://";);
+                       try {
+                               if (urlString != null && !urlString.isEmpty())
+                                       // Did user want to replace or add 
services?
+                                       importServices(urlString, choice == 
YES_OPTION);
+                       } catch (Exception ex) {
+                               logger.error(
+                                               "Service descriptions import: 
failed to import services from "
+                                                               + urlString, 
ex);
+                               showMessageDialog(parentComponent,
+                                               "Failed to import services from 
" + urlString, "Error",
+                                               ERROR_MESSAGE);
+                       }
+               }
+
+               if (parentComponent instanceof JButton)
+                       // lose the focus from the button after performing the 
action
+                       parentComponent.requestFocusInWindow();
+       }
+
+       private void importServices(final String urlString, final boolean 
addToCurrent)
+                       throws Exception {
+               // TODO: Open in separate thread to avoid hanging UI
+               URL url = new URL(urlString);
+
+               if (!addToCurrent)
+                       for (ServiceDescriptionProvider provider : new 
HashSet<>(
+                                       
serviceDescriptionRegistry.getServiceDescriptionProviders()))
+                               // remove all configurable service providers
+                               if (provider instanceof 
ConfigurableServiceProvider)
+                                       serviceDescriptionRegistry
+                                                       
.removeServiceDescriptionProvider(provider);
+
+               // import all providers from the URL
+               serviceDescriptionRegistry.loadServiceProviders(url);
+               serviceDescriptionRegistry.saveServiceDescriptions();
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RefreshProviderRegistryAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RefreshProviderRegistryAction.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RefreshProviderRegistryAction.java
new file mode 100644
index 0000000..5cd6ddb
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RefreshProviderRegistryAction.java
@@ -0,0 +1,51 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.actions;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import org.apache.taverna.servicedescriptions.ServiceDescriptionRegistry;
+
+/**
+ * Action for refreshing the service provider registry.
+ * <p>
+ * This would typically re-parse WSDLs, etc.
+ * 
+ * @see ServiceDescriptionRegistry#refresh()
+ * @author Stian Soiland-Reyes
+ */
+@SuppressWarnings("serial")
+public class RefreshProviderRegistryAction extends AbstractAction {
+       private static final String REFRESH = "Reload services";
+       private final ServiceDescriptionRegistry serviceDescriptionRegistry;
+
+       public RefreshProviderRegistryAction(
+                       ServiceDescriptionRegistry serviceDescriptionRegistry) {
+               super(REFRESH);
+               this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               serviceDescriptionRegistry.refresh();
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RemoveDefaultServicesAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RemoveDefaultServicesAction.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RemoveDefaultServicesAction.java
new file mode 100644
index 0000000..0460004
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RemoveDefaultServicesAction.java
@@ -0,0 +1,50 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.actions;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import org.apache.taverna.servicedescriptions.ConfigurableServiceProvider;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionProvider;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionRegistry;
+
+@SuppressWarnings("serial")
+public class RemoveDefaultServicesAction extends AbstractAction {
+       private final ServiceDescriptionRegistry serviceDescriptionRegistry;
+
+       public RemoveDefaultServicesAction(
+                       ServiceDescriptionRegistry serviceDescriptionRegistry) {
+               super("Remove default service providers");
+               this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               for (ServiceDescriptionProvider provider : 
serviceDescriptionRegistry
+                               .getDefaultServiceDescriptionProviders()) {
+                       if (!(provider instanceof ConfigurableServiceProvider))
+                               continue;
+                       serviceDescriptionRegistry
+                                       
.removeServiceDescriptionProvider(provider);
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RemoveUserServicesAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RemoveUserServicesAction.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RemoveUserServicesAction.java
new file mode 100644
index 0000000..43a43ba
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RemoveUserServicesAction.java
@@ -0,0 +1,58 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.actions;
+
+import static javax.swing.JOptionPane.YES_NO_OPTION;
+import static javax.swing.JOptionPane.YES_OPTION;
+import static javax.swing.JOptionPane.showConfirmDialog;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JLabel;
+
+import org.apache.taverna.servicedescriptions.ServiceDescriptionProvider;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionRegistry;
+
+@SuppressWarnings("serial")
+public class RemoveUserServicesAction extends AbstractAction {
+       private static final String CONFIRM_MESSAGE = "You are about to remove 
all services you have added. <br>"
+                       + "Are you <b>really</b> sure you want to do this?";
+       private final ServiceDescriptionRegistry serviceDescriptionRegistry;
+
+       public RemoveUserServicesAction(
+                       ServiceDescriptionRegistry serviceDescriptionRegistry) {
+               super("Remove all user added service providers");
+               this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               int option = showConfirmDialog(null, new JLabel("<html><body>"
+                               + CONFIRM_MESSAGE + "</body></html>"),
+                               "Confirm service deletion", YES_NO_OPTION);
+
+               if (option == YES_OPTION)
+                       for (ServiceDescriptionProvider provider : 
serviceDescriptionRegistry
+                                       .getUserAddedServiceProviders())
+                               serviceDescriptionRegistry
+                                               
.removeServiceDescriptionProvider(provider);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RestoreDefaultServicesAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RestoreDefaultServicesAction.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RestoreDefaultServicesAction.java
new file mode 100644
index 0000000..e7a5f46
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/actions/RestoreDefaultServicesAction.java
@@ -0,0 +1,49 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.actions;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import org.apache.taverna.servicedescriptions.ConfigurableServiceProvider;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionProvider;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionRegistry;
+
+@SuppressWarnings("serial")
+public class RestoreDefaultServicesAction extends AbstractAction {
+       private final ServiceDescriptionRegistry serviceDescriptionRegistry;
+
+       public RestoreDefaultServicesAction(
+                       ServiceDescriptionRegistry serviceDescriptionRegistry) {
+               super("Restore default service providers");
+               this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               for (ServiceDescriptionProvider provider : 
serviceDescriptionRegistry
+                               .getDefaultServiceDescriptionProviders()) {
+                       if (!(provider instanceof ConfigurableServiceProvider))
+                               continue;
+                       
serviceDescriptionRegistry.addServiceDescriptionProvider(provider);
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/config/ServiceDescriptionConfigPanel.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/config/ServiceDescriptionConfigPanel.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/config/ServiceDescriptionConfigPanel.java
new file mode 100644
index 0000000..61a7d1a
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/config/ServiceDescriptionConfigPanel.java
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (C) 2007 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 org.apache.taverna.workbench.ui.servicepanel.config;
+
+import static java.awt.GridBagConstraints.HORIZONTAL;
+import static java.awt.GridBagConstraints.NONE;
+import static java.awt.GridBagConstraints.WEST;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.border.EmptyBorder;
+
+import org.apache.taverna.servicedescriptions.ConfigurableServiceProvider;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionProvider;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionRegistry;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionsConfiguration;
+import org.apache.taverna.workbench.helper.Helper;
+
+@SuppressWarnings("serial")
+public class ServiceDescriptionConfigPanel extends JPanel {
+       private static final String REMOVE_PERMANENTLY = "Allow permanent 
removal of default service providers";
+       private static final String INCLUDE_DEFAULTS = "Include default service 
providers";
+
+       private final ServiceDescriptionsConfiguration config;
+       private JCheckBox includeDefaults;
+       private JCheckBox removePermanently;
+       private final ServiceDescriptionRegistry serviceDescRegistry;
+
+       public ServiceDescriptionConfigPanel(ServiceDescriptionsConfiguration 
config,
+                       ServiceDescriptionRegistry serviceDescRegistry) {
+               super(new GridBagLayout());
+               this.config = config;
+               this.serviceDescRegistry = serviceDescRegistry;
+               initialize();
+       }
+
+       private void initialize() {
+               removeAll();
+
+               GridBagConstraints gbc = new GridBagConstraints();
+
+               // Title describing what kind of settings we are configuring 
here
+               JTextArea descriptionText = new JTextArea(
+                               "Configure behaviour of default service 
providers in Service Panel");
+        descriptionText.setLineWrap(true);
+        descriptionText.setWrapStyleWord(true);
+        descriptionText.setEditable(false);
+        descriptionText.setFocusable(false);
+        descriptionText.setBorder(new EmptyBorder(10, 10, 10, 10));
+               gbc.gridx = 0;
+               gbc.gridy = 0;
+               gbc.anchor = WEST;
+               gbc.fill = HORIZONTAL;
+               add(descriptionText, gbc);
+
+               includeDefaults = new JCheckBox(INCLUDE_DEFAULTS);
+               gbc.gridx = 0;
+               gbc.gridy = 1;
+               gbc.anchor = WEST;
+               gbc.fill = NONE;
+        gbc.insets = new Insets(10, 0, 0, 0);
+               add(includeDefaults, gbc);
+
+               removePermanently = new JCheckBox(REMOVE_PERMANENTLY);
+               gbc.gridx = 0;
+               gbc.gridy = 2;
+        gbc.insets = new Insets(0, 0, 0, 0);
+               add(removePermanently, gbc);
+
+               // Filler
+               gbc.gridx = 0;
+               gbc.gridy = 3;
+               gbc.weighty = 1;
+               gbc.weightx = 1;
+               gbc.fill = GridBagConstraints.BOTH;
+        gbc.insets = new Insets(10, 0, 0, 0);
+               add(createButtonPanel(), gbc);
+
+               setFields(config);
+       }
+
+       /**
+        * Create the panel to contain the buttons
+        *
+        * @return
+        */
+       private JPanel createButtonPanel() {
+               final JPanel panel = new JPanel();
+
+               /**
+                * The helpButton shows help about the current component
+                */
+               JButton helpButton = new JButton(new AbstractAction("Help") {
+                       @Override
+                       public void actionPerformed(ActionEvent arg0) {
+                               Helper.showHelp(panel);
+                       }
+               });
+               panel.add(helpButton);
+
+               /**
+                * The resetButton changes the property values shown to those
+                * corresponding to the configuration currently applied.
+                */
+               JButton resetButton = new JButton(new AbstractAction("Reset") {
+                       @Override
+                       public void actionPerformed(ActionEvent arg0) {
+                               setFields(config);
+                       }
+               });
+               panel.add(resetButton);
+
+               /**
+                * The applyButton applies the shown field values to the
+                * {@link HttpProxyConfiguration} and saves them for future.
+                */
+               JButton applyButton = new JButton(new AbstractAction("Apply") {
+                       @Override
+                       public void actionPerformed(ActionEvent arg0) {
+                               applySettings();
+                               setFields(config);
+                       }
+               });
+               panel.add(applyButton);
+
+               return panel;
+       }
+
+       protected void applySettings() {
+               // Include default service providers
+               config.setIncludeDefaults(includeDefaults.isSelected());
+               for (ServiceDescriptionProvider provider : serviceDescRegistry
+                               .getDefaultServiceDescriptionProviders()) {
+                       if (! (provider instanceof ConfigurableServiceProvider))
+                               continue;
+                       if (config.isIncludeDefaults())
+                               
serviceDescRegistry.addServiceDescriptionProvider(provider);
+                       else
+                               
serviceDescRegistry.removeServiceDescriptionProvider(provider);
+               }
+
+               // Allow permanent removal of default service providers
+               config.setRemovePermanently(removePermanently.isSelected());
+       }
+
+       /**
+        * Set the shown configuration field values to those currently in use
+        * (i.e. last saved configuration).
+        *
+        */
+       private void setFields(ServiceDescriptionsConfiguration configurable) {
+               includeDefaults.setSelected(configurable.isIncludeDefaults());
+               
removePermanently.setSelected(configurable.isRemovePermanently());
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/config/ServiceDescriptionConfigUIFactory.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/config/ServiceDescriptionConfigUIFactory.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/config/ServiceDescriptionConfigUIFactory.java
new file mode 100644
index 0000000..a95b644
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/config/ServiceDescriptionConfigUIFactory.java
@@ -0,0 +1,56 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.config;
+
+import javax.swing.JPanel;
+
+import uk.org.taverna.configuration.Configurable;
+import uk.org.taverna.configuration.ConfigurationUIFactory;
+
+import org.apache.taverna.servicedescriptions.ServiceDescriptionRegistry;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionsConfiguration;
+
+public class ServiceDescriptionConfigUIFactory implements 
ConfigurationUIFactory {
+       private ServiceDescriptionsConfiguration 
serviceDescriptionsConfiguration;
+       private ServiceDescriptionRegistry serviceDescriptionRegistry;
+
+       @Override
+       public boolean canHandle(String uuid) {
+               return uuid.equals(serviceDescriptionsConfiguration.getUUID());
+       }
+
+       @Override
+       public Configurable getConfigurable() {
+               return serviceDescriptionsConfiguration;
+       }
+
+       @Override
+       public JPanel getConfigurationPanel() {
+               return new 
ServiceDescriptionConfigPanel(serviceDescriptionsConfiguration, 
serviceDescriptionRegistry);
+       }
+
+       public void setServiceDescriptionRegistry(ServiceDescriptionRegistry 
serviceDescriptionRegistry) {
+               this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+       }
+
+       public void 
setServiceDescriptionsConfiguration(ServiceDescriptionsConfiguration 
serviceDescriptionsConfiguration) {
+               this.serviceDescriptionsConfiguration = 
serviceDescriptionsConfiguration;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/menu/AddServiceProviderMenu.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/menu/AddServiceProviderMenu.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/menu/AddServiceProviderMenu.java
new file mode 100644
index 0000000..6ac89e2
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/menu/AddServiceProviderMenu.java
@@ -0,0 +1,112 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.menu;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JPopupMenu;
+
+import org.apache.taverna.servicedescriptions.ConfigurableServiceProvider;
+import org.apache.taverna.servicedescriptions.ServiceDescription;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionProvider;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionRegistry;
+import org.apache.taverna.workbench.ui.servicepanel.ServicePanel;
+import 
org.apache.taverna.workbench.ui.servicepanel.actions.AddServiceProviderAction;
+
+/**
+ * A menu that provides a set up menu actions for adding new service providers
+ * to the Service Panel.
+ * <p>
+ * The Actions are discovered from the {@link ServiceDescriptionProvider}s 
found
+ * through the SPI.
+ *
+ * @author Stuart Owen
+ * @author Stian Soiland-Reyes
+ * @author Alan R Williams
+ *
+ * @see ServiceDescription
+ * @see ServicePanel
+ * @see 
ServiceDescriptionRegistry#addServiceDescriptionProvider(ServiceDescriptionProvider)
+ */
+@SuppressWarnings("serial")
+public class AddServiceProviderMenu extends JButton {
+       public static class ServiceProviderComparator implements
+                       Comparator<ServiceDescriptionProvider> {
+               @Override
+               public int compare(ServiceDescriptionProvider o1,
+                               ServiceDescriptionProvider o2) {
+                       return o1.getName().toLowerCase().compareTo(
+                                       o2.getName().toLowerCase());
+               }
+       }
+
+       private final static String ADD_SERVICE_PROVIDER_MENU_NAME = "Import 
new services";
+
+       private final ServiceDescriptionRegistry serviceDescriptionRegistry;
+
+       public AddServiceProviderMenu(ServiceDescriptionRegistry 
serviceDescriptionRegistry) {
+               super();
+               this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+
+               final Component c = createCustomComponent();
+               setAction(new AbstractAction(ADD_SERVICE_PROVIDER_MENU_NAME) {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               ((JPopupMenu) 
c).show(AddServiceProviderMenu.this, 0,
+                                               
AddServiceProviderMenu.this.getHeight());
+                       }
+               });
+       }
+
+       private Component createCustomComponent() {
+               JPopupMenu addServiceMenu = new JPopupMenu(
+                               ADD_SERVICE_PROVIDER_MENU_NAME);
+               addServiceMenu.setToolTipText("Add a new service provider");
+               boolean isEmpty = true;
+               List<ConfigurableServiceProvider> providers = new ArrayList<>(
+                               
serviceDescriptionRegistry.getUnconfiguredServiceProviders());
+               Collections.sort(providers,  new ServiceProviderComparator());
+               for (ConfigurableServiceProvider provider : providers) {
+                       /*
+                        * Skip BioCatalogue's ConfigurableServiceProviderS as 
they should
+                        * not be used to add servcie directlry but rather 
though the
+                        * Service Catalogue perspective
+                        */
+                       if 
(provider.getId().toLowerCase().contains("servicecatalogue"))
+                               continue;
+
+                       AddServiceProviderAction addAction = new 
AddServiceProviderAction(
+                                       provider, this);
+                       
addAction.setServiceDescriptionRegistry(serviceDescriptionRegistry);
+                       addServiceMenu.add(addAction);
+                       isEmpty = false;
+               }
+               if (isEmpty)
+                       addServiceMenu.setEnabled(false);
+               return addServiceMenu;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/Filter.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/Filter.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/Filter.java
new file mode 100644
index 0000000..476aa9c
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/Filter.java
@@ -0,0 +1,32 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.tree;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+
+public interface Filter {
+       boolean pass(DefaultMutableTreeNode node);
+
+       String filterRepresentation(String original);
+
+       void setSuperseded(boolean superseded);
+
+       boolean isSuperseded();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeCellRenderer.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeCellRenderer.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeCellRenderer.java
new file mode 100644
index 0000000..ce1f8cd
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeCellRenderer.java
@@ -0,0 +1,58 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.tree;
+
+import static 
org.apache.taverna.workbench.icons.WorkbenchIcons.folderClosedIcon;
+import static org.apache.taverna.workbench.icons.WorkbenchIcons.folderOpenIcon;
+
+import java.awt.Component;
+
+import javax.swing.JTree;
+import javax.swing.tree.DefaultTreeCellRenderer;
+
+@SuppressWarnings("serial")
+public class FilterTreeCellRenderer extends DefaultTreeCellRenderer {
+       private Filter filter = null;
+
+       @Override
+       public Component getTreeCellRendererComponent(JTree tree, Object value,
+                       boolean sel, boolean expanded, boolean leaf, int row,
+                       boolean hasFocus) {
+
+               super.getTreeCellRendererComponent(tree, value, sel, expanded, 
leaf,
+                               row, hasFocus);
+               Filter filter = getFilter();
+               if (filter != null)
+                       setText(filter.filterRepresentation(getText()));
+               if (expanded)
+                       setIcon(folderOpenIcon);
+               else
+                       setIcon(folderClosedIcon);
+               return this;
+       }
+
+       public Filter getFilter() {
+               return filter;
+       }
+
+       public void setFilter(Filter currentFilter) {
+               this.filter = currentFilter;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeModel.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeModel.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeModel.java
new file mode 100644
index 0000000..e57701e
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeModel.java
@@ -0,0 +1,91 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.tree;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreePath;
+
+import org.apache.log4j.Logger;
+
+public final class FilterTreeModel extends DefaultTreeModel {
+       private static final long serialVersionUID = -8931308369832839862L;
+       private static final Logger logger = Logger
+                       .getLogger(FilterTreeModel.class);
+       
+       Filter currentFilter;
+
+       public FilterTreeModel(FilterTreeNode node) {
+               this(node, null);
+       }
+       
+       public FilterTreeModel(FilterTreeNode node, Filter filter) {
+               super(node);
+               currentFilter = filter;
+               node.setFilter(filter);
+       }
+
+       public void setFilter(Filter filter) {
+               if (root != null) {
+                       currentFilter = filter;
+                       ((FilterTreeNode) root).setFilter(filter);
+                       Object[] path = { root };
+                       fireTreeStructureChanged(this, path, null, null);
+               }
+       }
+
+       @Override
+       public int getChildCount(Object parent) {
+               if (parent instanceof FilterTreeNode)
+                       return (((FilterTreeNode) parent).getChildCount());
+               return 0;
+       }
+
+       @Override
+       public Object getChild(Object parent, int index) {
+               if (parent instanceof FilterTreeNode)
+                       return (((FilterTreeNode) parent).getChildAt(index));
+               return null;
+       }
+
+       /**
+        * @return the currentFilter
+        */
+       public Filter getCurrentFilter() {
+               return currentFilter;
+       }
+
+       public TreePath getTreePathForObjectPath(List<Object> path) {
+               List<FilterTreeNode> resultList = new ArrayList<>();
+               FilterTreeNode current = (FilterTreeNode) root;
+               resultList.add(current);
+               for (int i = 1; (i < path.size()) && (current != null); i++) {
+                       logger.debug("Looking in " + current.getUserObject() + 
" for " + path.get(i));
+                       current = current.getChildForObject(path.get(i));
+                       if (current != null)
+                               resultList.add(current);
+               }
+               if (current != null)
+                       return new TreePath(resultList.toArray());
+               return null;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeNode.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeNode.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeNode.java
new file mode 100644
index 0000000..9df6423
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeNode.java
@@ -0,0 +1,141 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.tree;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+
+import org.apache.log4j.Logger;
+
+public class FilterTreeNode extends DefaultMutableTreeNode {
+       private static final long serialVersionUID = 1933553584349932151L;
+       @SuppressWarnings("unused")
+       private static Logger logger = Logger.getLogger(FilterTreeNode.class);
+       
+       private Filter filter;
+       private boolean passed = true;
+       private List<FilterTreeNode> filteredChildren = new ArrayList<>();
+
+       public FilterTreeNode(Object userObject) {
+               super(userObject);
+               userObject.toString();
+       }
+
+       public Filter getFilter() {
+               return filter;
+       }
+       
+       public void setFilter(Filter filter) {
+               if ((filter == null) || !filter.isSuperseded()) {
+                       this.filter = filter;
+                       passed = false;
+                       filteredChildren.clear();
+                       if (filter == null) {
+                               passed = true;
+                               passFilterDown(null);
+                       } else if (filter.pass(this)) {
+                               passed = true;
+                               passFilterDown(null);
+                       } else {
+                               passFilterDown(filter);
+                               passed = filteredChildren.size() != 0;
+                       }
+               }
+       }
+
+       private void passFilterDown(Filter filter) {
+               int realChildCount = super.getChildCount();
+               for (int i = 0; i < realChildCount; i++) {
+                       FilterTreeNode realChild = (FilterTreeNode) 
super.getChildAt(i);
+                       realChild.setFilter(filter);
+                       if (realChild.isPassed())
+                               filteredChildren.add(realChild);
+               }
+       }
+
+       public void add(FilterTreeNode node) {
+               super.add(node);
+               node.setFilter(filter);
+               // TODO work up
+               if (node.isPassed())
+                       filteredChildren.add(node);
+       }
+       
+       @Override
+       public void remove(int childIndex) {
+               if (filter != null)
+                       // as child indexes might be inconsistent..
+                       throw new IllegalStateException("Can't remove while the 
filter is active");
+               super.remove(childIndex);
+       }
+
+       @Override
+       public int getChildCount() {
+               if (filter == null)
+                       return super.getChildCount();
+               return filteredChildren.size();
+       }
+
+       @Override
+       public FilterTreeNode getChildAt(int index) {
+               if (filter == null)
+                       return (FilterTreeNode) super.getChildAt(index);
+               return filteredChildren.get(index);
+       }
+
+       public boolean isPassed() {
+               return passed;
+       }
+       
+       public Set<FilterTreeNode> getLeaves() {
+               Set<FilterTreeNode> result = new HashSet<>();
+               if (super.getChildCount() == 0) {
+                       result.add(this);
+                       return result;
+               }
+
+               for (int i = 0; i < super.getChildCount(); i++) {
+                       FilterTreeNode child = (FilterTreeNode) 
super.getChildAt(i);
+                       result.addAll(child.getLeaves());
+               }
+               return result;
+       }
+
+       public FilterTreeNode getChildForObject(Object userObject) {
+               FilterTreeNode result = null;
+               for (int i=0; (i < super.getChildCount()) && (result == null); 
i++) {
+                       FilterTreeNode child = (FilterTreeNode) 
super.getChildAt(i);
+                       Object nodeObject = child.getUserObject();
+//                     logger.info("nodeObject is a " + nodeObject.getClass() 
+ " - " +
+//                                     "userObject is a " + 
userObject.getClass());
+                       if 
(nodeObject.toString().equals(userObject.toString())) {
+                               result = child;
+//                             logger.info(nodeObject + " is equal to " + 
userObject);
+//                     } else {
+//                             logger.info(nodeObject + " is not equal to " + 
userObject);
+                       }
+               }
+               return result;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeSelectionModel.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeSelectionModel.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeSelectionModel.java
new file mode 100644
index 0000000..c9a1315
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/FilterTreeSelectionModel.java
@@ -0,0 +1,45 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.tree;
+
+import javax.swing.tree.DefaultTreeSelectionModel;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+
+public class FilterTreeSelectionModel extends DefaultTreeSelectionModel{
+       private static final long serialVersionUID = 3127644524735089630L;
+       
+       public FilterTreeSelectionModel(){
+               super();
+               setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+       }
+       
+       @Override
+       public void setSelectionPath(TreePath path) {
+               /*
+                * Nothing happens here - only calls to mySetSelectionPath() 
will have
+                * the effect of a node being selected.
+                */
+       }
+       
+       public void mySetSelectionPath(TreePath path) {
+               super.setSelectionPath(path);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/MyFilter.java
----------------------------------------------------------------------
diff --git 
a/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/MyFilter.java
 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/MyFilter.java
new file mode 100644
index 0000000..9c1a170
--- /dev/null
+++ 
b/taverna-activity-palette-ui/src/main/java/org/apache/taverna/workbench/ui/servicepanel/tree/MyFilter.java
@@ -0,0 +1,88 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.servicepanel.tree;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+
+public class MyFilter implements Filter {
+       private static final String HTML_MATCH_END = "</font><font 
color=\"black\">";
+       private static final String HTML_MATCH_START = "</font><font 
color=\"red\">";
+       private static final String HTML_POSTFIX = "</font></html>";
+       private static final String HTML_PREFIX = "<html><font 
color=\"black\">";
+
+       private String filterString;
+       private boolean superseded;
+       private String filterLowerCase;
+
+       public MyFilter(String filterString) {
+               this.filterString = filterString;
+               this.filterLowerCase = filterString.toLowerCase();
+               this.superseded = false;
+       }
+
+       private boolean basicFilter(DefaultMutableTreeNode node) {
+               if (filterString.isEmpty())
+                       return true;
+               return node.getUserObject().toString().toLowerCase()
+                               .contains(filterLowerCase);
+       }
+
+       @Override
+       public boolean pass(DefaultMutableTreeNode node) {
+               return basicFilter(node);
+       }
+
+       @Override
+       public String filterRepresentation(String original) {
+               StringBuilder sb = new StringBuilder(HTML_PREFIX);
+               int from = 0;
+               String originalLowerCase = original.toLowerCase();
+               int index = originalLowerCase.indexOf(filterLowerCase, from);
+               while (index > -1) {
+                       sb.append(original.substring(from, index));
+                       sb.append(HTML_MATCH_START);
+                       sb.append(original.substring(index,
+                                       index + filterLowerCase.length()));
+                       sb.append(HTML_MATCH_END);
+                       from = index + filterLowerCase.length();
+                       index = originalLowerCase.indexOf(filterLowerCase, 
from);
+               }
+               if (from < original.length())
+                       sb.append(original.substring(from, original.length()));
+               return sb.append(HTML_POSTFIX).toString();
+       }
+
+       /**
+        * @return the superseded
+        */
+       @Override
+       public boolean isSuperseded() {
+               return superseded;
+       }
+
+       /**
+        * @param superseded
+        *            the superseded to set
+        */
+       @Override
+       public void setSuperseded(boolean superseded) {
+               this.superseded = superseded;
+       }
+}

Reply via email to