Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 14:43:25 GMT
  2. Package jalview.structure

File StructureSelectionManager.java

 

Coverage histogram

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

Code metrics

242
475
69
1
1,874
1,216
229
0.48
6.88
69
3.32

Classes

Class Line # Actions
StructureSelectionManager 74 475 229
0.589058558.9%
 

Contributing tests

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