Clover icon

Coverage Report

  1. Project Clover database Fri Nov 15 2024 13:56:46 GMT
  2. Package jalview.structure

File StructureSelectionManager.java

 

Coverage histogram

../../img/srcFileCovDistChart6.png
36% of files have more coverage

Code metrics

236
454
64
1
1,729
1,183
217
0.48
7.09
64
3.39

Classes

Class Line # Actions
StructureSelectionManager 69 454 217
0.555702955.6%
 

Contributing tests

This file is covered by 223 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.structure;
22   
23    import java.io.PrintStream;
24    import java.util.ArrayList;
25    import java.util.Arrays;
26    import java.util.Collections;
27    import java.util.Enumeration;
28    import java.util.HashMap;
29    import java.util.IdentityHashMap;
30    import java.util.List;
31    import java.util.Locale;
32    import java.util.Map;
33    import java.util.Vector;
34   
35    import jalview.analysis.AlignSeq;
36    import jalview.api.StructureSelectionManagerProvider;
37    import jalview.bin.Cache;
38    import jalview.bin.Console;
39    import jalview.commands.CommandI;
40    import jalview.commands.EditCommand;
41    import jalview.commands.OrderCommand;
42    import jalview.datamodel.AlignedCodonFrame;
43    import jalview.datamodel.AlignmentAnnotation;
44    import jalview.datamodel.AlignmentI;
45    import jalview.datamodel.Annotation;
46    import jalview.datamodel.ContiguousI;
47    import jalview.datamodel.HiddenColumns;
48    import jalview.datamodel.PDBEntry;
49    import jalview.datamodel.SearchResults;
50    import jalview.datamodel.SearchResultsI;
51    import jalview.datamodel.SequenceI;
52    import jalview.ext.jmol.JmolParser;
53    import jalview.gui.IProgressIndicator;
54    import jalview.gui.Preferences;
55    import jalview.io.AppletFormatAdapter;
56    import jalview.io.DataSourceType;
57    import jalview.io.StructureFile;
58    import jalview.structure.StructureImportSettings.TFType;
59    import jalview.util.MappingUtils;
60    import jalview.util.MessageManager;
61    import jalview.util.Platform;
62    import jalview.ws.sifts.SiftsClient;
63    import jalview.ws.sifts.SiftsException;
64    import jalview.ws.sifts.SiftsSettings;
65    import mc_view.Atom;
66    import mc_view.PDBChain;
67    import mc_view.PDBfile;
68   
 
