update author list in license for (JAL-826)
[jalview.git] / src / jalview / gui / AlignFrame.java
index ffb17d2..9b91255 100755 (executable)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.5)
- * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
+ * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle
  * 
  * This file is part of Jalview.
  * 
  */
 package jalview.gui;
 
-import java.beans.*;
-import java.io.*;
-import java.util.*;
-
-import java.awt.*;
-import java.awt.datatransfer.*;
-import java.awt.dnd.*;
-import java.awt.event.*;
-import java.awt.print.*;
-import javax.swing.*;
-import javax.swing.event.MenuEvent;
-
-import jalview.analysis.*;
+import jalview.analysis.AAFrequency;
+import jalview.analysis.AlignmentSorter;
+import jalview.analysis.Conservation;
+import jalview.analysis.CrossRef;
+import jalview.analysis.NJTree;
+import jalview.analysis.ParseProperties;
+import jalview.analysis.SequenceIdMatcher;
 import jalview.bin.Cache;
-import jalview.commands.*;
-import jalview.datamodel.*;
-import jalview.io.*;
-import jalview.jbgui.*;
-import jalview.schemes.*;
-import jalview.ws.*;
+import jalview.commands.CommandI;
+import jalview.commands.EditCommand;
+import jalview.commands.OrderCommand;
+import jalview.commands.RemoveGapColCommand;
+import jalview.commands.RemoveGapsCommand;
+import jalview.commands.SlideSequencesCommand;
+import jalview.commands.TrimRegionCommand;
+import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentOrder;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SeqCigar;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.io.AlignmentProperties;
+import jalview.io.AnnotationFile;
+import jalview.io.FeaturesFile;
+import jalview.io.FileLoader;
+import jalview.io.FormatAdapter;
+import jalview.io.HTMLOutput;
+import jalview.io.IdentifyFile;
+import jalview.io.JalviewFileChooser;
+import jalview.io.JalviewFileView;
+import jalview.io.JnetAnnotationMaker;
+import jalview.io.NewickFile;
+import jalview.jbgui.GAlignFrame;
+import jalview.schemes.Blosum62ColourScheme;
+import jalview.schemes.BuriedColourScheme;
+import jalview.schemes.ClustalxColourScheme;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemeProperty;
+import jalview.schemes.HelixColourScheme;
+import jalview.schemes.HydrophobicColourScheme;
+import jalview.schemes.NucleotideColourScheme;
+import jalview.schemes.PIDColourScheme;
+import jalview.schemes.PurinePyrimidineColourScheme;
+import jalview.schemes.ResidueProperties;
+import jalview.schemes.StrandColourScheme;
+import jalview.schemes.TaylorColourScheme;
+import jalview.schemes.TurnColourScheme;
+import jalview.schemes.UserColourScheme;
+import jalview.schemes.ZappoColourScheme;
+import jalview.ws.WSMenuEntryProviderI;
 import jalview.ws.jws1.Discoverer;
 import jalview.ws.jws2.Jws2Discoverer;
 
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetEvent;
+import java.awt.dnd.DropTargetListener;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.print.PageFormat;
+import java.awt.print.PrinterJob;
+import java.beans.PropertyChangeEvent;
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.swing.JButton;
+import javax.swing.JEditorPane;
+import javax.swing.JInternalFrame;
+import javax.swing.JLabel;
+import javax.swing.JLayeredPane;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+
 /**
  * DOCUMENT ME!
  * 
@@ -321,7 +402,22 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                     || evt.isShiftDown() || evt.isAltDown());
           }
           break;
-
+          
+        //case KeyEvent.VK_A:
+       //      if (viewport.cursorMode)
+       //     {
+       //              alignPanel.seqPanel.insertNucAtCursor(false,"A");
+       //              //System.out.println("A");
+       //     }
+       //      break;
+        /*     
+        case KeyEvent.VK_CLOSE_BRACKET:
+               if (viewport.cursorMode)
+            {
+                       System.out.println("closing bracket");
+            }
+               break;
+         */
         case KeyEvent.VK_DELETE:
         case KeyEvent.VK_BACK_SPACE:
           if (!viewport.cursorMode)
@@ -494,6 +590,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       }
       ap.av.updateConservation(ap);
       ap.av.updateConsensus(ap);
