Merge branch 'patch/JAL-4062_sort_and_merge_contiguousregions' into develop
[jalview.git] / src / jalview / structure / StructureSelectionManager.java
index b4bd781..2f1ddc0 100644 (file)
@@ -34,7 +34,7 @@ import java.util.Vector;
 
 import jalview.analysis.AlignSeq;
 import jalview.api.StructureSelectionManagerProvider;
 
 import jalview.analysis.AlignSeq;
 import jalview.api.StructureSelectionManagerProvider;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.commands.CommandI;
 import jalview.commands.EditCommand;
 import jalview.commands.OrderCommand;
 import jalview.commands.CommandI;
 import jalview.commands.EditCommand;
 import jalview.commands.OrderCommand;
@@ -42,6 +42,7 @@ import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.ContiguousI;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SearchResults;
@@ -52,6 +53,7 @@ import jalview.gui.IProgressIndicator;
 import jalview.io.AppletFormatAdapter;
 import jalview.io.DataSourceType;
 import jalview.io.StructureFile;
 import jalview.io.AppletFormatAdapter;
 import jalview.io.DataSourceType;
 import jalview.io.StructureFile;
+import jalview.structure.StructureImportSettings.TFType;
 import jalview.util.MappingUtils;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.util.MappingUtils;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
@@ -153,16 +155,16 @@ public class StructureSelectionManager
   {
     if (mappings.isEmpty())
     {
   {
     if (mappings.isEmpty())
     {
-      System.err.println("reportMapping: No PDB/Sequence mappings.");
+      jalview.bin.Console.errPrintln("reportMapping: No PDB/Sequence mappings.");
     }
     else
     {
     }
     else
     {
-      System.err.println(
+      jalview.bin.Console.errPrintln(
               "reportMapping: There are " + mappings.size() + " mappings.");
       int i = 0;
       for (StructureMapping sm : mappings)
       {
               "reportMapping: There are " + mappings.size() + " mappings.");
       int i = 0;
       for (StructureMapping sm : mappings)
       {
-        System.err.println("mapping " + i++ + " : " + sm.pdbfile);
+        jalview.bin.Console.errPrintln("mapping " + i++ + " : " + sm.pdbfile);
       }
     }
   }
       }
     }
   }