69    public class StructureSelectionManager
70    {
71    public final static String NEWLINE = System.lineSeparator();
72   
73    static IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> instances;
74   
75    private List<StructureMapping> mappings = new ArrayList<>();
76   
77    private boolean processSecondaryStructure = false;
78   
79    private boolean secStructServices = false;
80   
81    private boolean addTempFacAnnot = false;
82   
83    /*
84    * Set of any registered mappings between (dataset) sequences.
85    */
86    private List<AlignedCodonFrame> seqmappings = new ArrayList<>();
87   
88    private List<CommandListener> commandListeners = new ArrayList<>();
89   
90    private List<SelectionListener> sel_listeners = new ArrayList<>();
91   
92    /**
93    * @return true if will try to use external services for processing secondary
94    * structure
95    */
 
96  0 toggle public boolean isSecStructServices()
97    {
98  0 return secStructServices;
99    }
100   
101    /**
102    * control use of external services for processing secondary structure
103    *
104    * @param secStructServices
105    */
 
106  127 toggle public void setSecStructServices(boolean secStructServices)
107    {
108  127 this.secStructServices = secStructServices;
109    }
110   
111    /**
112    * flag controlling addition of any kind of structural annotation
113    *
114    * @return true if temperature factor annotation will be added
115    */
 
116  0 toggle public boolean isAddTempFacAnnot()
117    {
118  0 return addTempFacAnnot;
119    }
120   
121    /**
122    * set flag controlling addition of structural annotation
123    *
124    * @param addTempFacAnnot
125    */
 
126  129 toggle public void setAddTempFacAnnot(boolean addTempFacAnnot)
127    {
128  129 this.addTempFacAnnot = addTempFacAnnot;
129    }
130   
131    /**
132    *
133    * @return if true, the structure manager will attempt to add secondary
134    * structure lines for unannotated sequences
135    */
136   
 
137  0 toggle public boolean isProcessSecondaryStructure()
138    {
139  0 return processSecondaryStructure;
140    }
141   
142    /**
143    * Control whether structure manager will try to annotate mapped sequences
144    * with secondary structure from PDB data.
145    *
146    * @param enable
147    */
 
148  129 toggle public void setProcessSecondaryStructure(boolean enable)
149    {
150  129 processSecondaryStructure = enable;
151    }
152   
153    /**
154    * debug function - write all mappings to stdout
155    */
 
156  0 toggle public void reportMapping()
157    {
158  0 if (mappings.isEmpty())
159    {
160  0 jalview.bin.Console
161    .errPrintln("reportMapping: No PDB/Sequence mappings.");
162    }
163    else
164    {
165  0 jalview.bin.Console.errPrintln(
166    "reportMapping: There are " + mappings.size() + " mappings.");
167  0 int i = 0;
168  0 for (StructureMapping sm : mappings)
169    {
170  0 jalview.bin.Console
171    .errPrintln("mapping " + i++ + " : " + sm.pdbfile);
172    }
173    }
174    }
175   
176    /**
177    * map between the PDB IDs (or structure identifiers) used by Jalview and the
178    * absolute filenames for PDB data that corresponds to it
179    */
180    Map<String, String> pdbIdFileName = new HashMap<>();
181   
182    Map<String, String> pdbFileNameId = new HashMap<>();
183   
 
184  277 toggle public void registerPDBFile(String idForFile, String absoluteFile)
185    {
186  277 pdbIdFileName.put(idForFile, absoluteFile);
187  277 pdbFileNameId.put(absoluteFile, idForFile);
188    }
189   
 
190  254 toggle public String findIdForPDBFile(String idOrFile)
191    {
192  254 String id = pdbFileNameId.get(idOrFile);
193  254 return id;
194    }
195   
 
196  1 toggle public String findFileForPDBId(String idOrFile)
197    {
198  1 String id = pdbIdFileName.get(idOrFile);
199  1 return id;
200    }
201   
 
202  135 toggle public boolean isPDBFileRegistered(String idOrFile)
203    {
204  135 return pdbFileNameId.containsKey(idOrFile)
205    || pdbIdFileName.containsKey(idOrFile);
206    }
207   
208    private static StructureSelectionManager nullProvider = null;
209   
 
210  5163 toggle public static StructureSelectionManager getStructureSelectionManager(
211    StructureSelectionManagerProvider context)
212    {
213  5163 if (context == null)
214    {
215  516 if (nullProvider == null)
216    {
217  47 if (instances != null)
218    {
219  0 throw new Error(MessageManager.getString(
220    "error.implementation_error_structure_selection_manager_null"),
221    new NullPointerException(MessageManager
222    .getString("exception.ssm_context_is_null")));
223    }
224    else
225    {
226  47 nullProvider = new StructureSelectionManager();
227    }
228  47 return nullProvider;
229    }
230    }
231  5116 if (instances == null)
232    {
233  54 instances = new java.util.IdentityHashMap<>();
234    }
235  5116 StructureSelectionManager instance = instances.get(context);
236  5116 if (instance == null)
237    {
238  122 if (nullProvider != null)
239    {
240  115 instance = nullProvider;
241    }
242    else
243    {
244  7 instance = new StructureSelectionManager();
245    }
246  122 instances.put(context, instance);
247    }
248  5116 return instance;
249    }
250   
251    /**
252    * flag controlling whether SeqMappings are relayed from received sequence
253    * mouse over events to other sequences
254    */
255    boolean relaySeqMappings = true;
256   
257    /**
258    * Enable or disable relay of seqMapping events to other sequences. You might
259    * want to do this if there are many sequence mappings and the host computer
260    * is slow
261    *
262    * @param relay
263    */
 
264  0 toggle public void setRelaySeqMappings(boolean relay)
265    {
266  0 relaySeqMappings = relay;
267    }
268   
269    /**
270    * get the state of the relay seqMappings flag.
271    *
272    * @return true if sequence mouse overs are being relayed to other mapped
273    * sequences
274    */
 
275  0 toggle public boolean isRelaySeqMappingsEnabled()
276    {
277  0 return relaySeqMappings;
278    }
279   
280    Vector listeners = new Vector();
281   
282    /**
283    * register a listener for alignment sequence mouseover events
284    *
285    * @param svl
286    */
 
287  525 toggle public void addStructureViewerListener(Object svl)
288    {
289  525 if (!listeners.contains(svl))
290    {
291  523 listeners.addElement(svl);
292    }
293    }
294   
295    /**
296    * Returns the filename the PDB id is already mapped to if known, or null if
297    * it is not mapped
298    *
299    * @param pdbid
300    * @return
301    */
 
302  1 toggle public String alreadyMappedToFile(String pdbid)
303    {
304  1 for (StructureMapping sm : mappings)
305    {
306  1 if (sm.getPdbId().equalsIgnoreCase(pdbid))
307    {
308  0 return sm.pdbfile;
309    }
310    }
311  1 return null;
312    }
313   
314    /**
315    * Import structure data and register a structure mapping for broadcasting
316    * colouring, mouseovers and selection events (convenience wrapper).
317    *
318    * @param sequence
319    * - one or more sequences to be mapped to pdbFile
320    * @param targetChains
321    * - optional chain specification for mapping each sequence to pdb
322    * (may be nill, individual elements may be nill)
323    * @param pdbFile
324    * - structure data resource
325    * @param protocol
326    * - how to resolve data from resource
327    * @return null or the structure data parsed as a pdb file
328    */
 
329  45 toggle synchronized public StructureFile setMapping(SequenceI[] sequence,
330    String[] targetChains, String pdbFile, DataSourceType protocol,
331    IProgressIndicator progress)
332    {
333  45 return computeMapping(true, sequence, targetChains, pdbFile, protocol,
334    progress, null, null, true);
335    }
336   
337    /**
338    * Import a single structure file and register sequence structure mappings for
339    * broadcasting colouring, mouseovers and selection events (convenience
340    * wrapper).
341    *
342    * @param forStructureView
343    * when true, record the mapping for use in mouseOvers
344    * @param sequence
345    * - one or more sequences to be mapped to pdbFile
346    * @param targetChains
347    * - optional chain specification for mapping each sequence to pdb
348    * (may be nill, individual elements may be nill)
349    * @param pdbFile
350    * - structure data resource
351    * @param protocol
352    * - how to resolve data from resource
353    * @return null or the structure data parsed as a pdb file
354    */
 
355  3 toggle synchronized public StructureFile setMapping(boolean forStructureView,
356    SequenceI[] sequenceArray, String[] targetChainIds,
357    String pdbFile, DataSourceType sourceType, TFType tft,
358    String paeFilename)
359    {
360  3 return setMapping(forStructureView, sequenceArray, targetChainIds,
361    pdbFile, sourceType, tft, paeFilename, true);
362    }
363   
364    /**
365    * create sequence structure mappings between each sequence and the given
366    * pdbFile (retrieved via the given protocol). Either constructs a mapping
367    * using NW alignment or derives one from any available SIFTS mapping data.
368    *
369    * @param forStructureView
370    * when true, record the mapping for use in mouseOvers
371    *
372    * @param sequenceArray
373    * - one or more sequences to be mapped to pdbFile
374    * @param targetChainIds
375    * - optional chain specification for mapping each sequence to pdb
376    * (may be nill, individual elements may be nill) - JBPNote: JAL-2693
377    * - this should be List<List<String>>, empty lists indicate no
378    * predefined mappings
379    * @param pdbFile
380    * - structure data resource
381    * @param sourceType
382    * - how to resolve data from resource
383    * @param tft
384    * - specify how to interpret the temperature factor column in the
385    * atom data
386    * @param paeFilename
387    * - when not null, specifies a filename containing a matrix
388    * formatted in JSON using one of the known PAE formats
389    * @param doXferSettings
390    * - when true, transfer annotation to mapped sequences in
391    * sequenceArray
392    * @return null or the structure data parsed as a pdb file
393    */
 
394  58 toggle synchronized public StructureFile setMapping(boolean forStructureView,
395    SequenceI[] sequenceArray, String[] targetChainIds,
396    String pdbFile, DataSourceType sourceType, TFType tft,
397    String paeFilename, boolean doXferSettings)
398    {
399  58 return computeMapping(forStructureView, sequenceArray, targetChainIds,
400    pdbFile, sourceType, null, tft, paeFilename, doXferSettings);
401    }
402   
403    /**
404    * import / map chain using metadata from a PDBEntry object
405    * @param forStructureView
406    * @param sequenceArray
407    * @param pdbEntry
408    * @param targetChainIds
409    * @return
410    */
 
411  45 toggle synchronized public StructureFile setMapping(boolean forStructureView,
412    SequenceI[] sequenceArray, PDBEntry pdbEntry, String[] targetChainIds, IProgressIndicator progress)
413    {
414  45 return computeMapping(forStructureView, sequenceArray, targetChainIds,
415    pdbEntry.getFile(), pdbEntry.getProtocol(), progress, pdbEntry.getTempFacTypeTFType(), pdbEntry.getPAEFile(), true);
416    }
417    /**
418    * import / map chain using metadata from a PDBEntry object
419    * @param forStructureView
420    * @param sequenceArray
421    * @param pdbEntry
422    * @param targetChainIds
423    * @return
424    */
 
425  0 toggle synchronized public StructureFile setMapping(boolean forStructureView,
426    SequenceI[] sequenceArray, PDBEntry pdbEntry, String[] targetChainIds)
427    {
428  0 return computeMapping(forStructureView, sequenceArray, targetChainIds,
429    pdbEntry.getFile(), pdbEntry.getProtocol(), null, pdbEntry.getTempFacTypeTFType(), pdbEntry.getPAEFile(), true);
430    }
431   
432    /**
433    * create sequence structure mappings between each sequence and the given
434    * pdbFile (retrieved via the given protocol). Either constructs a mapping
435    * using NW alignment or derives one from any available SIFTS mapping data.
436    *
437    * @param forStructureView
438    * when true, record the mapping for use in mouseOvers
439    *
440    * @param sequenceArray
441    * - one or more sequences to be mapped to pdbFile
442    * @param targetChainIds
443    * - optional chain specification for mapping each sequence to pdb
444    * (may be nill, individual elements may be nill) - JBPNote: JAL-2693
445    * - this should be List<List<String>>, empty lists indicate no
446    * predefined mappings
447    * @param pdbFile
448    * - structure data resource
449    * @param sourceType
450    * - how to resolve data from resource
451    * @param IProgressIndicator
452    * reference to UI component that maintains a progress bar for the
453    * mapping operation
454    * @param tft
455    * - specify how to interpret the temperature factor column in the
456    * atom data
457    * @param paeFilename
458    * - when not null, specifies a filename containing a matrix
459    * formatted in JSON using one of the known PAE formats
460    * @param doXferSettings
461    * - when true, transfer annotation to mapped sequences in
462    * sequenceArray
463    * @return null or the structure data parsed as a pdb file
464    */
 
465  150 toggle synchronized public StructureFile computeMapping(boolean forStructureView,
466    SequenceI[] sequenceArray, String[] targetChainIds,
467    String pdbFile, DataSourceType sourceType,
468    IProgressIndicator progress, TFType tft, String paeFilename,
469    boolean doXferSettings)
470    {
471  150 long progressSessionId = System.currentTimeMillis() * 3;
472   
473    /**
474    * do we extract and transfer annotation from 3D data ?
475    */
476    // FIXME: possibly should just delete
477   
478  150 boolean parseSecStr = processSecondaryStructure
479    && !isStructureFileProcessed(pdbFile, sequenceArray);
480   
481  150 StructureFile pdb = null;
482  150 boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
483  150 try
484    {
485    // FIXME if sourceType is not null, we've lost data here
486  150 sourceType = AppletFormatAdapter.checkProtocol(pdbFile);
487  150 pdb = new JmolParser(false, pdbFile, sourceType);
488  150 if (paeFilename != null)
489    {
490  57 pdb.setPAEMatrix(paeFilename);
491    }
492  150 pdb.setTemperatureFactorType(tft);
493  150 pdb.addSettings(parseSecStr && processSecondaryStructure,
494    parseSecStr && addTempFacAnnot,
495    parseSecStr && secStructServices);
496    // save doXferSettings and reset after doParse()
497  150 boolean temp = pdb.getDoXferSettings();
498  150 pdb.setDoXferSettings(doXferSettings);
499  150 pdb.doParse();
500  150 pdb.setDoXferSettings(temp);
501  150 if (pdb.getId() != null && pdb.getId().trim().length() > 0
502    && DataSourceType.FILE == sourceType)
503    {
504  138 registerPDBFile(pdb.getId().trim(), pdbFile);
505    }
506    // if PDBId is unavailable then skip SIFTS mapping execution path
507    // TODO: JAL-3868 need to know if structure is actually from
508    // PDB (has valid PDB ID and has provenance suggesting it
509    // actually came from PDB)
510  150 boolean isProtein = false;
511  150 for (SequenceI s : sequenceArray)
512    {
513  150 if (s.isProtein())
514    {
515  150 isProtein = true;
516  150 break;
517    }
518    }
519  150 isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable()
520    && !pdb.getId().startsWith("AF-") && isProtein;
521   
522    } catch (Exception ex)
523    {
524  0 ex.printStackTrace();
525  0 return null;
526    }
527    /*
528    * sifts client - non null if SIFTS mappings are to be used
529    */
530  150 SiftsClient siftsClient = null;
531  150 try
532    {
533  150 if (isMapUsingSIFTs)
534    {
535  0 siftsClient = new SiftsClient(pdb);
536    }
537    } catch (SiftsException e)
538    {
539  0 isMapUsingSIFTs = false;
540  0 Console.error("SIFTS mapping failed", e);
541  0 Console.error("Falling back on Needleman & Wunsch alignment");
542  0 siftsClient = null;
543    }
544   
545  150 String targetChainId;
546  345 for (int s = 0; s < sequenceArray.length; s++)
547    {
548  195 boolean infChain = true;
549  195 final SequenceI seq = sequenceArray[s];
550  195 SequenceI ds = seq;
551  388 while (ds.getDatasetSequence() != null)
552    {
553  193 ds = ds.getDatasetSequence();
554    }
555   
556  195 if (targetChainIds != null && targetChainIds[s] != null)
557    {
558  40 infChain = false;
559  40 targetChainId = targetChainIds[s];
560    }
561  155 else if (seq.getName().indexOf("|") > -1)
562    {
563  59 targetChainId = seq.getName()
564    .substring(seq.getName().lastIndexOf("|") + 1);
565  59 if (targetChainId.length() > 1)
566    {
567  1 if (targetChainId.trim().length() == 0)
568    {
569  0 targetChainId = " ";
570    }
571    else
572    {
573    // not a valid chain identifier
574  1 targetChainId = "";
575    }
576    }
577    }
578    else
579    {
580  96 targetChainId = "";
581    }
582   
583    /*
584    * Attempt pairwise alignment of the sequence with each chain in the PDB,
585    * and remember the highest scoring chain
586    */
587  195 float max = -10;
588  195 AlignSeq maxAlignseq = null;
589  195 String maxChainId = " ";
590  195 PDBChain maxChain = null;
591  195 boolean first = true;
592  195 for (PDBChain chain : pdb.getChains())
593    {
594  247 if (targetChainId.length() > 0 && !targetChainId.equals(chain.id)
595    && !infChain)
596    {
597  16 continue; // don't try to map chains don't match.
598    }
599    // TODO: correctly determine sequence type for mixed na/peptide
600    // structures
601  231 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
602  231 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
603    type);
604    // equivalent to:
605    // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
606    // as.calcScoreMatrix();
607    // as.traceAlignment();
608   
609  231 if (first || as.maxscore > max
610    || (as.maxscore == max && chain.id.equals(targetChainId)))
611    {
612  203 first = false;
613  203 maxChain = chain;
614  203 max = as.maxscore;
615  203 maxAlignseq = as;
616  203 maxChainId = chain.id;
617    }
618    }
619  195 if (maxChain == null)
620    {
621  0 continue;
622    }
623   
624  195 if (sourceType == DataSourceType.PASTE)
625    {
626  16 pdbFile = "INLINE" + pdb.getId();
627    }
628   
629  195 List<StructureMapping> seqToStrucMapping = new ArrayList<>();
630  195 if (isMapUsingSIFTs && seq.isProtein())
631    {
632  0 if (progress != null)
633    {
634  0 progress.setProgressBar(
635    MessageManager
636    .getString("status.obtaining_mapping_with_sifts"),
637    progressSessionId);
638    }
639  0 jalview.datamodel.Mapping sqmpping = maxAlignseq
640    .getMappingFromS1(false);
641  0 if (targetChainId != null && !targetChainId.trim().isEmpty())
642    {
643  0 StructureMapping siftsMapping;
644  0 try
645    {
646  0 siftsMapping = getStructureMapping(seq, pdbFile, targetChainId,
647    pdb, maxChain, sqmpping, maxAlignseq, siftsClient);
648  0 seqToStrucMapping.add(siftsMapping);
649  0 maxChain.makeExactMapping(siftsMapping, seq);
650  0 maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS",
651    pdb.getId().toLowerCase(Locale.ROOT));
652  0 maxChain.transferResidueAnnotation(siftsMapping, null);
653  0 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
654   
655    } catch (SiftsException e)
656    {
657    // fall back to NW alignment
658  0 Console.error(e.getMessage());
659  0 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
660    targetChainId, maxChain, pdb, maxAlignseq);
661  0 seqToStrucMapping.add(nwMapping);
662  0 maxChain.makeExactMapping(maxAlignseq, seq);
663  0 maxChain.transferRESNUMFeatures(seq, "IEA:Jalview",
664    pdb.getId().toLowerCase(Locale.ROOT)); // FIXME: is
665    // this
666    // "IEA:Jalview" ?
667  0 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
668  0 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
669    }
670    }
671    else
672    {
673  0 List<StructureMapping> foundSiftsMappings = new ArrayList<>();
674  0 for (PDBChain chain : pdb.getChains())
675    {
676  0 StructureMapping siftsMapping = null;
677  0 try
678    {
679  0 siftsMapping = getStructureMapping(seq, pdbFile, chain.id,
680    pdb, chain, sqmpping, maxAlignseq, siftsClient);
681  0 foundSiftsMappings.add(siftsMapping);
682  0 chain.makeExactMapping(siftsMapping, seq);
683  0 chain.transferRESNUMFeatures(seq, "IEA: SIFTS",
684    pdb.getId().toLowerCase(Locale.ROOT));// FIXME: is this
685    // "IEA:SIFTS" ?
686  0 chain.transferResidueAnnotation(siftsMapping, null);
687    } catch (SiftsException e)
688    {
689  0 jalview.bin.Console.errPrintln(e.getMessage());
690    } catch (Exception e)
691    {
692  0 jalview.bin.Console.errPrintln(
693    "Unexpected exception during SIFTS mapping - falling back to NW for this sequence/structure pair");
694  0 jalview.bin.Console.errPrintln(e.getMessage());
695    }
696    }
697  0 if (!foundSiftsMappings.isEmpty())
698    {
699  0 seqToStrucMapping.addAll(foundSiftsMappings);
700  0 ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
701    }
702    else
703    {
704  0 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
705    maxChainId, maxChain, pdb, maxAlignseq);
706  0 seqToStrucMapping.add(nwMapping);
707  0 maxChain.transferRESNUMFeatures(seq, null,
708    pdb.getId().toLowerCase(Locale.ROOT)); // FIXME: is this
709    // "IEA:Jalview" ?
710  0 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
711  0 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
712    }
713    }
714    }
715    else
716    {
717  195 if (progress != null)
718    {
719  0 progress.setProgressBar(
720    MessageManager.getString(
721    "status.obtaining_mapping_with_nw_alignment"),
722    progressSessionId);
723    }
724  195 StructureMapping nwMapping = getNWMappings(seq, pdbFile, maxChainId,
725    maxChain, pdb, maxAlignseq);
726  195 seqToStrucMapping.add(nwMapping);
727  195 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
728    }
729  195 if (forStructureView)
730    {
731  138 for (StructureMapping sm : seqToStrucMapping)
732    {
733  138 addStructureMapping(sm); // not addAll!
734    }
735    }
736  195 if (progress != null)
737    {
738  0 progress.setProgressBar(null, progressSessionId);
739    }
740    }
741  150 return pdb;
742    }
743   
744    /**
745    * check if we need to extract secondary structure from given pdbFile and
746    * transfer to sequences
747    *
748    * @param pdbFile
749    * @param sequenceArray
750    * @return
751    */
 
