use OOMwarning to warn user when out of Memory occurs
[jalview.git] / src / jalview / gui / AlignFrame.java
index e870dea..3aa69f1 100755 (executable)
@@ -1,19 +1,19 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer
- * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
- *
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
+ * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- *
+ * 
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
+ * 
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Softwarechang
+ * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 package jalview.gui;
@@ -45,7 +45,7 @@ import jalview.ws.*;
  * @version $Revision$
  */
 public class AlignFrame
-    extends GAlignFrame implements DropTargetListener
+    extends GAlignFrame implements DropTargetListener, IProgressIndicator
 {
   /** DOCUMENT ME!! */
   public static final int DEFAULT_WIDTH = 700;
@@ -59,11 +59,17 @@ public class AlignFrame
   Vector alignPanels = new Vector();
 
 
-  /** DOCUMENT ME!! */
+  /** 
+   * Last format used to load or save alignments in this window 
+   */
   String currentFileFormat = null;
-
+  /**
+   * Current filename for this alignment
+   */
   String fileName = null;
 
+  
+
 
   /**
    * Creates a new AlignFrame object.
@@ -156,7 +162,12 @@ public class AlignFrame
    addKeyListener();
 
   }
-
+  /**
+   * Change the filename and format for the alignment, and
+   * enable the 'reload' button functionality.
+   * @param file valid filename
+   * @param format format of file
+   */
   public void setFileName(String file, String format)
   {
      fileName = file;
@@ -504,11 +515,17 @@ public class AlignFrame
     {
       calculateMenu.remove(calculateMenu.getItemCount()-2);
     }
-    setShowProductsEnabled();
   }
 
 
-
+  /**
+   * set up menus for the currently viewport.
+   * This may be called after any operation that affects the data in the current view (selection changed, etc) to update the menus to reflect the new state.
+   */
+  public void setMenusForViewport()
+  {
+    setMenusFromViewport(viewport);
+  }
   /**
    * Need to call this method when tabs are selected for multiple views,
    * or when loading from Jalview2XML.java
@@ -522,6 +539,7 @@ public class AlignFrame
     conservationMenuItem.setSelected(av.getConservationSelected());
     seqLimits.setSelected(av.getShowJVSuffix());
     idRightAlign.setSelected(av.rightAlignIds);
+    centreColumnLabelsMenuItem.setState(av.centreColumnLabels);
     renderGapsMenuItem.setSelected(av.renderGaps);
     wrapMenuItem.setSelected(av.wrapAlignment);
     scaleAbove.setVisible(av.wrapAlignment);
@@ -538,11 +556,16 @@ public class AlignFrame
     hiddenMarkers.setState(av.showHiddenMarkers);
     applyToAllGroups.setState(av.colourAppliesToAllGroups);
 
+    setShowProductsEnabled();
+
     updateEditMenuBar();
   }
 
 
   Hashtable progressBars;
+  /* (non-Javadoc)
+   * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
+   */
   public void setProgressBar(String message, long id)
   {
     if(progressBars == null)
@@ -580,13 +603,22 @@ public class AlignFrame
 
       progressBars.put(new Long(id), progressPanel);
     }
-
+    // update GUI
+    setMenusForViewport();
     validate();
   }
-
-
-
-
+  /**
+   * 
+   * @return true if any progress bars are still active
+   */
+  public boolean operationInProgress()
+  {
+    if (progressBars!=null && progressBars.size()>0)
+    {
+      return true;
+    }
+    return false;
+  }
   /*
    Added so Castor Mapping file can obtain Jalview Version
   */