@@ -321,11 +323,11 @@ public class StructureSelectionManager
    * @return null or the structure data parsed as a pdb file
    */
   synchronized public StructureFile setMapping(SequenceI[] sequence,
    * @return null or the structure data parsed as a pdb file
    */
   synchronized public StructureFile setMapping(SequenceI[] sequence,
-          String[] targetChains, String pdbFile, DataSourceType protocol, 
+          String[] targetChains, String pdbFile, DataSourceType protocol,
           IProgressIndicator progress)
   {
     return computeMapping(true, sequence, targetChains, pdbFile, protocol,
           IProgressIndicator progress)
   {
     return computeMapping(true, sequence, targetChains, pdbFile, protocol,
-            progress);
+            progress, null, null, true);
   }
 
   /**
   }
 
   /**
@@ -348,10 +350,45 @@ public class StructureSelectionManager
    */
   synchronized public StructureFile setMapping(boolean forStructureView,
           SequenceI[] sequenceArray, String[] targetChainIds,
    */
   synchronized public StructureFile setMapping(boolean forStructureView,
           SequenceI[] sequenceArray, String[] targetChainIds,
-          String pdbFile, DataSourceType sourceType)
+          String pdbFile, DataSourceType sourceType, TFType tft,
+          String paeFilename)
+  {
+    return setMapping(forStructureView, sequenceArray, targetChainIds,
+            pdbFile, sourceType, tft, paeFilename, true);
+  }
+
+
+  /**
+   * create sequence structure mappings between each sequence and the given
+   * pdbFile (retrieved via the given protocol). Either constructs a mapping
+   * using NW alignment or derives one from any available SIFTS mapping data.
+   * 
+   * @param forStructureView
+   *          when true, record the mapping for use in mouseOvers
+   * 
+   * @param sequenceArray
+   *          - one or more sequences to be mapped to pdbFile
+   * @param targetChainIds
+   *          - optional chain specification for mapping each sequence to pdb
+   *          (may be nill, individual elements may be nill) - JBPNote: JAL-2693
+   *          - this should be List<List<String>>, empty lists indicate no
+   *          predefined mappings
+   * @param pdbFile
+   *          - structure data resource
+   * @param sourceType
+   *          - how to resolve data from resource
+   * @param tft - specify how to interpret the temperature factor column in the atom data
+   * @param paeFilename - when not null, specifies a filename containing a matrix formatted in JSON using one of the known PAE formats
+   * @param doXferSettings - when true, transfer annotation to mapped sequences in sequenceArray 
+   * @return null or the structure data parsed as a pdb file
+   */
+  synchronized public StructureFile setMapping(boolean forStructureView,
+          SequenceI[] sequenceArray, String[] targetChainIds,
+          String pdbFile, DataSourceType sourceType, TFType tft,
+          String paeFilename, boolean doXferSettings)
   {
     return computeMapping(forStructureView, sequenceArray, targetChainIds,
   {
     return computeMapping(forStructureView, sequenceArray, targetChainIds,
-            pdbFile, sourceType, null);
+            pdbFile, sourceType, null, tft, paeFilename, doXferSettings);
   }
 
   /**
   }
 
   /**
@@ -376,12 +413,16 @@ public class StructureSelectionManager
    * @param IProgressIndicator
    *          reference to UI component that maintains a progress bar for the
    *          mapping operation
    * @param IProgressIndicator
    *          reference to UI component that maintains a progress bar for the
    *          mapping operation
+   * @param tft - specify how to interpret the temperature factor column in the atom data
+   * @param paeFilename - when not null, specifies a filename containing a matrix formatted in JSON using one of the known PAE formats
+   * @param doXferSettings - when true, transfer annotation to mapped sequences in sequenceArray 
    * @return null or the structure data parsed as a pdb file
    */
    * @return null or the structure data parsed as a pdb file
    */
-  synchronized public StructureFile computeMapping(
-          boolean forStructureView, SequenceI[] sequenceArray,
-          String[] targetChainIds, String pdbFile, DataSourceType sourceType,
-          IProgressIndicator progress)
+  synchronized public StructureFile computeMapping(boolean forStructureView,
+          SequenceI[] sequenceArray, String[] targetChainIds,
+          String pdbFile, DataSourceType sourceType,
+          IProgressIndicator progress, TFType tft, String paeFilename,
+          boolean doXferSettings)
   {
     long progressSessionId = System.currentTimeMillis() * 3;
 
   {
     long progressSessionId = System.currentTimeMillis() * 3;
 
@@ -391,8 +432,7 @@ public class StructureSelectionManager
     // FIXME: possibly should just delete
 
     boolean parseSecStr = processSecondaryStructure
     // FIXME: possibly should just delete
 
     boolean parseSecStr = processSecondaryStructure
-            ? isStructureFileProcessed(pdbFile, sequenceArray)
-            : false;
+            && !isStructureFileProcessed(pdbFile, sequenceArray);
 
     StructureFile pdb = null;
     boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
 
     StructureFile pdb = null;
     boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
@@ -401,27 +441,39 @@ public class StructureSelectionManager
       // FIXME if sourceType is not null, we've lost data here
       sourceType = AppletFormatAdapter.checkProtocol(pdbFile);
       pdb = new JmolParser(false, pdbFile, sourceType);
       // FIXME if sourceType is not null, we've lost data here
       sourceType = AppletFormatAdapter.checkProtocol(pdbFile);
       pdb = new JmolParser(false, pdbFile, sourceType);
+      if (paeFilename != null)
+      {
+        pdb.setPAEMatrix(paeFilename);
+      }
+      pdb.setTemperatureFactorType(tft);
       pdb.addSettings(parseSecStr && processSecondaryStructure,
               parseSecStr && addTempFacAnnot,
               parseSecStr && secStructServices);
       pdb.addSettings(parseSecStr && processSecondaryStructure,
               parseSecStr && addTempFacAnnot,
               parseSecStr && secStructServices);
+      // save doXferSettings and reset after doParse()
+      boolean temp = pdb.getDoXferSettings();
+      pdb.setDoXferSettings(doXferSettings);
       pdb.doParse();
       pdb.doParse();
+      pdb.setDoXferSettings(temp);
       if (pdb.getId() != null && pdb.getId().trim().length() > 0
               && DataSourceType.FILE == sourceType)
       {
         registerPDBFile(pdb.getId().trim(), pdbFile);
       }
       // if PDBId is unavailable then skip SIFTS mapping execution path
       if (pdb.getId() != null && pdb.getId().trim().length() > 0
               && DataSourceType.FILE == sourceType)
       {
         registerPDBFile(pdb.getId().trim(), pdbFile);
       }
       // if PDBId is unavailable then skip SIFTS mapping execution path
-      // TODO: JAL-3868 need to know if structure is actually from 
-      // PDB (has valid PDB ID and has provenance suggesting it 
+      // TODO: JAL-3868 need to know if structure is actually from
+      // PDB (has valid PDB ID and has provenance suggesting it
       // actually came from PDB)
       boolean isProtein = false;
       // actually came from PDB)
       boolean isProtein = false;
-      for (SequenceI s:sequenceArray) {
-        if (s.isProtein()) {
+      for (SequenceI s : sequenceArray)
+      {
+        if (s.isProtein())
+        {
           isProtein = true;
           break;
         }
       }
           isProtein = true;
           break;
         }
       }
-      isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable() && !pdb.getId().startsWith("AF-") && isProtein;
+      isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable()
+              && !pdb.getId().startsWith("AF-") && isProtein;
 
     } catch (Exception ex)
     {
 
     } catch (Exception ex)
     {
@@ -441,8 +493,8 @@ public class StructureSelectionManager
     } catch (SiftsException e)
     {
       isMapUsingSIFTs = false;
     } catch (SiftsException e)
     {
       isMapUsingSIFTs = false;
-      Cache.log.error("SIFTS mapping failed", e);
-      Cache.log.error("Falling back on Needleman & Wunsch alignment");
+      Console.error("SIFTS mapping failed", e);
+      Console.error("Falling back on Needleman & Wunsch alignment");
       siftsClient = null;
     }
 
       siftsClient = null;
     }
 
@@ -533,9 +585,11 @@ public class StructureSelectionManager
       List<StructureMapping> seqToStrucMapping = new ArrayList<>();
       if (isMapUsingSIFTs && seq.isProtein())
       {
       List<StructureMapping> seqToStrucMapping = new ArrayList<>();
       if (isMapUsingSIFTs && seq.isProtein())
       {
-        if (progress!=null) {
-          progress.setProgressBar(MessageManager
-                .getString("status.obtaining_mapping_with_sifts"),
+        if (progress != null)
+        {
+          progress.setProgressBar(
+                  MessageManager
+                          .getString("status.obtaining_mapping_with_sifts"),
                   progressSessionId);
         }
         jalview.datamodel.Mapping sqmpping = maxAlignseq
                   progressSessionId);
         }
         jalview.datamodel.Mapping sqmpping = maxAlignseq
@@ -549,21 +603,23 @@ public class StructureSelectionManager
                     pdb, maxChain, sqmpping, maxAlignseq, siftsClient);
             seqToStrucMapping.add(siftsMapping);
             maxChain.makeExactMapping(siftsMapping, seq);
                     pdb, maxChain, sqmpping, maxAlignseq, siftsClient);
             seqToStrucMapping.add(siftsMapping);
             maxChain.makeExactMapping(siftsMapping, seq);
-            maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS",pdb.getId().toLowerCase(Locale.ROOT));
+            maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS",
+                    pdb.getId().toLowerCase(Locale.ROOT));
             maxChain.transferResidueAnnotation(siftsMapping, null);
             ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
 
           } catch (SiftsException e)
           {
             // fall back to NW alignment
             maxChain.transferResidueAnnotation(siftsMapping, null);
             ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
 
           } catch (SiftsException e)
           {
             // fall back to NW alignment
-            Cache.log.error(e.getMessage());
+            Console.error(e.getMessage());
             StructureMapping nwMapping = getNWMappings(seq, pdbFile,
                     targetChainId, maxChain, pdb, maxAlignseq);
             seqToStrucMapping.add(nwMapping);
             maxChain.makeExactMapping(maxAlignseq, seq);
             StructureMapping nwMapping = getNWMappings(seq, pdbFile,
                     targetChainId, maxChain, pdb, maxAlignseq);
             seqToStrucMapping.add(nwMapping);
             maxChain.makeExactMapping(maxAlignseq, seq);
-            maxChain.transferRESNUMFeatures(seq, "IEA:Jalview",pdb.getId().toLowerCase(Locale.ROOT)); // FIXME: is
-                                                                 // this
-                                                        // "IEA:Jalview" ?
+            maxChain.transferRESNUMFeatures(seq, "IEA:Jalview",
+                    pdb.getId().toLowerCase(Locale.ROOT)); // FIXME: is
+            // this
+            // "IEA:Jalview" ?
             maxChain.transferResidueAnnotation(nwMapping, sqmpping);
             ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
           }
             maxChain.transferResidueAnnotation(nwMapping, sqmpping);
             ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
           }