752  135 toggle private boolean isStructureFileProcessed(String pdbFile,
753    SequenceI[] sequenceArray)
754    {
755  135 boolean processed = false;
756  135 if (isPDBFileRegistered(pdbFile))
757    {
758  84 for (SequenceI sq : sequenceArray)
759    {
760  125 SequenceI ds = sq;
761  250 while (ds.getDatasetSequence() != null)
762    {
763  125 ds = ds.getDatasetSequence();
764    }
765  125 ;
766  125 if (ds.getAnnotation() != null)
767    {
768  103 for (AlignmentAnnotation ala : ds.getAnnotation())
769    {
770    // false if any annotation present from this structure
771    // JBPNote this fails for jmol/chimera view because the *file* is
772    // passed, not the structure data ID -
773  254 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
774    {
775  0 processed = true;
776    }
777    }
778    }
779    }
780    }
781  135 return processed;
782    }
783   
 
784  145 toggle public void addStructureMapping(StructureMapping sm)
785    {
786  145 if (!mappings.contains(sm))
787    {
788  78 mappings.add(sm);
789    }
790    }
791   
792    /**
793    * retrieve a mapping for seq from SIFTs using associated DBRefEntry for
794    * uniprot or PDB
795    *
796    * @param seq
797    * @param pdbFile
798    * @param targetChainId
799    * @param pdb
800    * @param maxChain
801    * @param sqmpping
802    * @param maxAlignseq
803    * @param siftsClient
804    * client for retrieval of SIFTS mappings for this structure
805    * @return
806    * @throws SiftsException
807    */
 