@@ -671,7 +703,7 @@ public class AlignFrame
   public void save_actionPerformed(ActionEvent e)
   {
     if(fileName==null
-       || currentFileFormat==null
+       || (currentFileFormat==null || jalview.io.AppletFormatAdapter.isValidFormat(currentFileFormat, true))
        || fileName.startsWith("http")
         )
     {
@@ -692,10 +724,8 @@ public class AlignFrame
   {
     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
         getProperty( "LAST_DIRECTORY"),
-        new String[]
-        { "fa, fasta, fastq", "aln", "pfam", "msf", "pir", "blc","amsa","jar" },
-        new String[]
-        { "Fasta", "Clustal", "PFAM", "MSF", "PIR", "BLC", "AMSA", "Jalview" },
+        jalview.io.AppletFormatAdapter.WRITABLE_EXTENSIONS,
+        jalview.io.AppletFormatAdapter.WRITABLE_FNAMES,
         currentFileFormat,
         false);
 
@@ -725,8 +755,11 @@ public class AlignFrame
                                     currentFileFormat);
 
       jalview.bin.Cache.setProperty("LAST_DIRECTORY", fileName);
-
-      saveAlignment(fileName, currentFileFormat.substring(0,currentFileFormat.indexOf(" ")));
+      if (currentFileFormat.indexOf(" ")>-1)
+      {
+        currentFileFormat = currentFileFormat.substring(0, currentFileFormat.indexOf(" "));
+      }
+      saveAlignment(fileName, currentFileFormat);
     }
   }
 
@@ -752,8 +785,18 @@ public class AlignFrame
 
     }
     else
-    {
-
+    {        
+      if (!jalview.io.AppletFormatAdapter.isValidFormat(format, true))
+      {
+        // JBPNote need to have a raise_gui flag here
+        JOptionPane.showInternalMessageDialog(
+                this, "Cannot save file " + fileName + " using format "+format,
+                "Alignment output format not supported",
+                JOptionPane.WARNING_MESSAGE);
+        saveAs_actionPerformed(null);
+        return false;
+      }
+        
       String[] omitHidden = null;
 
       if (viewport.hasHiddenColumns)
@@ -770,11 +813,10 @@ public class AlignFrame
       }
       }
       FormatAdapter f = new FormatAdapter();
-
       String output = f.formatSequences(
           format,
           (Alignment) viewport.alignment, // class cast exceptions will occur in the distant future
-          omitHidden, f.getCacheSuffixDefault(format));
+          omitHidden, f.getCacheSuffixDefault(format), viewport.colSel);
 
       if (output == null)
       {
@@ -846,7 +888,7 @@ public class AlignFrame
     cap.setText(new FormatAdapter().formatSequences(
         e.getActionCommand(),
         viewport.alignment,
-        omitHidden));
+        omitHidden, viewport.colSel));
   }
 
   /**
@@ -1366,20 +1408,7 @@ public class AlignFrame
     }
     catch (OutOfMemoryError er)
     {
-      er.printStackTrace();
-      javax.swing.SwingUtilities.invokeLater(new Runnable()
-          {
-            public void run()
-            {
-              javax.swing.JOptionPane.showInternalMessageDialog(Desktop.desktop,
-                  "Out of memory copying region!!"
-                  +
-                  "\nSee help files for increasing Java Virtual Machine memory."
-                  , "Out of memory",
-                  javax.swing.JOptionPane.WARNING_MESSAGE);
-            }
-          });
-
+      new OOMWarning("copying region", er);
       return;
     }
 
@@ -1429,9 +1458,9 @@ public class AlignFrame
   }
 
   /**
-   * DOCUMENT ME!
+   * Paste contents of Jalview clipboard
    *
-   * @param newAlignment DOCUMENT ME!
+   * @param newAlignment true to paste to a new alignment, otherwise add to this.
    */
   void paste(boolean newAlignment)
   {
@@ -1460,20 +1489,7 @@ public class AlignFrame
       }
       catch (OutOfMemoryError er)
       {
-        er.printStackTrace();
-        javax.swing.SwingUtilities.invokeLater(new Runnable()
-        {
-          public void run()
-          {
-            javax.swing.JOptionPane.showInternalMessageDialog(Desktop.desktop,
-                "Out of memory pasting sequences!!"
-                +
-                "\nSee help files for increasing Java Virtual Machine memory."
-                , "Out of memory",
-                javax.swing.JOptionPane.WARNING_MESSAGE);
-          }
-        });
-
+        new OOMWarning("Out of memory pasting sequences!!", er);
         return;
       }
 
@@ -2160,6 +2176,12 @@ public class AlignFrame
     alignPanel.paintAlignment(true);
   }
 