@@ -576,24 +632,22 @@ public class StructureSelectionManager
             StructureMapping siftsMapping = null;
             try
             {
             StructureMapping siftsMapping = null;
             try
             {
-              siftsMapping = getStructureMapping(seq,
-                      pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq,
-                      siftsClient);
+              siftsMapping = getStructureMapping(seq, pdbFile, chain.id,
+                      pdb, chain, sqmpping, maxAlignseq, siftsClient);
               foundSiftsMappings.add(siftsMapping);
               chain.makeExactMapping(siftsMapping, seq);
               foundSiftsMappings.add(siftsMapping);
               chain.makeExactMapping(siftsMapping, seq);
-              chain.transferRESNUMFeatures(seq, "IEA: SIFTS",pdb.getId().toLowerCase(Locale.ROOT));// FIXME: is this
+              chain.transferRESNUMFeatures(seq, "IEA: SIFTS",
+                      pdb.getId().toLowerCase(Locale.ROOT));// FIXME: is this
               // "IEA:SIFTS" ?
               chain.transferResidueAnnotation(siftsMapping, null);
             } catch (SiftsException e)
             {
               // "IEA:SIFTS" ?
               chain.transferResidueAnnotation(siftsMapping, null);
             } catch (SiftsException e)
             {
-              System.err.println(e.getMessage());
-            }
-            catch (Exception e)
+              jalview.bin.Console.errPrintln(e.getMessage());
+            } catch (Exception e)
             {
             {
-              System.err
-                      .println(
-                              "Unexpected exception during SIFTS mapping - falling back to NW for this sequence/structure pair");
-              System.err.println(e.getMessage());
+              jalview.bin.Console.errPrintln(
+                      "Unexpected exception during SIFTS mapping - falling back to NW for this sequence/structure pair");
+              jalview.bin.Console.errPrintln(e.getMessage());
             }
           }
           if (!foundSiftsMappings.isEmpty())
             }
           }
           if (!foundSiftsMappings.isEmpty())
