Clover icon

Coverage Report

  1. Project Clover database Sun Jan 11 2026 02:28:45 GMT
  2. Package jalview.structure

File StructureSelectionManager.java

 

Coverage histogram

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

Code metrics

240
472
69
1
1,863
1,211
228
0.48
6.84
69
3.3

Classes

Class Line # Actions
StructureSelectionManager 74 472 228
0.5877080658.8%
 

Contributing tests

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