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.ws.sifts.SiftsClient;
45 import jalview.ws.sifts.SiftsException;
46 import jalview.ws.sifts.SiftsSettings;
48 import java.io.PrintStream;
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.Collections;
52 import java.util.Enumeration;
53 import java.util.HashMap;
54 import java.util.IdentityHashMap;
55 import java.util.List;
57 import java.util.Vector;
60 import MCview.PDBChain;
61 import MCview.PDBfile;
63 public class StructureSelectionManager
65 public final static String NEWLINE = System.lineSeparator();
67 static IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> instances;
69 private List<StructureMapping> mappings = new ArrayList<>();
71 private boolean processSecondaryStructure = false;
73 private boolean secStructServices = false;
75 private boolean addTempFacAnnot = false;
77 private IProgressIndicator progressIndicator;
79 private SiftsClient siftsClient = null;
81 private long progressSessionId;
84 * Set of any registered mappings between (dataset) sequences.
86 private List<AlignedCodonFrame> seqmappings = new ArrayList<>();
88 private List<CommandListener> commandListeners = new ArrayList<>();
90 private List<SelectionListener> sel_listeners = new ArrayList<>();
93 * @return true if will try to use external services for processing secondary
96 public boolean isSecStructServices()
98 return secStructServices;
102 * control use of external services for processing secondary structure
104 * @param secStructServices
106 public void setSecStructServices(boolean secStructServices)
108 this.secStructServices = secStructServices;
112 * flag controlling addition of any kind of structural annotation
114 * @return true if temperature factor annotation will be added
116 public boolean isAddTempFacAnnot()
118 return addTempFacAnnot;
122 * set flag controlling addition of structural annotation
124 * @param addTempFacAnnot
126 public void setAddTempFacAnnot(boolean addTempFacAnnot)
128 this.addTempFacAnnot = addTempFacAnnot;
133 * @return if true, the structure manager will attempt to add secondary
134 * structure lines for unannotated sequences
137 public boolean isProcessSecondaryStructure()
139 return processSecondaryStructure;
143 * Control whether structure manager will try to annotate mapped sequences
144 * with secondary structure from PDB data.
148 public void setProcessSecondaryStructure(boolean enable)
150 processSecondaryStructure = enable;
154 * debug function - write all mappings to stdout
156 public void reportMapping()
158 if (mappings.isEmpty())
160 System.err.println("reportMapping: No PDB/Sequence mappings.");
165 "reportMapping: There are " + mappings.size() + " mappings.");
167 for (StructureMapping sm : mappings)
169 System.err.println("mapping " + i++ + " : " + sm.pdbfile);
175 * map between the PDB IDs (or structure identifiers) used by Jalview and the
176 * absolute filenames for PDB data that corresponds to it
178 Map<String, String> pdbIdFileName = new HashMap<>();
180 Map<String, String> pdbFileNameId = new HashMap<>();
182 public void registerPDBFile(String idForFile, String absoluteFile)
184 pdbIdFileName.put(idForFile, absoluteFile);
185 pdbFileNameId.put(absoluteFile, idForFile);
188 public String findIdForPDBFile(String idOrFile)
190 String id = pdbFileNameId.get(idOrFile);
194 public String findFileForPDBId(String idOrFile)
196 String id = pdbIdFileName.get(idOrFile);
200 public boolean isPDBFileRegistered(String idOrFile)
202 return pdbFileNameId.containsKey(idOrFile)
203 || pdbIdFileName.containsKey(idOrFile);
206 private static StructureSelectionManager nullProvider = null;
208 public static StructureSelectionManager getStructureSelectionManager(
209 StructureSelectionManagerProvider context)
213 if (nullProvider == null)
215 if (instances != null)
217 throw new Error(MessageManager.getString(
218 "error.implementation_error_structure_selection_manager_null"),
219 new NullPointerException(MessageManager
220 .getString("exception.ssm_context_is_null")));
224 nullProvider = new StructureSelectionManager();
229 if (instances == null)
231 instances = new java.util.IdentityHashMap<>();
233 StructureSelectionManager instance = instances.get(context);
234 if (instance == null)
236 if (nullProvider != null)
238 instance = nullProvider;
242 instance = new StructureSelectionManager();
244 instances.put(context, instance);
250 * flag controlling whether SeqMappings are relayed from received sequence
251 * mouse over events to other sequences
253 boolean relaySeqMappings = true;
256 * Enable or disable relay of seqMapping events to other sequences. You might
257 * want to do this if there are many sequence mappings and the host computer
262 public void setRelaySeqMappings(boolean relay)
264 relaySeqMappings = relay;
268 * get the state of the relay seqMappings flag.
270 * @return true if sequence mouse overs are being relayed to other mapped
273 public boolean isRelaySeqMappingsEnabled()
275 return relaySeqMappings;
278 Vector listeners = new Vector();
281 * register a listener for alignment sequence mouseover events
285 public void addStructureViewerListener(Object svl)
287 if (!listeners.contains(svl))
289 listeners.addElement(svl);
294 * Returns the file name for a mapped PDB id (or null if not mapped).
299 public String alreadyMappedToFile(String pdbid)
301 for (StructureMapping sm : mappings)
303 if (sm.getPdbId().equals(pdbid))
312 * Import structure data and register a structure mapping for broadcasting
313 * colouring, mouseovers and selection events (convenience wrapper).
316 * - one or more sequences to be mapped to pdbFile
317 * @param targetChains
318 * - optional chain specification for mapping each sequence to pdb
319 * (may be nill, individual elements may be nill)
321 * - structure data resource
323 * - how to resolve data from resource
324 * @return null or the structure data parsed as a pdb file
326 synchronized public StructureFile setMapping(SequenceI[] sequence,
327 List<String>[] targetChains, String pdbFile,
328 DataSourceType protocol)
330 return setMapping(true, sequence, targetChains, pdbFile, protocol);
334 * create sequence structure mappings between each sequence and the given
335 * pdbFile (retrieved via the given protocol).
337 * @param forStructureView
338 * when true, record the mapping for use in mouseOvers
340 * @param sequenceArray
341 * - one or more sequences to be mapped to pdbFile
342 * @param targetChainIds
343 * - optional chain specification for mapping each sequence to pdb
344 * (may be nill, individual elements may be nill) - JBPNote: JAL-2693
345 * - this should be List<List<String>>, empty lists indicate no
346 * predefined mappings
348 * - structure data resource
350 * - how to resolve data from resource
351 * @return null or the structure data parsed as a pdb file
353 synchronized public StructureFile setMapping(boolean forStructureView,
354 SequenceI[] sequenceArray, List<String>[] targetChainIds,
355 String pdbFile, DataSourceType sourceType)
358 * There will be better ways of doing this in the future, for now we'll use
359 * the tried and tested MCview pdb mapping
361 boolean parseSecStr = processSecondaryStructure;
362 if (isPDBFileRegistered(pdbFile))
364 for (SequenceI sq : sequenceArray)
367 while (ds.getDatasetSequence() != null)
369 ds = ds.getDatasetSequence();
372 if (ds.getAnnotation() != null)
374 for (AlignmentAnnotation ala : ds.getAnnotation())
376 // false if any annotation present from this structure
377 // JBPNote this fails for jmol/chimera view because the *file* is
378 // passed, not the structure data ID -
379 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
387 StructureFile pdb = null;
388 boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
391 sourceType = AppletFormatAdapter.checkProtocol(pdbFile);
392 pdb = new JmolParser(pdbFile, sourceType);
394 if (pdb.getId() != null && pdb.getId().trim().length() > 0
395 && DataSourceType.FILE == sourceType)
397 registerPDBFile(pdb.getId().trim(), pdbFile);
399 // if PDBId is unavailable then skip SIFTS mapping execution path
400 isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable();
402 } catch (Exception ex)
404 ex.printStackTrace();
412 siftsClient = new SiftsClient(pdb);
414 } catch (SiftsException e)
416 isMapUsingSIFTs = false;
420 List<String> targetChainId = new ArrayList();
421 String _targetChainId;
422 for (int s = 0; s < sequenceArray.length; s++)
424 boolean infChain = true;
425 final SequenceI seq = sequenceArray[s];
427 while (ds.getDatasetSequence() != null)
429 ds = ds.getDatasetSequence();
432 if (targetChainIds != null && targetChainIds[s] != null)
435 targetChainId = targetChainIds[s];
437 else if (seq.getName().indexOf("|") > -1)
439 targetChainId = new ArrayList();
440 _targetChainId=seq.getName()
441 .substring(seq.getName().lastIndexOf("|") + 1);
442 if (_targetChainId.length() > 1)
444 if (_targetChainId.trim().length() == 0)
446 _targetChainId = " ";
450 // not a valid chain identifier
454 targetChainId.add(_targetChainId);
463 * Attempt pairwise alignment of the sequence with each chain in the PDB,
464 * and remember the highest scoring chain
467 AlignSeq maxAlignseq = null;
468 String maxChainId = " ";
469 PDBChain maxChain = null;
470 boolean first = true;
471 List<PDBChain> maximalChain = new ArrayList<>();
472 List<AlignSeq> maximalAlignseqs = new ArrayList<>();
473 List<String> maximalChainIds = new ArrayList<>();
474 for (PDBChain chain : pdb.getChains())
476 if (targetChainId.size() > 0 && !targetChainId.contains(chain.id)
479 continue; // don't try to map chains don't match.
481 // TODO: correctly determine sequence type for mixed na/peptide
483 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
484 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
487 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
488 // as.calcScoreMatrix();
489 // as.traceAlignment();
491 if (targetChainId.size() > 0 && targetChainId.contains(chain.id))
493 // Don't care - just pick this chain as the mapping
497 maxChainId = chain.id;
498 // if targetChainId is specified then it is expected to be unique, so
499 // precisely one maximal chain will be added
500 maximalChainIds.add(chain.id);
501 maximalChain.add(chain);
502 maximalAlignseqs.add(as);
506 // select chains with maximal mappings to this sequence
507 if (first || as.maxscore > max)
509 // clear out old maximal mappings (if any)
511 maximalChain.clear();
515 maxChainId = chain.id;
518 if (as.maxscore == max)
520 maximalChainIds.add(chain.id);
521 maximalChain.add(chain);
522 maximalAlignseqs.add(as);
526 if (maxChain == null)
531 if (sourceType == DataSourceType.PASTE)
533 pdbFile = "INLINE" + pdb.getId();
536 List<StructureMapping> seqToStrucMapping = new ArrayList<>();
537 if (isMapUsingSIFTs && seq.isProtein())
539 setProgressBar(null);
540 setProgressBar(MessageManager
541 .getString("status.obtaining_mapping_with_sifts"));
542 jalview.datamodel.Mapping sqmpping = maxAlignseq
543 .getMappingFromS1(false);
544 if (targetChainId != null && !targetChainId.isEmpty())
546 List<StructureMapping> siftsMappings;
549 siftsMappings = getStructureMapping(seq, pdbFile, targetChainId,
550 pdb, maxChain, sqmpping, maxAlignseq);
551 for (StructureMapping siftsMapping : siftsMappings)
553 seqToStrucMapping.add(siftsMapping);
554 maxChain.makeExactMapping(maxAlignseq, seq);
555 maxChain.transferRESNUMFeatures(seq, null);// FIXME: is this
557 maxChain.transferResidueAnnotation(siftsMapping, sqmpping);
558 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
561 } catch (SiftsException e)
563 // fall back to NW alignment
564 System.err.println(e.getMessage());
565 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
566 maximalChainIds, maximalChain, pdb, maximalAlignseqs)
568 seqToStrucMapping.add(nwMapping);
569 maxChain.makeExactMapping(maxAlignseq, seq);
570 maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
572 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
573 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
578 List<StructureMapping> foundSiftsMappings = new ArrayList<>();
579 for (PDBChain chain : pdb.getChains())
583 foundSiftsMappings.addAll(getStructureMapping(seq, pdbFile,
584 Arrays.asList(new String[]
585 { chain.id }), pdb, chain, sqmpping, maxAlignseq));
586 } catch (SiftsException e)
588 System.err.println(e.getMessage());
591 if (!foundSiftsMappings.isEmpty())
593 seqToStrucMapping.addAll(foundSiftsMappings);
594 maxChain.makeExactMapping(maxAlignseq, seq);
595 maxChain.transferRESNUMFeatures(seq, null);// FIXME: is this
597 maxChain.transferResidueAnnotation(foundSiftsMappings.get(0),
599 ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
603 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
604 maximalChainIds, maximalChain, pdb, maximalAlignseqs)
606 seqToStrucMapping.add(nwMapping);
607 maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
609 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
610 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
616 setProgressBar(null);
617 setProgressBar(MessageManager
618 .getString("status.obtaining_mapping_with_nw_alignment"));
619 List<StructureMapping> nwMapping = getNWMappings(seq, pdbFile,
620 maximalChainIds, maximalChain, pdb, maximalAlignseqs);
621 seqToStrucMapping.addAll(nwMapping);
622 for (PDBChain mc : maximalChain)
624 ds.addPDBId(mc.sequence.getAllPDBEntries().get(0));
630 if (forStructureView)
632 mappings.addAll(seqToStrucMapping);
638 public void addStructureMapping(StructureMapping sm)
644 * retrieve a mapping for seq from SIFTs using associated DBRefEntry for
649 * @param targetChainId
655 * @throws SiftsException
657 private List<StructureMapping> getStructureMapping(SequenceI seq,
658 String pdbFile, List<String> targetChainIdList, StructureFile pdb,
659 PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
660 AlignSeq maxAlignseq) throws SiftsException
662 List<StructureMapping> currChainMappingList = new ArrayList();
666 String targetChainId = (targetChainIdList == null
667 || p >= targetChainIdList.size()) ? null
668 : targetChainIdList.get(p);
669 StructureMapping curChainMapping = siftsClient
671 .getSiftsStructureMapping(seq, pdbFile, targetChainId);
674 PDBChain chain = pdb.findChain(targetChainId);
677 chain.transferResidueAnnotation(curChainMapping, sqmpping);
678 currChainMappingList.add(curChainMapping);
680 } catch (Exception e)
684 } while (targetChainIdList != null && ++p < targetChainIdList.size());
685 return currChainMappingList;
688 private List<StructureMapping> getNWMappings(SequenceI seq,
690 List<String> maximalChainId, List<PDBChain> maximalChain,
691 StructureFile pdb, List<AlignSeq> maximalAlignseq)
693 List<StructureMapping> nwMappings = new ArrayList();
694 for (int ch = 0; ch < maximalChain.size(); ch++)
696 String maxChainId = maximalChainId.get(ch);
697 PDBChain maxChain = maximalChain.get(ch);
698 AlignSeq maxAlignseq = maximalAlignseq.get(ch);
699 final StringBuilder mappingDetails = new StringBuilder(128);
700 mappingDetails.append(NEWLINE)
701 .append("Sequence \u27f7 Structure mapping details");
702 mappingDetails.append(NEWLINE);
704 .append("Method: inferred with Needleman & Wunsch alignment");
705 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
706 .append(NEWLINE).append("Sequence = ")
707 .append(maxChain.sequence.getSequenceAsString());
708 mappingDetails.append(NEWLINE).append("No of residues = ")
709 .append(maxChain.residues.size()).append(NEWLINE)
711 PrintStream ps = new PrintStream(System.out)
714 public void print(String x)
716 mappingDetails.append(x);
720 public void println()
722 mappingDetails.append(NEWLINE);
726 maxAlignseq.printAlignment(ps);
728 mappingDetails.append(NEWLINE).append("PDB start/end ");
729 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
731 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
732 mappingDetails.append(NEWLINE).append("SEQ start/end ");
735 .valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
737 mappingDetails.append(
738 String.valueOf(maxAlignseq.seq1end + (seq.getStart() - 1)));
739 mappingDetails.append(NEWLINE);
740 maxChain.makeExactMapping(maxAlignseq, seq);
741 jalview.datamodel.Mapping sqmpping = maxAlignseq
742 .getMappingFromS1(false);
743 maxChain.transferRESNUMFeatures(seq, null);
745 HashMap<Integer, int[]> mapping = new HashMap<>();
752 Atom tmp = maxChain.atoms.elementAt(index);
753 if ((resNum != tmp.resNumber || insCode != tmp.insCode)
754 && tmp.alignmentMapping != -1)
756 resNum = tmp.resNumber;
757 insCode = tmp.insCode;
758 if (tmp.alignmentMapping >= -1)
760 mapping.put(tmp.alignmentMapping + 1,
762 { tmp.resNumber, tmp.atomIndex });
767 } while (index < maxChain.atoms.size());
769 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
770 pdb.getId(), maxChainId, mapping, mappingDetails.toString());
771 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
772 nwMappings.add(nwMapping);
777 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
779 listeners.removeElement(svl);
780 if (svl instanceof SequenceListener)
782 for (int i = 0; i < listeners.size(); i++)
784 if (listeners.elementAt(i) instanceof StructureListener)
786 ((StructureListener) listeners.elementAt(i))
787 .releaseReferences(svl);
792 if (pdbfiles == null)
798 * Remove mappings to the closed listener's PDB files, but first check if
799 * another listener is still interested
801 List<String> pdbs = new ArrayList<>(Arrays.asList(pdbfiles));
803 StructureListener sl;
804 for (int i = 0; i < listeners.size(); i++)
806 if (listeners.elementAt(i) instanceof StructureListener)
808 sl = (StructureListener) listeners.elementAt(i);
809 for (String pdbfile : sl.getStructureFiles())
811 pdbs.remove(pdbfile);
817 * Rebuild the mappings set, retaining only those which are for 'other' PDB
822 List<StructureMapping> tmp = new ArrayList<>();
823 for (StructureMapping sm : mappings)
825 if (!pdbs.contains(sm.pdbfile))
836 * Propagate mouseover of a single position in a structure
842 public void mouseOverStructure(int pdbResNum, String chain,
845 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
846 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
847 mouseOverStructure(atoms);
851 * Propagate mouseover or selection of multiple positions in a structure
855 public void mouseOverStructure(List<AtomSpec> atoms)
857 if (listeners == null)
859 // old or prematurely sent event
862 boolean hasSequenceListener = false;
863 for (int i = 0; i < listeners.size(); i++)
865 if (listeners.elementAt(i) instanceof SequenceListener)
867 hasSequenceListener = true;
870 if (!hasSequenceListener)
875 SearchResultsI results = findAlignmentPositionsForStructurePositions(
877 for (Object li : listeners)
879 if (li instanceof SequenceListener)
881 ((SequenceListener) li).highlightSequence(results);
887 * Constructs a SearchResults object holding regions (if any) in the Jalview
888 * alignment which have a mapping to the structure viewer positions in the
894 public SearchResultsI findAlignmentPositionsForStructurePositions(
895 List<AtomSpec> atoms)
897 SearchResultsI results = new SearchResults();
898 for (AtomSpec atom : atoms)
900 SequenceI lastseq = null;
902 for (StructureMapping sm : mappings)
904 if (sm.pdbfile.equals(atom.getPdbFile())
905 && sm.pdbchain.equals(atom.getChain()))
907 int indexpos = sm.getSeqPos(atom.getPdbResNum());
908 if (lastipos != indexpos && lastseq != sm.sequence)
910 results.addResult(sm.sequence, indexpos, indexpos);
912 lastseq = sm.sequence;
913 // construct highlighted sequence list
914 for (AlignedCodonFrame acf : seqmappings)
916 acf.markMappedRegion(sm.sequence, indexpos, results);
926 * highlight regions associated with a position (indexpos) in seq
929 * the sequence that the mouse over occurred on
931 * the absolute position being mouseovered in seq (0 to seq.length())
933 * the sequence position (if -1, seq.findPosition is called to
934 * resolve the residue number)
936 public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
939 boolean hasSequenceListeners = handlingVamsasMo
940 || !seqmappings.isEmpty();
941 SearchResultsI results = null;
944 seqPos = seq.findPosition(indexpos);
946 for (int i = 0; i < listeners.size(); i++)
948 Object listener = listeners.elementAt(i);
949 if (listener == source)
951 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
952 // Temporary fudge with SequenceListener.getVamsasSource()
955 if (listener instanceof StructureListener)
957 highlightStructure((StructureListener) listener, seq, seqPos);
961 if (listener instanceof SequenceListener)
963 final SequenceListener seqListener = (SequenceListener) listener;
964 if (hasSequenceListeners
965 && seqListener.getVamsasSource() != source)
967 if (relaySeqMappings)
971 results = MappingUtils.buildSearchResults(seq, seqPos,
974 if (handlingVamsasMo)
976 results.addResult(seq, seqPos, seqPos);
979 if (!results.isEmpty())
981 seqListener.highlightSequence(results);
986 else if (listener instanceof VamsasListener && !handlingVamsasMo)
988 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
991 else if (listener instanceof SecondaryStructureListener)
993 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
1001 * Send suitable messages to a StructureListener to highlight atoms
1002 * corresponding to the given sequence position(s)
1008 public void highlightStructure(StructureListener sl, SequenceI seq,
1011 if (!sl.isListeningFor(seq))
1016 List<AtomSpec> atoms = new ArrayList<>();
1017 for (StructureMapping sm : mappings)
1019 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
1020 || (sm.sequence.getDatasetSequence() != null && sm.sequence
1021 .getDatasetSequence() == seq.getDatasetSequence()))
1023 for (int index : positions)
1025 atomNo = sm.getAtomNum(index);
1029 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
1030 sm.getPDBResNum(index), atomNo));
1035 sl.highlightAtoms(atoms);
1039 * true if a mouse over event from an external (ie Vamsas) source is being
1042 boolean handlingVamsasMo = false;
1047 * as mouseOverSequence but only route event to SequenceListeners
1051 * in an alignment sequence
1053 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
1054 VamsasSource source)
1056 handlingVamsasMo = true;
1057 long msg = sequenceI.hashCode() * (1 + position);
1061 mouseOverSequence(sequenceI, position, -1, source);
1063 handlingVamsasMo = false;
1066 public Annotation[] colourSequenceFromStructure(SequenceI seq,
1070 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
1071 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
1073 * Annotation [] annotations = new Annotation[seq.getLength()];
1075 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
1076 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
1077 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
1079 * for (int j = 0; j < mappings.length; j++) {
1081 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
1082 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
1083 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
1084 * "+mappings[j].pdbfile);
1086 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
1087 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
1089 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
1090 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
1091 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
1092 * mappings[j].pdbfile); }
1094 * annotations[index] = new Annotation("X",null,' ',0,col); } return
1095 * annotations; } } } }
1097 * return annotations;
1101 public void structureSelectionChanged()
1105 public void sequenceSelectionChanged()
1109 public void sequenceColoursChanged(Object source)
1111 StructureListener sl;
1112 for (int i = 0; i < listeners.size(); i++)
1114 if (listeners.elementAt(i) instanceof StructureListener)
1116 sl = (StructureListener) listeners.elementAt(i);
1117 sl.updateColours(source);
1122 public StructureMapping[] getMapping(String pdbfile)
1124 List<StructureMapping> tmp = new ArrayList<>();
1125 for (StructureMapping sm : mappings)
1127 if (sm.pdbfile.equals(pdbfile))
1132 return tmp.toArray(new StructureMapping[tmp.size()]);
1136 * Returns a readable description of all mappings for the given pdbfile to any
1137 * of the given sequences
1143 public String printMappings(String pdbfile, List<SequenceI> seqs)
1145 if (pdbfile == null || seqs == null || seqs.isEmpty())
1150 StringBuilder sb = new StringBuilder(64);
1151 for (StructureMapping sm : mappings)
1153 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
1155 sb.append(sm.mappingDetails);
1157 // separator makes it easier to read multiple mappings
1158 sb.append("=====================");
1164 return sb.toString();
1168 * Remove the given mapping
1172 public void deregisterMapping(AlignedCodonFrame acf)
1176 boolean removed = seqmappings.remove(acf);
1177 if (removed && seqmappings.isEmpty())
1179 System.out.println("All mappings removed");
1185 * Add each of the given codonFrames to the stored set, if not aready present.
1189 public void registerMappings(List<AlignedCodonFrame> mappings)
1191 if (mappings != null)
1193 for (AlignedCodonFrame acf : mappings)
1195 registerMapping(acf);
1201 * Add the given mapping to the stored set, unless already stored.
1203 public void registerMapping(AlignedCodonFrame acf)
1207 if (!seqmappings.contains(acf))
1209 seqmappings.add(acf);
1215 * Resets this object to its initial state by removing all registered
1216 * listeners, codon mappings, PDB file mappings
1218 public void resetAll()
1220 if (mappings != null)
1224 if (seqmappings != null)
1226 seqmappings.clear();
1228 if (sel_listeners != null)
1230 sel_listeners.clear();
1232 if (listeners != null)
1236 if (commandListeners != null)
1238 commandListeners.clear();
1240 if (view_listeners != null)
1242 view_listeners.clear();
1244 if (pdbFileNameId != null)
1246 pdbFileNameId.clear();
1248 if (pdbIdFileName != null)
1250 pdbIdFileName.clear();
1254 public void addSelectionListener(SelectionListener selecter)
1256 if (!sel_listeners.contains(selecter))
1258 sel_listeners.add(selecter);
1262 public void removeSelectionListener(SelectionListener toremove)
1264 if (sel_listeners.contains(toremove))
1266 sel_listeners.remove(toremove);
1270 public synchronized void sendSelection(
1271 jalview.datamodel.SequenceGroup selection,
1272 jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
1273 SelectionSource source)
1275 for (SelectionListener slis : sel_listeners)
1279 slis.selection(selection, colsel, hidden, source);
1284 Vector<AlignmentViewPanelListener> view_listeners = new Vector<>();
1286 public synchronized void sendViewPosition(
1287 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1288 int startSeq, int endSeq)
1291 if (view_listeners != null && view_listeners.size() > 0)
1293 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1295 while (listeners.hasMoreElements())
1297 AlignmentViewPanelListener slis = listeners.nextElement();
1300 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1308 * release all references associated with this manager provider
1310 * @param jalviewLite
1312 public static void release(StructureSelectionManagerProvider jalviewLite)
1314 // synchronized (instances)
1316 if (instances == null)
1320 StructureSelectionManager mnger = (instances.get(jalviewLite));
1323 instances.remove(jalviewLite);
1327 } catch (Throwable x)
1334 public void registerPDBEntry(PDBEntry pdbentry)
1336 if (pdbentry.getFile() != null
1337 && pdbentry.getFile().trim().length() > 0)
1339 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1343 public void addCommandListener(CommandListener cl)
1345 if (!commandListeners.contains(cl))
1347 commandListeners.add(cl);
1351 public boolean hasCommandListener(CommandListener cl)
1353 return this.commandListeners.contains(cl);
1356 public boolean removeCommandListener(CommandListener l)
1358 return commandListeners.remove(l);
1362 * Forward a command to any command listeners (except for the command's
1366 * the command to be broadcast (in its form after being performed)
1368 * if true, the command was being 'undone'
1371 public void commandPerformed(CommandI command, boolean undo,
1372 VamsasSource source)
1374 for (CommandListener listener : commandListeners)
1376 listener.mirrorCommand(command, undo, this, source);
1381 * Returns a new CommandI representing the given command as mapped to the
1382 * given sequences. If no mapping could be made, or the command is not of a
1383 * mappable kind, returns null.
1391 public CommandI mapCommand(CommandI command, boolean undo,
1392 final AlignmentI mapTo, char gapChar)
1394 if (command instanceof EditCommand)
1396 return MappingUtils.mapEditCommand((EditCommand) command, undo, mapTo,
1397 gapChar, seqmappings);
1399 else if (command instanceof OrderCommand)
1401 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1402 mapTo, seqmappings);
1407 public IProgressIndicator getProgressIndicator()
1409 return progressIndicator;
1412 public void setProgressIndicator(IProgressIndicator progressIndicator)
1414 this.progressIndicator = progressIndicator;
1417 public long getProgressSessionId()
1419 return progressSessionId;
1422 public void setProgressSessionId(long progressSessionId)
1424 this.progressSessionId = progressSessionId;
1427 public void setProgressBar(String message)
1429 if (progressIndicator == null)
1433 progressIndicator.setProgressBar(message, progressSessionId);
1436 public List<AlignedCodonFrame> getSequenceMappings()
1442 * utilty method - transform array of chain characters
1445 * @return array of lists with a chain in each
1447 public static List<String>[] perChainList(String[] chains)
1449 List<String>[] chainsL = new List[chains.length];
1451 for (String ch : chains)
1453 chainsL[p] = new ArrayList();
1454 chainsL[p++].add(ch);