@@ -606,8 +660,9 @@ public class StructureSelectionManager
             StructureMapping nwMapping = getNWMappings(seq, pdbFile,
                     maxChainId, maxChain, pdb, maxAlignseq);
             seqToStrucMapping.add(nwMapping);
             StructureMapping nwMapping = getNWMappings(seq, pdbFile,
                     maxChainId, maxChain, pdb, maxAlignseq);
             seqToStrucMapping.add(nwMapping);
-            maxChain.transferRESNUMFeatures(seq, null,pdb.getId().toLowerCase(Locale.ROOT)); // FIXME: is this
-                                                        // "IEA:Jalview" ?
+            maxChain.transferRESNUMFeatures(seq, null,
+                    pdb.getId().toLowerCase(Locale.ROOT)); // FIXME: is this
+            // "IEA:Jalview" ?
             maxChain.transferResidueAnnotation(nwMapping, sqmpping);
             ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
           }
             maxChain.transferResidueAnnotation(nwMapping, sqmpping);
             ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
           }
@@ -617,8 +672,9 @@ public class StructureSelectionManager
       {
         if (progress != null)
         {
       {
         if (progress != null)
         {
-          progress.setProgressBar(MessageManager
-                                 .getString("status.obtaining_mapping_with_nw_alignment"),
+          progress.setProgressBar(
+                  MessageManager.getString(
+                          "status.obtaining_mapping_with_nw_alignment"),
                   progressSessionId);
         }
         StructureMapping nwMapping = getNWMappings(seq, pdbFile, maxChainId,
                   progressSessionId);
         }
         StructureMapping nwMapping = getNWMappings(seq, pdbFile, maxChainId,
@@ -652,7 +708,7 @@ public class StructureSelectionManager
   private boolean isStructureFileProcessed(String pdbFile,
           SequenceI[] sequenceArray)
   {
   private boolean isStructureFileProcessed(String pdbFile,
           SequenceI[] sequenceArray)
   {
-    boolean parseSecStr = true;
+    boolean processed = false;
     if (isPDBFileRegistered(pdbFile))
     {
       for (SequenceI sq : sequenceArray)
     if (isPDBFileRegistered(pdbFile))
     {
       for (SequenceI sq : sequenceArray)
@@ -672,13 +728,13 @@ public class StructureSelectionManager
             // passed, not the structure data ID -
             if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
             {
             // passed, not the structure data ID -
             if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
             {
-              parseSecStr = false;
+              processed = true;
             }
           }
         }
       }
     }
             }
           }
         }
       }
     }
