JAL-845 linked protein/dna 'slave' further PoC functionality
[jalview.git] / src / jalview / structure / StructureSelectionManager.java
index 5a3beb4..945e08d 100644 (file)
@@ -24,28 +24,25 @@ import jalview.analysis.AlignSeq;
 import jalview.api.StructureSelectionManagerProvider;
 import jalview.commands.CommandI;
 import jalview.commands.EditCommand;
-import jalview.commands.EditCommand.Action;
-import jalview.commands.EditCommand.Edit;
+import jalview.commands.OrderCommand;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SearchResults;
-import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.io.AppletFormatAdapter;
+import jalview.util.MappingUtils;
 import jalview.util.MessageManager;
-import jalview.util.StringUtils;
 
 import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
-import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.Vector;
 
@@ -56,7 +53,7 @@ public class StructureSelectionManager
 {
   static IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> instances;
 
-  StructureMapping[] mappings;
+  private List<StructureMapping> mappings = new ArrayList<StructureMapping>();
 
   private boolean processSecondaryStructure = false;
 
@@ -68,6 +65,8 @@ public class StructureSelectionManager
 
   private List<CommandListener> commandListeners = new ArrayList<CommandListener>();
 
+  private List<SelectionListener> sel_listeners = new ArrayList<SelectionListener>();
+
   /**
    * @return true if will try to use external services for processing secondary
    *         structure
@@ -134,17 +133,18 @@ public class StructureSelectionManager
    */
   public void reportMapping()
   {
-    if (mappings == null)
+    if (mappings.isEmpty())
     {
       System.err.println("reportMapping: No PDB/Sequence mappings.");
     }
     else
     {
-      System.err.println("reportMapping: There are " + mappings.length
+      System.err.println("reportMapping: There are " + mappings.size()
               + " mappings.");
-      for (int m = 0; m < mappings.length; m++)
+      int i = 0;
+      for (StructureMapping sm : mappings)
       {
-        System.err.println("mapping " + m + " : " + mappings[m].pdbfile);
+        System.err.println("mapping " + i++ + " : " + sm.pdbfile);
       }
     }
   }
@@ -265,16 +265,19 @@ public class StructureSelectionManager
     }
   }
 
+  /**
+   * Returns the file name for a mapped PDB id (or null if not mapped).
+   * 
+   * @param pdbid
+   * @return
+   */
   public String alreadyMappedToFile(String pdbid)
   {
-    if (mappings != null)
+    for (StructureMapping sm : mappings)
     {
-      for (int i = 0; i < mappings.length; i++)
+      if (sm.getPdbId().equals(pdbid))
       {
-        if (mappings[i].getPdbId().equals(pdbid))
-        {
-          return mappings[i].pdbfile;
-        }
+        return sm.pdbfile;
       }
     }
     return null;
@@ -501,19 +504,7 @@ public class StructureSelectionManager
               mappingDetails.toString());
       if (forStructureView)
       {
-
-        if (mappings == null)
-        {
-          mappings = new StructureMapping[1];
-        }
-        else
-        {
-          StructureMapping[] tmp = new StructureMapping[mappings.length + 1];
-          System.arraycopy(mappings, 0, tmp, 0, mappings.length);
-          mappings = tmp;
-        }
-
-        mappings[mappings.length - 1] = newMapping;
+        mappings.add(newMapping);
       }
       maxChain.transferResidueAnnotation(newMapping, sqmpping);
     }
@@ -565,19 +556,18 @@ public class StructureSelectionManager
       }
     }
 
-    if (pdbs.size() > 0 && mappings != null)
+    if (pdbs.size() > 0)
     {
-      Vector tmp = new Vector();
-      for (int i = 0; i < mappings.length; i++)
+      List<StructureMapping> tmp = new ArrayList<StructureMapping>();
+      for (StructureMapping sm : mappings)
       {
-        if (!pdbs.contains(mappings[i].pdbfile))
+        if (!pdbs.contains(sm.pdbfile))
         {
-          tmp.addElement(mappings[i]);
+          tmp.add(sm);
         }
       }
 
-      mappings = new StructureMapping[tmp.size()];
-      tmp.copyInto(mappings);
+      mappings = tmp;
     }
   }
 
@@ -588,7 +578,6 @@ public class StructureSelectionManager
       // old or prematurely sent event
       return;
     }