808  0 toggle private StructureMapping getStructureMapping(SequenceI seq,
809    String pdbFile, String targetChainId, StructureFile pdb,
810    PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
811    AlignSeq maxAlignseq, SiftsClient siftsClient)
812    throws SiftsException
813    {
814  0 StructureMapping curChainMapping = siftsClient
815    .getSiftsStructureMapping(seq, pdbFile, targetChainId);
816  0 try
817    {
818  0 PDBChain chain = pdb.findChain(targetChainId);
819  0 if (chain != null)
820    {
821  0 chain.transferResidueAnnotation(curChainMapping, null);
822    }
823    } catch (Exception e)
824    {
825  0 e.printStackTrace();
826    }
827  0 return curChainMapping;
828    }
829   
 
830  195 toggle private StructureMapping getNWMappings(SequenceI seq, String pdbFile,
831    String maxChainId, PDBChain maxChain, StructureFile pdb,
832    AlignSeq maxAlignseq)
833    {
834  195 final StringBuilder mappingDetails = new StringBuilder(128);
835  195 mappingDetails.append(NEWLINE)
836    .append("Sequence \u27f7 Structure mapping details");
837  195 mappingDetails.append(NEWLINE);
838  195 mappingDetails
839    .append("Method: inferred with Needleman & Wunsch alignment");
840  195 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
841    .append(NEWLINE).append("Sequence = ")
842    .append(maxChain.sequence.getSequenceAsString());
843  195 mappingDetails.append(NEWLINE).append("No of residues = ")
844    .append(maxChain.residues.size()).append(NEWLINE)
845    .append(NEWLINE);
846  195 PrintStream ps = new PrintStream(System.out)
847    {
 
848  195 toggle @Override
849    public void print(String x)
850    {
851  195 mappingDetails.append(x);
852    }
853   
 
854  0 toggle @Override
855    public void println()
856    {
857  0 mappingDetails.append(NEWLINE);
858    }
859    };
860   
861  195 maxAlignseq.printAlignment(ps);
862   
863  195 mappingDetails.append(NEWLINE).append("PDB start/end ");
864  195 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
865    .append(" ");
866  195 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
867  195 mappingDetails.append(NEWLINE).append("SEQ start/end ");
868  195 mappingDetails
869    .append(String
870    .valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
871    .append(" ");
872  195 mappingDetails.append(
873    String.valueOf(maxAlignseq.seq1end + (seq.getStart() - 1)));
874  195 mappingDetails.append(NEWLINE);
875  195 maxChain.makeExactMapping(maxAlignseq, seq);
876  195 jalview.datamodel.Mapping sqmpping = maxAlignseq
877    .getMappingFromS1(false);
878  195 maxChain.transferRESNUMFeatures(seq, null,
879    pdb.getId().toLowerCase(Locale.ROOT));
880   
881  195 HashMap<Integer, int[]> mapping = new HashMap<>();
882  195 int resNum = -10000;
883  195 int index = 0;
884  195 char insCode = ' ';
885   
886  195 do
887    {
888  21404 Atom tmp = maxChain.atoms.elementAt(index);
889  21404 if ((resNum != tmp.resNumber || insCode != tmp.insCode)
890    && tmp.alignmentMapping != -1)
891    {
892  21354 resNum = tmp.resNumber;
893  21354 insCode = tmp.insCode;
894  21354 if (tmp.alignmentMapping >= -1)
895    {
896  21354 mapping.put(tmp.alignmentMapping + 1,
897    new int[]
898    { tmp.resNumber, tmp.atomIndex });
899    }
900    }
901   
902  21404 index++;
903  21404 } while (index < maxChain.atoms.size());
904   
905  195 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
906    pdb.getId(), maxChainId, mapping, mappingDetails.toString());
907  195 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
908  195 return nwMapping;
909    }
910   
 