+      ap.av.updateStrucConsensus(ap);
     }
   }
 
@@ -565,11 +662,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     conservationMenuItem.setEnabled(!nucleotide);
     modifyConservation.setEnabled(!nucleotide);
     showGroupConservation.setEnabled(!nucleotide);
+    rnahelicesColour.setEnabled(nucleotide);
+    purinePyrimidineColour.setEnabled(nucleotide);
     // Remember AlignFrame always starts as protein
-    if (!nucleotide)
-    {
-      calculateMenu.remove(calculateMenu.getItemCount() - 2);
-    }
+    //if (!nucleotide)
+   // {
+   //   showTr
+   //   calculateMenu.remove(calculateMenu.getItemCount() - 2);
+   // }
   }
 
   /**
@@ -619,7 +719,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     applyToAllGroups.setState(av.colourAppliesToAllGroups);
     showNpFeatsMenuitem.setSelected(av.isShowNpFeats());
     showDbRefsMenuitem.setSelected(av.isShowDbRefs());
-
+    autoCalculate.setSelected(av.autoCalculateConsensus);
+    sortByTree.setSelected(av.sortByTree);
+    listenToViewSelections.setSelected(av.followSelection);
+    rnahelicesColour.setEnabled(av.alignment.hasRNAStructure());
+    rnahelicesColour.setSelected(av.getGlobalColourScheme() instanceof jalview.schemes.RNAHelicesColour);
     setShowProductsEnabled();
 
     updateEditMenuBar();
@@ -675,7 +779,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       progressBars.put(lId, progressPanel);
     }
     // update GUI
-    setMenusForViewport();
+    // setMenusForViewport();
     validate();
   }
 
@@ -1115,7 +1219,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       String choice = chooser.getSelectedFile().getPath();
       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
-      loadJalviewDataFile(choice);
+      loadJalviewDataFile(choice, null, null, null);
     }
 
   }
@@ -2000,6 +2104,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     alignPanel.idPanel.idCanvas.searchResults = null;
     alignPanel.paintAlignment(true);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
+    viewport.sendSelection();
   }
 
   /**
@@ -2025,14 +2130,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
 
     alignPanel.paintAlignment(true);
-    viewport.sendSelection();
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
+    viewport.sendSelection();
   }
 
   public void invertColSel_actionPerformed(ActionEvent e)
   {
     viewport.invertColumnSelection();
     alignPanel.paintAlignment(true);
+    viewport.sendSelection();
   }
 
   /**
@@ -2243,8 +2349,57 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
   public void newView_actionPerformed(ActionEvent e)
   {
+    newView(true);
+  }
+
+  /**
+   * 
+   * @param copyAnnotation
+   *          if true then duplicate all annnotation, groups and settings
+   * @return new alignment panel, already displayed.
+   */
+  public AlignmentPanel newView(boolean copyAnnotation)
+  {
+    return newView(null, copyAnnotation);
+  }
+
+  /**
+   * 
+   * @param viewTitle
+   *          title of newly created view
+   * @return new alignment panel, already displayed.
+   */
+  public AlignmentPanel newView(String viewTitle)
+  {
+    return newView(viewTitle, true);
+  }
+
+  /**
+   * 
+   * @param viewTitle
+   *          title of newly created view
+   * @param copyAnnotation
+   *          if true then duplicate all annnotation, groups and settings
+   * @return new alignment panel, already displayed.
+   */
+  public AlignmentPanel newView(String viewTitle, boolean copyAnnotation)
+  {
     AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel,
             true);
+    if (!copyAnnotation)
+    {
+      // just remove all the current annotation except for the automatic stuff
+      newap.av.alignment.deleteAllGroups();
+      for (AlignmentAnnotation alan : newap.av.alignment
+              .getAlignmentAnnotation())
+      {
+        if (!alan.autoCalculated)
+        {
+          newap.av.alignment.deleteAnnotation(alan);
+        }
+        ;
+      }
+    }
 
     newap.av.gatherViewsHere = false;
 
@@ -2257,8 +2412,19 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     newap.av.redoList = viewport.redoList;
 
     int index = Desktop.getViewCount(viewport.getSequenceSetId());