-    boolean hasSequenceListeners = handlingVamsasMo || seqmappings != null;
     SearchResults results = null;
     SequenceI lastseq = null;
     int lastipos = -1, indexpos;
@@ -600,28 +589,20 @@ public class StructureSelectionManager
         {
           results = new SearchResults();
         }
-        if (mappings != null)
+        for (StructureMapping sm : mappings)
         {
-          for (int j = 0; j < mappings.length; j++)
+          if (sm.pdbfile.equals(pdbfile) && sm.pdbchain.equals(chain))
           {
-            if (mappings[j].pdbfile.equals(pdbfile)
-                    && mappings[j].pdbchain.equals(chain))
+            indexpos = sm.getSeqPos(pdbResNum);
+            if (lastipos != indexpos && lastseq != sm.sequence)
             {
-              indexpos = mappings[j].getSeqPos(pdbResNum);
-              if (lastipos != indexpos && lastseq != mappings[j].sequence)
+              results.addResult(sm.sequence, indexpos, indexpos);
+              lastipos = indexpos;
+              lastseq = sm.sequence;
+              // construct highlighted sequence list
+              for (AlignedCodonFrame acf : seqmappings)
               {
-                results.addResult(mappings[j].sequence, indexpos, indexpos);
-                lastipos = indexpos;
-                lastseq = mappings[j].sequence;
-                // construct highlighted sequence list
-                if (seqmappings != null)
-                {
-                  for (AlignedCodonFrame acf : seqmappings)
-                  {
-                    acf.markMappedRegion(mappings[j].sequence, indexpos,
-                            results);
-                  }
-                }
+                acf.markMappedRegion(sm.sequence, indexpos, results);
               }
             }
           }
@@ -655,7 +636,8 @@ public class StructureSelectionManager
   public void mouseOverSequence(SequenceI seq, int indexpos, int index,
           VamsasSource source)
   {
-    boolean hasSequenceListeners = handlingVamsasMo || seqmappings != null;
+    boolean hasSequenceListeners = handlingVamsasMo
+            || !seqmappings.isEmpty();
     SearchResults results = null;
     if (index == -1)
     {
@@ -686,7 +668,13 @@ public class StructureSelectionManager
             {
               if (results == null)
               {
-                results = buildSearchResults(seq, index);
+                results = MappingUtils.buildSearchResults(seq, index,
+                        seqmappings);
+              }
+              if (handlingVamsasMo)
+              {
+                results.addResult(seq, index, index);
+
               }
               seqListener.highlightSequence(results);
             }
@@ -707,39 +695,6 @@ public class StructureSelectionManager
   }
 
   /**
-   * Returns a SearchResults object describing the mapped region corresponding
-   * to the specified sequence position.
-   * 
-   * @param seq
-   * @param index
-   * @return
-   */
-  protected SearchResults buildSearchResults(SequenceI seq, int index)
-  {
-    SearchResults results;
-    results = new SearchResults();
-    if (index >= seq.getStart() && index <= seq.getEnd())
-    {
-      if (seqmappings != null)
-      {
-        for (AlignedCodonFrame acf : seqmappings)
-        {
-          acf.markMappedRegion(seq, index, results);
-        }
-      }
-      // hasSequenceListeners = results.getSize() > 0;
-      if (handlingVamsasMo)
-      {
-        // maybe have to resolve seq to a dataset sequence...
-        // add in additional direct sequence and/or dataset sequence
-        // highlighting
-        results.addResult(seq, index, index);
-      }
-    }
-    return results;
-  }
-
-  /**
    * Send suitable messages to a StructureListener to highlight atoms
    * corresponding to the given sequence position.
    * 
@@ -751,26 +706,21 @@ public class StructureSelectionManager
           int index)
   {
     int atomNo;
-    if (mappings != null)
+    List<AtomSpec> atoms = new ArrayList<AtomSpec>();
+    for (StructureMapping sm : mappings)
     {
-      List<AtomSpec> atoms = new ArrayList<AtomSpec>();
-      for (int j = 0; j < mappings.length; j++)
+      if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence())
       {
-        if (mappings[j].sequence == seq
-                || mappings[j].sequence == seq.getDatasetSequence())
-        {
-          atomNo = mappings[j].getAtomNum(index);
+        atomNo = sm.getAtomNum(index);
 
-          if (atomNo > 0)
-          {
-            atoms.add(new AtomSpec(mappings[j].pdbfile,
-                    mappings[j].pdbchain, mappings[j].getPDBResNum(index),
-                    atomNo));
-          }
+        if (atomNo > 0)
+        {
+          atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain, sm
+                  .getPDBResNum(index), atomNo));
         }
       }
-      sl.highlightAtoms(atoms);
     }
+    sl.highlightAtoms(atoms);
   }
 
   /**
@@ -859,34 +809,25 @@ public class StructureSelectionManager
 
   public StructureMapping[] getMapping(String pdbfile)
   {
-    Vector tmp = new Vector();
-    if (mappings != null)
-    {
-      for (int i = 0; i < mappings.length; i++)
+    List<StructureMapping> tmp = new ArrayList<StructureMapping>();
+    for (StructureMapping sm : mappings)
       {
-        if (mappings[i].pdbfile.equals(pdbfile))
+      if (sm.pdbfile.equals(pdbfile))
         {
-          tmp.addElement(mappings[i]);
+        tmp.add(sm);
         }
-      }
-    }
-    StructureMapping[] ret = new StructureMapping[tmp.size()];
-    for (int i = 0; i < tmp.size(); i++)
-    {
-      ret[i] = (StructureMapping) tmp.elementAt(i);
     }
-
-    return ret;
+    return tmp.toArray(new StructureMapping[tmp.size()]);
   }
 
   public String printMapping(String pdbfile)
   {
-    StringBuffer sb = new StringBuffer();
-    for (int i = 0; i < mappings.length; i++)
+    StringBuilder sb = new StringBuilder(64);
+    for (StructureMapping sm : mappings)
     {
-      if (mappings[i].pdbfile.equals(pdbfile))
+      if (sm.pdbfile.equals(pdbfile))
       {
-        sb.append(mappings[i].mappingDetails);
+        sb.append(sm.mappingDetails);
       }
     }
 
@@ -926,13 +867,11 @@ public class StructureSelectionManager
     }
   }
 
-  Vector<SelectionListener> sel_listeners = new Vector<SelectionListener>();
-
   public void addSelectionListener(SelectionListener selecter)
   {
     if (!sel_listeners.contains(selecter))
     {
-      sel_listeners.addElement(selecter);
+      sel_listeners.add(selecter);
     }
   }
 
@@ -940,7 +879,7 @@ public class StructureSelectionManager
   {
     if (sel_listeners.contains(toremove))
     {
-      sel_listeners.removeElement(toremove);
+      sel_listeners.remove(toremove);
     }
   }
 
@@ -948,18 +887,11 @@ public class StructureSelectionManager
           jalview.datamodel.SequenceGroup selection,
           jalview.datamodel.ColumnSelection colsel, SelectionSource source)
   {
-    if (sel_listeners != null && sel_listeners.size() > 0)
+    for (SelectionListener slis : sel_listeners)
     {
-      Enumeration listeners = sel_listeners.elements();
-      while (listeners.hasMoreElements())
+      if (slis != source)
       {
-        SelectionListener slis = ((SelectionListener) listeners
-                .nextElement());
-        if (slis != source)
-        {
-          slis.selection(selection, colsel, source);
-        }
-        ;
+        slis.selection(selection, colsel, source);
       }
     }
   }
@@ -1056,143 +988,36 @@ public class StructureSelectionManager
   {
     for (CommandListener listener : commandListeners)
     {
-      if (listener.getVamsasSource() != source)
-      {
-        listener.mirrorCommand(command, undo, this);
-      }
+      listener.mirrorCommand(command, undo, this, source);
     }
   }
 
   /**
-   * Returns a new EditCommand representing the given command as mapped to the
-   * given sequences. If there is no mapping, returns an empty EditCommand.
+   * Returns a new CommandI representing the given command as mapped to the
+   * given sequences. If no mapping could be made, or the command is not of a
+   * mappable kind, returns null.
    * 
    * @param command
    * @param undo
-   * @param targetSeqs
+   * @param alignmentI
    * @param gapChar
    * @return
    */
-  public EditCommand mapEditCommand(EditCommand command, boolean undo,
-          final List<SequenceI> targetSeqs, char gapChar)
+  public CommandI mapCommand(CommandI command,
+          boolean undo,
+          final AlignmentI alignmentI, char gapChar)
   {
-    /*
-     * Cache a copy of the target sequences so we can mimic successive edits on
-     * them. This lets us compute mappings for all edits in the set.
-     */
-    Map<SequenceI, SequenceI> targetCopies = new HashMap<SequenceI, SequenceI>();
-    for (SequenceI seq : targetSeqs)
+    if (command instanceof EditCommand)
     {
-      SequenceI ds = seq.getDatasetSequence();
-      if (ds != null)
-      {
-        final Sequence copy = new Sequence("", new String(seq.getSequence()));
-        copy.setDatasetSequence(ds);
-        targetCopies.put(ds, copy);
-      }
+      return MappingUtils.mapEditCommand((EditCommand) command, undo,
+              alignmentI, gapChar,
+            seqmappings);
     }
-
-    /*
-     * Compute 'source' sequences as they were before applying edits:
-     */
-    Map<SequenceI, SequenceI> originalSequences = command.priorState(undo);
-
-    EditCommand result = new EditCommand();
-    Iterator<Edit> edits = command.getEditIterator(!undo);
-    while (edits.hasNext())
+    else if (command instanceof OrderCommand)
     {
-      Edit edit = edits.next();
-      Action action = edit.getAction();
-
-      /*
-       * Invert sense of action if an Undo.
-       */
-      if (undo)
-      {
-        action = action == Action.INSERT_GAP ? Action.DELETE_GAP
-                : (action == Action.DELETE_GAP ? Action.INSERT_GAP : action);
-      }
-      final int count = edit.getNumber();
-      final int editPos = edit.getPosition();
-      for (SequenceI seq : edit.getSequences())
-      {
-        /*
-         * Get residue position at (or to right of) edit location. Note we use
-         * our 'copy' of the sequence before editing for this.
-         */
-        SequenceI ds = seq.getDatasetSequence();
-        if (ds == null)
-        {
-          continue;
-        }
-        final SequenceI actedOn = originalSequences.get(ds);
-        final int seqpos = actedOn.findPosition(editPos);
-
-        /*
-         * Determine all mappings from this position to mapped sequences.
-         */
-        SearchResults sr = buildSearchResults(seq, seqpos);
-
-        if (!sr.isEmpty())
-        {
-          for (SequenceI targetSeq : targetSeqs)
-          {
-            ds = targetSeq.getDatasetSequence();
-            if (ds == null)
-            {
-              continue;
-            }
-            SequenceI copyTarget = targetCopies.get(ds);
-            final int[] match = sr.getResults(copyTarget, 0,
-                    copyTarget.getLength());
-            if (match != null)
-            {
-              final int ratio = 3; // TODO: compute this - how?
-              final int mappedCount = count * ratio;
-
-              /*
-               * Shift Delete start position left, as it acts on positions to
-               * its right.
-               */
-              int mappedEditPos = action == Action.DELETE_GAP ? match[0]
-                      - mappedCount : match[0];
-              Edit e = new EditCommand().new Edit(action, new SequenceI[]
-              { targetSeq }, mappedEditPos, mappedCount, gapChar);
-              result.addEdit(e);
-
-              /*
-               * and 'apply' the edit to our copy of its target sequence
-               */
-              if (action == Action.INSERT_GAP)
-              {
-                copyTarget.setSequence(new String(StringUtils.insertCharAt(
-                        copyTarget.getSequence(), mappedEditPos,
-                        mappedCount,
-                        gapChar)));
-              }
-              else if (action == Action.DELETE_GAP)
-              {
-                copyTarget.setSequence(new String(StringUtils.deleteChars(
-                        copyTarget.getSequence(), mappedEditPos,
-                        mappedEditPos + mappedCount)));
-              }
-            }
-          }
-        }
-        /*
-         * and 'apply' the edit to our copy of its source sequence
-         */
-        if (action == Action.INSERT_GAP) {
-          actedOn.setSequence(new String(StringUtils.insertCharAt(
-                  actedOn.getSequence(), editPos, count, gapChar)));
-        }
-        else if (action == Action.DELETE_GAP)
-        {
-          actedOn.setSequence(new String(StringUtils.deleteChars(
-                  actedOn.getSequence(), editPos, editPos + count)));
-        }
-      }
+      return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
+              alignmentI, seqmappings);
     }
-    return result;
+    return null;
   }
 }