+  public void centreColumnLabels_actionPerformed(ActionEvent e)
+  {
+    viewport.centreColumnLabels = centreColumnLabelsMenuItem.getState();
+    alignPanel.paintAlignment(true);
+  }
+
 
 
   /**
@@ -2853,7 +2875,7 @@ public class AlignFrame
   {
     SequenceI [] oldOrder = viewport.getAlignment().getSequencesArray();
     AlignmentSorter.sortByPID(viewport.getAlignment(),
-                              viewport.getAlignment().getSequenceAt(0));
+                              viewport.getAlignment().getSequenceAt(0), null);
     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
                                     viewport.alignment));
     alignPanel.paintAlignment(true);
@@ -3116,7 +3138,7 @@ public class AlignFrame
       public void actionPerformed(ActionEvent e)
       {
         SequenceI [] oldOrder = viewport.getAlignment().getSequencesArray();
-        AlignmentSorter.sortByAnnotationScore(scoreLabel, viewport.getAlignment());
+        AlignmentSorter.sortByAnnotationScore(scoreLabel, viewport.getAlignment());//,viewport.getSelectionGroup());
         addHistoryItem(new OrderCommand("Sort by "+scoreLabel, oldOrder, viewport.alignment));
         alignPanel.paintAlignment(true);
       }
@@ -3234,7 +3256,7 @@ public class AlignFrame
    * or just the selected set will be submitted for multiple alignment.
    *
    */
-  private jalview.datamodel.AlignmentView gatherSequencesForAlignment()
+  public jalview.datamodel.AlignmentView gatherSequencesForAlignment()
   {
     // Now, check we have enough sequences
     AlignmentView msa = null;
@@ -3272,12 +3294,14 @@ public class AlignFrame
   }
 
   /**
-   * Decides what is submitted to a secondary structure prediction service,
-   * the currently selected sequence, or the currently selected alignment
+   * Decides what is submitted to a secondary structure prediction service:
+   * the first sequence in the alignment, or in the current selection,
+   * or, if the alignment is 'aligned' (ie padded with gaps), then the
+   * currently selected region or the whole alignment.
    * (where the first sequence in the set is the one that the prediction
    * will be for).
    */
-  AlignmentView gatherSeqOrMsaForSecStrPrediction()
+  public AlignmentView gatherSeqOrMsaForSecStrPrediction()
   {
    AlignmentView seqs = null;
 
@@ -3320,21 +3344,28 @@ public class AlignFrame
     {
       String choice = chooser.getSelectedFile().getPath();
       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
-
+      jalview.io.NewickFile fin = null;
       try
       {
-        jalview.io.NewickFile fin = new jalview.io.NewickFile(choice,
+        fin = new jalview.io.NewickFile(choice,
             "File");
         viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());
       }
       catch (Exception ex)
       {
         JOptionPane.showMessageDialog(Desktop.desktop,
-                                      "Problem reading tree file",
                                       ex.getMessage(),
+                                      "Problem reading tree file",
                                       JOptionPane.WARNING_MESSAGE);
         ex.printStackTrace();
       }
+      if (fin!=null && fin.hasWarningMessage())
+      {
+        JOptionPane.showMessageDialog(Desktop.desktop,
+                fin.getWarningMessage(),
+                "Possible problem with tree file",
+                JOptionPane.WARNING_MESSAGE);
+      }
     }
   }
 
@@ -3399,7 +3430,7 @@ public class AlignFrame
     {
       ex.printStackTrace();
     }
-
+    
     return tp;
   }
 
