diff --git a/uk/ac/sanger/artemis/components/filetree/FileList.java b/uk/ac/sanger/artemis/components/filetree/FileList.java
new file mode 100644
index 0000000000000000000000000000000000000000..e32322eadf835e5a280f60a7b19fa8e1bfa23497
--- /dev/null
+++ b/uk/ac/sanger/artemis/components/filetree/FileList.java
@@ -0,0 +1,144 @@
+/********************************************************************
+*
+*  This library is free software; you can redistribute it and/or
+*  modify it under the terms of the GNU Library General Public
+*  License as published by the Free Software Foundation; either
+*  version 2 of the License, or (at your option) any later version.
+*
+*  This library 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
+*  Library General Public License for more details.
+*
+*  You should have received a copy of the GNU Library General Public
+*  License along with this library; if not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+*  Boston, MA  02111-1307, USA.
+*
+*  @author: Copyright (C) Tim Carver
+*
+********************************************************************/
+
+package uk.ac.sanger.artemis.components.filetree;
+
+import uk.ac.sanger.artemis.j2ssh.SshFileManager;
+import java.util.Vector;
+import java.util.Collections;
+import java.io.IOException;
+import java.io.File;
+
+public class FileList 
+{
+  /** vector containing directories */
+  private Vector vdir;
+  private Vector vfile;
+  private static SshFileManager ssh_client = new SshFileManager();
+
+  public FileList()
+  {
+  }
+
+  protected void getDirList(String dir)
+  {
+    try
+    {
+      ssh_client.remoteList(dir);
+    }
+    catch(IOException ioe)
+    {
+      ioe.printStackTrace();
+    }
+    vdir  = ssh_client.getDirList(); 
+    vfile = ssh_client.getFileList();
+    Collections.sort(vfile);
+  }
+
+  /**
+  *
+  * Delete the given file / directory
+  *
+  */
+  protected boolean delete(String file)
+  {
+    return ssh_client.delete(file);
+  }
+
+  /**
+  *
+  * Make a directory
+  *
+  */
+  protected boolean mkdir(String dir)
+  {
+    return ssh_client.mkdir(dir);
+  }
+
+
+  /**
+  *
+  * Print working directory
+  *
+  */
+  protected String pwd()
+  {
+    return ssh_client.pwd();
+  }
+
+  /**
+  *
+  * Rename a file
+  *
+  */
+  protected boolean rename(String old_file, String new_file)
+  {
+    return ssh_client.rename(old_file, new_file);
+  }
+
+
+  /**
+  *
+  * Put a file
+  *
+  */
+  protected boolean put(String dir, File local_file)
+  {
+    return ssh_client.put(dir, local_file);
+  }
+
+
+  /**
+  *
+  * Get the file contents
+  *
+  */
+  protected byte[] getFileContents(String file)
+  {
+    return ssh_client.getFileContents(file);
+  }
+
+
+  /**
+  *
+  * Gets the list of files as a Vector
+  * @return     list of files as a Vector
+  *
+  */
+  public Vector fileVector() 
+  {
+    return vfile;
+  }
+
+
+  /**
+  *
+  * Gets whether this name is a directory
+  * @return     true if it is a directory
+  *
+  */
+  public boolean isDirectory(String d) 
+  {
+    return vdir.contains(d);
+  }
+ 
+
+}
diff --git a/uk/ac/sanger/artemis/components/filetree/FileManager.java b/uk/ac/sanger/artemis/components/filetree/FileManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..85aca7e09dbf8bf8fb5289c05775f71b01f22f7b
--- /dev/null
+++ b/uk/ac/sanger/artemis/components/filetree/FileManager.java
@@ -0,0 +1,435 @@
+/********************************************************************
+*
+*  This library is free software; you can redistribute it and/or
+*  modify it under the terms of the GNU Library General Public
+*  License as published by the Free Software Foundation; either
+*  version 2 of the License, or (at your option) any later version.
+*
+*  This library 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
+*  Library General Public License for more details.
+*
+*  You should have received a copy of the GNU Library General Public
+*  License along with this library; if not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+*  Boston, MA  02111-1307, USA.
+*
+*  Copyright (C) Genome Research Limited
+*
+********************************************************************/
+
+package uk.ac.sanger.artemis.components.filetree;
+
+import uk.ac.sanger.artemis.util.StringVector;
+import uk.ac.sanger.artemis.Options;
+
+import javax.swing.*;
+import java.io.File;
+import java.io.FileFilter;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.awt.*;
+
+public class FileManager extends JFrame
+{
+
+  /** busy cursor */
+  private Cursor cbusy = new Cursor(Cursor.WAIT_CURSOR);
+  /** done cursor */
+  private Cursor cdone = new Cursor(Cursor.DEFAULT_CURSOR);
+
+  public FileManager(JFrame frame)
+  {
+    this(frame,getArtemisFilter());
+  }
+
+  /**
+  *
+  * File Manager Frame
+  * @param frame  parent frame
+  *
+  */
+  public FileManager(JFrame frame, FileFilter filter)
+  {
+    super("File Manager");
+
+    FileTree ftree  = new FileTree(new File(System.getProperty("user.dir")),
+                                   frame, filter);
+    JScrollPane jsp = new JScrollPane(ftree);
+    JPanel pane = (JPanel)getContentPane();
+    pane.setLayout(new BorderLayout());
+    pane.add(jsp, BorderLayout.CENTER);
+    setJMenuBar(makeMenuBar(pane,ftree));
+    pane.add(getFileFileterComboBox(ftree), BorderLayout.SOUTH);
+
+    Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+    jsp.setPreferredSize(new Dimension(210,
+                         (int)(screen.getHeight()/2)));
+    pack();
+    
+    int yloc = (int)((screen.getHeight()-getHeight())/2);
+    setLocation(0,yloc);  
+    setVisible(true);
+  }
+
+  protected JComboBox getFileFileterComboBox(final FileTree ftree)
+  {
+    String[] filters = { "Artemis Files", "Sequence Files", 
+                         "Feature Files", "All Files" };
+    final JComboBox comboFilter = new JComboBox(filters);
+    comboFilter.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        String select = (String)comboFilter.getSelectedItem(); 
+        if(select.equals("Artemis Files"))
+          ftree.setFilter(getArtemisFilter());
+        else if(select.equals("Sequence Files"))
+          ftree.setFilter(getSequenceFilter());
+        else if(select.equals("Feature Files"))
+          ftree.setFilter(getFeatureFilter());
+        else if(select.equals("All Files"))
+        {
+          ftree.setFilter(new FileFilter()
+          {
+            public boolean accept(File pathname)
+            {
+              if(pathname.getName().startsWith("."))
+                return false;
+              return true;
+            }
+          });
+        }
+      }
+    });
+    return comboFilter;
+  }
+
+  /**
+  *
+  * Get a file filter for sequence and feature suffixes.
+  * @return file filter
+  */
+  protected static FileFilter getArtemisFilter()
+  {
+    final StringVector sequence_suffixes =
+      Options.getOptions().getOptionValues("sequence_file_suffixes");
+
+    final StringVector feature_suffixes =
+      Options.getOptions().getOptionValues("feature_file_suffixes");
+
+    final FileFilter artemis_filter = new FileFilter()
+    {
+      public boolean accept(File pathname)
+      {
+        if(pathname.isDirectory() &&
+           !pathname.getName().startsWith("."))
+          return true;
+          
+        for(int i = 0; i<sequence_suffixes.size(); ++i)
+        {
+          final String suffix = sequence_suffixes.elementAt(i);
+
+          if(pathname.getName().endsWith("." + suffix) ||
+             pathname.getName().endsWith("." + suffix + ".gz"))
+            return true;
+        }
+
+        for(int i = 0; i<feature_suffixes.size(); ++i)
+        {
+          final String suffix = feature_suffixes.elementAt(i);
+
+          if(pathname.getName().endsWith("." + suffix) ||
+             pathname.getName().endsWith("." + suffix + ".gz"))
+            return true;
+        }
+        return false;
+      }
+    };
+    return artemis_filter;
+  }
+
+
+  /**
+  *
+  * Get a file filter for feature suffixes.
+  * @return file filter
+  */
+  protected static FileFilter getFeatureFilter()
+  {
+    final StringVector feature_suffixes =
+      Options.getOptions().getOptionValues("feature_file_suffixes");
+
+    final FileFilter feature_filter = new FileFilter()
+    {
+      public boolean accept(File pathname)
+      {
+        if(pathname.isDirectory() &&
+           !pathname.getName().startsWith("."))
+          return true;
+
+        for(int i = 0; i<feature_suffixes.size(); ++i)
+        {
+          final String suffix = feature_suffixes.elementAt(i);
+
+          if(pathname.getName().endsWith("." + suffix) ||
+             pathname.getName().endsWith("." + suffix + ".gz"))
+            return true;
+        }
+        return false;
+      }
+    };
+    return feature_filter;
+  }
+
+  /**
+  *
+  * Get a file filter for sequence suffixes.
+  * @return file filter
+  */
+  protected static FileFilter getSequenceFilter()
+  {
+    final StringVector sequence_suffixes =
+      Options.getOptions().getOptionValues("sequence_file_suffixes");
+
+    final FileFilter seq_filter = new FileFilter()
+    {
+      public boolean accept(File pathname)
+      {
+        if(pathname.isDirectory() &&
+           !pathname.getName().startsWith("."))
+          return true;
+         
+        for(int i = 0; i<sequence_suffixes.size(); ++i)
+        {
+          final String suffix = sequence_suffixes.elementAt(i);
+
+          if(pathname.getName().endsWith("." + suffix) ||
+             pathname.getName().endsWith("." + suffix + ".gz"))
+            return true;
+        }
+
+        return false;
+      }
+    };
+    return seq_filter;
+  }
+
+  /**
+  *
+  * Set up a menu and tool bar
+  * @param pane   panel to add toolbar to
+  * @param ftree  file tree display
+  *
+  */
+  private JMenuBar makeMenuBar(JPanel pane, final FileTree ftree)
+  {
+    JMenuBar mBar = new JMenuBar();
+    JMenu fileMenu = new JMenu("File");
+    mBar.add(fileMenu);
+    
+    JMenuItem fileMenuGoto = new JMenuItem("Go to Directory ...");
+    fileMenuGoto.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        String dir = ftree.getRoot().getAbsolutePath();
+        String newDir = JOptionPane.showInputDialog(FileManager.this,
+                                             "Go to Directory:",dir);      
+
+        if(newDir == null)
+          return;
+       
+        newDir = newDir.trim();
+        File newDirFile = new File(newDir);
+        
+        if(newDirFile.exists() &&
+           newDirFile.canRead() &&
+           !newDir.equals(dir))
+          ftree.newRoot(newDir);
+        else
+        {
+          String error = null;
+          if(!newDirFile.exists())
+            error = new String(newDir+" doesn't exist!");
+          else if(!newDirFile.canRead())
+            error = new String(newDir+" cannot be read!");
+          else if(newDir.equals(dir))
+            error = new String("Same directory!");
+
+          if(error != null)
+            JOptionPane.showMessageDialog(FileManager.this,
+                                        error, "Warning",
+                                        JOptionPane.WARNING_MESSAGE);
+        }
+      }
+    });
+    fileMenu.add(fileMenuGoto);
+    fileMenu.add(new JSeparator());
+    
+    JMenuItem fileMenuClose = new JMenuItem("Close");
+    fileMenuClose.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        setVisible(false);
+      }
+    });
+    fileMenu.add(fileMenuClose);
+
+    // tool bar set up
+    JToolBar toolBar  = new JToolBar();
+    Dimension buttonSize = new Dimension(22,24);
+
+    JButton upBt = new JButton()
+    {
+      public void paintComponent(Graphics g)
+      {
+        super.paintComponent(g);
+        Graphics2D g2 = (Graphics2D)g;
+
+        g2.setColor(new Color(0,128,0));
+        float loc1[][] = { {11,18}, {7,18}, {7,14},
+                           {3,14},  {11,4} };
+                  
+        g2.fill(makeShape(loc1));
+        g2.setColor(Color.green);
+
+        float loc2[][] = { {11,18}, {15,18}, {15,14},
+                           {19,14},  {11,4} };
+        g2.fill(makeShape(loc2));
+
+        setSize(22,24);
+      }
+    };
+    upBt.setPreferredSize(buttonSize);
+    upBt.setMinimumSize(buttonSize);
+
+    upBt.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        FileManager.this.setCursor(cbusy);
+        File root = ftree.getRoot();
+        String parent = root.getParent();
+        if(parent != null)
+          ftree.newRoot(parent);
+        FileManager.this.setCursor(cdone);
+      }
+    });
+    toolBar.add(upBt);
+
+// yeastpub
+    JButton shortCut1 = new JButton()
+    {
+      public void paintComponent(Graphics g)
+      {
+        super.paintComponent(g);
+        Graphics2D g2 = (Graphics2D)g;
+        Font font = new Font("Monospaced", Font.BOLD, 14);
+        g2.setFont(font);
+
+        g2.setColor(Color.black);
+        g2.drawString("Y",4,18);
+        g2.setColor(Color.red);
+        g2.drawString("P",10,15);
+        setSize(22,24);
+      }
+    };
+    shortCut1.setPreferredSize(buttonSize);
+    shortCut1.setMinimumSize(buttonSize);
+    shortCut1.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        ftree.newRoot("/nfs/disk222/yeastpub");
+      }
+    });
+
+    if((new File("/nfs/disk222/yeastpub")).exists())
+      toolBar.add(shortCut1);
+
+// pathdata
+   JButton shortCut2 = new JButton()
+    {
+      public void paintComponent(Graphics g)
+      {
+        super.paintComponent(g);
+        Graphics2D g2 = (Graphics2D)g;
+        Font font = new Font("Monospaced", Font.BOLD, 14);
+        g2.setFont(font);
+
+        g2.setColor(Color.black);
+        g2.drawString("P",4,18);
+        g2.setColor(Color.red);
+        g2.drawString("D",10,15);
+        setSize(22,24);
+      }
+    };
+    shortCut2.setPreferredSize(buttonSize);
+    shortCut2.setMinimumSize(buttonSize);
+    shortCut2.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        ftree.newRoot("/nfs/pathdata/");
+      }
+    });
+
+    if((new File("/nfs/pathdata/")).exists())
+      toolBar.add(shortCut2);
+
+// home button
+    JButton homeBt = new JButton()
+    {
+      public void paintComponent(Graphics g)
+      {
+        super.paintComponent(g);
+        Graphics2D g2 = (Graphics2D)g;
+                                                                                
+        g2.setColor(Color.blue);
+        float loc1[][] = { {3,14}, {11,3}, {19,14},
+                           {17,14}, {17,18}, {5,18}, {5,14} };
+        g2.fill(makeShape(loc1));
+                                                                                
+        setSize(22,24);
+      }
+    };
+    homeBt.setPreferredSize(buttonSize);
+    homeBt.setMinimumSize(buttonSize);
+    homeBt.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        ftree.newRoot(System.getProperty("user.home"));
+      }
+    });
+    toolBar.add(homeBt);
+
+    toolBar.add(Box.createVerticalStrut(35));
+    pane.add(toolBar, BorderLayout.NORTH);
+
+    return mBar;
+  }
+
+  /**
+  *
+  * Used to draw a Shape.
+  *
+  */
+  public static GeneralPath makeShape(float loc[][]) 
+  {
+    GeneralPath path = new GeneralPath(GeneralPath.WIND_NON_ZERO);
+
+    path.moveTo(loc[0][0],loc[0][1]);
+
+    for(int i=1; i<loc.length; i++)
+      path.lineTo(loc[i][0],loc[i][1]);
+    
+    return path;
+  }
+
+
+}
+
diff --git a/uk/ac/sanger/artemis/components/filetree/FileNode.java b/uk/ac/sanger/artemis/components/filetree/FileNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..6542722e7c292e2c4d383102599d9c0a697e1529
--- /dev/null
+++ b/uk/ac/sanger/artemis/components/filetree/FileNode.java
@@ -0,0 +1,159 @@
+/********************************************************************
+*
+*  This library is free software; you can redistribute it and/or
+*  modify it under the terms of the GNU Library General Public
+*  License as published by the Free Software Foundation; either
+*  version 2 of the License, or (at your option) any later version.
+*
+*  This library 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
+*  Library General Public License for more details.
+*
+*  You should have received a copy of the GNU Library General Public
+*  License along with this library; if not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+*  Boston, MA  02111-1307, USA.
+*
+*  Copyright (C) Genome Research Limited
+*
+********************************************************************/
+
+package uk.ac.sanger.artemis.components.filetree;
+
+import java.awt.datatransfer.*;
+import javax.swing.tree.*;
+import java.io.*;
+import java.util.*;
+
+/**
+*
+* File node for local file tree manager
+*
+*/
+public class FileNode extends DefaultMutableTreeNode 
+                 implements Transferable, Serializable
+{
+    /** true if explored */
+    private boolean explored = false;
+    /** data flavour of a file node */
+    public static DataFlavor FILENODE =
+           new DataFlavor(FileNode.class, "Local file");
+    /** flavours file node and string */
+    static DataFlavor flavors[] = { FILENODE, DataFlavor.stringFlavor };
+
+    /**
+    *
+    * @param file	file node file
+    *
+    */
+    public FileNode(File file)
+    { 
+      setUserObject(file); 
+    }
+
+    /** Determine if this is a directory */
+    public boolean getAllowsChildren() { return isDirectory(); }
+    /** Determine if this is a file */
+    public boolean isLeaf() { return !isDirectory(); }
+    /** Get the File this node represents */
+    public File getFile() { return (File)getUserObject(); }
+    /** Determine if this node has been explored */
+    public boolean isExplored() { return explored; }
+    /** Determine if this is a directory */
+    public boolean isDirectory() 
+    {
+      File file = getFile();
+      return file.isDirectory();
+    }
+
+    /**
+    *
+    * Returns the name of the file 
+    *
+    */
+    public String toString() 
+    {
+      File file = (File)getUserObject();
+      String filename = file.toString();
+      int index = filename.lastIndexOf(File.separator);
+
+      return (index != -1 && index != filename.length()-1) ? 
+                          filename.substring(index+1) : 
+                                            filename;
+    }
+
+    /**
+    *
+    * Explores a directory adding a FileNode for each
+    * child
+    *
+    */
+    public void explore(FileFilter filter) 
+    {
+      if(!isDirectory())
+        return;
+
+      if(!isExplored()) 
+      {
+        File file = getFile();
+        explored = true;
+        File[] children;
+// filter files
+        children = file.listFiles(filter);
+        
+// sort into alphabetic order
+        java.util.Arrays.sort(children);
+        for(int i=0; i < children.length; ++i)
+          add(new FileNode(children[i]));
+      }
+    }
+
+    /**
+    *
+    * Forces the directory to be re-explored
+    *
+    */
+    public void reExplore(FileFilter filter)
+    {
+      explored = false;
+      removeAllChildren();
+      explore(filter);
+    }
+ 
+// Transferable
+    public DataFlavor[] getTransferDataFlavors()
+    {
+      return flavors;
+    }
+
+    public boolean isDataFlavorSupported(DataFlavor f)
+    {
+      if(f.equals(FILENODE) || f.equals(DataFlavor.stringFlavor))
+        return true;
+      return false;
+    }
+
+    public Object getTransferData(DataFlavor d)
+        throws UnsupportedFlavorException, IOException
+    {
+      if(d.equals(FILENODE))
+        return this;
+      else if(d.equals(DataFlavor.stringFlavor))
+        return getFile().getAbsolutePath();
+      else throw new UnsupportedFlavorException(d);
+    }
+
+//Serializable
+   private void writeObject(java.io.ObjectOutputStream out) throws IOException
+   {
+     out.defaultWriteObject();
+   }
+
+   private void readObject(java.io.ObjectInputStream in)
+     throws IOException, ClassNotFoundException
+   {
+     in.defaultReadObject();
+   }
+
+}
diff --git a/uk/ac/sanger/artemis/components/filetree/FileTree.java b/uk/ac/sanger/artemis/components/filetree/FileTree.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd86e466b3b628700df6f045f9f24d55b1bc347f
--- /dev/null
+++ b/uk/ac/sanger/artemis/components/filetree/FileTree.java
@@ -0,0 +1,947 @@
+/********************************************************************
+*
+*  This library is free software; you can redistribute it and/or
+*  modify it under the terms of the GNU Library General Public
+*  License as published by the Free Software Foundation; either
+*  version 2 of the License, or (at your option) any later version.
+*
+*  This library 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
+*  Library General Public License for more details.
+*
+*  You should have received a copy of the GNU Library General Public
+*  License along with this library; if not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+*  Boston, MA  02111-1307, USA.
+*
+*  Copyright (C) Genome Research Limited
+*
+********************************************************************/
+
+package uk.ac.sanger.artemis.components.filetree;
+
+import uk.ac.sanger.artemis.components.SwingWorker;
+import uk.ac.sanger.artemis.components.EntryEdit;
+import uk.ac.sanger.artemis.components.EntryFileDialog;
+
+import uk.ac.sanger.artemis.io.EntryInformation;
+import uk.ac.sanger.artemis.io.SimpleEntryInformation;
+import uk.ac.sanger.artemis.*;
+import uk.ac.sanger.artemis.util.InputStreamProgressListener;
+import uk.ac.sanger.artemis.util.InputStreamProgressEvent;
+import uk.ac.sanger.artemis.util.FileDocument;
+import uk.ac.sanger.artemis.util.OutOfRangeException;
+import uk.ac.sanger.artemis.sequence.NoSequenceException;
+import uk.ac.sanger.artemis.components.MessageDialog;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.datatransfer.*;
+import java.awt.dnd.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+import java.io.*;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+
+/**
+*
+* Creates a local file tree manager. This acts as a drag 
+* source and sink for files.
+*
+*/
+public class FileTree extends JTree implements DragGestureListener,
+                 DragSourceListener, DropTargetListener, ActionListener,
+                 Autoscroll 
+{
+
+  /** root directory */
+  private File root;
+  /** store of directories that are opened */
+  private Vector openNode;
+  /** file separator */
+  private String fs = new String(System.getProperty("file.separator"));
+  /** popup menu */
+  private JPopupMenu popup;
+  /** busy cursor */
+  private Cursor cbusy = new Cursor(Cursor.WAIT_CURSOR);
+  /** done cursor */
+  private Cursor cdone = new Cursor(Cursor.DEFAULT_CURSOR);
+  /** AutoScroll margin */
+  private static final int AUTOSCROLL_MARGIN = 45;
+  /** used by AutoScroll method */
+  private Insets autoscrollInsets = new Insets( 0, 0, 0, 0 );
+  /** file filter */
+  private FileFilter filter = null;
+
+  /**
+  *
+  * @param rt		root directory
+  * @param f		frame
+  *
+  */
+  public FileTree(File rt, final JFrame f,
+                  FileFilter filter)
+  {
+    this.root   = rt;
+    this.filter = filter;
+
+    DragSource dragSource = DragSource.getDefaultDragSource();
+
+    dragSource.createDefaultDragGestureRecognizer(
+       this,                             // component where drag originates
+       DnDConstants.ACTION_COPY_OR_MOVE, // actions
+       this);                            // drag gesture recognizer
+
+    setDropTarget(new DropTarget(this,this));
+    DefaultTreeModel model = createTreeModel(root);
+    setModel(model);
+    createTreeModelListener();
+
+    this.getSelectionModel().setSelectionMode
+                  (TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
+
+    // Popup menu
+    addMouseListener(new PopupListener());
+    popup = new JPopupMenu();
+    
+    JMenuItem menuItem = new JMenuItem("Refresh");
+    menuItem.addActionListener(this);
+    popup.add(menuItem);
+    popup.add(new JSeparator());
+    //open menu
+    JMenu openMenu = new JMenu("Open With");
+    popup.add(openMenu);
+    menuItem = new JMenuItem("Jemboss Alignment Editor");
+    menuItem.addActionListener(this);
+    openMenu.add(menuItem);
+    menuItem = new JMenuItem("Artemis");
+    menuItem.addActionListener(this);
+    openMenu.add(menuItem);
+
+    menuItem = new JMenuItem("Rename...");
+    menuItem.addActionListener(this);
+    popup.add(menuItem);
+    menuItem = new JMenuItem("New Folder...");
+    menuItem.addActionListener(this);
+    popup.add(menuItem);
+    menuItem = new JMenuItem("Delete...");
+    menuItem.addActionListener(this);
+    popup.add(menuItem);
+    popup.add(new JSeparator());
+    menuItem = new JMenuItem("De-select All");
+    menuItem.addActionListener(this);
+    popup.add(menuItem);
+
+    //Listen for when a file is selected
+    MouseListener mouseListener = new MouseAdapter() 
+    {
+      public void mouseClicked(MouseEvent me) 
+      {
+        if(me.getClickCount() == 2 && isFileSelection() &&
+           !me.isPopupTrigger()) 
+        {
+          f.setCursor(cbusy);
+          FileNode node = getSelectedNode();
+          String selected = node.getFile().getAbsolutePath();
+          showFilePane(selected);
+          f.setCursor(cdone);
+        }
+      }
+    };
+    this.addMouseListener(mouseListener);
+
+    addTreeExpansionListener(new TreeExpansionListener()
+    {
+      public void treeCollapsed(TreeExpansionEvent e){} 
+      public void treeExpanded(TreeExpansionEvent e) 
+      {
+        TreePath path = e.getPath();
+        if(path != null) 
+        {
+          FileNode node = (FileNode)path.getLastPathComponent();
+
+          if(!node.isExplored()) 
+          {  
+            f.setCursor(cbusy);
+            exploreNode(node);
+            f.setCursor(cdone);
+          }
+        }
+      }
+    });
+
+  }
+
+
+  /**
+  *
+  * Popup menu actions
+  * @param e	action event
+  * 
+  */
+  public void actionPerformed(ActionEvent e) 
+  {
+
+    JMenuItem source = (JMenuItem)(e.getSource());
+    final FileNode node = getSelectedNode();
+
+    if(source.getText().equals("Refresh")) 
+    {
+      if(node == null)
+        newRoot(root.getAbsolutePath());
+      else if(node.isLeaf())
+        refresh((FileNode)node.getParent());
+      else 
+        refresh(node);
+      return;
+    }
+
+    if(node == null)
+    {
+      JOptionPane.showMessageDialog(null,"No file selected.",
+                        "Warning",
+                        JOptionPane.WARNING_MESSAGE);
+      return;
+    }
+    
+    final File f = node.getFile();
+
+    if(source.getText().equals("Jemboss Alignment Editor"))
+    {
+      org.emboss.jemboss.editor.AlignJFrame ajFrame =
+               new org.emboss.jemboss.editor.AlignJFrame(f);
+      ajFrame.setVisible(true);
+    }
+    else if(source.getText().equals("Artemis"))
+    {
+      setCursor(cbusy);
+      String selected = node.getFile().getAbsolutePath();
+      showFilePane(selected);
+      setCursor(cdone);
+    }
+    else if(source.getText().equals("Text Editor"))
+      showFilePane(f.getAbsolutePath());
+    else if(source.getText().equals("New Folder..."))
+    {
+      String path = null;
+      if(node.isLeaf())
+        path = f.getParent();
+      else
+        path = f.getAbsolutePath();
+
+      String inputValue = JOptionPane.showInputDialog(null,
+                    "Folder Name","Create New Folder in "+path,
+                    JOptionPane.QUESTION_MESSAGE);
+
+      if(inputValue != null && !inputValue.equals("") )
+      {
+        String fullname = path+fs+inputValue;
+        File dir = new File(fullname);
+        
+        if(dir.exists())
+          JOptionPane.showMessageDialog(null, fullname+" alread exists!",
+                                   "Error", JOptionPane.ERROR_MESSAGE);
+        else
+        {
+          if(dir.mkdir())
+            addObject(inputValue,path,node);
+          else
+            JOptionPane.showMessageDialog(null,
+                       "Cannot make the folder\n"+fullname,
+                       "Error", JOptionPane.ERROR_MESSAGE);     
+        }
+      }
+    }
+    else if(source.getText().equals("Delete..."))
+    {
+      File fn[] = getSelectedFiles();
+      String names = "";
+      for(int i=0; i<fn.length;i++)
+         names = names.concat(fn[i].getAbsolutePath()+"\n");
+      int n = JOptionPane.showConfirmDialog(null,
+                                 "Delete \n"+names+"?",
+                                 "Delete Files",
+                                 JOptionPane.YES_NO_OPTION);
+
+      FileNode nodes[] = getSelectedNodes();
+      if(n == JOptionPane.YES_OPTION)
+        for(int i=0; i<nodes.length;i++)
+          deleteFile(nodes[i]);
+    }
+    else if(source.getText().equals("De-select All"))
+      clearSelection();
+    else if(isFileSelection() && source.getText().equals("Rename..."))
+    {
+      String inputValue = (String)JOptionPane.showInputDialog(null,
+                              "New File Name","Rename "+f.getName(), 
+                              JOptionPane.QUESTION_MESSAGE,null,null,f.getName());
+
+      if(inputValue != null && !inputValue.equals("") )
+      {
+        String path = f.getParent();
+        String fullname   = path+fs+inputValue;
+        File newFile = new File(fullname);
+
+        try
+        {
+          renameFile(f,node,newFile.getCanonicalPath());
+        }
+        catch(IOException ioe){}
+      }
+    }
+  }
+
+
+  /**
+  *
+  * Delete a file from the tree
+  * @param node		node to delete
+  *
+  */
+  public void deleteFile(final FileNode node)
+  {
+    File f = node.getFile();
+    if(f.delete())
+    {
+      Runnable deleteFileFromTree = new Runnable()
+      {
+        public void run () { deleteObject(node); };
+      };
+      SwingUtilities.invokeLater(deleteFileFromTree);
+    }
+    else
+      JOptionPane.showMessageDialog(null,"Cannot delete\n"+
+                         f.getAbsolutePath(),"Warning",
+                         JOptionPane.ERROR_MESSAGE);
+  }
+ 
+ 
+  /**
+  *
+  * Method to rename a file and update the filenode's.
+  * @param oldFile 	file to rename
+  * @param oldNode 	filenode to be removed
+  * @param newFullName 	name of the new file
+  *
+  */
+  private void renameFile(final File oldFile, final FileNode oldNode, 
+                          String newFullName)
+  {
+    final File fnew = new File(newFullName);
+    if(fnew.exists())
+      JOptionPane.showMessageDialog(null, newFullName+" alread exists!",
+                               "Warning", JOptionPane.ERROR_MESSAGE);
+    else
+    {
+      if(oldFile.renameTo(fnew))
+      {
+        Runnable renameFileInTree = new Runnable()
+        {
+          public void run ()
+          {
+            addObject(fnew.getName(),fnew.getParent(),oldNode);
+	    deleteObject(oldNode);
+          };
+        };
+        SwingUtilities.invokeLater(renameFileInTree);
+      }
+      else
+        JOptionPane.showMessageDialog(null, 
+                   "Cannot rename \n"+oldFile.getAbsolutePath()+
+                   "\nto\n"+fnew.getAbsolutePath(), "Rename Error",
+                   JOptionPane.ERROR_MESSAGE);
+    }
+    return;
+  }
+
+
+  /**
+  * 
+  * Define a directory root for the file tree
+  * @param newRoot 	directory to use as the root for
+  *        		the tree.
+  *
+  */
+  public void newRoot(String newRoot)
+  {
+    root = new File(newRoot);
+    DefaultTreeModel model = (DefaultTreeModel)getModel();
+    model = createTreeModel(root);
+    setModel(model);
+  }
+
+  /**
+  *
+  * Get the current root node.
+  * @return directory root.
+  *
+  */
+  public File getRoot()
+  {
+    return root;
+  }
+
+  /**
+  *
+  * Refresh
+  * @param FileNode node to refresh 
+  *
+  */
+  public void refresh(FileNode node)
+  {
+    node.reExplore(filter);
+    DefaultTreeModel model = (DefaultTreeModel)getModel();
+    model.nodeStructureChanged(node);
+  }
+
+  /**
+  *
+  * Set the current file filter
+  *
+  */
+  public void setFilter(FileFilter filter)
+  { 
+    this.filter = filter;
+    Enumeration en = openNode.elements();
+
+    while(en.hasMoreElements())
+      refresh((FileNode)en.nextElement());
+  }
+
+  /**
+  *
+  * Get FileNode of selected node
+  * @return     node that is currently selected
+  *
+  */
+  public FileNode getSelectedNode()
+  {
+    TreePath path = getLeadSelectionPath();
+    if(path == null)
+      return null;
+    FileNode node = (FileNode)path.getLastPathComponent();
+    return node;
+  }
+
+
+  /**
+  *
+  * Get FileNodes of selected nodes
+  * @return     node that is currently selected
+  *
+  */
+  public FileNode[] getSelectedNodes()
+  {
+    TreePath path[] = getSelectionPaths();
+    if(path == null)
+      return null;
+
+    int numberSelected = path.length;
+    FileNode nodes[] = new FileNode[numberSelected];
+    for(int i=0;i<numberSelected;i++)
+       nodes[i] = (FileNode)path[i].getLastPathComponent();
+
+    return nodes;
+  }
+
+
+  /**
+  *
+  * Get selected files
+  * @return     node that is currently selected
+  *
+  */
+  public File[] getSelectedFiles()
+  {
+    FileNode[] fn = getSelectedNodes();
+    int numberSelected = fn.length;
+    File files[] = new File[numberSelected];
+    for(int i=0;i<numberSelected;i++)
+       files[i] = fn[i].getFile();
+
+    return files;
+  }
+
+
+  /**
+  *
+  * Return true if selected node is a file
+  * @return true is a file is selected, false if
+  *         a directory is selected
+  *
+  */
+  public boolean isFileSelection()
+  {
+    TreePath path = getLeadSelectionPath();
+    if(path == null)
+      return false;
+
+    FileNode node = (FileNode)path.getLastPathComponent();
+    return node.isLeaf();
+  }
+
+
+  /**
+  *
+  * Make the given directory the root and create a new
+  * DefaultTreeModel.
+  * @param root         root directory
+  * @param              tree model with the root node set
+  *                     to the given directory
+  *
+  */
+  private DefaultTreeModel createTreeModel(File root)
+  {
+    FileNode rootNode = new FileNode(root);
+    rootNode.explore(filter);
+    openNode = new Vector();
+    openNode.add(rootNode);
+    return new DefaultTreeModel(rootNode);
+  }
+
+
+  /**
+  *
+  * Adding a file (or directory) to the file tree manager.
+  * This looks to see if the directory has already been opened
+  * and updates the filetree if it has.
+  * @param child        new child to add in
+  * @param path         path to where child is to be added
+  * @param node         node to add child to
+  *
+  */
+  public DefaultMutableTreeNode addObject(String child,
+                            String path, FileNode node)
+  {
+
+    DefaultTreeModel model = (DefaultTreeModel)getModel();
+    if(node == null)
+    {
+      node = getNode(path);
+      if(node==null)
+        return null;
+    }
+
+    FileNode parentNode = getNode(path);
+    File newleaf = new File(path + fs + child);
+    FileNode childNode = null;
+
+    if(parentNode.isExplored())
+    {
+      childNode = new FileNode(newleaf);
+      int index = getAnIndex(parentNode,child);
+      if(index > -1)
+        model.insertNodeInto(childNode, parentNode, index);
+    }
+    else if(parentNode.isDirectory())
+    {
+      exploreNode(parentNode);
+      childNode = getNode(path + fs + child);
+    }
+
+    // Make sure the user can see the new node.
+    this.scrollPathToVisible(new TreePath(childNode.getPath()));
+    return childNode;
+  }
+
+
+  /**
+  *
+  * Delete a node from the JTree
+  * @param node         node for deletion
+  *
+  */
+  public void deleteObject(FileNode node)
+  {
+    DefaultTreeModel model =(DefaultTreeModel)getModel();
+    FileNode parentNode = getNode(node.getFile().getParent());
+    model.removeNodeFromParent(node);
+  }
+
+
+  /**
+  *
+  * Explore a directory node
+  * @param dirNode      direcory node to display
+  *
+  */
+  public void exploreNode(FileNode dirNode)
+  {
+    DefaultTreeModel model = (DefaultTreeModel)getModel();
+    dirNode.explore(filter);
+    openNode.add(dirNode);
+    model.nodeStructureChanged(dirNode);
+  }
+
+  /**
+  *
+  * Gets the node from the existing explored nodes and their
+  * children.
+  * @param path         path to a file or directory
+  * @return             corresponding node if the directory or
+  *                     file is visible otherwise returns null.
+  *
+  */
+  private FileNode getNode(String path)
+  {
+    Enumeration en = openNode.elements();
+
+    while(en.hasMoreElements())
+    {
+      FileNode node = (FileNode)en.nextElement();
+      String nodeName = node.getFile().getAbsolutePath();
+      if(nodeName.equals(path))
+        return node;
+    }
+
+// check children of explored nodes
+    en = openNode.elements();
+    while(en.hasMoreElements())
+    {
+      FileNode child = getChildNode((FileNode)en.nextElement(),path);
+      if(child != null)
+        return child;
+    }
+
+    return null;
+  }
+
+
+  /**
+  *
+  * Gets the child node of a parent node
+  * @param parent       parent node
+  * @param childName    name of child
+  * @return the child node
+  *
+  */
+  private FileNode getChildNode(FileNode parent, String childName)
+  {
+    for(Enumeration children = parent.children(); children.hasMoreElements() ;)
+    {
+      FileNode childNode = (FileNode)children.nextElement();
+      String nodeName = childNode.getFile().getAbsolutePath();
+      if(childName.equals(nodeName))
+        return childNode;
+    }
+
+    return null;
+  }
+
+  /**
+  *
+  * Finds a new index for adding a new file to the file manager.
+  * @param parentNode   parent directory node
+  * @param child        new child node
+  * @return             index of the child in the directory
+  *
+  */
+  private int getAnIndex(FileNode parentNode, String child)
+  {
+    //find the index for the child
+    int num = parentNode.getChildCount();
+    int childIndex = num;
+    for(int i=0;i<num;i++)
+    {
+      String nodeName =
+            ((FileNode)parentNode.getChildAt(i)).getFile().getName();
+      if(nodeName.compareTo(child) > 0)
+      {
+        childIndex = i;
+        break;
+      }
+      else if (nodeName.compareTo(child) == 0)  //file already exists
+      {
+        childIndex = -1;
+        break;
+      }
+    }
+    return childIndex;
+  }
+
+
+  /**
+  *
+  * Read a file into a byte array.
+  * @param filename     file name
+  * @return             byte[] contents of file
+  *
+  */
+  protected static byte[] readByteFile(String filename)
+  {
+
+    File fn = new File(filename);
+    byte[] b = null;
+    try
+    {
+      long s = fn.length();
+      if(s == 0)
+        return b;
+      b = new byte[(int)s];
+      FileInputStream fi = new FileInputStream(fn);
+      fi.read(b);
+      fi.close();
+    }
+    catch (IOException ioe)
+    {
+      System.out.println("Cannot read file: " + filename);
+    }
+    return b;
+  }
+
+  /**
+  *
+  * Opens a JFrame with the file contents displayed.
+  * @param filename     file name to display
+  *
+  */
+  private void showFilePane(final String filename)
+  {
+    SwingWorker entryWorker = new SwingWorker()
+    {
+      EntryEdit entry_edit;
+      public Object construct()
+      {
+        try
+        {
+          EntryInformation new_entry_information =
+             new SimpleEntryInformation(Options.getArtemisEntryInformation());
+
+          final Entry entry =  new Entry(EntryFileDialog.getEntryFromFile(
+                         null, new FileDocument(new File(filename)),
+                         new_entry_information, true));
+          if(entry == null)
+            return null;
+
+          final EntryGroup entry_group =
+              new SimpleEntryGroup(entry.getBases());
+
+          entry_group.add(entry);
+          entry_edit = new EntryEdit(entry_group);
+          return null;
+        }
+        catch(NoSequenceException e)
+        {
+          new MessageDialog(null, "read failed: entry contains no sequence");
+        }
+        catch(OutOfRangeException e)
+        {
+          new MessageDialog(null, "read failed: one of the features in " +
+                     " the entry has an out of range " +
+                     "location: " + e.getMessage());
+
+        }
+        catch(NullPointerException npe){}
+
+        return null;
+      }
+
+      public void finished()
+      {
+        if(entry_edit != null)
+          entry_edit.setVisible(true);
+      }
+    };
+    entryWorker.start();
+
+  }
+
+
+////////////////////
+// DRAG AND DROP
+////////////////////
+// drag source
+  public void dragGestureRecognized(DragGestureEvent e) 
+  {
+    // ignore if mouse popup trigger
+    InputEvent ie = e.getTriggerEvent();
+    if(ie instanceof MouseEvent) 
+      if(((MouseEvent)ie).isPopupTrigger()) 
+        return;
+    
+    // drag only files 
+    if(isFileSelection())
+      e.startDrag(DragSource.DefaultCopyDrop,     // cursor
+                 (Transferable)getSelectedNode(), // transferable data
+                                       this);     // drag source listener
+  }
+  public void dragDropEnd(DragSourceDropEvent e) {}
+  public void dragEnter(DragSourceDragEvent e) {}
+  public void dragExit(DragSourceEvent e) {}
+  public void dragOver(DragSourceDragEvent e) {}
+  public void dropActionChanged(DragSourceDragEvent e) {}
+
+// drop sink
+  public void dragEnter(DropTargetDragEvent e)
+  {
+    if(e.isDataFlavorSupported(FileNode.FILENODE)) 
+      e.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
+  }
+
+  public void drop(DropTargetDropEvent e)
+  {
+
+    Transferable t = e.getTransferable();
+    final FileNode dropNode = getSelectedNode();
+    if(dropNode == null)
+    {
+      e.rejectDrop();
+      return;
+    }
+
+    //local drop
+    if(t.isDataFlavorSupported(FileNode.FILENODE))
+    {
+       try
+       {
+         FileNode fn = (FileNode)t.getTransferData(FileNode.FILENODE);
+         fn = getNode(fn.getFile().getAbsolutePath());
+
+         if (dropNode.isLeaf())
+         {
+           e.rejectDrop();
+           return;
+         }
+        
+         String dropDir = dropNode.getFile().getAbsolutePath();
+         String newFullName = dropDir+fs+fn.toString();
+         renameFile(fn.getFile(),fn,newFullName);  
+       }
+       catch(Exception ufe){}        
+    }
+    else
+    {
+      e.rejectDrop();
+      return;
+    }
+
+  }
+
+
+  /**
+  *
+  * When a suitable DataFlavor is offered over a remote file
+  * node the node is highlighted/selected and the drag
+  * accepted. Otherwise the drag is rejected.
+  *
+  */
+  public void dragOver(DropTargetDragEvent e)
+  {
+    if(e.isDataFlavorSupported(FileNode.FILENODE))
+    {
+      Point ploc = e.getLocation();
+      TreePath ePath = getPathForLocation(ploc.x,ploc.y);
+      if (ePath == null)
+      {
+        e.rejectDrag();
+        return;
+      }
+      FileNode node = (FileNode)ePath.getLastPathComponent();
+      if(!node.isDirectory())
+        e.rejectDrag();
+      else 
+      {
+        setSelectionPath(ePath);
+        e.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
+      }
+    }
+    else
+      e.rejectDrag();
+    
+    return;
+  }
+
+  public void dropActionChanged(DropTargetDragEvent e) {}
+  public void dragExit(DropTargetEvent e){}
+
+
+////////////////////
+// AUTO SCROLLING //
+////////////////////
+  /**
+  *
+  * Handles the auto scrolling of the JTree.
+  * @param location The location of the mouse.
+  *
+  */
+  public void autoscroll( Point location )
+  {
+    int top = 0, left = 0, bottom = 0, right = 0;
+    Dimension size = getSize();
+    Rectangle rect = getVisibleRect();
+    int bottomEdge = rect.y + rect.height;
+    int rightEdge = rect.x + rect.width;
+    if( location.y - rect.y < AUTOSCROLL_MARGIN && rect.y > 0 ) 
+      top = AUTOSCROLL_MARGIN;
+    if( location.x - rect.x < AUTOSCROLL_MARGIN && rect.x > 0 )
+      left = AUTOSCROLL_MARGIN;
+    if( bottomEdge - location.y < AUTOSCROLL_MARGIN && bottomEdge < size.height )
+      bottom = AUTOSCROLL_MARGIN;
+    if( rightEdge - location.x < AUTOSCROLL_MARGIN && rightEdge < size.width ) 
+      right = AUTOSCROLL_MARGIN;
+    rect.x += right - left;
+    rect.y += bottom - top;
+    scrollRectToVisible( rect );
+  }
+
+
+  /**
+  *
+  * Gets the insets used for the autoscroll.
+  * @return The insets.
+  *
+  */
+  public Insets getAutoscrollInsets()
+  {
+    Dimension size = getSize();
+    Rectangle rect = getVisibleRect();
+    autoscrollInsets.top = rect.y + AUTOSCROLL_MARGIN;
+    autoscrollInsets.left = rect.x + AUTOSCROLL_MARGIN;
+    autoscrollInsets.bottom = size.height - (rect.y+rect.height) + AUTOSCROLL_MARGIN;
+    autoscrollInsets.right  = size.width - (rect.x+rect.width) + AUTOSCROLL_MARGIN;
+    return autoscrollInsets;
+  }
+
+  /**
+  *
+  * Popup menu listener
+  *
+  */
+  class PopupListener extends MouseAdapter
+  {
+    public void mousePressed(MouseEvent e)
+    {
+      maybeShowPopup(e);
+    }
+
+    public void mouseReleased(MouseEvent e)
+    {
+      maybeShowPopup(e);
+    }
+
+    private void maybeShowPopup(MouseEvent e)
+    {
+      if(e.isPopupTrigger())
+        popup.show(e.getComponent(),
+                e.getX(), e.getY());
+    }
+  }
+
+  public static void main(String[] args)
+  {
+    JFrame tree_frame = new JFrame("File Manager");
+    FileTree ftree    = new FileTree(new File(System.getProperty("user.home")),
+                                     tree_frame,null);
+    JScrollPane jsp   = new JScrollPane(ftree);
+    tree_frame.getContentPane().add(jsp);
+    tree_frame.pack();
+    tree_frame.setVisible(true);
+  } 
+
+}
+
diff --git a/uk/ac/sanger/artemis/components/filetree/LocalAndRemoteFileManager.java b/uk/ac/sanger/artemis/components/filetree/LocalAndRemoteFileManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..b105a2e9c78404e48805148f64a1ad96c3bac0be
--- /dev/null
+++ b/uk/ac/sanger/artemis/components/filetree/LocalAndRemoteFileManager.java
@@ -0,0 +1,541 @@
+/********************************************************************
+*
+*  This library is free software; you can redistribute it and/or
+*  modify it under the terms of the GNU Library General Public
+*  License as published by the Free Software Foundation; either
+*  version 2 of the License, or (at your option) any later version.
+*
+*  This library 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
+*  Library General Public License for more details.
+*
+*  You should have received a copy of the GNU Library General Public
+*  License along with this library; if not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+*  Boston, MA  02111-1307, USA.
+*
+*  Copyright (C) Genome Research Limited
+*
+********************************************************************/
+
+package uk.ac.sanger.artemis.components.filetree;
+
+import uk.ac.sanger.artemis.util.StringVector;
+import uk.ac.sanger.artemis.Options;
+
+import javax.swing.*;
+import java.io.File;
+import java.io.FileFilter;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.awt.*;
+
+public class LocalAndRemoteFileManager extends JFrame
+{
+
+  /** busy cursor */
+  private Cursor cbusy = new Cursor(Cursor.WAIT_CURSOR);
+  /** done cursor */
+  private Cursor cdone = new Cursor(Cursor.DEFAULT_CURSOR);
+
+  public LocalAndRemoteFileManager(JFrame frame)
+  {
+    this(frame,getArtemisFilter());
+  }
+
+  /**
+  *
+  * File Manager Frame
+  * @param frame  parent frame
+  *
+  */
+  public LocalAndRemoteFileManager(JFrame frame, FileFilter filter)
+  {
+    super("File Manager");
+
+    final JPanel localPanel = new JPanel(new BorderLayout());
+    FileTree ftree  = new FileTree(new File(System.getProperty("user.dir")),
+                                       frame, filter);
+    JScrollPane localTree = new JScrollPane(ftree);
+    localPanel.add(localTree,BorderLayout.CENTER);
+
+    final JPanel remotePanel = new JPanel(new BorderLayout());
+
+    FileList flist = new FileList();
+    String pwd = flist.pwd();
+    SshFileTree sshtree = new SshFileTree(pwd);
+    JScrollPane remoteTree = new JScrollPane(sshtree);
+    remotePanel.add(remoteTree,BorderLayout.CENTER);
+
+    final JSplitPane treePane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+                                               localPanel,remotePanel);
+
+    JPanel pane = (JPanel)getContentPane();
+    pane.setLayout(new BorderLayout());
+    pane.add(treePane, BorderLayout.CENTER);
+
+    Dimension screen    = Toolkit.getDefaultToolkit().getScreenSize();
+    Dimension panelSize = new Dimension(210, (int)(screen.getHeight()/3));
+    setJMenuBar(makeMenuBar(pane,ftree,sshtree,localPanel,remotePanel,treePane,panelSize));
+    localPanel.add(getFileFileterComboBox(ftree), BorderLayout.SOUTH);
+  
+    remoteTree.setPreferredSize(panelSize);
+    localTree.setPreferredSize(panelSize);
+
+    pack();
+    
+    int yloc = (int)((screen.getHeight()-getHeight())/2);
+    setLocation(0,yloc);  
+    setVisible(true);
+  }
+
+  protected JComboBox getFileFileterComboBox(final FileTree ftree)
+  {
+    String[] filters = { "Artemis Files", "Sequence Files", 
+                         "Feature Files", "All Files" };
+    final JComboBox comboFilter = new JComboBox(filters);
+    comboFilter.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        String select = (String)comboFilter.getSelectedItem(); 
+        if(select.equals("Artemis Files"))
+          ftree.setFilter(getArtemisFilter());
+        else if(select.equals("Sequence Files"))
+          ftree.setFilter(getSequenceFilter());
+        else if(select.equals("Feature Files"))
+          ftree.setFilter(getFeatureFilter());
+        else if(select.equals("All Files"))
+        {
+          ftree.setFilter(new FileFilter()
+          {
+            public boolean accept(File pathname)
+            {
+              if(pathname.getName().startsWith("."))
+                return false;
+              return true;
+            }
+          });
+        }
+      }
+    });
+    return comboFilter;
+  }
+
+  /**
+  *
+  * Get a file filter for sequence and feature suffixes.
+  * @return file filter
+  */
+  protected static FileFilter getArtemisFilter()
+  {
+    final StringVector sequence_suffixes =
+      Options.getOptions().getOptionValues("sequence_file_suffixes");
+
+    final StringVector feature_suffixes =
+      Options.getOptions().getOptionValues("feature_file_suffixes");
+
+    final FileFilter artemis_filter = new FileFilter()
+    {
+      public boolean accept(File pathname)
+      {
+        if(pathname.isDirectory() &&
+           !pathname.getName().startsWith("."))
+          return true;
+          
+        for(int i = 0; i<sequence_suffixes.size(); ++i)
+        {
+          final String suffix = sequence_suffixes.elementAt(i);
+
+          if(pathname.getName().endsWith("." + suffix) ||
+             pathname.getName().endsWith("." + suffix + ".gz"))
+            return true;
+        }
+
+        for(int i = 0; i<feature_suffixes.size(); ++i)
+        {
+          final String suffix = feature_suffixes.elementAt(i);
+
+          if(pathname.getName().endsWith("." + suffix) ||
+             pathname.getName().endsWith("." + suffix + ".gz"))
+            return true;
+        }
+        return false;
+      }
+    };
+    return artemis_filter;
+  }
+
+
+  /**
+  *
+  * Get a file filter for feature suffixes.
+  * @return file filter
+  */
+  protected static FileFilter getFeatureFilter()
+  {
+    final StringVector feature_suffixes =
+      Options.getOptions().getOptionValues("feature_file_suffixes");
+
+    final FileFilter feature_filter = new FileFilter()
+    {
+      public boolean accept(File pathname)
+      {
+        if(pathname.isDirectory() &&
+           !pathname.getName().startsWith("."))
+          return true;
+
+        for(int i = 0; i<feature_suffixes.size(); ++i)
+        {
+          final String suffix = feature_suffixes.elementAt(i);
+
+          if(pathname.getName().endsWith("." + suffix) ||
+             pathname.getName().endsWith("." + suffix + ".gz"))
+            return true;
+        }
+        return false;
+      }
+    };
+    return feature_filter;
+  }
+
+  /**
+  *
+  * Get a file filter for sequence suffixes.
+  * @return file filter
+  */
+  protected static FileFilter getSequenceFilter()
+  {
+    final StringVector sequence_suffixes =
+      Options.getOptions().getOptionValues("sequence_file_suffixes");
+
+    final FileFilter seq_filter = new FileFilter()
+    {
+      public boolean accept(File pathname)
+      {
+        if(pathname.isDirectory() &&
+           !pathname.getName().startsWith("."))
+          return true;
+         
+        for(int i = 0; i<sequence_suffixes.size(); ++i)
+        {
+          final String suffix = sequence_suffixes.elementAt(i);
+
+          if(pathname.getName().endsWith("." + suffix) ||
+             pathname.getName().endsWith("." + suffix + ".gz"))
+            return true;
+        }
+
+        return false;
+      }
+    };
+    return seq_filter;
+  }
+
+  /**
+  *
+  * Set up a menu and tool bar
+  * @param pane   panel to add toolbar to
+  * @param ftree  file tree display
+  *
+  */
+  private JMenuBar makeMenuBar(JPanel pane, final FileTree ftree, final SshFileTree sshtree,
+                               final JPanel localPanel, final JPanel remotePanel,
+                               final JSplitPane treePane, final Dimension panelSize)
+  {
+    JMenuBar mBar = new JMenuBar();
+    JMenu fileMenu = new JMenu("File");
+    mBar.add(fileMenu);
+    
+    JMenuItem fileMenuGoto = new JMenuItem("Go to Directory ...");
+    fileMenuGoto.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        String dir = ftree.getRoot().getAbsolutePath();
+        String newDir = JOptionPane.showInputDialog(LocalAndRemoteFileManager.this,
+                                             "Go to Directory:",dir);      
+
+        if(newDir == null)
+          return;
+       
+        newDir = newDir.trim();
+        File newDirFile = new File(newDir);
+        
+        if(newDirFile.exists() &&
+           newDirFile.canRead() &&
+           !newDir.equals(dir))
+          ftree.newRoot(newDir);
+        else
+        {
+          String error = null;
+          if(!newDirFile.exists())
+            error = new String(newDir+" doesn't exist!");
+          else if(!newDirFile.canRead())
+            error = new String(newDir+" cannot be read!");
+          else if(newDir.equals(dir))
+            error = new String("Same directory!");
+
+          if(error != null)
+            JOptionPane.showMessageDialog(LocalAndRemoteFileManager.this,
+                                        error, "Warning",
+                                        JOptionPane.WARNING_MESSAGE);
+        }
+      }
+    });
+    fileMenu.add(fileMenuGoto);
+    fileMenu.add(new JSeparator());
+    
+    JRadioButtonMenuItem prefV = new JRadioButtonMenuItem("Vertical Split");
+    fileMenu.add(prefV);
+    prefV.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        treePane.remove(remotePanel);
+        treePane.remove(localPanel);
+        treePane.setOrientation(JSplitPane.VERTICAL_SPLIT);
+        treePane.setTopComponent(localPanel);
+        treePane.setBottomComponent(remotePanel);
+        remotePanel.setPreferredSize(panelSize);
+        localPanel.setPreferredSize(panelSize);
+
+        pack();
+        treePane.setDividerLocation(0.5);
+      }
+    });
+//  prefV.setSelected(true);
+    ButtonGroup group = new ButtonGroup();
+    group.add(prefV);
+
+    JRadioButtonMenuItem prefH = new JRadioButtonMenuItem("Horizontal Split");
+    fileMenu.add(prefH);
+    prefH.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        treePane.remove(remotePanel);
+        treePane.remove(localPanel);
+        treePane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
+        treePane.setLeftComponent(localPanel);
+        treePane.setRightComponent(remotePanel);
+
+        remotePanel.setPreferredSize(panelSize);
+        localPanel.setPreferredSize(panelSize);
+
+        pack();
+        treePane.setDividerLocation(0.5);
+      }
+    });
+    group.add(prefH);
+    prefH.setSelected(true);
+
+    JMenuItem fileMenuClose = new JMenuItem("Close");
+    fileMenuClose.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        setVisible(false);
+      }
+    });
+    fileMenu.add(fileMenuClose);
+
+    // remote tool bar set up
+    JToolBar remoteToolBar  = new JToolBar();
+    Dimension buttonSize = new Dimension(22,24);
+
+    JButton remoteUpBt = new UpButton();
+    remoteUpBt.setPreferredSize(buttonSize);
+    remoteUpBt.setMinimumSize(buttonSize);
+
+    remoteUpBt.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        LocalAndRemoteFileManager.this.setCursor(cbusy);
+        sshtree.up();
+        LocalAndRemoteFileManager.this.setCursor(cdone);
+      }
+    });
+    remoteToolBar.add(remoteUpBt);
+
+    remoteToolBar.add(Box.createVerticalStrut(35));
+    remotePanel.add(remoteToolBar, BorderLayout.NORTH);
+
+    // local tool bar set up
+    JToolBar toolBar  = new JToolBar();
+
+    JButton upBt = new UpButton();
+    upBt.setPreferredSize(buttonSize);
+    upBt.setMinimumSize(buttonSize);
+
+    upBt.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        LocalAndRemoteFileManager.this.setCursor(cbusy);
+        File root = ftree.getRoot();
+        String parent = root.getParent();
+        if(parent != null)
+          ftree.newRoot(parent);
+        LocalAndRemoteFileManager.this.setCursor(cdone);
+      }
+    });
+    toolBar.add(upBt);
+
+// yeastpub
+    JButton shortCut1 = new JButton()
+    {
+      public void paintComponent(Graphics g)
+      {
+        super.paintComponent(g);
+        Graphics2D g2 = (Graphics2D)g;
+        Font font = new Font("Monospaced", Font.BOLD, 14);
+        g2.setFont(font);
+
+        g2.setColor(Color.black);
+        g2.drawString("Y",4,18);
+        g2.setColor(Color.red);
+        g2.drawString("P",10,15);
+        setSize(22,24);
+      }
+    };
+    shortCut1.setPreferredSize(buttonSize);
+    shortCut1.setMinimumSize(buttonSize);
+    shortCut1.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        ftree.newRoot("/nfs/disk222/yeastpub");
+      }
+    });
+
+    if((new File("/nfs/disk222/yeastpub")).exists())
+      toolBar.add(shortCut1);
+
+// pathdata
+   JButton shortCut2 = new JButton()
+    {
+      public void paintComponent(Graphics g)
+      {
+        super.paintComponent(g);
+        Graphics2D g2 = (Graphics2D)g;
+        Font font = new Font("Monospaced", Font.BOLD, 14);
+        g2.setFont(font);
+
+        g2.setColor(Color.black);
+        g2.drawString("P",4,18);
+        g2.setColor(Color.red);
+        g2.drawString("D",10,15);
+        setSize(22,24);
+      }
+    };
+    shortCut2.setPreferredSize(buttonSize);
+    shortCut2.setMinimumSize(buttonSize);
+    shortCut2.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        ftree.newRoot("/nfs/pathdata/");
+      }
+    });
+
+    if((new File("/nfs/pathdata/")).exists())
+      toolBar.add(shortCut2);
+
+// home button
+    JButton homeBt = new JButton()
+    {
+      public void paintComponent(Graphics g)
+      {
+        super.paintComponent(g);
+        Graphics2D g2 = (Graphics2D)g;
+                                                                                
+        g2.setColor(Color.blue);
+        float loc1[][] = { {3,14}, {11,3}, {19,14},
+                           {17,14}, {17,18}, {5,18}, {5,14} };
+        g2.fill(makeShape(loc1));
+                                                                                
+        setSize(22,24);
+      }
+    };
+    homeBt.setPreferredSize(buttonSize);
+    homeBt.setMinimumSize(buttonSize);
+    homeBt.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        ftree.newRoot(System.getProperty("user.home"));
+      }
+    });
+    toolBar.add(homeBt);
+
+    toolBar.add(Box.createVerticalStrut(35));
+    localPanel.add(toolBar, BorderLayout.NORTH);
+
+    return mBar;
+  }
+
+  /**
+  *
+  * Used to draw a Shape.
+  *
+  */
+  public static GeneralPath makeShape(float loc[][]) 
+  {
+    GeneralPath path = new GeneralPath(GeneralPath.WIND_NON_ZERO);
+
+    path.moveTo(loc[0][0],loc[0][1]);
+
+    for(int i=1; i<loc.length; i++)
+      path.lineTo(loc[i][0],loc[i][1]);
+    
+    return path;
+  }
+
+  class UpButton extends JButton
+  {
+    public void paintComponent(Graphics g)
+    {
+      super.paintComponent(g);
+      Graphics2D g2 = (Graphics2D)g; 
+
+      g2.setColor(new Color(0,128,0));
+      float loc1[][] = { {11,18}, {7,18}, {7,14},
+                         {3,14},  {11,4} };
+                
+      g2.fill(makeShape(loc1));
+      g2.setColor(Color.green);
+
+      float loc2[][] = { {11,18}, {15,18}, {15,14},
+                         {19,14},  {11,4} };
+      g2.fill(makeShape(loc2));
+
+      setSize(22,24);
+    }
+  }
+
+  public static void main(String args[])
+  {
+    final javax.swing.LookAndFeel look_and_feel =
+      javax.swing.UIManager.getLookAndFeel();
+
+    final javax.swing.plaf.FontUIResource font_ui_resource =
+      Options.getOptions().getFontUIResource();
+
+    java.util.Enumeration keys = UIManager.getDefaults().keys();
+    while(keys.hasMoreElements())
+    {
+      Object key = keys.nextElement();
+      Object value = UIManager.get(key);
+      if(value instanceof javax.swing.plaf.FontUIResource)
+        UIManager.put(key, font_ui_resource);
+    }
+
+    JFrame frame = new LocalAndRemoteFileManager(null);
+    frame.pack();
+    frame.setVisible(true);
+  }
+}
+
diff --git a/uk/ac/sanger/artemis/components/filetree/RemoteFileNode.java b/uk/ac/sanger/artemis/components/filetree/RemoteFileNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..4e7a678a716f57b9e8dbee715831beaddb72b90f
--- /dev/null
+++ b/uk/ac/sanger/artemis/components/filetree/RemoteFileNode.java
@@ -0,0 +1,266 @@
+/********************************************************************
+*
+*  This library is free software; you can redistribute it and/or
+*  modify it under the terms of the GNU Library General Public
+*  License as published by the Free Software Foundation; either
+*  version 2 of the License, or (at your option) any later version.
+*
+*  This library 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
+*  Library General Public License for more details.
+*
+*  You should have received a copy of the GNU Library General Public
+*  License along with this library; if not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+*  Boston, MA  02111-1307, USA.
+*
+*  @author: Copyright (C) Tim Carver
+*
+********************************************************************/
+
+package uk.ac.sanger.artemis.components.filetree;
+
+import java.awt.datatransfer.*;
+import javax.swing.tree.*;
+import java.io.*;
+import java.util.*;
+
+/**
+*
+* File node for remote file tree manager
+*
+*/
+public class RemoteFileNode extends DefaultMutableTreeNode 
+                    implements Transferable, Serializable
+{
+  /** true if node is explored */
+  private boolean explored = false;
+  /** true if node is a directory */
+  private boolean isDir = false;
+  /** full name of node */
+  private String fullname;
+  /** path to the file on the server */
+  private String serverPathToFile;
+  /** root directory */
+  private String rootdir; 
+
+  /** parent directory listing */
+  private transient FileList parentList;        // make transient for
+  /** jemboss properties */
+  private transient Properties mysettings;      // Transferable to work
+  /** remote server file roots */
+  private transient String froots;
+  /** file separator for server files */
+  private String fs = "/";
+
+  final public static DataFlavor REMOTEFILENODE = 
+         new DataFlavor(RemoteFileNode.class, "Remote file");
+  static DataFlavor remoteFlavors[] = { REMOTEFILENODE, 
+                             DataFlavor.stringFlavor };
+
+
+  /**
+  *
+  * @param mysettings		jemboss properties
+  * @param froots		remote server file roots
+  * @param file		file for this node
+  * @param parentList		parent directory listing
+  * @param parent		parent to this node
+  *
+  */
+  public RemoteFileNode(Properties mysettings, String froots,
+                  String file, FileList parentList, String parent)
+  {
+    this(mysettings, froots, file, parentList, parent, false);
+  }
+
+  /**
+  *
+  * @param mysettings         jemboss properties
+  * @param froots             remote server file roots
+  * @param file               file for this node
+  * @param parentList         parent directory listing
+  * @param parent             parent to this node
+  * @param ldir		true if the node is a directory
+  *
+  */
+  public RemoteFileNode(Properties mysettings, String froots,
+                  String file, FileList parentList, String parent,
+                  boolean ldir)
+  { 
+    this.mysettings = mysettings;
+    this.froots = froots;
+    this.parentList = parentList;
+    isDir = ldir;
+    rootdir = froots;
+    serverPathToFile = froots;
+
+    if(parent != null)
+    {
+      if(parent.endsWith("/."))
+        parent = parent.substring(0,parent.length()-1);
+      else if(parent.endsWith(fs))
+        parent = parent.substring(0,parent.length());
+
+      if(parent.equals("."))
+        fullname = file;
+      else
+      {
+        fullname = parent + fs + file;
+        if(serverPathToFile.endsWith(fs))
+          serverPathToFile = serverPathToFile.concat(parent);
+        else
+          serverPathToFile = serverPathToFile.concat(fs+parent);
+      }
+    }
+    
+    if(parentList != null)
+    {
+      if(parentList.isDirectory(file))
+        isDir = true;
+    }
+    else if(parent == null)
+      fullname = ".";
+
+    setUserObject(file); 
+  }
+   
+  /** @return		true if node is a directory */
+  public boolean getAllowsChildren() { return isDir; }
+  /** @return         true if node is a file */
+  public boolean isLeaf() { return !isDir; }
+  /** @return         true if node is a directory */
+  public boolean isDirectory() { return isDir; }
+  /** @return         the node name */
+  public String getFile() { return (String)getUserObject(); }
+  /** @return         root directory */
+  public String getRootDir() { return rootdir; }
+  /** @return         full name of the node */
+  public String getFullName() { return fullname; }
+  /** @return         path on server */
+  public String getPathName() { return serverPathToFile; }
+  /** @return         true if explored */
+  public boolean isExplored() { return explored; }
+   
+  protected void setDir(boolean isDir)
+  {
+    this.isDir = isDir;
+  }
+
+  /**
+  *
+  * Get the server name 
+  * @return 	server name
+  *
+  */
+  public String getServerName() 
+  { 
+    String prefix = serverPathToFile;
+    if(!prefix.endsWith(fs))
+      prefix = prefix.concat(fs);
+
+    if(fullname.equals("."))
+      return prefix;
+
+    return prefix + (String)getUserObject();
+  }
+
+  /**
+  *
+  * Explore the node and add new child nodes 
+  *
+  */
+  public void explore() 
+  {
+    if(!isDir)
+      return;
+
+    if(!explored)
+    {
+      FileList flist = new FileList();
+
+      String dir;
+      if(getRootDir().equals(""))
+        dir = new String("~/"+getFullName());
+      else
+        dir = new String(getRootDir()+"/"+getFullName());
+      dir = dir.trim();
+
+      flist.getDirList(dir);
+      Vector children = flist.fileVector();
+      for(int i=0;i<children.size();i++)
+        add(new RemoteFileNode(mysettings,froots,(String)children.get(i),
+                               flist,fullname));
+    }
+      explored = true;
+  }
+
+  protected boolean delete()
+  {
+    FileList flist = new FileList();
+    return flist.delete(getRootDir()+"/"+getFullName());
+  }
+
+  protected boolean mkdir(String dir)
+  {
+    FileList flist = new FileList();
+    return flist.mkdir(dir);
+  }
+
+  protected boolean rename(String new_file)
+  {
+    FileList flist = new FileList();
+    return flist.rename(getRootDir()+"/"+getFullName(), new_file);
+  }
+
+  protected boolean put(File local_file)
+  {
+    FileList flist = new FileList();
+    return flist.put(getRootDir()+"/"+getFullName(), local_file);
+  }
+
+
+  public byte[] getFileContents()
+  {
+    FileList flist = new FileList();
+    return flist.getFileContents(getRootDir()+"/"+getFullName());
+  }
+
+// Transferable
+  public DataFlavor[] getTransferDataFlavors()
+  {
+    return remoteFlavors;
+  }
+
+  public boolean isDataFlavorSupported(DataFlavor f)
+  {
+    if(f.equals(REMOTEFILENODE) || f.equals(DataFlavor.stringFlavor))
+      return true;
+    return false;
+  }
+
+  public Object getTransferData(DataFlavor d) 
+      throws UnsupportedFlavorException, IOException
+  {
+    if(d.equals(REMOTEFILENODE))
+      return this;
+    else if(d.equals(DataFlavor.stringFlavor))
+      return getServerName();
+    else throw new UnsupportedFlavorException(d);
+  } 
+
+// Serializable    
+  private void writeObject(java.io.ObjectOutputStream out) throws IOException 
+  {
+    out.defaultWriteObject();
+  }
+
+  private void readObject(java.io.ObjectInputStream in)
+    throws IOException, ClassNotFoundException 
+  {
+    in.defaultReadObject();
+  }
+
+}
+
diff --git a/uk/ac/sanger/artemis/components/filetree/SshFileTree.java b/uk/ac/sanger/artemis/components/filetree/SshFileTree.java
new file mode 100644
index 0000000000000000000000000000000000000000..19be4f2a0d514dccb5912bb23ac831eef8762594
--- /dev/null
+++ b/uk/ac/sanger/artemis/components/filetree/SshFileTree.java
@@ -0,0 +1,1000 @@
+/********************************************************************
+*
+*  This library is free software; you can redistribute it and/or
+*  modify it under the terms of the GNU Library General Public
+*  License as published by the Free Software Foundation; either
+*  version 2 of the License, or (at your option) any later version.
+*
+*  This library 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
+*  Library General Public License for more details.
+*
+*  You should have received a copy of the GNU Library General Public
+*  License along with this library; if not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+*  Boston, MA  02111-1307, USA.
+*
+*  @author: Copyright (C) Tim Carver
+*
+********************************************************************/
+
+package uk.ac.sanger.artemis.components.filetree;
+
+import uk.ac.sanger.artemis.components.SwingWorker;
+import uk.ac.sanger.artemis.components.EntryEdit;
+import uk.ac.sanger.artemis.components.EntryFileDialog;
+import uk.ac.sanger.artemis.io.EntryInformation;
+import uk.ac.sanger.artemis.io.SimpleEntryInformation;
+import uk.ac.sanger.artemis.*;
+import uk.ac.sanger.artemis.util.RemoteFileDocument;
+import uk.ac.sanger.artemis.util.OutOfRangeException;
+import uk.ac.sanger.artemis.sequence.NoSequenceException;
+import uk.ac.sanger.artemis.components.MessageDialog;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.datatransfer.*;
+import java.awt.dnd.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+import java.io.*;
+import java.util.*;
+
+
+/**
+*
+* Creates a remote file tree which is a drag source & sink
+*
+*/
+public class SshFileTree extends JTree implements DragGestureListener,
+                           DragSourceListener, DropTargetListener, ActionListener,
+                           Autoscroll 
+{
+
+  /** properties */
+  private Properties mysettings; 
+  /** remote directory roots */
+  private static String froots;
+  /** popup menu */
+  private JPopupMenu popup;
+  /** file separator */
+  private String fs = new String(System.getProperty("file.separator"));
+  /** line separator */
+  private String ls = new String(System.getProperty("line.separator"));
+  /** store of directories that are opened */
+  private Vector openNode;
+  /** busy cursor */
+  private Cursor cbusy = new Cursor(Cursor.WAIT_CURSOR);
+  /** done cursor */
+  private Cursor cdone = new Cursor(Cursor.DEFAULT_CURSOR);
+  /** AutoScroll margin */
+  private static final int AUTOSCROLL_MARGIN = 45;
+  /** used by AutoScroll method */
+  private Insets autoscrollInsets = new Insets( 0, 0, 0, 0 );
+
+
+  /**
+  *
+  * @param froots	remote directory roots
+  *
+  */
+  public SshFileTree(String froots)
+  {
+    this.froots = froots;
+
+    DragSource dragSource = DragSource.getDefaultDragSource();
+    dragSource.createDefaultDragGestureRecognizer(
+             this,                             // component where drag originates
+             DnDConstants.ACTION_COPY_OR_MOVE, // actions
+             this);                            // drag gesture recognizer
+
+    setDropTarget(new DropTarget(this,this));
+    DefaultTreeModel model = createTreeModel(froots);
+    setModel(model);
+    createTreeModelListener();
+
+    this.getSelectionModel().setSelectionMode
+                  (TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
+
+// popup menu
+    addMouseListener(new PopupListener());
+    popup = new JPopupMenu();
+    JMenuItem menuItem = new JMenuItem("Refresh");
+    menuItem.addActionListener(this);
+    popup.add(menuItem);
+    popup.add(new JSeparator());
+//open menu
+    JMenu openMenu = new JMenu("Open With");
+    popup.add(openMenu);
+    menuItem = new JMenuItem("Jemboss Aligmnment Editor");
+    menuItem.addActionListener(this);
+    openMenu.add(menuItem);
+    menuItem = new JMenuItem("Artemis");
+    menuItem.addActionListener(this);
+    openMenu.add(menuItem);
+
+    menuItem = new JMenuItem("Rename...");
+    menuItem.addActionListener(this);
+    popup.add(menuItem);
+    menuItem = new JMenuItem("New Folder...");
+    menuItem.addActionListener(this);
+    popup.add(menuItem);
+    menuItem = new JMenuItem("Delete...");
+    menuItem.addActionListener(this);
+    popup.add(menuItem);
+    popup.add(new JSeparator());
+    menuItem = new JMenuItem("De-select All");
+    menuItem.addActionListener(this);
+    popup.add(menuItem);
+
+
+    //Listen for when a file is selected
+    addMouseListener(new MouseListener()
+    {
+      public void mouseClicked(MouseEvent me)
+      {
+        if(me.getClickCount() == 2 && isFileSelection())
+        {
+          RemoteFileNode node = (RemoteFileNode)getLastSelectedPathComponent();
+          if(node==null)
+            return;
+          setCursor(cbusy);
+          if(node.isLeaf())
+            showFilePane(node);
+          setCursor(cdone);
+        }
+      }
+      public void mousePressed(MouseEvent me){}
+      public void mouseEntered(MouseEvent me){}
+      public void mouseExited(MouseEvent me){}
+      public void mouseReleased(MouseEvent me){}
+    });
+
+    addTreeExpansionListener(new TreeExpansionListener()
+    {
+      public void treeExpanded(TreeExpansionEvent e) 
+      {
+        TreePath path = e.getPath();
+        if(path != null) 
+        {
+          setCursor(cbusy);
+          RemoteFileNode node = (RemoteFileNode)path.getLastPathComponent();
+
+          if(!node.isExplored()) 
+            exploreNode(node);
+          setCursor(cdone);
+        }
+      }
+      public void treeCollapsed(TreeExpansionEvent e){}
+    });
+
+  }
+
+
+  /**
+  *
+  * This is used to refresh the file manager
+  *
+  */
+  public void refreshRoot()
+  {
+    DefaultTreeModel model = (DefaultTreeModel)getModel();
+    model = createTreeModel(froots);
+    setModel(model);
+  }
+
+
+  /**
+  *
+  * Define a directory root for the file tree
+  * @param newRoot      directory to use as the root for
+  *                     the tree.
+  *
+  */
+  public void up()
+  {
+    File current = new File(froots);
+    froots = current.getParentFile().getAbsolutePath();
+    DefaultTreeModel model = (DefaultTreeModel)getModel();
+    model = createTreeModel(froots);
+    setModel(model);
+  }
+
+  /**
+  *
+  * Popup menu actions
+  * @param e	action event
+  *
+  */
+  public void actionPerformed(ActionEvent e)
+  {
+
+    JMenuItem source = (JMenuItem)(e.getSource());
+    final RemoteFileNode node = getSelectedNode();
+    if(node == null)
+    {
+      JOptionPane.showMessageDialog(null,"No file selected.",
+                                    "Warning",
+                                    JOptionPane.WARNING_MESSAGE);
+      return;
+    }
+
+    final String fn = node.getFullName();
+    final String parent = node.getPathName();
+    String rootPath = node.getRootDir();
+    RemoteFileNode pn = node;
+
+    if(source.getText().equals("Refresh"))
+    {
+      refreshRoot();
+    }
+    else if(source.getText().equals("Jemboss Aligmnment Editor"))
+    {
+      final byte[] contents = node.getFileContents();
+      org.emboss.jemboss.editor.AlignJFrame ajFrame =
+                    new org.emboss.jemboss.editor.AlignJFrame(new String(contents), fn);
+      ajFrame.setVisible(true);
+    }
+    else if(source.getText().equals("Artemis"))
+      showFilePane(node);
+    else if(source.getText().equals("New Folder..."))
+    {
+      final String inputValue = JOptionPane.showInputDialog(null,
+                          "Folder Name","Create New Folder in",
+                          JOptionPane.QUESTION_MESSAGE);
+
+      String dropDest = null;
+    
+      if(node.isLeaf())
+      {
+        pn = (RemoteFileNode)node.getParent();
+        dropDest = pn.getFullName() + "/" + inputValue; //assumes unix file sep.!
+      }
+      else
+        dropDest = node.getFullName() + "/" + inputValue;
+
+      String newNode = pn.getServerName();
+      if(!newNode.endsWith("/"))
+        newNode = newNode.concat("/");
+      newNode = newNode.concat(inputValue);
+
+      if(nodeExists(pn,newNode))
+        return;
+
+      if(inputValue != null && !inputValue.equals("") )
+      {
+        final RemoteFileNode pnn = pn;
+        node.mkdir(newNode);
+
+        Runnable addDirToTree = new Runnable()
+        {
+          public void run () { addObject(pnn,inputValue,true); };
+        };
+        SwingUtilities.invokeLater(addDirToTree);
+      }
+    }
+    else if(source.getText().equals("Delete..."))
+    {
+      RemoteFileNode nodes[] = getSelectedNodes();
+      String sname = "";
+      for(int i=0;i<nodes.length;i++)
+        sname = sname.concat(nodes[i].getServerName()+ls);
+ 
+      int n = JOptionPane.showConfirmDialog(null,
+             "Delete"+ls+sname+"?", "Delete "+sname,
+             JOptionPane.YES_NO_OPTION);
+      if(n == JOptionPane.YES_OPTION)
+        for(int i=0;i<nodes.length;i++)
+          deleteNode(nodes[i]);
+    }
+    else if(source.getText().equals("De-select All"))
+      clearSelection();
+    else if(source.getText().equals("Rename..."))
+    {
+      if(node.isLeaf())
+      {
+        String inputValue = (String)JOptionPane.showInputDialog(null,
+                              "New File Name","Rename "+fn,
+                              JOptionPane.QUESTION_MESSAGE,null,null,fn);
+
+        pn = (RemoteFileNode)node.getParent();
+
+        if(inputValue != null && !inputValue.equals("") )
+        {
+          String newfile = null;
+          if(parent.endsWith("/"))
+            newfile = parent+inputValue;
+          else
+            newfile = parent+"/"+inputValue;
+          String dir = ((RemoteFileNode)node.getParent()).getFullName();
+          if(inputValue.indexOf("/") > 0)
+          {
+            int index = inputValue.lastIndexOf("/");
+            dir = inputValue.substring(0,index);
+          }
+      
+          RemoteFileNode parentNode = getNode(dir);
+          if(!nodeExists(parentNode,newfile))
+            rename(rootPath,fn,parent,inputValue,node,parentNode);
+        }
+      }
+    }
+  }
+
+
+  /**
+  *
+  * Delete a node (file or directory) from the tree 
+  * and from the server
+  * @param node	node to remove
+  *
+  */
+  private void deleteNode(final RemoteFileNode node)
+  {
+    setCursor(cbusy);
+
+    boolean deleted = false;
+    deleted = node.delete();
+    
+    if(!deleted && !node.isLeaf())
+      JOptionPane.showMessageDialog(null,"Cannot delete"+ls+
+                 node.getServerName()+
+                 ls+"this directory is not empty","Warning",
+                 JOptionPane.ERROR_MESSAGE);
+    else if(deleted)
+    {
+      Runnable deleteFileFromTree = new Runnable()
+      {
+        public void run () { deleteObject(node); };
+      };
+      SwingUtilities.invokeLater(deleteFileFromTree);
+    }
+
+    setCursor(cdone);
+  }
+
+
+  /**
+  *
+  * Explore a directory node
+  * @param dirNode      direcory node to display
+  *
+  */
+  public void exploreNode(RemoteFileNode dirNode)
+  {
+    DefaultTreeModel model = (DefaultTreeModel)getModel();
+    dirNode.explore();
+    openNode.add(dirNode);
+    model.nodeStructureChanged(dirNode);
+  }
+
+
+  /**
+  *
+  * Test if a child node exists
+  * @param parentNode	parent node
+  * @param child	child to test for
+  *
+  */
+  public boolean nodeExists(RemoteFileNode parentNode,String child)
+  {
+    RemoteFileNode childNode = getChildNode(parentNode,child);
+    if(childNode != null)
+    {
+      String ls = System.getProperty("line.separator");
+      JOptionPane.showMessageDialog(null, child+ls+" already exists!",
+                                    "File Exists",
+                                    JOptionPane.ERROR_MESSAGE);
+      return true;
+    }
+
+    return false;
+  }
+
+
+  /**
+  *
+  * Rename a node from the tree
+  * @param rootPath		root path
+  * @param fullname		full name of node to rename
+  * @param pathToNewFile	path to new file
+  * @param newfile		new file name
+  * @param node			node to rename
+  *
+  */
+  private void rename(String rootPath, final String fullname, 
+                      String pathToNewFile, final String newfile,
+                      final RemoteFileNode node, final RemoteFileNode parentNode)
+  {
+    setCursor(cbusy);
+    node.rename(pathToNewFile+"/"+newfile);
+    setCursor(cdone);
+    Runnable deleteFileFromTree = new Runnable()
+    {
+      public void run ()
+      {
+        addObject(parentNode,newfile,false);
+        deleteObject(node);
+      };
+    };
+    SwingUtilities.invokeLater(deleteFileFromTree);
+  }
+
+
+  /**
+  *
+  * Adding a file (or directory) to the file tree manager.
+  * This looks to see if the directory has already been opened
+  * and updates the filetree if it has.
+  * @param parentNode   parent node
+  * @param child        file to add to the tree
+  * @param ldir         true if child is a directory
+  *
+  */
+  public void addObject(RemoteFileNode parentNode,String child,
+                        boolean ldir)
+  {
+    DefaultTreeModel model = (DefaultTreeModel)getModel();
+    
+    if(parentNode == null)
+      return;
+
+    String path = parentNode.getFullName();
+    //create new file node
+    if(path.equals(" "))
+      path = "";
+
+    if(child.indexOf("/") > -1)
+      child = child.substring(child.lastIndexOf("/")+1);
+
+    RemoteFileNode childNode = null;
+    if(!parentNode.isExplored())
+    {
+      exploreNode(parentNode);
+      childNode = getNode(parentNode.getServerName() + "/" + child);
+    }
+    else
+    {
+      childNode = new RemoteFileNode(mysettings,froots,
+                                     child,null,path,ldir);
+
+      //find the index for the child
+      int num = parentNode.getChildCount();
+      int childIndex = num;
+      for(int i=0;i<num;i++)
+      {
+        String nodeName = ((RemoteFileNode)parentNode.getChildAt(i)).getFile();
+        if(nodeName.compareTo(child) > 0)
+        {
+          childIndex = i;
+          break;
+        }
+        else if(nodeName.compareTo(child) == 0)  //file already exists
+        {
+          childIndex = -1;
+          break;
+        }
+      }
+      if(childIndex != -1)
+        model.insertNodeInto(childNode,parentNode,childIndex);
+    }
+
+    // Make sure the user can see the new node.
+    this.scrollPathToVisible(new TreePath(childNode.getPath()));
+
+    return;
+  }
+
+
+  /**
+  *
+  * Delete a node from the tree
+  * @param node		node to remove
+  *
+  */
+  public void deleteObject(RemoteFileNode node)
+  {
+    RemoteFileNode parentNode = (RemoteFileNode)node.getParent();
+    DefaultTreeModel model = (DefaultTreeModel)getModel();
+    model.removeNodeFromParent(node);
+//  model.nodeStructureChanged(parentNode);
+    return;
+  }
+
+
+  /**
+  *
+  * Get RemoteFileNode of selected node
+  * @return     node that is currently selected
+  *
+  */
+  public RemoteFileNode getSelectedNode()
+  {
+    TreePath path = getLeadSelectionPath();
+    if(path == null)
+      return null;
+    RemoteFileNode node = (RemoteFileNode)path.getLastPathComponent();
+    return node;
+  }
+
+
+  /**
+  *
+  * Get RemoteFileNodes of selected nodes
+  * @return     node that is currently selected
+  *
+  */
+  public RemoteFileNode[] getSelectedNodes()
+  {
+    TreePath path[] = getSelectionPaths();
+    if(path == null)
+      return null;
+
+    int numberSelected = path.length;
+    RemoteFileNode nodes[] = new RemoteFileNode[numberSelected];
+    for(int i=0;i<numberSelected;i++)
+       nodes[i] = (RemoteFileNode)path[i].getLastPathComponent();
+
+    return nodes;
+  }
+
+
+  /**
+  *
+  * Determine if selected node is a file
+  * @return     true if the selected node is a file
+  *
+  */
+  public boolean isFileSelection()
+  {
+    TreePath path = getLeadSelectionPath();
+    if(path == null)
+      return false;
+    RemoteFileNode node = (RemoteFileNode)path.getLastPathComponent();
+    return !node.isDirectory();
+  }
+
+
+  /**
+  *
+  * Get the selected node file name
+  * @return     file name
+  *
+  */
+  public String getFilename()
+  {
+    TreePath path = getLeadSelectionPath();
+    RemoteFileNode node = (RemoteFileNode)path.getLastPathComponent();
+    return node.getServerName();
+  }
+
+
+  /**
+  *
+  * Creates the tree model for the given root
+  * @param root         root to create model for
+  * @return             tree model
+  *
+  */
+  private DefaultTreeModel createTreeModel(String root)
+  {
+    setCursor(cbusy);
+  
+    File f = new File(root);
+    RemoteFileNode rootNode = new RemoteFileNode(mysettings,froots,
+                                                 f.getName(),null,null);
+
+    rootNode.setDir(true);
+    rootNode.explore();
+    openNode = new Vector();
+    openNode.add(rootNode);
+    setCursor(cdone);
+    return new DefaultTreeModel(rootNode);
+  }
+
+  /**
+  *
+  * Gets the node from the existing explored nodes and their children.
+  * @param path         path to a file or directory
+  * @return             corresponding node if the directory or
+  *                     file is visible otherwise returns null.
+  *
+  */
+  private RemoteFileNode getNode(String path)
+  {
+    Enumeration en = openNode.elements();
+
+    while(en.hasMoreElements())
+    {
+      RemoteFileNode node = (RemoteFileNode)en.nextElement();
+      String nodeName = node.getFullName();
+
+      if(nodeName.equals(path))
+        return node;
+    }
+
+// check children of explored nodes
+    en = openNode.elements();
+    while(en.hasMoreElements())
+    {
+      RemoteFileNode child = getChildNode((RemoteFileNode)en.nextElement(),path);
+      if(child != null)
+        return child;
+    }
+
+    return null;
+  }
+
+
+  /**
+  *
+  * Gets the child node of a parent node
+  * @param parent       parent node
+  * @param childName    name of child
+  * @return the child node
+  *
+  */
+  private RemoteFileNode getChildNode(RemoteFileNode parent, String childName)
+  {
+    for(Enumeration children = parent.children();
+                    children.hasMoreElements() ;)
+    {
+      RemoteFileNode childNode = (RemoteFileNode)children.nextElement();
+      String nodeName = childNode.getServerName();
+      if(childName.equals(nodeName))
+        return childNode;
+    }
+
+    return null;
+  }
+
+
+  /**
+  *
+  * Opens a JFrame with the file contents displayed.
+  * @param filename     file name
+  * @param mysettings   jemboss properties
+  *
+  */
+  public static void showFilePane(final RemoteFileNode node)
+  {
+    SwingWorker entryWorker = new SwingWorker()
+    {
+      EntryEdit entry_edit;
+      public Object construct()
+      {
+        try
+        {
+          EntryInformation new_entry_information =
+             new SimpleEntryInformation(Options.getArtemisEntryInformation());
+
+          final Entry entry =  new Entry(EntryFileDialog.getEntryFromFile(
+                         null, new RemoteFileDocument(node),
+                         new_entry_information, true));
+          if(entry == null)
+            return null;
+
+          final EntryGroup entry_group =
+              new SimpleEntryGroup(entry.getBases());
+
+          entry_group.add(entry);
+          entry_edit = new EntryEdit(entry_group);
+          return null;
+        }
+        catch(NoSequenceException e)
+        {
+          new MessageDialog(null, "read failed: entry contains no sequence");
+        }
+        catch(OutOfRangeException e)
+        {
+          new MessageDialog(null, "read failed: one of the features in " +
+                     " the entry has an out of range " +
+                     "location: " + e.getMessage());
+
+        }
+        catch(NullPointerException npe){}
+
+        return null;
+      }
+
+      public void finished()
+      {
+        if(entry_edit != null)
+          entry_edit.setVisible(true);
+      }
+    };
+    entryWorker.start();
+  }
+
+
+////////////////////
+// DRAG AND DROP
+////////////////////
+  public void dragGestureRecognized(DragGestureEvent e) 
+  {
+    // ignore if mouse popup trigger
+    InputEvent ie = e.getTriggerEvent();
+    if(ie instanceof MouseEvent)
+      if(((MouseEvent)ie).isPopupTrigger())
+        return;
+
+    // drag only files 
+    if(isFileSelection())
+      e.startDrag(DragSource.DefaultCopyDrop,     // cursor
+                 (Transferable)getSelectedNode(), // transferable data
+                                       this);     // drag source listener
+  }
+
+// Source
+  public void dragDropEnd(DragSourceDropEvent e) {}
+  public void dragEnter(DragSourceDragEvent e) {}
+  public void dragExit(DragSourceEvent e) {}
+  public void dragOver(DragSourceDragEvent e) {}
+  public void dropActionChanged(DragSourceDragEvent e) {}
+
+// Target
+  public void dragEnter(DropTargetDragEvent e)
+  {
+    if(e.isDataFlavorSupported(FileNode.FILENODE) ||
+       e.isDataFlavorSupported(RemoteFileNode.REMOTEFILENODE))
+      e.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
+  }
+
+  public void drop(DropTargetDropEvent e)
+  {
+    Transferable t = e.getTransferable();
+
+    if(t.isDataFlavorSupported(RemoteFileNode.REMOTEFILENODE))
+    {
+      try
+      {
+        Point ploc = e.getLocation();
+        TreePath dropPath = getPathForLocation(ploc.x,ploc.y);
+        if(dropPath != null)
+        {
+          RemoteFileNode fn =
+            (RemoteFileNode)t.getTransferData(RemoteFileNode.REMOTEFILENODE);
+
+          fn = getNode(fn.getServerName()); // need to get the instance of
+                                            // this directly to manipulate tree
+          String dropDest = null;
+          RemoteFileNode fdropPath = (RemoteFileNode)dropPath.getLastPathComponent();
+          String dropRoot = fdropPath.getRootDir();
+          String dropFile = null;
+          if(fdropPath.getFile().equals(" "))
+            dropFile = fn.getFile();
+          else
+            dropFile = fdropPath.getFile()+"/"+fn.getFile();
+
+          if(!nodeExists(fdropPath,fdropPath.getServerName()+fn.getFile()))
+            rename(fn.getRootDir(),fn.getFullName(),
+                   fdropPath.getPathName(),
+                   dropFile, fn, fdropPath);
+        }
+      }
+      catch(Exception ex){}
+    }
+    else if(t.isDataFlavorSupported(FileNode.FILENODE))
+    {
+      try
+      {
+        Point ploc = e.getLocation();
+        TreePath dropPath = getPathForLocation(ploc.x,ploc.y);
+        if (dropPath != null) 
+        {
+          FileNode fn = (FileNode)t.getTransferData(FileNode.FILENODE);
+          File lfn = fn.getFile();
+
+          String dropDest = null;
+          RemoteFileNode fdropPath = (RemoteFileNode)dropPath.getLastPathComponent();
+          String dropRoot = fdropPath.getRootDir();
+ 
+          RemoteFileNode pn = fdropPath;         
+          if(fdropPath.isLeaf())
+          {
+            pn = (RemoteFileNode)fdropPath.getParent();
+            dropDest = pn.getFullName() + "/" + lfn.getName(); //assumes unix file sep.!
+          }
+          else
+            dropDest = fdropPath.getFullName()+ "/" + lfn.getName();
+
+          if(!nodeExists(pn,pn.getServerName()+lfn.getName()))
+          {
+            pn.put(lfn);
+            try 
+            {
+              
+//            Vector params = new Vector();
+//            byte[] fileData = getLocalFile(lfn);
+//            params.addElement("fileroot=" + dropRoot);
+//            params.addElement(dropDest);
+//            params.addElement(fileData);
+
+//            setCursor(cbusy);
+//            PrivateRequest gReq = new PrivateRequest(mysettings,"EmbreoFile",
+//                                                           "put_file",params);
+//            setCursor(cdone);
+              //add file to remote file tree
+              RemoteFileNode parentNode = fdropPath;
+              if(parentNode.isLeaf())
+                parentNode = (RemoteFileNode)fdropPath.getParent();
+              else
+                parentNode = fdropPath;
+           
+              if(parentNode.isExplored())
+                addObject(parentNode,lfn.getName(),false);
+              else
+              {
+                exploreNode(parentNode);
+                RemoteFileNode childNode = getNode(parentNode.getServerName() 
+                                                       + "/" + lfn.getName());
+                scrollPathToVisible(new TreePath(childNode.getPath())); 
+              }
+            } 
+            catch (Exception exp) 
+            {
+              setCursor(cdone);
+              System.out.println("SshFileTree: caught exception " + dropRoot +
+                  " Destination: " + dropDest + " Local File " + lfn.toString());
+            }
+          }
+          else
+            e.rejectDrop();
+        }
+      }
+      catch (Exception ex) 
+      {
+      }
+    } 
+    else
+      e.rejectDrop();
+
+  }
+
+  /**
+  *
+  * When a suitable DataFlavor is offered over a remote file
+  * node the node is highlighted/selected and the drag
+  * accepted. Otherwise the drag is rejected.
+  *
+  */
+  public void dragOver(DropTargetDragEvent e)
+  {
+    if (e.isDataFlavorSupported(FileNode.FILENODE))
+    {
+      Point ploc = e.getLocation();
+      TreePath ePath = getPathForLocation(ploc.x,ploc.y);
+      if (ePath == null)
+        e.rejectDrag();
+      else
+      {
+        setSelectionPath(ePath);
+        e.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
+      }
+    }
+    else if(e.isDataFlavorSupported(RemoteFileNode.REMOTEFILENODE))
+    {
+      Point ploc = e.getLocation();
+      TreePath ePath = getPathForLocation(ploc.x,ploc.y);
+      if (ePath == null)
+      {
+        e.rejectDrag();
+        return;
+      }
+      RemoteFileNode node = (RemoteFileNode)ePath.getLastPathComponent();
+      if(!node.isDirectory())
+        e.rejectDrag();
+      else
+      {
+        setSelectionPath(ePath);
+        e.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
+      }
+    }
+    else
+      e.rejectDrag();
+
+  }
+
+  public void dropActionChanged(DropTargetDragEvent e) {}
+  public void dragExit(DropTargetEvent e){}
+
+
+////////////////////
+// AUTO SCROLLING //
+////////////////////
+  /**
+  *
+  * Handles the auto scrolling of the JTree.
+  * @param location The location of the mouse.
+  *
+  */
+  public void autoscroll( Point location )
+  {
+    int top = 0, left = 0, bottom = 0, right = 0;
+    Dimension size = getSize();
+    Rectangle rect = getVisibleRect();
+    int bottomEdge = rect.y + rect.height;
+    int rightEdge = rect.x + rect.width;
+    if( location.y - rect.y < AUTOSCROLL_MARGIN && rect.y > 0 )
+      top = AUTOSCROLL_MARGIN;
+    if( location.x - rect.x < AUTOSCROLL_MARGIN && rect.x > 0 )
+      left = AUTOSCROLL_MARGIN;
+    if( bottomEdge - location.y < AUTOSCROLL_MARGIN && bottomEdge < size.height )
+      bottom = AUTOSCROLL_MARGIN;
+    if( rightEdge - location.x < AUTOSCROLL_MARGIN && rightEdge < size.width )
+      right = AUTOSCROLL_MARGIN;
+    rect.x += right - left;
+    rect.y += bottom - top;
+    scrollRectToVisible( rect );
+  }
+
+
+  /**
+  *
+  * Gets the insets used for the autoscroll.
+  * @return The insets.
+  *
+  */
+  public Insets getAutoscrollInsets()
+  {
+    Dimension size = getSize();
+    Rectangle rect = getVisibleRect();
+    autoscrollInsets.top = rect.y + AUTOSCROLL_MARGIN;
+    autoscrollInsets.left = rect.x + AUTOSCROLL_MARGIN;
+    autoscrollInsets.bottom = size.height - (rect.y+rect.height) + AUTOSCROLL_MARGIN;
+    autoscrollInsets.right  = size.width - (rect.x+rect.width) + AUTOSCROLL_MARGIN;
+    return autoscrollInsets;
+  }
+
+  /**
+  *
+  * Popup menu listener
+  *
+  */
+  class PopupListener extends MouseAdapter
+  {
+    public void mousePressed(MouseEvent e)
+    {
+      maybeShowPopup(e);
+    }
+
+    public void mouseReleased(MouseEvent e)
+    {
+      maybeShowPopup(e);
+    }
+
+    private void maybeShowPopup(MouseEvent e)
+    {
+      if(e.isPopupTrigger())
+        popup.show(e.getComponent(),
+                e.getX(), e.getY());
+    }
+  }
+
+ public static void main(String args[])
+ {
+    final javax.swing.LookAndFeel look_and_feel =
+      javax.swing.UIManager.getLookAndFeel();
+
+    final javax.swing.plaf.FontUIResource font_ui_resource =
+      Options.getOptions().getFontUIResource();
+
+    java.util.Enumeration keys = UIManager.getDefaults().keys();
+    while(keys.hasMoreElements())
+    {
+      Object key = keys.nextElement();
+      Object value = UIManager.get(key);
+      if(value instanceof javax.swing.plaf.FontUIResource)
+        UIManager.put(key, font_ui_resource);
+    }
+
+   JFrame frame = new JFrame("SSH :: File Manager");
+   JScrollPane jsp = new JScrollPane(new SshFileTree("/nfs/team81/tjc"));
+   frame.getContentPane().add(jsp);
+   frame.pack();
+   frame.setVisible(true);
+ }
+
+}