911  529 toggle public void removeStructureViewerListener(Object svl, String[] pdbfiles)
912    {
913  529 listeners.removeElement(svl);
914  529 if (svl instanceof SequenceListener)
915    {
916  1328 for (int i = 0; i < listeners.size(); i++)
917    {
918  822 if (listeners.elementAt(i) instanceof StructureListener)
919    {
920  40 ((StructureListener) listeners.elementAt(i))
921    .releaseReferences(svl);
922    }
923    }
924    }
925   
926  529 if (pdbfiles == null)
927    {
928  506 return;
929    }
930   
931    /*
932    * Remove mappings to the closed listener's PDB files, but first check if
933    * another listener is still interested
934    */
935  23 List<String> pdbs = new ArrayList<>(Arrays.asList(pdbfiles));
936   
937  23 StructureListener sl;
938  76 for (int i = 0; i < listeners.size(); i++)
939    {
940  53 if (listeners.elementAt(i) instanceof StructureListener)
941    {
942  6 sl = (StructureListener) listeners.elementAt(i);
943  6 for (String pdbfile : sl.getStructureFiles())
944    {
945  7 pdbs.remove(pdbfile);
946    }
947    }
948    }
949   
950    /*
951    * Rebuild the mappings set, retaining only those which are for 'other' PDB
952    * files
953    */
954  23 if (pdbs.size() > 0)
955    {
956  22 List<StructureMapping> tmp = new ArrayList<>();
957  22 for (StructureMapping sm : mappings)
958    {
959  37 if (!pdbs.contains(sm.pdbfile))
960    {
961  7 tmp.add(sm);
962    }
963    }
964   
965  22 mappings = tmp;
966    }
967    }
968   
969    /**
970    * hack to highlight a range of positions at once on any structure views
971    *
972    * @param sequenceRef
973    * @param is
974    * - series of int start-end ranges as positions on sequenceRef
975    * @param i
976    * @param object
977    */
 
978  0 toggle public void highlightPositionsOn(SequenceI sequenceRef, int[][] is,
979    Object source)
980    {
981  0 boolean hasSequenceListeners = handlingVamsasMo
982    || !seqmappings.isEmpty();
983  0 SearchResultsI results = null;
984  0 ArrayList<Integer> listOfPositions = new ArrayList<Integer>();
985  0 for (int[] s_e : is)
986    {
987  0 for (int p = s_e[0]; p <= s_e[1]; listOfPositions.add(p++))
988  0 ;
989    }
990  0 int seqpos[] = new int[listOfPositions.size()];
991  0 int i = 0;
992  0 for (Integer p : listOfPositions)
993    {
994  0 seqpos[i++] = p;
995    }
996   
997  0 for (i = 0; i < listeners.size(); i++)
998    {
999  0 Object listener = listeners.elementAt(i);
1000  0 if (listener == source)
1001    {
1002    // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
1003    // Temporary fudge with SequenceListener.getVamsasSource()
1004  0 continue;
1005    }
1006  0 if (listener instanceof StructureListener)
1007    {
1008  0 highlightStructure((StructureListener) listener, sequenceRef,
1009    seqpos);
1010    }
1011   
1012    }
1013    }
1014   
1015    /**
1016    * Propagate mouseover of a single position in a structure
1017    *
1018    * @param pdbResNum
1019    * @param chain
1020    * @param pdbfile
1021    * @return
1022    */
 
1023  1 toggle public String mouseOverStructure(int pdbResNum, String chain,
1024    String pdbfile)
1025    {
1026  1 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
1027  1 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
1028  1 return mouseOverStructure(atoms);
1029    }
1030   
1031    /**
1032    * Propagate mouseover or selection of multiple positions in a structure
1033    *
1034    * @param atoms
1035    */
 