@@ -3410,13 +3441,20 @@ public class AlignFrame
    */
   public void BuildWebServiceMenu()
   {
+    // TODO: add support for context dependent disabling of services based on alignment and current selection
+    // TODO: add additional serviceHandle parameter to specify abstract handler class independently of AbstractName
+    // TODO: add in rediscovery GUI function to restart discoverer
+    // TODO: group services by location as well as function and/or introduce object broker mechanism.
     if ( (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 secstrpr = (Vector) Discoverer.services.get("SecStrPred");
+      Vector seqsrch = (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, alignframe)
       Vector wsmenu = new Vector();
-      final AlignFrame af = this;
+      final IProgressIndicator af = this;
       if (msaws != null)
       {
         // Add any Multiple Sequence Alignment Services
@@ -3425,42 +3463,9 @@ public class AlignFrame
         {
           final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) msaws.
               get(i);
-          final JMenuItem method = new JMenuItem(sh.getName());
-          method.addActionListener(new ActionListener()
-          {
-            public void actionPerformed(ActionEvent e)
-            {
-              AlignmentView msa = gatherSequencesForAlignment();
-              new jalview.ws.MsaWSClient(sh, title, msa,
-                                         false, true,
-                                         viewport.getAlignment().getDataset(),
-                                         af);
-
-            }
-
-          });
-          msawsmenu.add(method);
-          // Deal with services that we know accept partial alignments.
-          if (sh.getName().indexOf("lustal") > -1)
-          {
-            // We know that ClustalWS can accept partial alignments for refinement.
-            final JMenuItem methodR = new JMenuItem(sh.getName()+" Realign");
-            methodR.addActionListener(new ActionListener()
-            {
-              public void actionPerformed(ActionEvent e)
-              {
-                AlignmentView msa = gatherSequencesForAlignment();
-                new jalview.ws.MsaWSClient(sh, title, msa,
-                                           true, true,
-                                           viewport.getAlignment().getDataset(),
-                                           af);
-
-              }
-
-            });
-            msawsmenu.add(methodR);
-
-          }
+          jalview.ws.WSClient impl = jalview.ws.Discoverer.getServiceClient(sh);
+          impl.attachWSMenuEntry(msawsmenu, this);
+        
         }
         wsmenu.add(msawsmenu);
       }
@@ -3472,32 +3477,25 @@ public class AlignFrame
         {
           final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle)
               secstrpr.get(i);
-          final JMenuItem method = new JMenuItem(sh.getName());
-          method.addActionListener(new ActionListener()
-          {
-            public void actionPerformed(ActionEvent e)
-            {
-              AlignmentView msa = gatherSeqOrMsaForSecStrPrediction();
-              if (msa.getSequences().length == 1)
-              {
-                // Single Sequence prediction
-                new jalview.ws.JPredClient(sh, title, false, msa, af, true);
-              }
-              else
-              {
-                if (msa.getSequences().length > 1)
-                {
-                  // Sequence profile based prediction
-                  new jalview.ws.JPredClient(sh,
-                      title, true, msa, af, true);
-                }
-              }
-            }
-          });
-          secstrmenu.add(method);
+          jalview.ws.WSClient impl = jalview.ws.Discoverer.getServiceClient(sh);
+          impl.attachWSMenuEntry(secstrmenu, this);
         }
         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.elementAt(i);
+          jalview.ws.WSClient impl = jalview.ws.Discoverer.getServiceClient(sh);
+          impl.attachWSMenuEntry(seqsrchmenu, this);
+        }
+        // finally, add the whole shebang onto the webservices menu
+        wsmenu.add(seqsrchmenu); 
+      }
       resetWebServiceMenu();
       for (int i = 0, j = wsmenu.size(); i < j; i++)
       {
@@ -3509,9 +3507,6 @@ public class AlignFrame
       resetWebServiceMenu();
       this.webService.add(this.webServiceNoServices);
     }
-    // TODO: add in rediscovery function
-    // TODO: reduce code redundancy.
-    // TODO: group services by location as well as function.
   }
 
 
@@ -3525,15 +3520,22 @@ public class AlignFrame
     webService.removeAll();
     // Temporary hack - DBRef Fetcher always top level ws entry.
     JMenuItem rfetch = new JMenuItem("Fetch DB References");
-    rfetch.setToolTipText("Retrieve and parse uniprot records for the alignment or the currently selected sequences");
+    rfetch.setToolTipText("Retrieve and parse sequence database records for the alignment or the currently selected sequences");
     webService.add(rfetch);
     rfetch.addActionListener(new ActionListener() {
 
       public void actionPerformed(ActionEvent e)
       {
-        new jalview.ws.DBRefFetcher(
-                alignPanel.av.getSequenceSelection(),
-                alignPanel.alignFrame).fetchDBRefs(false);
+        new Thread(new Runnable() {
+
+          public void run()
+          {
+            new jalview.ws.DBRefFetcher(
+                    alignPanel.av.getSequenceSelection(),
+                    alignPanel.alignFrame).fetchDBRefs(false);
+          }
+        }).start();
+        
       }
 
     });
