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
864 public String mouseOverStructure(int pdbResNum, String chain,
867 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
868 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
869 return mouseOverStructure(atoms);
873 * Propagate mouseover or selection of multiple positions in a structure
877 public String mouseOverStructure(List<AtomSpec> atoms)
879 if (listeners == null)
881 // old or prematurely sent event
884 boolean hasSequenceListener = false;
885 for (int i = 0; i < listeners.size(); i++)
887 if (listeners.elementAt(i) instanceof SequenceListener)
889 hasSequenceListener = true;
892 if (!hasSequenceListener)
897 SearchResultsI results = findAlignmentPositionsForStructurePositions(
899 String result = null;
900 for (Object li : listeners)
902 if (li instanceof SequenceListener)
904 String s = ((SequenceListener) li).highlightSequence(results);
915 * Constructs a SearchResults object holding regions (if any) in the Jalview
916 * alignment which have a mapping to the structure viewer positions in the
922 public SearchResultsI findAlignmentPositionsForStructurePositions(
923 List<AtomSpec> atoms)
925 SearchResultsI results = new SearchResults();
926 for (AtomSpec atom : atoms)
928 SequenceI lastseq = null;
930 for (StructureMapping sm : mappings)
932 if (sm.pdbfile.equals(atom.getPdbFile())
933 && sm.pdbchain.equals(atom.getChain()))
935 int indexpos = sm.getSeqPos(atom.getPdbResNum());
936 if (lastipos != indexpos || lastseq != sm.sequence)
938 results.addResult(sm.sequence, indexpos, indexpos);
940 lastseq = sm.sequence;
941 // construct highlighted sequence list
942 for (AlignedCodonFrame acf : seqmappings)
944 acf.markMappedRegion(sm.sequence, indexpos, results);
954 * highlight regions associated with a position (indexpos) in seq
957 * the sequence that the mouse over occurred on
959 * the absolute position being mouseovered in seq (0 to seq.length())
961 * the sequence position (if -1, seq.findPosition is called to
962 * resolve the residue number)
964 public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
967 boolean hasSequenceListeners = handlingVamsasMo
968 || !seqmappings.isEmpty();
969 SearchResultsI results = null;
972 seqPos = seq.findPosition(indexpos);
974 for (int i = 0; i < listeners.size(); i++)
976 Object listener = listeners.elementAt(i);
977 if (listener == source)
979 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
980 // Temporary fudge with SequenceListener.getVamsasSource()
983 if (listener instanceof StructureListener)
985 highlightStructure((StructureListener) listener, seq, seqPos);
989 if (listener instanceof SequenceListener)
991 final SequenceListener seqListener = (SequenceListener) listener;
992 if (hasSequenceListeners
993 && seqListener.getVamsasSource() != source)
995 if (relaySeqMappings)
999 results = MappingUtils.buildSearchResults(seq, seqPos,
1002 if (handlingVamsasMo)
1004 results.addResult(seq, seqPos, seqPos);
1007 if (!results.isEmpty())
1009 seqListener.highlightSequence(results);
1014 else if (listener instanceof VamsasListener && !handlingVamsasMo)
1016 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
1019 else if (listener instanceof SecondaryStructureListener)
1021 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
1029 * Send suitable messages to a StructureListener to highlight atoms
1030 * corresponding to the given sequence position(s)
1036 public void highlightStructure(StructureListener sl, SequenceI seq,
1039 if (!sl.isListeningFor(seq))
1044 List<AtomSpec> atoms = new ArrayList<>();
1045 for (StructureMapping sm : mappings)
1047 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
1048 || (sm.sequence.getDatasetSequence() != null && sm.sequence
1049 .getDatasetSequence() == seq.getDatasetSequence()))
1051 for (int index : positions)
1053 atomNo = sm.getAtomNum(index);
1057 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
1058 sm.getPDBResNum(index), atomNo));
1063 sl.highlightAtoms(atoms);
1067 * true if a mouse over event from an external (ie Vamsas) source is being
1070 boolean handlingVamsasMo = false;
1075 * as mouseOverSequence but only route event to SequenceListeners
1079 * in an alignment sequence
1081 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
1082 VamsasSource source)
1084 handlingVamsasMo = true;
1085 long msg = sequenceI.hashCode() * (1 + position);
1089 mouseOverSequence(sequenceI, position, -1, source);
1091 handlingVamsasMo = false;
1094 public Annotation[] colourSequenceFromStructure(SequenceI seq,
1098 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
1099 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
1101 * Annotation [] annotations = new Annotation[seq.getLength()];
1103 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
1104 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
1105 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
1107 * for (int j = 0; j < mappings.length; j++) {
1109 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
1110 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
1111 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
1112 * "+mappings[j].pdbfile);
1114 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
1115 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
1117 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
1118 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
1119 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
1120 * mappings[j].pdbfile); }
1122 * annotations[index] = new Annotation("X",null,' ',0,col); } return
1123 * annotations; } } } }
1125 * return annotations;
1129 public void structureSelectionChanged()
1133 public void sequenceSelectionChanged()
1137 public void sequenceColoursChanged(Object source)
1139 StructureListener sl;
1140 for (int i = 0; i < listeners.size(); i++)
1142 if (listeners.elementAt(i) instanceof StructureListener)
1144 sl = (StructureListener) listeners.elementAt(i);
1145 sl.updateColours(source);
1150 public StructureMapping[] getMapping(String pdbfile)
1152 List<StructureMapping> tmp = new ArrayList<>();
1153 for (StructureMapping sm : mappings)
1155 if (sm.pdbfile.equals(pdbfile))
1160 return tmp.toArray(new StructureMapping[tmp.size()]);
1164 * Answers a (possibly empty) list of structure to sequence mappings matching
1165 * the given pdb and chain ids
1171 public List<StructureMapping> getMappingForChain(String pdbId,
1174 List<StructureMapping> result = new ArrayList<>();
1175 for (StructureMapping sm : mappings)
1177 if (sm.pdbid.equals(pdbId) && sm.pdbchain.equals(chain))
1186 * Returns a readable description of all mappings for the given pdbfile to any
1187 * of the given sequences
1193 public String printMappings(String pdbfile, List<SequenceI> seqs)
1195 if (pdbfile == null || seqs == null || seqs.isEmpty())
1200 StringBuilder sb = new StringBuilder(64);
1201 for (StructureMapping sm : mappings)
1203 if (Platform.pathEquals(sm.pdbfile, pdbfile)
1204 && seqs.contains(sm.sequence))
1206 sb.append(sm.mappingDetails);
1208 // separator makes it easier to read multiple mappings
1209 sb.append("=====================");
1215 return sb.toString();
1219 * Remove the given mapping
1223 public void deregisterMapping(AlignedCodonFrame acf)
1227 boolean removed = seqmappings.remove(acf);
1228 if (removed && seqmappings.isEmpty())
1230 System.out.println("All mappings removed");
1236 * Add each of the given codonFrames to the stored set, if not aready present.
1240 public void registerMappings(List<AlignedCodonFrame> mappings)
1242 if (mappings != null)
1244 for (AlignedCodonFrame acf : mappings)
1246 registerMapping(acf);
1252 * Add the given mapping to the stored set, unless already stored.
1254 public void registerMapping(AlignedCodonFrame acf)
1258 if (!seqmappings.contains(acf))
1260 seqmappings.add(acf);
1266 * Resets this object to its initial state by removing all registered
1267 * listeners, codon mappings, PDB file mappings
1269 public void resetAll()
1271 if (mappings != null)
1275 if (seqmappings != null)
1277 seqmappings.clear();
1279 if (sel_listeners != null)
1281 sel_listeners.clear();
1283 if (listeners != null)
1287 if (commandListeners != null)
1289 commandListeners.clear();
1291 if (view_listeners != null)
1293 view_listeners.clear();
1295 if (pdbFileNameId != null)
1297 pdbFileNameId.clear();
1299 if (pdbIdFileName != null)
1301 pdbIdFileName.clear();
1305 public void addSelectionListener(SelectionListener selecter)
1307 if (!sel_listeners.contains(selecter))
1309 sel_listeners.add(selecter);
1313 public void removeSelectionListener(SelectionListener toremove)
1315 if (sel_listeners.contains(toremove))
1317 sel_listeners.remove(toremove);
1321 public synchronized void sendSelection(
1322 jalview.datamodel.SequenceGroup selection,
1323 jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
1324 SelectionSource source)
1326 for (SelectionListener slis : sel_listeners)
1330 slis.selection(selection, colsel, hidden, source);
1335 Vector<AlignmentViewPanelListener> view_listeners = new Vector<>();
1337 public synchronized void sendViewPosition(
1338 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1339 int startSeq, int endSeq)
1342 if (view_listeners != null && view_listeners.size() > 0)
1344 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1346 while (listeners.hasMoreElements())
1348 AlignmentViewPanelListener slis = listeners.nextElement();
1351 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1359 * release all references associated with this manager provider
1361 * @param jalviewLite
1363 public static void release(StructureSelectionManagerProvider jalviewLite)
1365 // synchronized (instances)
1367 if (instances == null)
1371 StructureSelectionManager mnger = (instances.get(jalviewLite));
1374 instances.remove(jalviewLite);
1377 /* bsoares 2019-03-20 finalize deprecated, no apparent external
1378 * resources to close
1380 // mnger.finalize();
1381 } catch (Throwable x)
1388 public void registerPDBEntry(PDBEntry pdbentry)
1390 if (pdbentry.getFile() != null
1391 && pdbentry.getFile().trim().length() > 0)
1393 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1397 public void addCommandListener(CommandListener cl)
1399 if (!commandListeners.contains(cl))
1401 commandListeners.add(cl);
1405 public boolean hasCommandListener(CommandListener cl)
1407 return this.commandListeners.contains(cl);
1410 public boolean removeCommandListener(CommandListener l)
1412 return commandListeners.remove(l);
1416 * Forward a command to any command listeners (except for the command's
1420 * the command to be broadcast (in its form after being performed)
1422 * if true, the command was being 'undone'
1425 public void commandPerformed(CommandI command, boolean undo,
1426 VamsasSource source)
1428 for (CommandListener listener : commandListeners)
1430 listener.mirrorCommand(command, undo, this, source);
1435 * Returns a new CommandI representing the given command as mapped to the
1436 * given sequences. If no mapping could be made, or the command is not of a
1437 * mappable kind, returns null.
1445 public CommandI mapCommand(CommandI command, boolean undo,
1446 final AlignmentI mapTo, char gapChar)
1448 if (command instanceof EditCommand)
1450 return MappingUtils.mapEditCommand((EditCommand) command, undo, mapTo,
1451 gapChar, seqmappings);
1453 else if (command instanceof OrderCommand)
1455 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1456 mapTo, seqmappings);
1461 public List<AlignedCodonFrame> getSequenceMappings()