-    String newViewName = "View " + index;
-
+    // make sure the new view has a unique name - this is essential for Jalview
+    // 2 archives
+    boolean addFirstIndex = false;
+    if (viewTitle == null || viewTitle.trim().length() == 0)
+    {
+      viewTitle = "View";
+      addFirstIndex = true;
+    }
+    else
+    {
+      index = 1;// we count from 1 if given a specific name
+    }
+    String newViewName = viewTitle + ((addFirstIndex) ? " " + index : "");
     Vector comps = (Vector) PaintRefresher.components.get(viewport
             .getSequenceSetId());
     Vector existingNames = new Vector();
@@ -2276,7 +2442,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     while (existingNames.contains(newViewName))
     {
-      newViewName = "View " + (++index);
+      newViewName = viewTitle + " " + (++index);
     }
 
     newap.av.viewName = newViewName;
@@ -2288,6 +2454,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       viewport.gatherViewsHere = true;
     }
     tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
+    return newap;
   }
 
   public void expandViews_actionPerformed(ActionEvent e)
@@ -2663,57 +2830,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     JEditorPane editPane = new JEditorPane("text/html", "");
     editPane.setEditable(false);
-    StringBuffer contents = new StringBuffer("<html>");
-
-    float avg = 0;
-    int min = Integer.MAX_VALUE, max = 0;
-    for (int i = 0; i < viewport.alignment.getHeight(); i++)
-    {
-      int size = viewport.alignment.getSequenceAt(i).getEnd()
-              - viewport.alignment.getSequenceAt(i).getStart();
-      avg += size;
-      if (size > max)
-        max = size;
-      if (size < min)
-        min = size;
-    }
-    avg = avg / (float) viewport.alignment.getHeight();
-
-    contents.append("<br>Sequences: " + viewport.alignment.getHeight());
-    contents.append("<br>Minimum Sequence Length: " + min);
-    contents.append("<br>Maximum Sequence Length: " + max);
-    contents.append("<br>Average Length: " + (int) avg);
-
-    if (((Alignment) viewport.alignment).getProperties() != null)
-    {
-      Hashtable props = ((Alignment) viewport.alignment).getProperties();
-      Enumeration en = props.keys();
-      contents.append("<br><br><table border=\"1\">");
-      while (en.hasMoreElements())
-      {
-        String key = en.nextElement().toString();
-        StringBuffer val = new StringBuffer();
-        String vals = props.get(key).toString();
-        int pos = 0, npos;
-        do
-        {
-          npos = vals.indexOf("\n", pos);
-          if (npos == -1)
-          {
-            val.append(vals.substring(pos));
-          }
-          else
-          {
-            val.append(vals.substring(pos, npos));
-            val.append("<br>");
-          }
-          pos = npos + 1;
-        } while (npos != -1);
-        contents.append("<tr><td>" + key + "</td><td>" + val + "</td></tr>");
-      }
-      contents.append("</table>");
-    }
-    editPane.setText(contents.toString() + "</html>");
+    StringBuffer contents = new AlignmentProperties(viewport.alignment)
+            .formatAsHtml();
+    editPane.setText("<html>" + contents.toString() + "</html>");
     JInternalFrame frame = new JInternalFrame();
     frame.getContentPane().add(new JScrollPane(editPane));
 
@@ -2870,10 +2989,25 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     changeColour(new NucleotideColourScheme());
   }
 
+  public void purinePyrimidineColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new PurinePyrimidineColourScheme());
+  }
+  /*
+  public void covariationColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new CovariationColourScheme(viewport.alignment.getAlignmentAnnotation()[0]));
+  }
+  */
   public void annotationColour_actionPerformed(ActionEvent e)
   {
     new AnnotationColourChooser(viewport, alignPanel);
   }