@@ -3600,7 +3602,8 @@ public class AlignFrame
 
           public void actionPerformed(ActionEvent e)
           {
-            af.showProductsFor(sel, ds, isRegSel, dna, source);
+            // TODO: new thread for this call with vis-delay
+            af.showProductsFor(af.viewport.getSequenceSelection(), ds, isRegSel, dna, source);
           }
           
         });
@@ -3617,32 +3620,64 @@ public class AlignFrame
   }
 protected void showProductsFor(SequenceI[] sel, Alignment ds, boolean isRegSel, boolean dna, String source)
   {
-  Alignment prods = CrossRef.findXrefSequences(sel, dna, source, ds);
-  if (prods!=null)
-  {
-    SequenceI[] sprods = new SequenceI[prods.getHeight()];
-    for (int s=0; s<sprods.length;s++)
-    {
-      sprods[s] = (prods.getSequenceAt(s)).deriveSequence();
-      if (!ds.getSequences().contains(sprods[s].getDatasetSequence()))
-        ds.addSequence(sprods[s].getDatasetSequence());
-    }
-    Alignment al = new Alignment(sprods);
-    AlignedCodonFrame[] cf = prods.getCodonFrames();
-    for (int s=0; cf!=null && s<cf.length; s++)
+  final boolean fisRegSel = isRegSel;
+  final boolean fdna = dna;
+  final String fsrc = source;
+  final AlignFrame ths = this;
+  final SequenceI[] fsel = sel;
+  Runnable foo = new Runnable() {
+
+    public void run()
     {
-      al.addCodonFrame(cf[s]);
-      cf[s] = null;
+      final long sttime = System.currentTimeMillis();
+      ths.setProgressBar("Searching for sequences from "+fsrc, sttime);
+      try {
+        Alignment ds = ths.getViewport().alignment.getDataset(); // update our local dataset reference
+      Alignment prods = CrossRef.findXrefSequences(fsel, fdna, fsrc, ds);
+      if (prods!=null)
+      {
+        SequenceI[] sprods = new SequenceI[prods.getHeight()];
+        for (int s=0; s<sprods.length;s++)
+        {
+          sprods[s] = (prods.getSequenceAt(s)).deriveSequence();
+          if (ds.getSequences()==null || !ds.getSequences().contains(sprods[s].getDatasetSequence()))
+            ds.addSequence(sprods[s].getDatasetSequence());
+          sprods[s].updatePDBIds();
+        }
+        Alignment al = new Alignment(sprods);
+        AlignedCodonFrame[] cf = prods.getCodonFrames();
+        for (int s=0; cf!=null && s<cf.length; s++)
+        {
+          al.addCodonFrame(cf[s]);
+          cf[s] = null;
+        }
+        al.setDataset(ds);
+        AlignFrame naf = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+        String newtitle =""+((fdna) ? "Proteins " : "Nucleotides ") + " for "+((fisRegSel) ? "selected region of " : "")
+                + getTitle();
+        Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH,
+                DEFAULT_HEIGHT);
+      } else {
+        System.err.println("No Sequences generated for xRef type "+fsrc);
+      }
+      }
+      catch (Exception e)
+      {
+        jalview.bin.Cache.log.error("Exception when finding crossreferences",e);
+      }
+      catch (OutOfMemoryError e) {
+        new OOMWarning("whilst fetching crossreferences", e);
+      }
+      catch (Error e)
+      {
+        jalview.bin.Cache.log.error("Error when finding crossreferences",e);
+      }
+      ths.setProgressBar("Finished searching for sequences from "+fsrc, sttime);
     }
-    al.setDataset(ds);
-    AlignFrame naf = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
-    String newtitle =""+((dna) ? "Proteins " : "Nucleotides ") + " for "+((isRegSel) ? "selected region of " : "")
-            + getTitle();
-    Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH,
-            DEFAULT_HEIGHT);
-  } else {
-    System.err.println("No Sequences generated for xRef type "+source);
-  }
+    
+  };
+  Thread frunner = new Thread(foo);
+  frunner.start();
   }
 
 
