2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
21 package jalview.structure;
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.util.Platform;
45 import jalview.ws.sifts.SiftsClient;
46 import jalview.ws.sifts.SiftsException;
47 import jalview.ws.sifts.SiftsSettings;
49 import java.io.PrintStream;
50 import java.util.ArrayList;
51 import java.util.Arrays;
52 import java.util.Collections;
53 import java.util.Enumeration;
54 import java.util.HashMap;
55 import java.util.IdentityHashMap;
56 import java.util.List;
58 import java.util.Vector;
61 import MCview.PDBChain;
62 import MCview.PDBfile;
64 public class StructureSelectionManager
66 public final static String NEWLINE = System.lineSeparator();
68 static IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> instances;
70 private List<StructureMapping> mappings = new ArrayList<>();
72 private boolean processSecondaryStructure = false;
74 private boolean secStructServices = false;
76 private boolean addTempFacAnnot = false;
79 * Set of any registered mappings between (dataset) sequences.
81 private List<AlignedCodonFrame> seqmappings = new ArrayList<>();
83 private List<CommandListener> commandListeners = new ArrayList<>();
85 private List<SelectionListener> sel_listeners = new ArrayList<>();
88 * @return true if will try to use external services for processing secondary
91 public boolean isSecStructServices()
93 return secStructServices;
97 * control use of external services for processing secondary structure
99 * @param secStructServices
101 public void setSecStructServices(boolean secStructServices)
103 this.secStructServices = secStructServices;
107 * flag controlling addition of any kind of structural annotation
109 * @return true if temperature factor annotation will be added
111 public boolean isAddTempFacAnnot()
113 return addTempFacAnnot;
117 * set flag controlling addition of structural annotation
119 * @param addTempFacAnnot
121 public void setAddTempFacAnnot(boolean addTempFacAnnot)
123 this.addTempFacAnnot = addTempFacAnnot;
128 * @return if true, the structure manager will attempt to add secondary
129 * structure lines for unannotated sequences
132 public boolean isProcessSecondaryStructure()
134 return processSecondaryStructure;
138 * Control whether structure manager will try to annotate mapped sequences
139 * with secondary structure from PDB data.
143 public void setProcessSecondaryStructure(boolean enable)
145 processSecondaryStructure = enable;
149 * debug function - write all mappings to stdout
151 public void reportMapping()
153 if (mappings.isEmpty())
155 System.err.println("reportMapping: No PDB/Sequence mappings.");
160 "reportMapping: There are " + mappings.size() + " mappings.");
162 for (StructureMapping sm : mappings)
164 System.err.println("mapping " + i++ + " : " + sm.pdbfile);
170 * map between the PDB IDs (or structure identifiers) used by Jalview and the
171 * absolute filenames for PDB data that corresponds to it
173 Map<String, String> pdbIdFileName = new HashMap<>();
175 Map<String, String> pdbFileNameId = new HashMap<>();
177 public void registerPDBFile(String idForFile, String absoluteFile)
179 pdbIdFileName.put(idForFile, absoluteFile);
180 pdbFileNameId.put(absoluteFile, idForFile);
183 public String findIdForPDBFile(String idOrFile)
185 String id = pdbFileNameId.get(idOrFile);
189 public String findFileForPDBId(String idOrFile)
191 String id = pdbIdFileName.get(idOrFile);
195 public boolean isPDBFileRegistered(String idOrFile)
197 return pdbFileNameId.containsKey(idOrFile)
198 || pdbIdFileName.containsKey(idOrFile);
201 private static StructureSelectionManager nullProvider = null;
203 public static StructureSelectionManager getStructureSelectionManager(
204 StructureSelectionManagerProvider context)
208 if (nullProvider == null)
210 if (instances != null)
212 throw new Error(MessageManager.getString(
213 "error.implementation_error_structure_selection_manager_null"),
214 new NullPointerException(MessageManager
215 .getString("exception.ssm_context_is_null")));
219 nullProvider = new StructureSelectionManager();
224 if (instances == null)
226 instances = new java.util.IdentityHashMap<>();
228 StructureSelectionManager instance = instances.get(context);
229 if (instance == null)
231 if (nullProvider != null)
233 instance = nullProvider;
237 instance = new StructureSelectionManager();
239 instances.put(context, instance);
245 * flag controlling whether SeqMappings are relayed from received sequence
246 * mouse over events to other sequences
248 boolean relaySeqMappings = true;
251 * Enable or disable relay of seqMapping events to other sequences. You might
252 * want to do this if there are many sequence mappings and the host computer
257 public void setRelaySeqMappings(boolean relay)
259 relaySeqMappings = relay;
263 * get the state of the relay seqMappings flag.
265 * @return true if sequence mouse overs are being relayed to other mapped
268 public boolean isRelaySeqMappingsEnabled()
270 return relaySeqMappings;
273 Vector listeners = new Vector();
276 * register a listener for alignment sequence mouseover events
280 public void addStructureViewerListener(Object svl)
282 if (!listeners.contains(svl))
284 listeners.addElement(svl);
289 * Returns the filename the PDB id is already mapped to if known, or null if
295 public String alreadyMappedToFile(String pdbid)
297 for (StructureMapping sm : mappings)
299 if (sm.getPdbId().equalsIgnoreCase(pdbid))
308 * Import structure data and register a structure mapping for broadcasting
309 * colouring, mouseovers and selection events (convenience wrapper).
312 * - one or more sequences to be mapped to pdbFile
313 * @param targetChains
314 * - optional chain specification for mapping each sequence to pdb
315 * (may be nill, individual elements may be nill)
317 * - structure data resource
319 * - how to resolve data from resource
320 * @return null or the structure data parsed as a pdb file
322 synchronized public StructureFile setMapping(SequenceI[] sequence,
323 String[] targetChains, String pdbFile, DataSourceType protocol,
324 IProgressIndicator progress)
326 return computeMapping(true, sequence, targetChains, pdbFile, protocol,
331 * Import a single structure file and register sequence structure mappings for
332 * broadcasting colouring, mouseovers and selection events (convenience
335 * @param forStructureView
336 * when true, record the mapping for use in mouseOvers
338 * - one or more sequences to be mapped to pdbFile
339 * @param targetChains
340 * - optional chain specification for mapping each sequence to pdb
341 * (may be nill, individual elements may be nill)
343 * - structure data resource
345 * - how to resolve data from resource
346 * @return null or the structure data parsed as a pdb file
348 synchronized public StructureFile setMapping(boolean forStructureView,
349 SequenceI[] sequenceArray, String[] targetChainIds,
350 String pdbFile, DataSourceType sourceType)
352 return computeMapping(forStructureView, sequenceArray, targetChainIds,
353 pdbFile, sourceType, null);
357 * create sequence structure mappings between each sequence and the given
358 * pdbFile (retrieved via the given protocol). Either constructs a mapping
359 * using NW alignment or derives one from any available SIFTS mapping data.
361 * @param forStructureView
362 * when true, record the mapping for use in mouseOvers
364 * @param sequenceArray
365 * - one or more sequences to be mapped to pdbFile
366 * @param targetChainIds
367 * - optional chain specification for mapping each sequence to pdb
368 * (may be nill, individual elements may be nill) - JBPNote: JAL-2693
369 * - this should be List<List<String>>, empty lists indicate no
370 * predefined mappings
372 * - structure data resource
374 * - how to resolve data from resource
375 * @param IProgressIndicator
376 * reference to UI component that maintains a progress bar for the
378 * @return null or the structure data parsed as a pdb file
380 synchronized public StructureFile computeMapping(
381 boolean forStructureView, SequenceI[] sequenceArray,
382 String[] targetChainIds, String pdbFile, DataSourceType sourceType,
383 IProgressIndicator progress)
385 long progressSessionId = System.currentTimeMillis() * 3;
388 * do we extract and transfer annotation from 3D data ?
390 // FIXME: possibly should just delete
392 boolean parseSecStr = processSecondaryStructure
393 ? isStructureFileProcessed(pdbFile, sequenceArray)
396 StructureFile pdb = null;
397 boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
400 // FIXME if sourceType is not null, we've lost data here
401 sourceType = AppletFormatAdapter.checkProtocol(pdbFile);
402 pdb = new JmolParser(false, pdbFile, sourceType);
403 pdb.addSettings(parseSecStr && processSecondaryStructure,
404 parseSecStr && addTempFacAnnot,
405 parseSecStr && secStructServices);
407 if (pdb.getId() != null && pdb.getId().trim().length() > 0
408 && DataSourceType.FILE == sourceType)
410 registerPDBFile(pdb.getId().trim(), pdbFile);
412 // if PDBId is unavailable then skip SIFTS mapping execution path
413 isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable();
415 } catch (Exception ex)
417 ex.printStackTrace();
421 * sifts client - non null if SIFTS mappings are to be used
423 SiftsClient siftsClient = null;
428 siftsClient = new SiftsClient(pdb);
430 } catch (SiftsException e)
432 isMapUsingSIFTs = false;
437 String targetChainId;
438 for (int s = 0; s < sequenceArray.length; s++)
440 boolean infChain = true;
441 final SequenceI seq = sequenceArray[s];
443 while (ds.getDatasetSequence() != null)
445 ds = ds.getDatasetSequence();
448 if (targetChainIds != null && targetChainIds[s] != null)
451 targetChainId = targetChainIds[s];
453 else if (seq.getName().indexOf("|") > -1)
455 targetChainId = seq.getName()
456 .substring(seq.getName().lastIndexOf("|") + 1);
457 if (targetChainId.length() > 1)
459 if (targetChainId.trim().length() == 0)
465 // not a valid chain identifier
476 * Attempt pairwise alignment of the sequence with each chain in the PDB,
477 * and remember the highest scoring chain
480 AlignSeq maxAlignseq = null;
481 String maxChainId = " ";
482 PDBChain maxChain = null;
483 boolean first = true;
484 for (PDBChain chain : pdb.getChains())
486 if (targetChainId.length() > 0 && !targetChainId.equals(chain.id)
489 continue; // don't try to map chains don't match.
491 // TODO: correctly determine sequence type for mixed na/peptide
493 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
494 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
497 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
498 // as.calcScoreMatrix();
499 // as.traceAlignment();
501 if (first || as.maxscore > max
502 || (as.maxscore == max && chain.id.equals(targetChainId)))
508 maxChainId = chain.id;
511 if (maxChain == null)
516 if (sourceType == DataSourceType.PASTE)
518 pdbFile = "INLINE" + pdb.getId();
521 List<StructureMapping> seqToStrucMapping = new ArrayList<>();
522 if (isMapUsingSIFTs && seq.isProtein())
524 if (progress!=null) {
525 progress.setProgressBar(MessageManager
526 .getString("status.obtaining_mapping_with_sifts"),
529 jalview.datamodel.Mapping sqmpping = maxAlignseq
530 .getMappingFromS1(false);
531 if (targetChainId != null && !targetChainId.trim().isEmpty())
533 StructureMapping siftsMapping;
536 siftsMapping = getStructureMapping(seq, pdbFile, targetChainId,
537 pdb, maxChain, sqmpping, maxAlignseq, siftsClient);
538 seqToStrucMapping.add(siftsMapping);
539 maxChain.makeExactMapping(siftsMapping, seq);
540 maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
542 maxChain.transferResidueAnnotation(siftsMapping, null);
543 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
545 } catch (SiftsException e)
547 // fall back to NW alignment
548 System.err.println(e.getMessage());
549 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
550 targetChainId, maxChain, pdb, maxAlignseq);
551 seqToStrucMapping.add(nwMapping);
552 maxChain.makeExactMapping(maxAlignseq, seq);
553 maxChain.transferRESNUMFeatures(seq, "IEA:Jalview"); // FIXME: is
556 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
557 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
562 List<StructureMapping> foundSiftsMappings = new ArrayList<>();
563 for (PDBChain chain : pdb.getChains())
565 StructureMapping siftsMapping = null;
568 siftsMapping = getStructureMapping(seq,
569 pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq,
571 foundSiftsMappings.add(siftsMapping);
572 chain.makeExactMapping(siftsMapping, seq);
573 chain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
575 chain.transferResidueAnnotation(siftsMapping, null);
576 } catch (SiftsException e)
578 System.err.println(e.getMessage());
584 "Unexpected exception during SIFTS mapping - falling back to NW for this sequence/structure pair");
585 System.err.println(e.getMessage());
588 if (!foundSiftsMappings.isEmpty())
590 seqToStrucMapping.addAll(foundSiftsMappings);
591 ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
595 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
596 maxChainId, maxChain, pdb, maxAlignseq);
597 seqToStrucMapping.add(nwMapping);
598 maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
600 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
601 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
607 if (progress != null)
609 progress.setProgressBar(MessageManager
610 .getString("status.obtaining_mapping_with_nw_alignment"),
613 StructureMapping nwMapping = getNWMappings(seq, pdbFile, maxChainId,
614 maxChain, pdb, maxAlignseq);
615 seqToStrucMapping.add(nwMapping);
616 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
618 if (forStructureView)
620 for (StructureMapping sm : seqToStrucMapping)
622 addStructureMapping(sm); // not addAll!
625 if (progress != null)
627 progress.setProgressBar(null, progressSessionId);
634 * check if we need to extract secondary structure from given pdbFile and
635 * transfer to sequences
638 * @param sequenceArray
641 private boolean isStructureFileProcessed(String pdbFile,
642 SequenceI[] sequenceArray)
644 boolean parseSecStr = true;
645 if (isPDBFileRegistered(pdbFile))
647 for (SequenceI sq : sequenceArray)
650 while (ds.getDatasetSequence() != null)
652 ds = ds.getDatasetSequence();
655 if (ds.getAnnotation() != null)
657 for (AlignmentAnnotation ala : ds.getAnnotation())
659 // false if any annotation present from this structure
660 // JBPNote this fails for jmol/chimera view because the *file* is
661 // passed, not the structure data ID -
662 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
673 public void addStructureMapping(StructureMapping sm)
675 if (!mappings.contains(sm))
682 * retrieve a mapping for seq from SIFTs using associated DBRefEntry for
687 * @param targetChainId
693 * client for retrieval of SIFTS mappings for this structure
695 * @throws SiftsException
697 private StructureMapping getStructureMapping(SequenceI seq,
698 String pdbFile, String targetChainId, StructureFile pdb,
699 PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
700 AlignSeq maxAlignseq, SiftsClient siftsClient) throws SiftsException
702 StructureMapping curChainMapping = siftsClient
703 .getSiftsStructureMapping(seq, pdbFile, targetChainId);
706 PDBChain chain = pdb.findChain(targetChainId);
709 chain.transferResidueAnnotation(curChainMapping, null);
711 } catch (Exception e)
715 return curChainMapping;
718 private StructureMapping getNWMappings(SequenceI seq, String pdbFile,
719 String maxChainId, PDBChain maxChain, StructureFile pdb,
720 AlignSeq maxAlignseq)
722 final StringBuilder mappingDetails = new StringBuilder(128);
723 mappingDetails.append(NEWLINE)
724 .append("Sequence \u27f7 Structure mapping details");
725 mappingDetails.append(NEWLINE);
727 .append("Method: inferred with Needleman & Wunsch alignment");
728 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
729 .append(NEWLINE).append("Sequence = ")
730 .append(maxChain.sequence.getSequenceAsString());
731 mappingDetails.append(NEWLINE).append("No of residues = ")
732 .append(maxChain.residues.size()).append(NEWLINE)
734 PrintStream ps = new PrintStream(System.out)
737 public void print(String x)
739 mappingDetails.append(x);
743 public void println()
745 mappingDetails.append(NEWLINE);
749 maxAlignseq.printAlignment(ps);
751 mappingDetails.append(NEWLINE).append("PDB start/end ");
752 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
754 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
755 mappingDetails.append(NEWLINE).append("SEQ start/end ");
758 .valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
760 mappingDetails.append(
761 String.valueOf(maxAlignseq.seq1end + (seq.getStart() - 1)));
762 mappingDetails.append(NEWLINE);
763 maxChain.makeExactMapping(maxAlignseq, seq);
764 jalview.datamodel.Mapping sqmpping = maxAlignseq
765 .getMappingFromS1(false);
766 maxChain.transferRESNUMFeatures(seq, null);
768 HashMap<Integer, int[]> mapping = new HashMap<>();
775 Atom tmp = maxChain.atoms.elementAt(index);
776 if ((resNum != tmp.resNumber || insCode != tmp.insCode)
777 && tmp.alignmentMapping != -1)
779 resNum = tmp.resNumber;
780 insCode = tmp.insCode;
781 if (tmp.alignmentMapping >= -1)
783 mapping.put(tmp.alignmentMapping + 1,
785 { tmp.resNumber, tmp.atomIndex });
790 } while (index < maxChain.atoms.size());
792 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
793 pdb.getId(), maxChainId, mapping, mappingDetails.toString());
794 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
798 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
800 listeners.removeElement(svl);
801 if (svl instanceof SequenceListener)
803 for (int i = 0; i < listeners.size(); i++)
805 if (listeners.elementAt(i) instanceof StructureListener)
807 ((StructureListener) listeners.elementAt(i))
808 .releaseReferences(svl);
813 if (pdbfiles == null)
819 * Remove mappings to the closed listener's PDB files, but first check if
820 * another listener is still interested
822 List<String> pdbs = new ArrayList<>(Arrays.asList(pdbfiles));
824 StructureListener sl;
825 for (int i = 0; i < listeners.size(); i++)
827 if (listeners.elementAt(i) instanceof StructureListener)
829 sl = (StructureListener) listeners.elementAt(i);
830 for (String pdbfile : sl.getStructureFiles())
832 pdbs.remove(pdbfile);
838 * Rebuild the mappings set, retaining only those which are for 'other' PDB
843 List<StructureMapping> tmp = new ArrayList<>();
844 for (StructureMapping sm : mappings)
846 if (!pdbs.contains(sm.pdbfile))
857 * Propagate mouseover of a single position in a structure
863 public void mouseOverStructure(int pdbResNum, String chain,
866 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
867 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
868 mouseOverStructure(atoms);
872 * Propagate mouseover or selection of multiple positions in a structure
876 public void mouseOverStructure(List<AtomSpec> atoms)
878 if (listeners == null)
880 // old or prematurely sent event
883 boolean hasSequenceListener = false;
884 for (int i = 0; i < listeners.size(); i++)
886 if (listeners.elementAt(i) instanceof SequenceListener)
888 hasSequenceListener = true;
891 if (!hasSequenceListener)
896 SearchResultsI results = findAlignmentPositionsForStructurePositions(
898 for (Object li : listeners)
900 if (li instanceof SequenceListener)
902 ((SequenceListener) li).highlightSequence(results);
908 * Constructs a SearchResults object holding regions (if any) in the Jalview
909 * alignment which have a mapping to the structure viewer positions in the
915 public SearchResultsI findAlignmentPositionsForStructurePositions(
916 List<AtomSpec> atoms)
918 SearchResultsI results = new SearchResults();
919 for (AtomSpec atom : atoms)
921 SequenceI lastseq = null;
923 for (StructureMapping sm : mappings)
925 if (sm.pdbfile.equals(atom.getPdbFile())
926 && sm.pdbchain.equals(atom.getChain()))
928 int indexpos = sm.getSeqPos(atom.getPdbResNum());
929 if (lastipos != indexpos || lastseq != sm.sequence)
931 results.addResult(sm.sequence, indexpos, indexpos);
933 lastseq = sm.sequence;
934 // construct highlighted sequence list
935 for (AlignedCodonFrame acf : seqmappings)
937 acf.markMappedRegion(sm.sequence, indexpos, results);
947 * highlight regions associated with a position (indexpos) in seq
950 * the sequence that the mouse over occurred on
952 * the absolute position being mouseovered in seq (0 to seq.length())
954 * the sequence position (if -1, seq.findPosition is called to
955 * resolve the residue number)
957 public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
960 boolean hasSequenceListeners = handlingVamsasMo
961 || !seqmappings.isEmpty();
962 SearchResultsI results = null;
965 seqPos = seq.findPosition(indexpos);
967 for (int i = 0; i < listeners.size(); i++)
969 Object listener = listeners.elementAt(i);
970 if (listener == source)
972 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
973 // Temporary fudge with SequenceListener.getVamsasSource()
976 if (listener instanceof StructureListener)
978 highlightStructure((StructureListener) listener, seq, seqPos);
982 if (listener instanceof SequenceListener)
984 final SequenceListener seqListener = (SequenceListener) listener;
985 if (hasSequenceListeners
986 && seqListener.getVamsasSource() != source)
988 if (relaySeqMappings)
992 results = MappingUtils.buildSearchResults(seq, seqPos,
995 if (handlingVamsasMo)
997 results.addResult(seq, seqPos, seqPos);
1000 if (!results.isEmpty())
1002 seqListener.highlightSequence(results);
1007 else if (listener instanceof VamsasListener && !handlingVamsasMo)
1009 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
1012 else if (listener instanceof SecondaryStructureListener)
1014 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
1022 * Send suitable messages to a StructureListener to highlight atoms
1023 * corresponding to the given sequence position(s)
1029 public void highlightStructure(StructureListener sl, SequenceI seq,
1032 if (!sl.isListeningFor(seq))
1037 List<AtomSpec> atoms = new ArrayList<>();
1038 for (StructureMapping sm : mappings)
1040 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
1041 || (sm.sequence.getDatasetSequence() != null && sm.sequence
1042 .getDatasetSequence() == seq.getDatasetSequence()))
1044 for (int index : positions)
1046 atomNo = sm.getAtomNum(index);
1050 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
1051 sm.getPDBResNum(index), atomNo));
1056 sl.highlightAtoms(atoms);
1060 * true if a mouse over event from an external (ie Vamsas) source is being
1063 boolean handlingVamsasMo = false;
1068 * as mouseOverSequence but only route event to SequenceListeners
1072 * in an alignment sequence
1074 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
1075 VamsasSource source)
1077 handlingVamsasMo = true;
1078 long msg = sequenceI.hashCode() * (1 + position);
1082 mouseOverSequence(sequenceI, position, -1, source);
1084 handlingVamsasMo = false;
1087 public Annotation[] colourSequenceFromStructure(SequenceI seq,
1091 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
1092 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
1094 * Annotation [] annotations = new Annotation[seq.getLength()];
1096 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
1097 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
1098 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
1100 * for (int j = 0; j < mappings.length; j++) {
1102 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
1103 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
1104 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
1105 * "+mappings[j].pdbfile);
1107 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
1108 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
1110 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
1111 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
1112 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
1113 * mappings[j].pdbfile); }
1115 * annotations[index] = new Annotation("X",null,' ',0,col); } return
1116 * annotations; } } } }
1118 * return annotations;
1122 public void structureSelectionChanged()
1126 public void sequenceSelectionChanged()
1130 public void sequenceColoursChanged(Object source)
1132 StructureListener sl;
1133 for (int i = 0; i < listeners.size(); i++)
1135 if (listeners.elementAt(i) instanceof StructureListener)
1137 sl = (StructureListener) listeners.elementAt(i);
1138 sl.updateColours(source);
1143 public StructureMapping[] getMapping(String pdbfile)
1145 List<StructureMapping> tmp = new ArrayList<>();
1146 for (StructureMapping sm : mappings)
1148 if (sm.pdbfile.equals(pdbfile))
1153 return tmp.toArray(new StructureMapping[tmp.size()]);
1157 * Returns a readable description of all mappings for the given pdbfile to any
1158 * of the given sequences
1164 public String printMappings(String pdbfile, List<SequenceI> seqs)
1166 if (pdbfile == null || seqs == null || seqs.isEmpty())
1171 StringBuilder sb = new StringBuilder(64);
1172 for (StructureMapping sm : mappings)
1174 if (Platform.pathEquals(sm.pdbfile, pdbfile)
1175 && seqs.contains(sm.sequence))
1177 sb.append(sm.mappingDetails);
1179 // separator makes it easier to read multiple mappings
1180 sb.append("=====================");
1186 return sb.toString();
1190 * Remove the given mapping
1194 public void deregisterMapping(AlignedCodonFrame acf)
1198 boolean removed = seqmappings.remove(acf);
1199 if (removed && seqmappings.isEmpty())
1201 System.out.println("All mappings removed");
1207 * Add each of the given codonFrames to the stored set, if not aready present.
1211 public void registerMappings(List<AlignedCodonFrame> mappings)
1213 if (mappings != null)
1215 for (AlignedCodonFrame acf : mappings)
1217 registerMapping(acf);
1223 * Add the given mapping to the stored set, unless already stored.
1225 public void registerMapping(AlignedCodonFrame acf)
1229 if (!seqmappings.contains(acf))
1231 seqmappings.add(acf);
1237 * Resets this object to its initial state by removing all registered
1238 * listeners, codon mappings, PDB file mappings
1240 public void resetAll()
1242 if (mappings != null)
1246 if (seqmappings != null)
1248 seqmappings.clear();
1250 if (sel_listeners != null)
1252 sel_listeners.clear();
1254 if (listeners != null)
1258 if (commandListeners != null)
1260 commandListeners.clear();
1262 if (view_listeners != null)
1264 view_listeners.clear();
1266 if (pdbFileNameId != null)
1268 pdbFileNameId.clear();
1270 if (pdbIdFileName != null)
1272 pdbIdFileName.clear();
1276 public void addSelectionListener(SelectionListener selecter)
1278 if (!sel_listeners.contains(selecter))
1280 sel_listeners.add(selecter);
1284 public void removeSelectionListener(SelectionListener toremove)
1286 if (sel_listeners.contains(toremove))
1288 sel_listeners.remove(toremove);
1292 public synchronized void sendSelection(
1293 jalview.datamodel.SequenceGroup selection,
1294 jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
1295 SelectionSource source)
1297 for (SelectionListener slis : sel_listeners)
1301 slis.selection(selection, colsel, hidden, source);
1306 Vector<AlignmentViewPanelListener> view_listeners = new Vector<>();
1308 public synchronized void sendViewPosition(
1309 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1310 int startSeq, int endSeq)
1313 if (view_listeners != null && view_listeners.size() > 0)
1315 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1317 while (listeners.hasMoreElements())
1319 AlignmentViewPanelListener slis = listeners.nextElement();
1322 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1330 * release all references associated with this manager provider
1332 * @param jalviewLite
1334 public static void release(StructureSelectionManagerProvider jalviewLite)
1336 // synchronized (instances)
1338 if (instances == null)
1342 StructureSelectionManager mnger = (instances.get(jalviewLite));
1345 instances.remove(jalviewLite);
1348 /* bsoares 2019-03-20 finalize deprecated, no apparent external
1349 * resources to close
1351 // mnger.finalize();
1352 } catch (Throwable x)
1359 public void registerPDBEntry(PDBEntry pdbentry)
1361 if (pdbentry.getFile() != null
1362 && pdbentry.getFile().trim().length() > 0)
1364 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1368 public void addCommandListener(CommandListener cl)
1370 if (!commandListeners.contains(cl))
1372 commandListeners.add(cl);
1376 public boolean hasCommandListener(CommandListener cl)
1378 return this.commandListeners.contains(cl);
1381 public boolean removeCommandListener(CommandListener l)
1383 return commandListeners.remove(l);
1387 * Forward a command to any command listeners (except for the command's
1391 * the command to be broadcast (in its form after being performed)
1393 * if true, the command was being 'undone'
1396 public void commandPerformed(CommandI command, boolean undo,
1397 VamsasSource source)
1399 for (CommandListener listener : commandListeners)
1401 listener.mirrorCommand(command, undo, this, source);
1406 * Returns a new CommandI representing the given command as mapped to the
1407 * given sequences. If no mapping could be made, or the command is not of a
1408 * mappable kind, returns null.
1416 public CommandI mapCommand(CommandI command, boolean undo,
1417 final AlignmentI mapTo, char gapChar)
1419 if (command instanceof EditCommand)
1421 return MappingUtils.mapEditCommand((EditCommand) command, undo, mapTo,
1422 gapChar, seqmappings);
1424 else if (command instanceof OrderCommand)
1426 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1427 mapTo, seqmappings);
1432 public List<AlignedCodonFrame> getSequenceMappings()