1036  1 toggle public String mouseOverStructure(List<AtomSpec> atoms)
1037    {
1038  1 if (listeners == null)
1039    {
1040    // old or prematurely sent event
1041  0 return null;
1042    }
1043  1 boolean hasSequenceListener = false;
1044  3 for (int i = 0; i < listeners.size(); i++)
1045    {
1046  2 if (listeners.elementAt(i) instanceof SequenceListener)
1047    {
1048  1 hasSequenceListener = true;
1049    }
1050    }
1051  1 if (!hasSequenceListener)
1052    {
1053  0 return null;
1054    }
1055   
1056  1 SearchResultsI results = findAlignmentPositionsForStructurePositions(
1057    atoms);
1058  1 String result = null;
1059  1 for (Object li : listeners)
1060    {
1061  2 if (li instanceof SequenceListener)
1062    {
1063  1 String s = ((SequenceListener) li).highlightSequence(results);
1064  1 if (s != null)
1065    {
1066  0 result = s;
1067    }
1068    }
1069    }
1070  1 return result;
1071    }
1072   
1073    /**
1074    * Constructs a SearchResults object holding regions (if any) in the Jalview
1075    * alignment which have a mapping to the structure viewer positions in the
1076    * supplied list
1077    *
1078    * @param atoms
1079    * @return
1080    */
 
1081  1 toggle public SearchResultsI findAlignmentPositionsForStructurePositions(
1082    List<AtomSpec> atoms)
1083    {
1084  1 SearchResultsI results = new SearchResults();
1085  1 for (AtomSpec atom : atoms)
1086    {
1087  1 SequenceI lastseq = null;
1088  1 int lastipos = -1;
1089  1 for (StructureMapping sm : mappings)
1090    {
1091  2 if (sm.pdbfile.equals(atom.getPdbFile())
1092    && sm.pdbchain.equals(atom.getChain()))
1093    {
1094  1 int indexpos = sm.getSeqPos(atom.getPdbResNum());
1095  1 if (lastipos != indexpos || lastseq != sm.sequence)
1096    {
1097  1 results.appendResult(sm.sequence, indexpos, indexpos);
1098  1 lastipos = indexpos;
1099  1 lastseq = sm.sequence;
1100    // construct highlighted sequence list
1101  1 for (AlignedCodonFrame acf : seqmappings)
1102    {
1103  0 acf.markMappedRegion(sm.sequence, indexpos, results);
1104    }
1105    }
1106    }
1107    }
1108    }
1109  1 return results;
1110    }
1111   
1112    /**
1113    * highlight regions associated with a position (indexpos) in seq
1114    *
1115    * @param seq
1116    * the sequence that the mouse over occurred on
1117    * @param indexpos
1118    * the absolute position being mouseovered in seq (0 to seq.length())
1119    * @param seqPos
1120    * the sequence position (if -1, seq.findPosition is called to
1121    * resolve the residue number)
1122    */
 
1123  0 toggle public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
1124    VamsasSource source)
1125    {
1126  0 boolean hasSequenceListeners = handlingVamsasMo
1127    || !seqmappings.isEmpty();
1128  0 SearchResultsI results = null;
1129  0 if (seqPos == -1)
1130    {
1131  0 seqPos = seq.findPosition(indexpos);
1132    }
1133  0 for (int i = 0; i < listeners.size(); i++)
1134    {
1135  0 Object listener = listeners.elementAt(i);
1136  0 if (listener == source)
1137    {
1138    // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
1139    // Temporary fudge with SequenceListener.getVamsasSource()
1140  0 continue;
1141    }
1142  0 if (listener instanceof StructureListener)
1143    {
1144  0 highlightStructure((StructureListener) listener, seq, seqPos);
1145    }
1146    else
1147    {
1148  0 if (listener instanceof SequenceListener)
1149    {
1150  0 final SequenceListener seqListener = (SequenceListener) listener;
1151  0 if (hasSequenceListeners
1152    && seqListener.getVamsasSource() != source)
1153    {
1154  0 if (relaySeqMappings)
1155    {
1156  0 if (results == null)
1157    {
1158  0 results = MappingUtils.buildSearchResults(seq, seqPos,
1159    seqmappings);
1160    }
1161  0 if (handlingVamsasMo)
1162    {
1163  0 results.addResult(seq, seqPos, seqPos);
1164   
1165    }
1166  0 if (!results.isEmpty())
1167    {
1168  0 seqListener.highlightSequence(results);
1169    }
1170    }
1171    }
1172    }
1173  0 else if (listener instanceof VamsasListener && !handlingVamsasMo)
1174    {
1175  0 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
1176    source);
1177    }
1178  0 else if (listener instanceof SecondaryStructureListener)
1179    {
1180  0 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
1181    indexpos, seqPos);
1182    }
1183    }
1184    }
1185    }
1186   
1187    /**
1188    * Send suitable messages to a StructureListener to highlight atoms
1189    * corresponding to the given sequence position(s)
1190    *
1191    * @param sl
1192    * @param seq
1193    * @param positions
1194    */
 
1195  0 toggle public void highlightStructure(StructureListener sl, SequenceI seq,
1196    int... positions)
1197    {
1198  0 if (!sl.isListeningFor(seq))
1199    {
1200  0 return;
1201    }
1202  0 int atomNo;
1203  0 List<AtomSpec> atoms = new ArrayList<>();
1204  0 for (StructureMapping sm : mappings)
1205    {
1206  0 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
1207    || (sm.sequence.getDatasetSequence() != null && sm.sequence
1208    .getDatasetSequence() == seq.getDatasetSequence()))
1209    {
1210  0 for (int index : positions)
1211    {
1212  0 atomNo = sm.getAtomNum(index);
1213   
1214  0 if (atomNo > 0)
1215    {
1216  0 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
1217    sm.getPDBResNum(index), atomNo));
1218    }
1219    }
1220    }
1221    }
1222  0 sl.highlightAtoms(atoms);
1223    }
1224   
 
1225  0 toggle public void highlightStructureRegionsFor(StructureListener sl,
1226    SequenceI[] seqs, int... columns)
1227    {
1228  0 List<SequenceI> to_highlight = new ArrayList<SequenceI>();
1229  0 for (SequenceI seq : seqs)
1230    {
1231  0 if (sl.isListeningFor(seq))
1232    {
1233  0 to_highlight.add(seq);
1234    }
1235    }
1236  0 if (to_highlight.size() == 0)
1237    {
1238  0 return;
1239    }
1240  0 List<AtomSpec> atoms = new ArrayList<>();
1241  0 for (SequenceI seq : to_highlight)
1242    {
1243  0 int atomNo;
1244  0 for (StructureMapping sm : mappings)
1245    {
1246  0 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
1247    || (sm.sequence.getDatasetSequence() != null && sm.sequence
1248    .getDatasetSequence() == seq.getDatasetSequence()))
1249    {
1250   
1251  0 for (int i = 0; i < columns.length; i += 2)
1252    {
1253  0 ContiguousI positions = seq.findPositions(columns[i] + 1,
1254    columns[i + 1] + 1);
1255  0 if (positions == null)
1256    {
1257  0 continue;
1258    }
1259  0 for (int index = positions.getBegin(); index <= positions
1260    .getEnd(); index++)
1261    {
1262   
1263  0 atomNo = sm.getAtomNum(index);
1264   
1265  0 if (atomNo > 0)
1266    {
1267  0 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
1268    sm.getPDBResNum(index), atomNo));
1269    }
1270    }
1271    }
1272    }
1273    }
1274  0 if (atoms.size() > 0)
1275    {
1276  0 sl.highlightAtoms(atoms);
1277    }
1278    }
1279    }
1280   
1281    /**
1282    * true if a mouse over event from an external (ie Vamsas) source is being
1283    * handled
1284    */
1285    boolean handlingVamsasMo = false;
1286   
1287    long lastmsg = 0;
1288   
1289    /**
1290    * as mouseOverSequence but only route event to SequenceListeners
1291    *
1292    * @param sequenceI
1293    * @param position
1294    * in an alignment sequence
1295    */
 