@@ -3717,9 +3752,10 @@ public void showTranslation_actionPerformed(ActionEvent e)
 }
 
 /**
- * DOCUMENT ME!
- *
- * @param String DOCUMENT ME!
+ * Try to load a features file onto the alignment.
+ * @param file contents or path to retrieve file 
+ * @param type access mode of file (see jalview.io.AlignFile)
+ * @return true if features file was parsed corectly.
  */
 public boolean parseFeaturesFile(String file, String type)
 {
@@ -3820,12 +3856,15 @@ public void drop(DropTargetDropEvent evt)
     }
 }
 
-  // This method will attempt to load a "dropped" file first by testing
-  // whether its and Annotation file, then features file. If both are
-  // false then the user may have dropped an alignment file onto this
-  // AlignFrame
+  /**     
+   * Attempt to load a "dropped" file: First by testing
+   * whether it's and Annotation file, then a JNet file, and finally a features file. If all are
+   * false then the user may have dropped an alignment file onto this
+   * AlignFrame.
+   * @param file either a filename or a URL string.
+   */
    public void loadJalviewDataFile(String file)
-  {
+   {
     try
     {
       String protocol = "File";
@@ -3840,34 +3879,38 @@ public void drop(DropTargetDropEvent evt)
 
       if (!isAnnotation)
       {
-        boolean isGroupsFile = parseFeaturesFile(file,protocol);
-        if (!isGroupsFile)
+        // 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.equalsIgnoreCase("JnetFile"))
         {
-          String format = new IdentifyFile().Identify(file, protocol);
-
-          if(format.equalsIgnoreCase("JnetFile"))
-          {
-            jalview.io.JPredFile predictions = new jalview.io.JPredFile(
-                file, protocol);
-            new JnetAnnotationMaker().add_annotation(predictions,
+          jalview.io.JPredFile predictions = new jalview.io.JPredFile(
+                  file, protocol);
+          new JnetAnnotationMaker().add_annotation(predictions,
                 viewport.getAlignment(),
                 0, false);
-            alignPanel.adjustAnnotationHeight();
-            alignPanel.paintAlignment(true);
-          }
-          else
+          isAnnotation=true;
+        }
+        else
+        {
+          // 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 alignment file to load into the current view.
+          if (!isGroupsFile)
           {
             new FileLoader().LoadFile(viewport, file, protocol, format);
+          } else {
+            alignPanel.paintAlignment(true);
+          }
         }
       }
-      }
-      else
+      if (isAnnotation)
       {
-        // (isAnnotation)
+        
         alignPanel.adjustAnnotationHeight();
+        viewport.updateSequenceIdColours();
         buildSortByAnnotationScoresMenu();
+        alignPanel.paintAlignment(true);
       }
-
     }
     catch (Exception ex)
     {
@@ -3915,8 +3958,9 @@ public void drop(DropTargetDropEvent evt)
   protected void extractScores_actionPerformed(ActionEvent e)
   {
     ParseProperties pp = new jalview.analysis.ParseProperties(viewport.alignment);
-    if (pp.getScoresFromDescription("col", "score column ", "\\W+([-+]?\\d*\\.?\\d*e?-?\\d*)\\W+([-+]?\\d*\\.?\\d*e?-?\\d*)")>0)
-    {
+    // TODO: verify regex and introduce GUI dialog for version 2.5
+    //if (pp.getScoresFromDescription("col", "score column ", "\\W*([-+]?\\d*\\.?\\d*e?-?\\d*)\\W+([-+]?\\d*\\.?\\d*e?-?\\d*)", true)>0)
+    if (pp.getScoresFromDescription("description column", "score in description column ", "\\W*([-+eE0-9.]+)", true)>0)    {
       buildSortByAnnotationScoresMenu();
     }
   }