Clover icon

Coverage Report

  1. Project Clover database Mon Nov 18 2024 09:56:54 GMT
  2. Package jalview.structure

File StructureSelectionManager.java

 

Coverage histogram

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

Code metrics

262
500
63
1
1,849
1,275
238
0.48
7.94
63
3.78

Classes

Class Line # Actions
StructureSelectionManager 73 500 238
0.5393939653.9%
 

Contributing tests

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