1296  0 toggle public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
1297    VamsasSource source)
1298    {
1299  0 handlingVamsasMo = true;
1300  0 long msg = sequenceI.hashCode() * (1 + position);
1301  0 if (lastmsg != msg)
1302    {
1303  0 lastmsg = msg;
1304  0 mouseOverSequence(sequenceI, position, -1, source);
1305    }
1306  0 handlingVamsasMo = false;
1307    }
1308   
 
1309  0 toggle public Annotation[] colourSequenceFromStructure(SequenceI seq,
1310    String pdbid)
1311    {
1312  0 return null;
1313    // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
1314    // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
1315    /*
1316    * Annotation [] annotations = new Annotation[seq.getLength()];
1317    *
1318    * StructureListener sl; int atomNo = 0; for (int i = 0; i <
1319    * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
1320    * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
1321    *
1322    * for (int j = 0; j < mappings.length; j++) {
1323    *
1324    * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
1325    * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
1326    * jalview.bin.Console.outPrintln(pdbid+" "+mappings[j].getPdbId() +"
1327    * "+mappings[j].pdbfile);
1328    *
1329    * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
1330    * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
1331    *
1332    * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
1333    * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
1334    * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
1335    * mappings[j].pdbfile); }
1336    *
1337    * annotations[index] = new Annotation("X",null,' ',0,col); } return
1338    * annotations; } } } }
1339    *
1340    * return annotations;
1341    */
1342    }
1343   
 
1344  0 toggle public void structureSelectionChanged()
1345    {
1346    }
1347   
 
1348  0 toggle public void sequenceSelectionChanged()
1349    {
1350    }
1351   
 
1352  2750 toggle public void sequenceColoursChanged(Object source)
1353    {
1354  2750 StructureListener sl;
1355  12697 for (int i = 0; i < listeners.size(); i++)
1356    {
1357  9947 if (listeners.elementAt(i) instanceof StructureListener)
1358    {
1359  878 sl = (StructureListener) listeners.elementAt(i);
1360  878 sl.updateColours(source);
1361    }
1362    }
1363    }
1364   
 
1365  636 toggle public StructureMapping[] getMapping(String pdbfile)
1366    {
1367  636 List<StructureMapping> tmp = new ArrayList<>();
1368  635 for (StructureMapping sm : mappings)
1369    {
1370  664 if (sm.pdbfile.equals(pdbfile))
1371    {
1372  457 tmp.add(sm);
1373    }
1374    }
1375  636 return tmp.toArray(new StructureMapping[tmp.size()]);
1376    }
1377   
1378    /**
1379    * Returns a readable description of all mappings for the given pdbfile to any
1380    * of the given sequences
1381    *
1382    * @param pdbfile
1383    * @param seqs
1384    * @return
1385    */
 
1386  0 toggle public String printMappings(String pdbfile, List<SequenceI> seqs)
1387    {
1388  0 if (pdbfile == null || seqs == null || seqs.isEmpty())
1389    {
1390  0 return "";
1391    }
1392   
1393  0 StringBuilder sb = new StringBuilder(64);
1394  0 for (StructureMapping sm : mappings)
1395    {
1396  0 if (Platform.pathEquals(sm.pdbfile, pdbfile)
1397    && seqs.contains(sm.sequence))
1398    {
1399  0 sb.append(sm.mappingDetails);
1400  0 sb.append(NEWLINE);
1401    // separator makes it easier to read multiple mappings
1402  0 sb.append("=====================");
1403  0 sb.append(NEWLINE);
1404    }
1405    }
1406  0 sb.append(NEWLINE);
1407   
1408  0 return sb.toString();
1409    }
1410   
1411    /**
1412    * Remove the given mapping
1413    *
1414    * @param acf
1415    */
 
1416  27 toggle public void deregisterMapping(AlignedCodonFrame acf)
1417    {
1418  27 if (acf != null)
1419    {
1420  27 boolean removed = seqmappings.remove(acf);
1421  27 if (removed && seqmappings.isEmpty())
1422    { // debug
1423  2 jalview.bin.Console.outPrintln("All mappings removed");
1424    }
1425    }
1426    }
1427   
1428    /**
1429    * Add each of the given codonFrames to the stored set, if not aready present.
1430    *
1431    * @param mappings
1432    */
 
1433  554 toggle public void registerMappings(List<AlignedCodonFrame> mappings)
1434    {
1435  554 if (mappings != null)
1436    {
1437  554 for (AlignedCodonFrame acf : mappings)
1438    {
1439  152 registerMapping(acf);
1440    }
1441    }
1442    }
1443   
1444    /**
1445    * Add the given mapping to the stored set, unless already stored.
1446    */
 
1447  161 toggle public void registerMapping(AlignedCodonFrame acf)
1448    {
1449  161 if (acf != null)
1450    {
1451  161 if (!seqmappings.contains(acf))
1452    {
1453  38 seqmappings.add(acf);
1454    }
1455    }
1456    }
1457   
1458    /**
1459    * Resets this object to its initial state by removing all registered
1460    * listeners, codon mappings, PDB file mappings
1461    */
 
1462  237 toggle public void resetAll()
1463    {
1464  237 if (mappings != null)
1465    {
1466  237 mappings.clear();
1467    }
1468  237 if (seqmappings != null)
1469    {
1470  237 seqmappings.clear();
1471    }
1472  237 if (sel_listeners != null)
1473    {
1474  237 sel_listeners.clear();
1475    }
1476  237 if (listeners != null)
1477    {
1478  237 listeners.clear();
1479    }
1480  237 if (commandListeners != null)
1481    {
1482  237 commandListeners.clear();
1483    }
1484  237 if (view_listeners != null)
1485    {
1486  237 view_listeners.clear();
1487    }
1488  237 if (pdbFileNameId != null)
1489    {
1490  237 pdbFileNameId.clear();
1491    }
1492  237 if (pdbIdFileName != null)
1493    {
1494  237 pdbIdFileName.clear();
1495    }
1496    }
1497   
 
1498  478 toggle public void addSelectionListener(SelectionListener selecter)
1499    {
1500  478 if (!sel_listeners.contains(selecter))
1501    {
1502  478 sel_listeners.add(selecter);
1503    }
1504    }
1505   
 