+  
+  public void rnahelicesColour_actionPerformed(ActionEvent e)
+  {
+    new RNAHelicesColourChooser(viewport, alignPanel);
+  }
 
   /**
    * DOCUMENT ME!
@@ -3325,7 +3459,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               .getAlignment().getSequences());
     }
   }
+  public void sortByTreeOption_actionPerformed(ActionEvent e)
+  {
+    viewport.sortByTree = sortByTree.isSelected();
+  }
 
+  @Override
+  protected void listenToViewSelections_actionPerformed(ActionEvent e)
+  {
+    viewport.followSelection = listenToViewSelections.isSelected();
+  }
   /**
    * DOCUMENT ME!
    * 
@@ -3608,21 +3751,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     for (i = 0; i < treePanels.size(); i++)
     {
-      TreePanel tp = (TreePanel) treePanels.elementAt(i);
+      final TreePanel tp = (TreePanel) treePanels.elementAt(i);
       final JMenuItem item = new JMenuItem(tp.getTitle());
       final NJTree tree = ((TreePanel) treePanels.elementAt(i)).getTree();
       item.addActionListener(new java.awt.event.ActionListener()
       {
         public void actionPerformed(ActionEvent e)
         {
-          SequenceI[] oldOrder = viewport.getAlignment()
-                  .getSequencesArray();
-          AlignmentSorter.sortByTree(viewport.getAlignment(), tree);
-
-          addHistoryItem(new OrderCommand("Tree Sort", oldOrder,
-                  viewport.alignment));
-
-          alignPanel.paintAlignment(true);
+          tp.sortByTree_actionPerformed(null);
+          addHistoryItem(tp.sortAlignmentIn(alignPanel));
+          
         }
       });
 
@@ -3630,6 +3768,19 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
   }
 
+  public boolean sortBy(AlignmentOrder alorder, String undoname)
+  {
+    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+    AlignmentSorter.sortBy(viewport.getAlignment(), alorder);
+    if (undoname != null)
+    {
+      addHistoryItem(new OrderCommand(undoname, oldOrder,
+              viewport.alignment));
+    }
+    alignPanel.paintAlignment(true);
+    return true;
+  }
+
   /**
    * Work out whether the whole set of sequences or just the selected set will
    * be submitted for multiple alignment.
@@ -3853,17 +4004,26 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           // object broker mechanism.
           final Vector wsmenu = new Vector();
           final IProgressIndicator af = me;
-          if (Cache.getDefault("SHOW_JWS1_SERVICES", true)
-                  && Discoverer.services != null
+          final JMenu msawsmenu = new JMenu("Alignment");
+          final JMenu secstrmenu = new JMenu(
+                  "Secondary Structure Prediction");
+          final JMenu seqsrchmenu = new JMenu(
+                  "Sequence Database Search");
+          final JMenu analymenu = new JMenu(
+                  "Analysis");
+          // JAL-940 - only show secondary structure prediction services from the legacy server
+          if (// Cache.getDefault("SHOW_JWS1_SERVICES", true)
+                  // && 
+                  Discoverer.services != null
                   && (Discoverer.services.size() > 0))
           {
             // TODO: refactor to allow list of AbstractName/Handler bindings to
             // be
             // stored or retrieved from elsewhere
-            Vector msaws = (Vector) Discoverer.services.get("MsaWS");
+            Vector msaws = null; // (Vector) Discoverer.services.get("MsaWS");
             Vector secstrpr = (Vector) Discoverer.services
                     .get("SecStrPred");
-            Vector seqsrch = (Vector) Discoverer.services.get("SeqSearch");
+            Vector seqsrch = null; // (Vector) Discoverer.services.get("SeqSearch");
             // TODO: move GUI generation code onto service implementation - so a
             // client instance attaches itself to the GUI with method call like
             // jalview.ws.MsaWSClient.bind(servicehandle, Desktop.instance,
@@ -3871,7 +4031,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             if (msaws != null)
             {
               // Add any Multiple Sequence Alignment Services
-              final JMenu msawsmenu = new JMenu("Alignment");
               for (int i = 0, j = msaws.size(); i < j; i++)
               {
                 final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) msaws
@@ -3881,13 +4040,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 impl.attachWSMenuEntry(msawsmenu, me);
 
               }
-              wsmenu.add(msawsmenu);
             }
             if (secstrpr != null)
             {
               // Add any secondary structure prediction services
-              final JMenu secstrmenu = new JMenu(
-                      "Secondary Structure Prediction");
               for (int i = 0, j = secstrpr.size(); i < j; i++)
               {
                 final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) secstrpr
@@ -3896,13 +4052,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                         .getServiceClient(sh);
                 impl.attachWSMenuEntry(secstrmenu, me);
               }
-              wsmenu.add(secstrmenu);
             }
             if (seqsrch != null)
             {
               // Add any sequence search services
-              final JMenu seqsrchmenu = new JMenu(
-                      "Sequence Database Search");
               for (int i = 0, j = seqsrch.size(); i < j; i++)
               {
                 final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) seqsrch
@@ -3911,7 +4064,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                         .getServiceClient(sh);
                 impl.attachWSMenuEntry(seqsrchmenu, me);
               }
-              wsmenu.add(seqsrchmenu);
             }
           }
 
@@ -3923,15 +4075,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             {
               if (jws2servs.hasServices())
               {
-                JMenu jws2men = new JMenu("Jaba Web Services");
-                jws2servs.attachWSMenuEntry(jws2men, me);
-                for (int i = 0, iSize = jws2men.getMenuComponentCount(); i < iSize; i++)
-                {
-                  wsmenu.add(jws2men.getMenuComponent(i));
-                }
+                jws2servs.attachWSMenuEntry(msawsmenu, me);
               }
             }
           }
+          // Add all submenus in the order they should appear on the web services menu
+          wsmenu.add(msawsmenu);
+          wsmenu.add(secstrmenu);
+          wsmenu.add(analymenu);
+          // No search services yet
+          // wsmenu.add(seqsrchmenu);
 
           javax.swing.SwingUtilities.invokeLater(new Runnable()
           {
@@ -3939,9 +4092,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             {
               try
               {
-
-                resetWebServiceMenu();
-                // finally, add the whole shebang onto the webservices menu
+                webService.removeAll();
+                // first, add discovered services onto the webservices menu
                 if (wsmenu.size() > 0)
                 {
                   for (int i = 0, j = wsmenu.size(); i < j; i++)
@@ -3951,8 +4103,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 }
                 else
                 {
-                  me.webService.add(me.webServiceNoServices);
+                  webService.add(me.webServiceNoServices);
                 }
+                build_urlServiceMenu(me.webService);
+                build_fetchdbmenu(webService);
               } catch (Exception e)
               {
               }
@@ -3970,17 +4124,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
   }
 
-  /**
-   * empty the web service menu and add any ad-hoc functions not dynamically
-   * discovered.
-   * 
-   */
-  private void resetWebServiceMenu()
-  {
-    webService.removeAll();
-    build_fetchdbmenu(webService);
-    build_urlServiceMenu(webService);
-  }
 
   /**
    * construct any groupURL type service menu entries.
@@ -3989,6 +4132,27 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    */
   private void build_urlServiceMenu(JMenu webService)
   {
+    // TODO: remove this code when 2.7 is released
+    // DEBUG - alignmentView
+    /*
+     * JMenuItem testAlView = new JMenuItem("Test AlignmentView"); final
+     * AlignFrame af = this; testAlView.addActionListener(new ActionListener() {
+     * 
+     * @Override public void actionPerformed(ActionEvent e) {
+     * jalview.datamodel.AlignmentView.testSelectionViews(af.viewport.alignment,
+     * af.viewport.colSel, af.viewport.selectionGroup); }
+     * 
+     * }); webService.add(testAlView);
+     */
+    // TODO: refactor to RestClient discoverer and merge menu entries for
+    // rest-style services with other types of analysis/calculation service
+    // SHmmr test client - still being implemented.
+    // DEBUG - alignmentView
+    
+    for (jalview.ws.rest.RestClient client: jalview.ws.rest.RestClient.getRestClients()) {
+      client.attachWSMenuEntry(JvSwingUtils.findOrCreateMenu(webService, client.getAction()), this);
+    }
+
     if (Cache.getDefault("SHOW_ENFIN_SERVICES", true))
     {
       jalview.ws.EnfinEnvision2OneWay.getInstance().attachWSMenuEntry(
@@ -4265,7 +4429,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       featuresFile = new FeaturesFile(file, type)
               .parse(viewport.alignment.getDataset(),
                       alignPanel.seqPanel.seqCanvas.getFeatureRenderer().featureColours,
-                      false);
+                      false, jalview.bin.Cache.getDefault(
+                              "RELAXEDSEQIDMATCHING", false));
     } catch (Exception ex)
     {
       ex.printStackTrace();
@@ -4360,10 +4525,127 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       try
       {
-
+        // check to see if any of these files have names matching sequences in
+        // the alignment
+        SequenceIdMatcher idm = new SequenceIdMatcher(viewport
+                .getAlignment().getSequencesArray());
+        /**
+         * Object[] { String,SequenceI}
+         */
+        ArrayList<Object[]> filesmatched = new ArrayList<Object[]>();
+        ArrayList<String> filesnotmatched = new ArrayList<String>();
         for (int i = 0; i < files.size(); i++)
         {
-          loadJalviewDataFile(files.get(i).toString());
+          String file = files.get(i).toString();
+          String pdbfn = "";
+          String protocol = FormatAdapter.checkProtocol(file);
+          if (protocol == jalview.io.FormatAdapter.FILE)
+          {
+            File fl = new File(file);
+            pdbfn = fl.getName();
+          }
+          else if (protocol == jalview.io.FormatAdapter.URL)
+          {
+            URL url = new URL(file);
+            pdbfn = url.getFile();
+          }
+          if (pdbfn.length() > 0)
+          {
+            // attempt to find a match in the alignment
+            SequenceI[] mtch = idm.findAllIdMatches(pdbfn);
+            int l = 0, c = pdbfn.indexOf(".");
+            while (mtch == null && c != -1)
+            {
+              do 
+              {
+                l = c;
+              } while ((c = pdbfn.indexOf(".", l)) > l);
+              if (l > -1)
+              {
+                pdbfn = pdbfn.substring(0, l);
+              }
+              mtch = idm.findAllIdMatches(pdbfn);
+            }
+            if (mtch != null)
+            {
+              String type = null;
+              try
+              {
+                type = new IdentifyFile().Identify(file, protocol);
+              } catch (Exception ex)
+              {
+                type = null;
+              }
+              if (type != null)
+              {
+                if (type.equalsIgnoreCase("PDB"))
+                {
+                  filesmatched.add(new Object[]
+                  { file, protocol, mtch });
+                  continue;
+                }
+              }
+            }
+            // File wasn't named like one of the sequences or wasn't a PDB file.
+            filesnotmatched.add(file);
+          }
+        }
+        int assocfiles = 0;
+        if (filesmatched.size() > 0)
+        {
+          if (Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false)
+                  || JOptionPane
+                          .showConfirmDialog(
+                                  this,
+                                  "Do you want to automatically associate the "
+                                          + filesmatched.size()
+                                          + " PDB files with sequences in the alignment that have the same name ?",
+                                  "Automatically Associate PDB files by name",
+                                  JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
+
+          {
+            for (Object[] fm : filesmatched)
+            {
+              // try and associate
+              // TODO: may want to set a standard ID naming formalism for
+              // associating PDB files which have no IDs.
+              for (SequenceI toassoc: (SequenceI[])fm[2]) {
+              PDBEntry pe = new AssociatePdbFileWithSeq()
+                      .associatePdbWithSeq((String) fm[0], (String) fm[1],
+                              toassoc, false);
+              if (pe != null)
+              {
+                System.err
+                        .println("Associated file : " + ((String) fm[0])
+                                + " with "
+                                + toassoc.getDisplayId(true));
+                assocfiles++;
+              }
+              }
+              alignPanel.paintAlignment(true);
+            }
+          }
+        }
+        if (filesnotmatched.size() > 0)
+        {
+          if (assocfiles > 0
+                  && (Cache.getDefault(
+                          "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false) || JOptionPane
+                          .showConfirmDialog(
+                                  this,
+                                  "<html>Do you want to <em>ignore</em> the "
+                                          + filesnotmatched.size()
+                                          + " files whose names did not match any sequence IDs ?</html>",
+                                  "Ignore unmatched dropped files ?",
+                                  JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION))
+          {
+            return;
+          }
+          for (String fn : filesnotmatched)
+          {
+            loadJalviewDataFile(fn, null, null, null);
+          }
+
         }
       } catch (Exception ex)
       {
@@ -4381,26 +4663,31 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * @param file
    *          either a filename or a URL string.
    */
-  public void loadJalviewDataFile(String file)
+  public void loadJalviewDataFile(String file, String protocol,
+          String format, SequenceI assocSeq)
   {
     try
     {
-      String protocol = jalview.io.FormatAdapter.FILE;
-      String f = file.toLowerCase();
-      if (f.indexOf("http:") == 0 || f.indexOf("https:") == 0
-              || f.indexOf("file:") == 0)
+      if (protocol == null)
       {
-        protocol = jalview.io.FormatAdapter.URL;
+        protocol = jalview.io.FormatAdapter.checkProtocol(file);
       }
-
-      boolean isAnnotation = new AnnotationFile().readAnnotationFile(
-              viewport.alignment, file, protocol);
+      // if the file isn't identified, or not positively identified as some
+      // other filetype (PFAM is default unidentified alignment file type) then
+      // try to parse as annotation.
+      boolean isAnnotation = (format == null || format
+              .equalsIgnoreCase("PFAM")) ? new AnnotationFile()
+              .readAnnotationFile(viewport.alignment, file, protocol)
+              : false;
 
       if (!isAnnotation)
       {
         // try to see if its a JNet 'concise' style annotation file *before* we
         // try to parse it as a features file
-        String format = new IdentifyFile().Identify(file, protocol);
+        if (format == null)
+        {
+          format = new IdentifyFile().Identify(file, protocol);
+        }
         if (format.equalsIgnoreCase("JnetFile"))
         {
           jalview.io.JPredFile predictions = new jalview.io.JPredFile(file,
@@ -4411,6 +4698,27 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         }
         else
         {
+          /*
+           * if (format.equalsIgnoreCase("PDB")) {
+           * 
+           * String pdbfn = ""; // try to match up filename with sequence id try
+           * { if (protocol == jalview.io.FormatAdapter.FILE) { File fl = new
+           * File(file); pdbfn = fl.getName(); } else if (protocol ==
+           * jalview.io.FormatAdapter.URL) { URL url = new URL(file); pdbfn =
+           * url.getFile(); } } catch (Exception e) { } ; if (assocSeq == null)
+           * { SequenceIdMatcher idm = new SequenceIdMatcher(viewport
+           * .getAlignment().getSequencesArray()); if (pdbfn.length() > 0) { //
+           * attempt to find a match in the alignment SequenceI mtch =
+           * idm.findIdMatch(pdbfn); int l = 0, c = pdbfn.indexOf("."); while
+           * (mtch == null && c != -1) { while ((c = pdbfn.indexOf(".", l)) > l)
+           * { l = c; } if (l > -1) { pdbfn = pdbfn.substring(0, l); } mtch =
+           * idm.findIdMatch(pdbfn); } if (mtch != null) { // try and associate
+           * // prompt ? PDBEntry pe = new AssociatePdbFileWithSeq()
+           * .associatePdbWithSeq(file, protocol, mtch, true); if (pe != null) {
+           * System.err.println("Associated file : " + file + " with " +
+           * mtch.getDisplayId(true)); alignPanel.paintAlignment(true); } } //
+           * TODO: maybe need to load as normal otherwise return; } }
+           */
           // try to parse it as a features file
           boolean isGroupsFile = parseFeaturesFile(file, protocol);
           // if it wasn't a features file then we just treat it as a general
@@ -4572,7 +4880,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     });
     rfetch.add(fetchr);
-    final AlignFrame me=this;
+    final AlignFrame me = this;
     new Thread(new Runnable()
     {
       public void run()
@@ -4777,6 +5085,26 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       alignPanel.paintAlignment(true);
     }
   }
+
+  /**
+   * make the given alignmentPanel the currently selected tab
+   * 
+   * @param alignmentPanel
+   */
+  public void setDisplayedView(AlignmentPanel alignmentPanel)
+  {
+    if (!viewport.getSequenceSetId().equals(
+            alignmentPanel.av.getSequenceSetId()))
+    {
+      throw new Error(
+              "Implementation error: cannot show a view from another alignment in an AlignFrame.");
+    }
+    if (tabbedPane != null
+            & alignPanels.indexOf(alignmentPanel) != tabbedPane.getSelectedIndex())
+    {
+      tabbedPane.setSelectedIndex(alignPanels.indexOf(alignmentPanel));
+    }
+  }
 }
 
 class PrintThread extends Thread