Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package jalview.structure

File StructureSelectionManager.java

 

Coverage histogram

../../img/srcFileCovDistChart7.png
28% of files have more coverage

Code metrics

200
383
54
1
1,432
986
186
0.49
7.09
54
3.44

Classes

Class Line # Actions
StructureSelectionManager 63 383 186 228
0.642072264.2%
 

Contributing tests

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