-    return parseSecStr;
+    return processed;
   }
 
   public void addStructureMapping(StructureMapping sm)
   }
 
   public void addStructureMapping(StructureMapping sm)
@@ -708,7 +764,8 @@ public class StructureSelectionManager
   private StructureMapping getStructureMapping(SequenceI seq,
           String pdbFile, String targetChainId, StructureFile pdb,
           PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
   private StructureMapping getStructureMapping(SequenceI seq,
           String pdbFile, String targetChainId, StructureFile pdb,
           PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
-          AlignSeq maxAlignseq, SiftsClient siftsClient) throws SiftsException
+          AlignSeq maxAlignseq, SiftsClient siftsClient)
+          throws SiftsException
   {
     StructureMapping curChainMapping = siftsClient
             .getSiftsStructureMapping(seq, pdbFile, targetChainId);
   {
     StructureMapping curChainMapping = siftsClient
             .getSiftsStructureMapping(seq, pdbFile, targetChainId);
@@ -774,7 +831,8 @@ public class StructureSelectionManager
     maxChain.makeExactMapping(maxAlignseq, seq);
     jalview.datamodel.Mapping sqmpping = maxAlignseq
             .getMappingFromS1(false);
     maxChain.makeExactMapping(maxAlignseq, seq);
     jalview.datamodel.Mapping sqmpping = maxAlignseq
             .getMappingFromS1(false);
-    maxChain.transferRESNUMFeatures(seq, null, pdb.getId().toLowerCase(Locale.ROOT));
+    maxChain.transferRESNUMFeatures(seq, null,
+            pdb.getId().toLowerCase(Locale.ROOT));
 
     HashMap<Integer, int[]> mapping = new HashMap<>();
     int resNum = -10000;
 
     HashMap<Integer, int[]> mapping = new HashMap<>();
     int resNum = -10000;
@@ -865,6 +923,52 @@ public class StructureSelectionManager
   }
 
   /**
   }
 
   /**
+   * hack to highlight a range of positions at once on any structure views
+   * 
+   * @param sequenceRef
+   * @param is
+   *          - series of int start-end ranges as positions on sequenceRef
+   * @param i
+   * @param object
+   */
+  public void highlightPositionsOn(SequenceI sequenceRef, int[][] is,
+          Object source)
+  {
+    boolean hasSequenceListeners = handlingVamsasMo
+            || !seqmappings.isEmpty();
+    SearchResultsI results = null;
+    ArrayList<Integer> listOfPositions = new ArrayList<Integer>();
+    for (int[] s_e : is)
+    {
+      for (int p = s_e[0]; p <= s_e[1]; listOfPositions.add(p++))
+        ;
+    }
+    int seqpos[] = new int[listOfPositions.size()];
+    int i = 0;
+    for (Integer p : listOfPositions)
+    {
+      seqpos[i++] = p;
+    }
+
+    for (i = 0; i < listeners.size(); i++)
+    {
+      Object listener = listeners.elementAt(i);
+      if (listener == source)
+      {
+        // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
+        // Temporary fudge with SequenceListener.getVamsasSource()
+        continue;
+      }
+      if (listener instanceof StructureListener)
+      {
+        highlightStructure((StructureListener) listener, sequenceRef,
+                seqpos);
+      }
+
+    }
+  }
+
+  /**
    * Propagate mouseover of a single position in a structure
    * 
    * @param pdbResNum
    * Propagate mouseover of a single position in a structure
    * 
    * @param pdbResNum
@@ -946,7 +1050,7 @@ public class StructureSelectionManager
           int indexpos = sm.getSeqPos(atom.getPdbResNum());
           if (lastipos != indexpos || lastseq != sm.sequence)
           {
           int indexpos = sm.getSeqPos(atom.getPdbResNum());
           if (lastipos != indexpos || lastseq != sm.sequence)
           {
-            results.addResult(sm.sequence, indexpos, indexpos);
+            results.appendResult(sm.sequence, indexpos, indexpos);
             lastipos = indexpos;
             lastseq = sm.sequence;
             // construct highlighted sequence list
             lastipos = indexpos;
             lastseq = sm.sequence;
             // construct highlighted sequence list
@@ -1074,6 +1178,62 @@ public class StructureSelectionManager
     sl.highlightAtoms(atoms);
   }
 
     sl.highlightAtoms(atoms);
   }
 
+  public void highlightStructureRegionsFor(StructureListener sl,
+          SequenceI[] seqs, int... columns)
+  {
+    List<SequenceI> to_highlight = new ArrayList<SequenceI>();
+    for (SequenceI seq : seqs)
+    {
+      if (sl.isListeningFor(seq))
+      {
+        to_highlight.add(seq);
+      }
+    }
+    if (to_highlight.size() == 0)
+    {
+      return;
+    }
+    List<AtomSpec> atoms = new ArrayList<>();
+    for (SequenceI seq : to_highlight)
+    {
+      int atomNo;
+      for (StructureMapping sm : mappings)
+      {
+        if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
+                || (sm.sequence.getDatasetSequence() != null && sm.sequence
+                        .getDatasetSequence() == seq.getDatasetSequence()))
+        {
+
+          for (int i = 0; i < columns.length; i += 2)
+          {
+            ContiguousI positions = seq.findPositions(columns[i] + 1,
+                    columns[i + 1] + 1);
+            if (positions == null)
+            {
+              continue;
+            }
+            for (int index = positions.getBegin(); index <= positions
+                    .getEnd(); index++)
+            {
+
+              atomNo = sm.getAtomNum(index);
+
+              if (atomNo > 0)
+              {
+                atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
+                        sm.getPDBResNum(index), atomNo));
+              }
+            }
+          }
+        }
+      }
+      if (atoms.size() > 0)
+      {
+        sl.highlightAtoms(atoms);
+      }
+    }
+  }
+
   /**
    * true if a mouse over event from an external (ie Vamsas) source is being
    * handled
   /**
    * true if a mouse over event from an external (ie Vamsas) source is being
    * handled
@@ -1119,7 +1279,7 @@ public class StructureSelectionManager
      * 
      * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
      * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
      * 
      * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
      * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
-     * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
+     * jalview.bin.Console.outPrintln(pdbid+" "+mappings[j].getPdbId() +"
      * "+mappings[j].pdbfile);
      * 
      * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
      * "+mappings[j].pdbfile);
      * 
      * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
@@ -1216,7 +1376,7 @@ public class StructureSelectionManager
       boolean removed = seqmappings.remove(acf);
       if (removed && seqmappings.isEmpty())
       { // debug
       boolean removed = seqmappings.remove(acf);
       if (removed && seqmappings.isEmpty())
       { // debug
-        System.out.println("All mappings removed");
+        jalview.bin.Console.outPrintln("All mappings removed");
       }
     }
   }
       }
     }
   }
@@ -1452,4 +1612,44 @@ public class StructureSelectionManager
     return seqmappings;
   }
 
     return seqmappings;
   }
 
+  /**
+   * quick and dirty route to just highlight all structure positions for a range
+   * of columns
+   * 
+   * @param sequencesArray
+   * @param is
+   *          start-end columns on sequencesArray
+   * @param source
+   *          origin parent AlignmentPanel
+   */
+  public void highlightPositionsOnMany(SequenceI[] sequencesArray, int[] is,
+          Object source)
+  {
+    for (int i = 0; i < listeners.size(); i++)
+    {
+      Object listener = listeners.elementAt(i);
+      if (listener == source)
+      {
+        // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
+        // Temporary fudge with SequenceListener.getVamsasSource()
+        continue;
+      }
+      if (listener instanceof StructureListener)
+      {
+        highlightStructureRegionsFor((StructureListener) listener,
+                sequencesArray, is);
+      }
+    }
+  }
+
+  public Map<String, String> getPdbFileNameIdMap()
+  {
+    return pdbFileNameId;
+  }
+
+  public Map<String, String> getPdbIdFileNameMap()
+  {
+    return pdbIdFileName;
+  }
+
 }
 }