1506  506 toggle public void removeSelectionListener(SelectionListener toremove)
1507    {
1508  506 if (sel_listeners.contains(toremove))
1509    {
1510  253 sel_listeners.remove(toremove);
1511    }
1512    }
1513   
 
1514  23 toggle public synchronized void sendSelection(
1515    jalview.datamodel.SequenceGroup selection,
1516    jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
1517    SelectionSource source)
1518    {
1519  23 for (SelectionListener slis : sel_listeners)
1520    {
1521  104 if (slis != source)
1522    {
1523  104 slis.selection(selection, colsel, hidden, source);
1524    }
1525    }
1526    }
1527   
1528    Vector<AlignmentViewPanelListener> view_listeners = new Vector<>();
1529   
 
1530  0 toggle public synchronized void sendViewPosition(
1531    jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1532    int startSeq, int endSeq)
1533    {
1534   
1535  0 if (view_listeners != null && view_listeners.size() > 0)
1536    {
1537  0 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1538    .elements();
1539  0 while (listeners.hasMoreElements())
1540    {
1541  0 AlignmentViewPanelListener slis = listeners.nextElement();
1542  0 if (slis != source)
1543    {
1544  0 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1545    }
1546  0 ;
1547    }
1548    }
1549    }
1550   
1551    /**
1552    * release all references associated with this manager provider
1553    *
1554    * @param jalviewLite
1555    */
 
1556  0 toggle public static void release(StructureSelectionManagerProvider jalviewLite)
1557    {
1558    // synchronized (instances)
1559    {
1560  0 if (instances == null)
1561    {
1562  0 return;
1563    }
1564  0 StructureSelectionManager mnger = (instances.get(jalviewLite));
1565  0 if (mnger != null)
1566    {
1567  0 instances.remove(jalviewLite);
1568  0 try
1569    {
1570    /* bsoares 2019-03-20 finalize deprecated, no apparent external
1571    * resources to close
1572    */
1573    // mnger.finalize();
1574    } catch (Throwable x)
1575    {
1576    }
1577    }
1578    }
1579    }
1580   
 
1581  359 toggle public void registerPDBEntry(PDBEntry pdbentry)
1582    {
1583  359 if (pdbentry.getFile() != null
1584    && pdbentry.getFile().trim().length() > 0)
1585    {
1586  139 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1587    }
1588    }
1589   
 
1590  6 toggle public void addCommandListener(CommandListener cl)
1591    {
1592  6 if (!commandListeners.contains(cl))
1593    {
1594  6 commandListeners.add(cl);
1595    }
1596    }
1597   
 
1598  0 toggle public boolean hasCommandListener(CommandListener cl)
1599    {
1600  0 return this.commandListeners.contains(cl);
1601    }
1602   
 
1603  253 toggle public boolean removeCommandListener(CommandListener l)
1604    {
1605  253 return commandListeners.remove(l);
1606    }
1607   
1608    /**
1609    * Forward a command to any command listeners (except for the command's
1610    * source).
1611    *
1612    * @param command
1613    * the command to be broadcast (in its form after being performed)
1614    * @param undo
1615    * if true, the command was being 'undone'
1616    * @param source
1617    */
 
1618  1 toggle public void commandPerformed(CommandI command, boolean undo,
1619    VamsasSource source)
1620    {
1621  1 for (CommandListener listener : commandListeners)
1622    {
1623  0 listener.mirrorCommand(command, undo, this, source);
1624    }
1625    }
1626   
1627    /**
1628    * Returns a new CommandI representing the given command as mapped to the
1629    * given sequences. If no mapping could be made, or the command is not of a
1630    * mappable kind, returns null.
1631    *
1632    * @param command
1633    * @param undo
1634    * @param mapTo
1635    * @param gapChar
1636    * @return
1637    */
 
1638  0 toggle public CommandI mapCommand(CommandI command, boolean undo,
1639    final AlignmentI mapTo, char gapChar)
1640    {
1641  0 if (command instanceof EditCommand)
1642    {
1643  0 return MappingUtils.mapEditCommand((EditCommand) command, undo, mapTo,
1644    gapChar, seqmappings);
1645    }
1646  0 else if (command instanceof OrderCommand)
1647    {
1648  0 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1649    mapTo, seqmappings);
1650    }
1651  0 return null;
1652    }
1653   
 
1654  15 toggle public List<AlignedCodonFrame> getSequenceMappings()
1655    {
1656  15 return seqmappings;
1657    }
1658   
1659    /**
1660    * quick and dirty route to just highlight all structure positions for a range
1661    * of columns
1662    *
1663    * @param sequencesArray
1664    * @param is
1665    * start-end columns on sequencesArray
1666    * @param source
1667    * origin parent AlignmentPanel
1668    */
 
1669  8 toggle public void highlightPositionsOnMany(SequenceI[] sequencesArray, int[] is,
1670    Object source)
1671    {
1672  16 for (int i = 0; i < listeners.size(); i++)
1673    {
1674  8 Object listener = listeners.elementAt(i);
1675  8 if (listener == source)
1676    {
1677    // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
1678    // Temporary fudge with SequenceListener.getVamsasSource()
1679  0 continue;
1680    }
1681  8 if (listener instanceof StructureListener)
1682    {
1683  0 highlightStructureRegionsFor((StructureListener) listener,
1684    sequencesArray, is);
1685    }
1686    }
1687    }
1688   
 
1689  0 toggle public Map<String, String> getPdbFileNameIdMap()
1690    {
1691  0 return pdbFileNameId;
1692    }
1693   
 
1694  0 toggle public Map<String, String> getPdbIdFileNameMap()
1695    {
1696  0 return pdbIdFileName;
1697    }
1698   
 
1699  127 toggle public static void doConfigureStructurePrefs(
1700    StructureSelectionManager ssm)
1701    {
1702  127 doConfigureStructurePrefs(ssm,
1703    Cache.getDefault(Preferences.ADD_SS_ANN, true),
1704    Cache.getDefault(Preferences.ADD_TEMPFACT_ANN, true),
1705    Cache.getDefault(Preferences.STRUCT_FROM_PDB, true),
1706    Cache.getDefault(Preferences.USE_RNAVIEW, false));
1707    }
1708   
 
1709  127 toggle public static void doConfigureStructurePrefs(
1710    StructureSelectionManager ssm, boolean add_ss_ann,
1711    boolean add_tempfact_ann, boolean struct_from_pdb,
1712    boolean use_rnaview)
1713    {
1714  127 if (add_ss_ann)
1715    {
1716  127 ssm.setAddTempFacAnnot(add_tempfact_ann);
1717  127 ssm.setProcessSecondaryStructure(struct_from_pdb);
1718    // JAL-3915 - RNAView is no longer an option so this has no effect
1719  127 ssm.setSecStructServices(use_rnaview);
1720    }
1721    else
1722    {
1723  0 ssm.setAddTempFacAnnot(false);
1724  0 ssm.setProcessSecondaryStructure(false);
1725  0 ssm.setSecStructServices(false);
1726    }
1727    }
1728   
1729    }