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.bin.Instance;
26 import jalview.commands.CommandI;
27 import jalview.commands.EditCommand;
28 import jalview.commands.OrderCommand;
29 import jalview.datamodel.AlignedCodonFrame;
30 import jalview.datamodel.AlignmentAnnotation;
31 import jalview.datamodel.AlignmentI;
32 import jalview.datamodel.Annotation;
33 import jalview.datamodel.HiddenColumns;
34 import jalview.datamodel.PDBEntry;
35 import jalview.datamodel.SearchResults;
36 import jalview.datamodel.SearchResultsI;
37 import jalview.datamodel.SequenceI;
38 import jalview.ext.jmol.JmolParser;
39 import jalview.gui.IProgressIndicator;
40 import jalview.io.AppletFormatAdapter;
41 import jalview.io.DataSourceType;
42 import jalview.io.StructureFile;
43 import jalview.util.MappingUtils;
44 import jalview.util.MessageManager;
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 mc_view.PDBChain;
62 import mc_view.PDBfile;
64 public class StructureSelectionManager
67 public StructureSelectionManager()
71 public final static String NEWLINE = System.lineSeparator();
73 // BH unnecessary; IdentityHashMap can handle this
74 // private static StructureSelectionManager nullProvider;
76 private List<StructureMapping> mappings = new ArrayList<>();
78 private boolean processSecondaryStructure = false;
80 private boolean secStructServices = false;
82 private boolean addTempFacAnnot = false;
85 * Set of any registered mappings between (dataset) sequences.
87 private List<AlignedCodonFrame> seqmappings = new ArrayList<>();
89 private List<CommandListener> commandListeners = new ArrayList<>();
91 private List<SelectionListener> sel_listeners = new ArrayList<>();
94 * @return true if will try to use external services for processing secondary
97 public boolean isSecStructServices()
99 return secStructServices;
103 * control use of external services for processing secondary structure
105 * @param secStructServices
107 public void setSecStructServices(boolean secStructServices)
109 this.secStructServices = secStructServices;
113 * flag controlling addition of any kind of structural annotation
115 * @return true if temperature factor annotation will be added
117 public boolean isAddTempFacAnnot()
119 return addTempFacAnnot;
123 * set flag controlling addition of structural annotation
125 * @param addTempFacAnnot
127 public void setAddTempFacAnnot(boolean addTempFacAnnot)
129 this.addTempFacAnnot = addTempFacAnnot;
134 * @return if true, the structure manager will attempt to add secondary
135 * structure lines for unannotated sequences
138 public boolean isProcessSecondaryStructure()
140 return processSecondaryStructure;
144 * Control whether structure manager will try to annotate mapped sequences
145 * with secondary structure from PDB data.
149 public void setProcessSecondaryStructure(boolean enable)
151 processSecondaryStructure = enable;
155 * debug function - write all mappings to stdout
157 public void reportMapping()
159 if (mappings.isEmpty())
161 System.err.println("reportMapping: No PDB/Sequence mappings.");
166 "reportMapping: There are " + mappings.size() + " mappings.");
168 for (StructureMapping sm : mappings)
170 System.err.println("mapping " + i++ + " : " + sm.pdbfile);
176 * map between the PDB IDs (or structure identifiers) used by Jalview and the
177 * absolute filenames for PDB data that corresponds to it
179 Map<String, String> pdbIdFileName = new HashMap<>();
181 Map<String, String> pdbFileNameId = new HashMap<>();
183 public void registerPDBFile(String idForFile, String absoluteFile)
185 pdbIdFileName.put(idForFile, absoluteFile);
186 pdbFileNameId.put(absoluteFile, idForFile);
189 public String findIdForPDBFile(String idOrFile)
191 String id = pdbFileNameId.get(idOrFile);
195 public String findFileForPDBId(String idOrFile)
197 String id = pdbIdFileName.get(idOrFile);
201 public boolean isPDBFileRegistered(String idOrFile)
203 return pdbFileNameId.containsKey(idOrFile)
204 || pdbIdFileName.containsKey(idOrFile);
208 * flag controlling whether SeqMappings are relayed from received sequence
209 * mouse over events to other sequences
211 boolean relaySeqMappings = true;
214 * Enable or disable relay of seqMapping events to other sequences. You might
215 * want to do this if there are many sequence mappings and the host computer
220 public void setRelaySeqMappings(boolean relay)
222 relaySeqMappings = relay;
226 * get the state of the relay seqMappings flag.
228 * @return true if sequence mouse overs are being relayed to other mapped
231 public boolean isRelaySeqMappingsEnabled()
233 return relaySeqMappings;
236 Vector<Object> listeners = new Vector<>();
239 * register a listener for alignment sequence mouseover events
243 public void addStructureViewerListener(Object svl)
245 if (!listeners.contains(svl))
247 listeners.addElement(svl);
252 * Returns the filename the PDB id is already mapped to if known, or null if
258 public String alreadyMappedToFile(String pdbid)
260 for (StructureMapping sm : mappings)
262 if (sm.getPdbId().equalsIgnoreCase(pdbid))
271 * Import structure data and register a structure mapping for broadcasting
272 * colouring, mouseovers and selection events (convenience wrapper).
275 * - one or more sequences to be mapped to pdbFile
276 * @param targetChains
277 * - optional chain specification for mapping each sequence to pdb
278 * (may be nill, individual elements may be nill)
280 * - structure data resource
282 * - how to resolve data from resource
283 * @return null or the structure data parsed as a pdb file
285 synchronized public StructureFile setMapping(SequenceI[] sequence,
286 String[] targetChains, String pdbFile, DataSourceType protocol,
287 IProgressIndicator progress)
289 return computeMapping(true, sequence, targetChains, pdbFile, protocol,
294 * Import a single structure file and register sequence structure mappings for
295 * broadcasting colouring, mouseovers and selection events (convenience
298 * @param forStructureView
299 * when true, record the mapping for use in mouseOvers
301 * - one or more sequences to be mapped to pdbFile
302 * @param targetChains
303 * - optional chain specification for mapping each sequence to pdb
304 * (may be nill, individual elements may be nill)
306 * - structure data resource
308 * - how to resolve data from resource
309 * @return null or the structure data parsed as a pdb file
311 synchronized public StructureFile setMapping(boolean forStructureView,
312 SequenceI[] sequenceArray, String[] targetChainIds,
313 String pdbFile, DataSourceType sourceType)
315 return computeMapping(forStructureView, sequenceArray, targetChainIds,
316 pdbFile, sourceType, null);
320 * create sequence structure mappings between each sequence and the given
321 * pdbFile (retrieved via the given protocol). Either constructs a mapping
322 * using NW alignment or derives one from any available SIFTS mapping data.
324 * @param forStructureView
325 * when true, record the mapping for use in mouseOvers
327 * @param sequenceArray
328 * - one or more sequences to be mapped to pdbFile
329 * @param targetChainIds
330 * - optional chain specification for mapping each sequence to pdb
331 * (may be nill, individual elements may be nill) - JBPNote: JAL-2693
332 * - this should be List<List<String>>, empty lists indicate no
333 * predefined mappings
335 * - structure data resource
337 * - how to resolve data from resource
338 * @param IProgressIndicator
339 * reference to UI component that maintains a progress bar for the
341 * @return null or the structure data parsed as a pdb file
343 synchronized public StructureFile computeMapping(
344 boolean forStructureView, SequenceI[] sequenceArray,
345 String[] targetChainIds, String pdbFile, DataSourceType sourceType,
346 IProgressIndicator progress)
348 long progressSessionId = System.currentTimeMillis() * 3;
351 * do we extract and transfer annotation from 3D data ?
353 // FIXME: possibly should just delete
355 boolean parseSecStr = processSecondaryStructure
356 ? isStructureFileProcessed(pdbFile, sequenceArray)
359 StructureFile pdb = null;
360 boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
363 // FIXME if sourceType is not null, we've lost data here
364 sourceType = AppletFormatAdapter.checkProtocol(pdbFile);
365 pdb = new JmolParser(false, pdbFile, sourceType);
366 pdb.addSettings(parseSecStr && processSecondaryStructure,
367 parseSecStr && addTempFacAnnot,
368 parseSecStr && secStructServices);
370 if (pdb.getId() != null && pdb.getId().trim().length() > 0
371 && DataSourceType.FILE == sourceType)
373 registerPDBFile(pdb.getId().trim(), pdbFile);
375 // if PDBId is unavailable then skip SIFTS mapping execution path
376 isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable();
378 } catch (Exception ex)
380 ex.printStackTrace();
384 * sifts client - non null if SIFTS mappings are to be used
386 SiftsClient siftsClient = null;
391 siftsClient = new SiftsClient(pdb);
393 } catch (SiftsException e)
395 isMapUsingSIFTs = false;
400 String targetChainId;
401 for (int s = 0; s < sequenceArray.length; s++)
403 boolean infChain = true;
404 final SequenceI seq = sequenceArray[s];
406 while (ds.getDatasetSequence() != null)
408 ds = ds.getDatasetSequence();
411 if (targetChainIds != null && targetChainIds[s] != null)
414 targetChainId = targetChainIds[s];
416 else if (seq.getName().indexOf("|") > -1)
418 targetChainId = seq.getName()
419 .substring(seq.getName().lastIndexOf("|") + 1);
420 if (targetChainId.length() > 1)
422 if (targetChainId.trim().length() == 0)
428 // not a valid chain identifier
439 * Attempt pairwise alignment of the sequence with each chain in the PDB,
440 * and remember the highest scoring chain
443 AlignSeq maxAlignseq = null;
444 String maxChainId = " ";
445 PDBChain maxChain = null;
446 boolean first = true;
447 for (PDBChain chain : pdb.getChains())
449 if (targetChainId.length() > 0 && !targetChainId.equals(chain.id)
452 continue; // don't try to map chains don't match.
454 // TODO: correctly determine sequence type for mixed na/peptide
456 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
457 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
460 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
461 // as.calcScoreMatrix();
462 // as.traceAlignment();
464 if (first || as.maxscore > max
465 || (as.maxscore == max && chain.id.equals(targetChainId)))
471 maxChainId = chain.id;
474 if (maxChain == null)
479 if (sourceType == DataSourceType.PASTE)
481 pdbFile = "INLINE" + pdb.getId();
484 List<StructureMapping> seqToStrucMapping = new ArrayList<>();
485 if (isMapUsingSIFTs && seq.isProtein())
487 if (progress!=null) {
488 progress.setProgressBar(MessageManager
489 .getString("status.obtaining_mapping_with_sifts"),
492 jalview.datamodel.Mapping sqmpping = maxAlignseq
493 .getMappingFromS1(false);
494 if (targetChainId != null && !targetChainId.trim().isEmpty())
496 StructureMapping siftsMapping;
499 siftsMapping = getStructureMapping(seq, pdbFile, targetChainId,
500 pdb, maxChain, sqmpping, maxAlignseq, siftsClient);
501 seqToStrucMapping.add(siftsMapping);
502 maxChain.makeExactMapping(siftsMapping, seq);
503 maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
505 maxChain.transferResidueAnnotation(siftsMapping, null);
506 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
508 } catch (SiftsException e)
510 // fall back to NW alignment
511 System.err.println(e.getMessage());
512 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
513 targetChainId, maxChain, pdb, maxAlignseq);
514 seqToStrucMapping.add(nwMapping);
515 maxChain.makeExactMapping(maxAlignseq, seq);
516 maxChain.transferRESNUMFeatures(seq, "IEA:Jalview"); // FIXME: is
519 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
520 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
525 List<StructureMapping> foundSiftsMappings = new ArrayList<>();
526 for (PDBChain chain : pdb.getChains())
528 StructureMapping siftsMapping = null;
531 siftsMapping = getStructureMapping(seq,
532 pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq,
534 foundSiftsMappings.add(siftsMapping);
535 chain.makeExactMapping(siftsMapping, seq);
536 chain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
538 chain.transferResidueAnnotation(siftsMapping, null);
539 } catch (SiftsException e)
541 System.err.println(e.getMessage());
547 "Unexpected exception during SIFTS mapping - falling back to NW for this sequence/structure pair");
548 System.err.println(e.getMessage());
551 if (!foundSiftsMappings.isEmpty())
553 seqToStrucMapping.addAll(foundSiftsMappings);
554 ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
558 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
559 maxChainId, maxChain, pdb, maxAlignseq);
560 seqToStrucMapping.add(nwMapping);
561 maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
563 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
564 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
570 if (progress != null)
572 progress.setProgressBar(MessageManager
573 .getString("status.obtaining_mapping_with_nw_alignment"),
576 StructureMapping nwMapping = getNWMappings(seq, pdbFile, maxChainId,
577 maxChain, pdb, maxAlignseq);
578 seqToStrucMapping.add(nwMapping);
579 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
581 if (forStructureView)
583 for (StructureMapping sm : seqToStrucMapping)
585 addStructureMapping(sm); // not addAll!
588 if (progress != null)
590 progress.setProgressBar(null, progressSessionId);
597 * check if we need to extract secondary structure from given pdbFile and
598 * transfer to sequences
601 * @param sequenceArray
604 private boolean isStructureFileProcessed(String pdbFile,
605 SequenceI[] sequenceArray)
607 boolean parseSecStr = true;
608 if (isPDBFileRegistered(pdbFile))
610 for (SequenceI sq : sequenceArray)
613 while (ds.getDatasetSequence() != null)
615 ds = ds.getDatasetSequence();
618 if (ds.getAnnotation() != null)
620 for (AlignmentAnnotation ala : ds.getAnnotation())
622 // false if any annotation present from this structure
623 // JBPNote this fails for jmol/chimera view because the *file* is
624 // passed, not the structure data ID -
625 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
636 public void addStructureMapping(StructureMapping sm)
638 if (!mappings.contains(sm))
645 * retrieve a mapping for seq from SIFTs using associated DBRefEntry for
650 * @param targetChainId
656 * client for retrieval of SIFTS mappings for this structure
658 * @throws SiftsException
660 private StructureMapping getStructureMapping(SequenceI seq,
661 String pdbFile, String targetChainId, StructureFile pdb,
662 PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
663 AlignSeq maxAlignseq, SiftsClient siftsClient) throws SiftsException
665 StructureMapping curChainMapping = siftsClient
666 .getSiftsStructureMapping(seq, pdbFile, targetChainId);
669 PDBChain chain = pdb.findChain(targetChainId);
672 chain.transferResidueAnnotation(curChainMapping, null);
674 } catch (Exception e)
678 return curChainMapping;
681 private StructureMapping getNWMappings(SequenceI seq, String pdbFile,
682 String maxChainId, PDBChain maxChain, StructureFile pdb,
683 AlignSeq maxAlignseq)
685 final StringBuilder mappingDetails = new StringBuilder(128);
686 mappingDetails.append(NEWLINE)
687 .append("Sequence \u27f7 Structure mapping details");
688 mappingDetails.append(NEWLINE);
690 .append("Method: inferred with Needleman & Wunsch alignment");
691 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
692 .append(NEWLINE).append("Sequence = ")
693 .append(maxChain.sequence.getSequenceAsString());
694 mappingDetails.append(NEWLINE).append("No of residues = ")
695 .append(maxChain.residues.size()).append(NEWLINE)
697 PrintStream ps = new PrintStream(System.out)
700 public void print(String x)
702 mappingDetails.append(x);
706 public void println()
708 mappingDetails.append(NEWLINE);
712 maxAlignseq.printAlignment(ps);
714 mappingDetails.append(NEWLINE).append("PDB start/end ");
715 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
717 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
718 mappingDetails.append(NEWLINE).append("SEQ start/end ");
721 .valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
723 mappingDetails.append(
724 String.valueOf(maxAlignseq.seq1end + (seq.getStart() - 1)));
725 mappingDetails.append(NEWLINE);
726 maxChain.makeExactMapping(maxAlignseq, seq);
727 jalview.datamodel.Mapping sqmpping = maxAlignseq
728 .getMappingFromS1(false);
729 maxChain.transferRESNUMFeatures(seq, null);
731 HashMap<Integer, int[]> mapping = new HashMap<>();
738 Atom tmp = maxChain.atoms.elementAt(index);
739 if ((resNum != tmp.resNumber || insCode != tmp.insCode)
740 && tmp.alignmentMapping != -1)
742 resNum = tmp.resNumber;
743 insCode = tmp.insCode;
744 if (tmp.alignmentMapping >= -1)
746 mapping.put(tmp.alignmentMapping + 1,
748 { tmp.resNumber, tmp.atomIndex });
753 } while (index < maxChain.atoms.size());
755 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
756 pdb.getId(), maxChainId, mapping, mappingDetails.toString());
757 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
761 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
763 listeners.removeElement(svl);
764 if (svl instanceof SequenceListener)
766 for (int i = 0; i < listeners.size(); i++)
768 if (listeners.elementAt(i) instanceof StructureListener)
770 ((StructureListener) listeners.elementAt(i))
771 .releaseReferences(svl);
776 if (pdbfiles == null)
782 * Remove mappings to the closed listener's PDB files, but first check if
783 * another listener is still interested
785 List<String> pdbs = new ArrayList<>(Arrays.asList(pdbfiles));
787 StructureListener sl;
788 for (int i = 0; i < listeners.size(); i++)
790 if (listeners.elementAt(i) instanceof StructureListener)
792 sl = (StructureListener) listeners.elementAt(i);
793 for (String pdbfile : sl.getStructureFiles())
795 pdbs.remove(pdbfile);
801 * Rebuild the mappings set, retaining only those which are for 'other' PDB
806 List<StructureMapping> tmp = new ArrayList<>();
807 for (StructureMapping sm : mappings)
809 if (!pdbs.contains(sm.pdbfile))
820 * Propagate mouseover of a single position in a structure
826 public void mouseOverStructure(int pdbResNum, String chain,
829 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
830 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
831 mouseOverStructure(atoms);
835 * Propagate mouseover or selection of multiple positions in a structure
839 public void mouseOverStructure(List<AtomSpec> atoms)
841 if (listeners == null)
843 // old or prematurely sent event
846 boolean hasSequenceListener = false;
847 for (int i = 0; i < listeners.size(); i++)
849 if (listeners.elementAt(i) instanceof SequenceListener)
851 hasSequenceListener = true;
854 if (!hasSequenceListener)
859 SearchResultsI results = findAlignmentPositionsForStructurePositions(
861 for (Object li : listeners)
863 if (li instanceof SequenceListener)
865 ((SequenceListener) li).highlightSequence(results);
871 * Constructs a SearchResults object holding regions (if any) in the Jalview
872 * alignment which have a mapping to the structure viewer positions in the
878 public SearchResultsI findAlignmentPositionsForStructurePositions(
879 List<AtomSpec> atoms)
881 SearchResultsI results = new SearchResults();
882 for (AtomSpec atom : atoms)
884 SequenceI lastseq = null;
886 for (StructureMapping sm : mappings)
888 if (sm.pdbfile.equals(atom.getPdbFile())
889 && sm.pdbchain.equals(atom.getChain()))
891 int indexpos = sm.getSeqPos(atom.getPdbResNum());
892 if (lastipos != indexpos || lastseq != sm.sequence)
894 results.addResult(sm.sequence, indexpos, indexpos);
896 lastseq = sm.sequence;
897 // construct highlighted sequence list
898 for (AlignedCodonFrame acf : seqmappings)
900 acf.markMappedRegion(sm.sequence, indexpos, results);
910 * highlight regions associated with a position (indexpos) in seq
913 * the sequence that the mouse over occurred on
915 * the absolute position being mouseovered in seq (0 to seq.length())
917 * the sequence position (if -1, seq.findPosition is called to
918 * resolve the residue number)
920 public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
923 boolean hasSequenceListeners = handlingVamsasMo
924 || !seqmappings.isEmpty();
925 SearchResultsI results = null;
928 seqPos = seq.findPosition(indexpos);
930 for (int i = 0; i < listeners.size(); i++)
932 Object listener = listeners.elementAt(i);
933 if (listener == source)
935 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
936 // Temporary fudge with SequenceListener.getVamsasSource()
939 if (listener instanceof StructureListener)
941 highlightStructure((StructureListener) listener, seq, seqPos);
945 if (listener instanceof SequenceListener)
947 final SequenceListener seqListener = (SequenceListener) listener;
948 if (hasSequenceListeners
949 && seqListener.getVamsasSource() != source)
951 if (relaySeqMappings)
955 results = MappingUtils.buildSearchResults(seq, seqPos,
958 if (handlingVamsasMo)
960 results.addResult(seq, seqPos, seqPos);
963 if (!results.isEmpty())
965 seqListener.highlightSequence(results);
970 else if (listener instanceof VamsasListener && !handlingVamsasMo)
972 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
975 else if (listener instanceof SecondaryStructureListener)
977 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
985 * Send suitable messages to a StructureListener to highlight atoms
986 * corresponding to the given sequence position(s)
992 public void highlightStructure(StructureListener sl, SequenceI seq,
995 if (!sl.isListeningFor(seq))
1000 List<AtomSpec> atoms = new ArrayList<>();
1001 for (StructureMapping sm : mappings)
1003 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
1004 || (sm.sequence.getDatasetSequence() != null && sm.sequence
1005 .getDatasetSequence() == seq.getDatasetSequence()))
1007 for (int index : positions)
1009 atomNo = sm.getAtomNum(index);
1013 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
1014 sm.getPDBResNum(index), atomNo));
1019 sl.highlightAtoms(atoms);
1023 * true if a mouse over event from an external (ie Vamsas) source is being
1026 boolean handlingVamsasMo = false;
1031 * as mouseOverSequence but only route event to SequenceListeners
1035 * in an alignment sequence
1037 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
1038 VamsasSource source)
1040 handlingVamsasMo = true;
1041 long msg = sequenceI.hashCode() * (1 + position);
1045 mouseOverSequence(sequenceI, position, -1, source);
1047 handlingVamsasMo = false;
1050 public Annotation[] colourSequenceFromStructure(SequenceI seq,
1054 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
1055 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
1057 * Annotation [] annotations = new Annotation[seq.getLength()];
1059 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
1060 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
1061 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
1063 * for (int j = 0; j < mappings.length; j++) {
1065 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
1066 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
1067 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
1068 * "+mappings[j].pdbfile);
1070 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
1071 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
1073 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
1074 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
1075 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
1076 * mappings[j].pdbfile); }
1078 * annotations[index] = new Annotation("X",null,' ',0,col); } return
1079 * annotations; } } } }
1081 * return annotations;
1085 public void structureSelectionChanged()
1089 public void sequenceSelectionChanged()
1093 public void sequenceColoursChanged(Object source)
1095 StructureListener sl;
1096 for (int i = 0; i < listeners.size(); i++)
1098 if (listeners.elementAt(i) instanceof StructureListener)
1100 sl = (StructureListener) listeners.elementAt(i);
1101 sl.updateColours(source);
1106 public StructureMapping[] getMapping(String pdbfile)
1108 List<StructureMapping> tmp = new ArrayList<>();
1109 for (StructureMapping sm : mappings)
1111 if (sm.pdbfile.equals(pdbfile))
1116 return tmp.toArray(new StructureMapping[tmp.size()]);
1120 * Returns a readable description of all mappings for the given pdbfile to any
1121 * of the given sequences
1127 public String printMappings(String pdbfile, List<SequenceI> seqs)
1129 if (pdbfile == null || seqs == null || seqs.isEmpty())
1134 StringBuilder sb = new StringBuilder(64);
1135 for (StructureMapping sm : mappings)
1137 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
1139 sb.append(sm.mappingDetails);
1141 // separator makes it easier to read multiple mappings
1142 sb.append("=====================");
1148 return sb.toString();
1152 * Remove the given mapping
1156 public void deregisterMapping(AlignedCodonFrame acf)
1160 boolean removed = seqmappings.remove(acf);
1161 if (removed && seqmappings.isEmpty())
1163 System.out.println("All mappings removed");
1169 * Add each of the given codonFrames to the stored set, if not aready present.
1173 public void registerMappings(List<AlignedCodonFrame> mappings)
1175 if (mappings != null)
1177 for (AlignedCodonFrame acf : mappings)
1179 registerMapping(acf);
1185 * Add the given mapping to the stored set, unless already stored.
1187 public void registerMapping(AlignedCodonFrame acf)
1191 if (!seqmappings.contains(acf))
1193 seqmappings.add(acf);
1199 * Resets this object to its initial state by removing all registered
1200 * listeners, codon mappings, PDB file mappings
1202 public void resetAll()
1204 if (mappings != null)
1208 if (seqmappings != null)
1210 seqmappings.clear();
1212 if (sel_listeners != null)
1214 sel_listeners.clear();
1216 if (listeners != null)
1220 if (commandListeners != null)
1222 commandListeners.clear();
1224 if (view_listeners != null)
1226 view_listeners.clear();
1228 if (pdbFileNameId != null)
1230 pdbFileNameId.clear();
1232 if (pdbIdFileName != null)
1234 pdbIdFileName.clear();
1238 public void addSelectionListener(SelectionListener selecter)
1240 if (!sel_listeners.contains(selecter))
1242 sel_listeners.add(selecter);
1246 public void removeSelectionListener(SelectionListener toremove)
1248 if (sel_listeners.contains(toremove))
1250 sel_listeners.remove(toremove);
1254 public synchronized void sendSelection(
1255 jalview.datamodel.SequenceGroup selection,
1256 jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
1257 SelectionSource source)
1259 for (SelectionListener slis : sel_listeners)
1263 slis.selection(selection, colsel, hidden, source);
1268 Vector<AlignmentViewPanelListener> view_listeners = new Vector<>();
1270 public synchronized void sendViewPosition(
1271 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1272 int startSeq, int endSeq)
1275 if (view_listeners != null && view_listeners.size() > 0)
1277 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1279 while (listeners.hasMoreElements())
1281 AlignmentViewPanelListener slis = listeners.nextElement();
1284 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1291 public void registerPDBEntry(PDBEntry pdbentry)
1293 if (pdbentry.getFile() != null
1294 && pdbentry.getFile().trim().length() > 0)
1296 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1300 public void addCommandListener(CommandListener cl)
1302 if (!commandListeners.contains(cl))
1304 commandListeners.add(cl);
1308 public boolean hasCommandListener(CommandListener cl)
1310 return this.commandListeners.contains(cl);
1313 public boolean removeCommandListener(CommandListener l)
1315 return commandListeners.remove(l);
1319 * Forward a command to any command listeners (except for the command's
1323 * the command to be broadcast (in its form after being performed)
1325 * if true, the command was being 'undone'
1328 public void commandPerformed(CommandI command, boolean undo,
1329 VamsasSource source)
1331 for (CommandListener listener : commandListeners)
1333 listener.mirrorCommand(command, undo, this, source);
1338 * Returns a new CommandI representing the given command as mapped to the
1339 * given sequences. If no mapping could be made, or the command is not of a
1340 * mappable kind, returns null.
1348 public CommandI mapCommand(CommandI command, boolean undo,
1349 final AlignmentI mapTo, char gapChar)
1351 if (command instanceof EditCommand)
1353 return MappingUtils.mapEditCommand((EditCommand) command, undo, mapTo,
1354 gapChar, seqmappings);
1356 else if (command instanceof OrderCommand)
1358 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1359 mapTo, seqmappings);
1364 public List<AlignedCodonFrame> getSequenceMappings()
1369 public static StructureSelectionManager getStructureSelectionManager(
1370 StructureSelectionManagerProvider context)
1372 IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> map = Instance
1373 .getInstance().structureSelections;
1378 .getInstance().structureSelections = new IdentityHashMap<>();
1380 StructureSelectionManager instance = map.get(context);
1381 if (instance == null)
1383 // BH: actually, not possible except for coding error; this is an attempt
1384 // to discover that.
1385 if (context == null && !map.isEmpty())
1387 throw new Error(MessageManager.getString(
1388 "error.implementation_error_structure_selection_manager_null"),
1389 new NullPointerException(MessageManager
1390 .getString("exception.ssm_context_is_null")));
1393 instance = new StructureSelectionManager());
1399 * release all references associated with this manager provider
1404 public static void release(StructureSelectionManagerProvider provider)
1406 IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> map = Instance
1407 .getInstance().structureSelections;
1410 map.remove(provider);