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;
78 * Set of any registered mappings between (dataset) sequences.
80 private List<AlignedCodonFrame> seqmappings = new ArrayList<>();
82 private List<CommandListener> commandListeners = new ArrayList<>();
84 private List<SelectionListener> sel_listeners = new ArrayList<>();
87 * @return true if will try to use external services for processing secondary
90 public boolean isSecStructServices()
92 return secStructServices;
96 * control use of external services for processing secondary structure
98 * @param secStructServices
100 public void setSecStructServices(boolean secStructServices)
102 this.secStructServices = secStructServices;
106 * flag controlling addition of any kind of structural annotation
108 * @return true if temperature factor annotation will be added
110 public boolean isAddTempFacAnnot()
112 return addTempFacAnnot;
116 * set flag controlling addition of structural annotation
118 * @param addTempFacAnnot
120 public void setAddTempFacAnnot(boolean addTempFacAnnot)
122 this.addTempFacAnnot = addTempFacAnnot;
127 * @return if true, the structure manager will attempt to add secondary
128 * structure lines for unannotated sequences
131 public boolean isProcessSecondaryStructure()
133 return processSecondaryStructure;
137 * Control whether structure manager will try to annotate mapped sequences
138 * with secondary structure from PDB data.
142 public void setProcessSecondaryStructure(boolean enable)
144 processSecondaryStructure = enable;
148 * debug function - write all mappings to stdout
150 public void reportMapping()
152 if (mappings.isEmpty())
154 System.err.println("reportMapping: No PDB/Sequence mappings.");
159 "reportMapping: There are " + mappings.size() + " mappings.");
161 for (StructureMapping sm : mappings)
163 System.err.println("mapping " + i++ + " : " + sm.pdbfile);
169 * map between the PDB IDs (or structure identifiers) used by Jalview and the
170 * absolute filenames for PDB data that corresponds to it
172 Map<String, String> pdbIdFileName = new HashMap<>();
174 Map<String, String> pdbFileNameId = new HashMap<>();
176 public void registerPDBFile(String idForFile, String absoluteFile)
178 pdbIdFileName.put(idForFile, absoluteFile);
179 pdbFileNameId.put(absoluteFile, idForFile);
182 public String findIdForPDBFile(String idOrFile)
184 String id = pdbFileNameId.get(idOrFile);
188 public String findFileForPDBId(String idOrFile)
190 String id = pdbIdFileName.get(idOrFile);
194 public boolean isPDBFileRegistered(String idOrFile)
196 return pdbFileNameId.containsKey(idOrFile)
197 || pdbIdFileName.containsKey(idOrFile);
200 private static StructureSelectionManager nullProvider = null;
202 public static StructureSelectionManager getStructureSelectionManager(
203 StructureSelectionManagerProvider context)
207 if (nullProvider == null)
209 if (instances != null)
211 throw new Error(MessageManager.getString(
212 "error.implementation_error_structure_selection_manager_null"),
213 new NullPointerException(MessageManager
214 .getString("exception.ssm_context_is_null")));
218 nullProvider = new StructureSelectionManager();
223 if (instances == null)
225 instances = new java.util.IdentityHashMap<>();
227 StructureSelectionManager instance = instances.get(context);
228 if (instance == null)
230 if (nullProvider != null)
232 instance = nullProvider;
236 instance = new StructureSelectionManager();
238 instances.put(context, instance);
244 * flag controlling whether SeqMappings are relayed from received sequence
245 * mouse over events to other sequences
247 boolean relaySeqMappings = true;
250 * Enable or disable relay of seqMapping events to other sequences. You might
251 * want to do this if there are many sequence mappings and the host computer
256 public void setRelaySeqMappings(boolean relay)
258 relaySeqMappings = relay;
262 * get the state of the relay seqMappings flag.
264 * @return true if sequence mouse overs are being relayed to other mapped
267 public boolean isRelaySeqMappingsEnabled()
269 return relaySeqMappings;
272 Vector listeners = new Vector();
275 * register a listener for alignment sequence mouseover events
279 public void addStructureViewerListener(Object svl)
281 if (!listeners.contains(svl))
283 listeners.addElement(svl);
288 * Returns the file name for a mapped PDB id (or null if not mapped).
293 public String alreadyMappedToFile(String pdbid)
295 for (StructureMapping sm : mappings)
297 if (sm.getPdbId().equals(pdbid))
306 * Import structure data and register a structure mapping for broadcasting
307 * colouring, mouseovers and selection events (convenience wrapper).
310 * - one or more sequences to be mapped to pdbFile
311 * @param targetChains
312 * - optional chain specification for mapping each sequence to pdb
313 * (may be nill, individual elements may be nill)
315 * - structure data resource
317 * - how to resolve data from resource
318 * @return null or the structure data parsed as a pdb file
320 synchronized public StructureFile setMapping(SequenceI[] sequence,
321 String[] targetChains, String pdbFile, DataSourceType protocol,
322 IProgressIndicator progress)
324 return computeMapping(true, sequence, targetChains, pdbFile, protocol,
329 * Import a single structure file and register sequence structure mappings for
330 * broadcasting colouring, mouseovers and selection events (convenience
333 * @param forStructureView
334 * when true, record the mapping for use in mouseOvers
336 * - one or more sequences to be mapped to pdbFile
337 * @param targetChains
338 * - optional chain specification for mapping each sequence to pdb
339 * (may be nill, individual elements may be nill)
341 * - structure data resource
343 * - how to resolve data from resource
344 * @return null or the structure data parsed as a pdb file
346 synchronized public StructureFile setMapping(boolean forStructureView,
347 SequenceI[] sequenceArray, String[] targetChainIds,
348 String pdbFile, DataSourceType sourceType)
350 return computeMapping(forStructureView, sequenceArray, targetChainIds,
351 pdbFile, sourceType, null);
355 * create sequence structure mappings between each sequence and the given
356 * pdbFile (retrieved via the given protocol). Either constructs a mapping
357 * using NW alignment or derives one from any available SIFTS mapping data.
359 * @param forStructureView
360 * when true, record the mapping for use in mouseOvers
362 * @param sequenceArray
363 * - one or more sequences to be mapped to pdbFile
364 * @param targetChainIds
365 * - optional chain specification for mapping each sequence to pdb
366 * (may be nill, individual elements may be nill) - JBPNote: JAL-2693
367 * - this should be List<List<String>>, empty lists indicate no
368 * predefined mappings
370 * - structure data resource
372 * - how to resolve data from resource
373 * @param IProgressIndicator
374 * reference to UI component that maintains a progress bar for the
376 * @return null or the structure data parsed as a pdb file
378 synchronized public StructureFile computeMapping(
379 boolean forStructureView, SequenceI[] sequenceArray,
380 String[] targetChainIds, String pdbFile, DataSourceType sourceType,
381 IProgressIndicator progress)
383 long progressSessionId = System.currentTimeMillis() * 3;
386 * do we extract and transfer annotation from 3D data ?
388 // FIXME: possibly should just delete
390 boolean parseSecStr = processSecondaryStructure
391 ? isStructureFileProcessed(pdbFile, sequenceArray)
394 StructureFile pdb = null;
395 boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
398 // FIXME if sourceType is not null, we've lost data here
399 sourceType = AppletFormatAdapter.checkProtocol(pdbFile);
400 pdb = new JmolParser(pdbFile, sourceType);
402 if (pdb.getId() != null && pdb.getId().trim().length() > 0
403 && DataSourceType.FILE == sourceType)
405 registerPDBFile(pdb.getId().trim(), pdbFile);
407 // if PDBId is unavailable then skip SIFTS mapping execution path
408 isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable();
410 } catch (Exception ex)
412 ex.printStackTrace();
416 * sifts client - non null if SIFTS mappings are to be used
418 SiftsClient siftsClient = null;
423 siftsClient = new SiftsClient(pdb);
425 } catch (SiftsException e)
427 isMapUsingSIFTs = false;
432 String targetChainId;
433 for (int s = 0; s < sequenceArray.length; s++)
435 boolean infChain = true;
436 final SequenceI seq = sequenceArray[s];
438 while (ds.getDatasetSequence() != null)
440 ds = ds.getDatasetSequence();
443 if (targetChainIds != null && targetChainIds[s] != null)
446 targetChainId = targetChainIds[s];
448 else if (seq.getName().indexOf("|") > -1)
450 targetChainId = seq.getName()
451 .substring(seq.getName().lastIndexOf("|") + 1);
452 if (targetChainId.length() > 1)
454 if (targetChainId.trim().length() == 0)
460 // not a valid chain identifier
471 * Attempt pairwise alignment of the sequence with each chain in the PDB,
472 * and remember the highest scoring chain
475 AlignSeq maxAlignseq = null;
476 String maxChainId = " ";
477 PDBChain maxChain = null;
478 boolean first = true;
479 for (PDBChain chain : pdb.getChains())
481 if (targetChainId.length() > 0 && !targetChainId.equals(chain.id)
484 continue; // don't try to map chains don't match.
486 // TODO: correctly determine sequence type for mixed na/peptide
488 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
489 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
492 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
493 // as.calcScoreMatrix();
494 // as.traceAlignment();
496 if (first || as.maxscore > max
497 || (as.maxscore == max && chain.id.equals(targetChainId)))
503 maxChainId = chain.id;
506 if (maxChain == null)
511 if (sourceType == DataSourceType.PASTE)
513 pdbFile = "INLINE" + pdb.getId();
516 List<StructureMapping> seqToStrucMapping = new ArrayList<>();
517 if (isMapUsingSIFTs && seq.isProtein())
519 if (progress!=null) {
520 progress.setProgressBar(MessageManager
521 .getString("status.obtaining_mapping_with_sifts"),
524 jalview.datamodel.Mapping sqmpping = maxAlignseq
525 .getMappingFromS1(false);
526 if (targetChainId != null && !targetChainId.trim().isEmpty())
528 StructureMapping siftsMapping;
531 siftsMapping = getStructureMapping(seq, pdbFile, targetChainId,
532 pdb, maxChain, sqmpping, maxAlignseq, siftsClient);
533 seqToStrucMapping.add(siftsMapping);
534 maxChain.makeExactMapping(siftsMapping, seq);
535 maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
537 maxChain.transferResidueAnnotation(siftsMapping, null);
538 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
540 } catch (SiftsException e)
542 // fall back to NW alignment
543 System.err.println(e.getMessage());
544 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
545 targetChainId, maxChain, pdb, maxAlignseq);
546 seqToStrucMapping.add(nwMapping);
547 maxChain.makeExactMapping(maxAlignseq, seq);
548 maxChain.transferRESNUMFeatures(seq, "IEA:Jalview"); // FIXME: is
551 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
552 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
557 List<StructureMapping> foundSiftsMappings = new ArrayList<>();
558 for (PDBChain chain : pdb.getChains())
560 StructureMapping siftsMapping = null;
563 siftsMapping = getStructureMapping(seq,
564 pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq,
566 foundSiftsMappings.add(siftsMapping);
567 chain.makeExactMapping(siftsMapping, seq);
568 chain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
570 chain.transferResidueAnnotation(siftsMapping, null);
571 } catch (SiftsException e)
573 System.err.println(e.getMessage());
579 "Unexpected exception during SIFTS mapping - falling back to NW for this sequence/structure pair");
580 System.err.println(e.getMessage());
583 if (!foundSiftsMappings.isEmpty())
585 seqToStrucMapping.addAll(foundSiftsMappings);
586 ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
590 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
591 maxChainId, maxChain, pdb, maxAlignseq);
592 seqToStrucMapping.add(nwMapping);
593 maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
595 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
596 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
602 if (progress != null)
604 progress.setProgressBar(MessageManager
605 .getString("status.obtaining_mapping_with_nw_alignment"),
608 StructureMapping nwMapping = getNWMappings(seq, pdbFile, maxChainId,
609 maxChain, pdb, maxAlignseq);
610 seqToStrucMapping.add(nwMapping);
611 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
613 if (forStructureView)
615 mappings.addAll(seqToStrucMapping);
617 if (progress != null)
619 progress.setProgressBar(null, progressSessionId);
626 * check if we need to extract secondary structure from given pdbFile and
627 * transfer to sequences
630 * @param sequenceArray
633 private boolean isStructureFileProcessed(String pdbFile,
634 SequenceI[] sequenceArray)
636 boolean parseSecStr = true;
637 if (isPDBFileRegistered(pdbFile))
639 for (SequenceI sq : sequenceArray)
642 while (ds.getDatasetSequence() != null)
644 ds = ds.getDatasetSequence();
647 if (ds.getAnnotation() != null)
649 for (AlignmentAnnotation ala : ds.getAnnotation())
651 // false if any annotation present from this structure
652 // JBPNote this fails for jmol/chimera view because the *file* is
653 // passed, not the structure data ID -
654 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
665 public void addStructureMapping(StructureMapping sm)
671 * retrieve a mapping for seq from SIFTs using associated DBRefEntry for
676 * @param targetChainId
682 * client for retrieval of SIFTS mappings for this structure
684 * @throws SiftsException
686 private StructureMapping getStructureMapping(SequenceI seq,
687 String pdbFile, String targetChainId, StructureFile pdb,
688 PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
689 AlignSeq maxAlignseq, SiftsClient siftsClient) throws SiftsException
691 StructureMapping curChainMapping = siftsClient
692 .getSiftsStructureMapping(seq, pdbFile, targetChainId);
695 PDBChain chain = pdb.findChain(targetChainId);
698 chain.transferResidueAnnotation(curChainMapping, null);
700 } catch (Exception e)
704 return curChainMapping;
707 private StructureMapping getNWMappings(SequenceI seq, String pdbFile,
708 String maxChainId, PDBChain maxChain, StructureFile pdb,
709 AlignSeq maxAlignseq)
711 final StringBuilder mappingDetails = new StringBuilder(128);
712 mappingDetails.append(NEWLINE)
713 .append("Sequence \u27f7 Structure mapping details");
714 mappingDetails.append(NEWLINE);
716 .append("Method: inferred with Needleman & Wunsch alignment");
717 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
718 .append(NEWLINE).append("Sequence = ")
719 .append(maxChain.sequence.getSequenceAsString());
720 mappingDetails.append(NEWLINE).append("No of residues = ")
721 .append(maxChain.residues.size()).append(NEWLINE)
723 PrintStream ps = new PrintStream(System.out)
726 public void print(String x)
728 mappingDetails.append(x);
732 public void println()
734 mappingDetails.append(NEWLINE);
738 maxAlignseq.printAlignment(ps);
740 mappingDetails.append(NEWLINE).append("PDB start/end ");
741 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
743 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
744 mappingDetails.append(NEWLINE).append("SEQ start/end ");
747 .valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
749 mappingDetails.append(
750 String.valueOf(maxAlignseq.seq1end + (seq.getStart() - 1)));
751 mappingDetails.append(NEWLINE);
752 maxChain.makeExactMapping(maxAlignseq, seq);
753 jalview.datamodel.Mapping sqmpping = maxAlignseq
754 .getMappingFromS1(false);
755 maxChain.transferRESNUMFeatures(seq, null);
757 HashMap<Integer, int[]> mapping = new HashMap<>();
764 Atom tmp = maxChain.atoms.elementAt(index);
765 if ((resNum != tmp.resNumber || insCode != tmp.insCode)
766 && tmp.alignmentMapping != -1)
768 resNum = tmp.resNumber;
769 insCode = tmp.insCode;
770 if (tmp.alignmentMapping >= -1)
772 mapping.put(tmp.alignmentMapping + 1,
774 { tmp.resNumber, tmp.atomIndex });
779 } while (index < maxChain.atoms.size());
781 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
782 pdb.getId(), maxChainId, mapping, mappingDetails.toString());
783 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
787 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
789 listeners.removeElement(svl);
790 if (svl instanceof SequenceListener)
792 for (int i = 0; i < listeners.size(); i++)
794 if (listeners.elementAt(i) instanceof StructureListener)
796 ((StructureListener) listeners.elementAt(i))
797 .releaseReferences(svl);
802 if (pdbfiles == null)
808 * Remove mappings to the closed listener's PDB files, but first check if
809 * another listener is still interested
811 List<String> pdbs = new ArrayList<>(Arrays.asList(pdbfiles));
813 StructureListener sl;
814 for (int i = 0; i < listeners.size(); i++)
816 if (listeners.elementAt(i) instanceof StructureListener)
818 sl = (StructureListener) listeners.elementAt(i);
819 for (String pdbfile : sl.getStructureFiles())
821 pdbs.remove(pdbfile);
827 * Rebuild the mappings set, retaining only those which are for 'other' PDB
832 List<StructureMapping> tmp = new ArrayList<>();
833 for (StructureMapping sm : mappings)
835 if (!pdbs.contains(sm.pdbfile))
846 * Propagate mouseover of a single position in a structure
852 public void mouseOverStructure(int pdbResNum, String chain,
855 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
856 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
857 mouseOverStructure(atoms);
861 * Propagate mouseover or selection of multiple positions in a structure
865 public void mouseOverStructure(List<AtomSpec> atoms)
867 if (listeners == null)
869 // old or prematurely sent event
872 boolean hasSequenceListener = false;
873 for (int i = 0; i < listeners.size(); i++)
875 if (listeners.elementAt(i) instanceof SequenceListener)
877 hasSequenceListener = true;
880 if (!hasSequenceListener)
885 SearchResultsI results = findAlignmentPositionsForStructurePositions(
887 for (Object li : listeners)
889 if (li instanceof SequenceListener)
891 ((SequenceListener) li).highlightSequence(results);
897 * Constructs a SearchResults object holding regions (if any) in the Jalview
898 * alignment which have a mapping to the structure viewer positions in the
904 public SearchResultsI findAlignmentPositionsForStructurePositions(
905 List<AtomSpec> atoms)
907 SearchResultsI results = new SearchResults();
908 for (AtomSpec atom : atoms)
910 SequenceI lastseq = null;
912 for (StructureMapping sm : mappings)
914 if (sm.pdbfile.equals(atom.getPdbFile())
915 && sm.pdbchain.equals(atom.getChain()))
917 int indexpos = sm.getSeqPos(atom.getPdbResNum());
918 if (lastipos != indexpos || lastseq != sm.sequence)
920 results.addResult(sm.sequence, indexpos, indexpos);
922 lastseq = sm.sequence;
923 // construct highlighted sequence list
924 for (AlignedCodonFrame acf : seqmappings)
926 acf.markMappedRegion(sm.sequence, indexpos, results);
936 * highlight regions associated with a position (indexpos) in seq
939 * the sequence that the mouse over occurred on
941 * the absolute position being mouseovered in seq (0 to seq.length())
943 * the sequence position (if -1, seq.findPosition is called to
944 * resolve the residue number)
946 public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
949 boolean hasSequenceListeners = handlingVamsasMo
950 || !seqmappings.isEmpty();
951 SearchResultsI results = null;
954 seqPos = seq.findPosition(indexpos);
956 for (int i = 0; i < listeners.size(); i++)
958 Object listener = listeners.elementAt(i);
959 if (listener == source)
961 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
962 // Temporary fudge with SequenceListener.getVamsasSource()
965 if (listener instanceof StructureListener)
967 highlightStructure((StructureListener) listener, seq, seqPos);
971 if (listener instanceof SequenceListener)
973 final SequenceListener seqListener = (SequenceListener) listener;
974 if (hasSequenceListeners
975 && seqListener.getVamsasSource() != source)
977 if (relaySeqMappings)
981 results = MappingUtils.buildSearchResults(seq, seqPos,
984 if (handlingVamsasMo)
986 results.addResult(seq, seqPos, seqPos);
989 if (!results.isEmpty())
991 seqListener.highlightSequence(results);
996 else if (listener instanceof VamsasListener && !handlingVamsasMo)
998 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
1001 else if (listener instanceof SecondaryStructureListener)
1003 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
1011 * Send suitable messages to a StructureListener to highlight atoms
1012 * corresponding to the given sequence position(s)
1018 public void highlightStructure(StructureListener sl, SequenceI seq,
1021 if (!sl.isListeningFor(seq))
1026 List<AtomSpec> atoms = new ArrayList<>();
1027 for (StructureMapping sm : mappings)
1029 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
1030 || (sm.sequence.getDatasetSequence() != null && sm.sequence
1031 .getDatasetSequence() == seq.getDatasetSequence()))
1033 for (int index : positions)
1035 atomNo = sm.getAtomNum(index);
1039 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
1040 sm.getPDBResNum(index), atomNo));
1045 sl.highlightAtoms(atoms);
1049 * true if a mouse over event from an external (ie Vamsas) source is being
1052 boolean handlingVamsasMo = false;
1057 * as mouseOverSequence but only route event to SequenceListeners
1061 * in an alignment sequence
1063 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
1064 VamsasSource source)
1066 handlingVamsasMo = true;
1067 long msg = sequenceI.hashCode() * (1 + position);
1071 mouseOverSequence(sequenceI, position, -1, source);
1073 handlingVamsasMo = false;
1076 public Annotation[] colourSequenceFromStructure(SequenceI seq,
1080 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
1081 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
1083 * Annotation [] annotations = new Annotation[seq.getLength()];
1085 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
1086 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
1087 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
1089 * for (int j = 0; j < mappings.length; j++) {
1091 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
1092 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
1093 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
1094 * "+mappings[j].pdbfile);
1096 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
1097 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
1099 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
1100 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
1101 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
1102 * mappings[j].pdbfile); }
1104 * annotations[index] = new Annotation("X",null,' ',0,col); } return
1105 * annotations; } } } }
1107 * return annotations;
1111 public void structureSelectionChanged()
1115 public void sequenceSelectionChanged()
1119 public void sequenceColoursChanged(Object source)
1121 StructureListener sl;
1122 for (int i = 0; i < listeners.size(); i++)
1124 if (listeners.elementAt(i) instanceof StructureListener)
1126 sl = (StructureListener) listeners.elementAt(i);
1127 sl.updateColours(source);
1132 public StructureMapping[] getMapping(String pdbfile)
1134 List<StructureMapping> tmp = new ArrayList<>();
1135 for (StructureMapping sm : mappings)
1137 if (sm.pdbfile.equals(pdbfile))
1142 return tmp.toArray(new StructureMapping[tmp.size()]);
1146 * Returns a readable description of all mappings for the given pdbfile to any
1147 * of the given sequences
1153 public String printMappings(String pdbfile, List<SequenceI> seqs)
1155 if (pdbfile == null || seqs == null || seqs.isEmpty())
1160 StringBuilder sb = new StringBuilder(64);
1161 for (StructureMapping sm : mappings)
1163 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
1165 sb.append(sm.mappingDetails);
1167 // separator makes it easier to read multiple mappings
1168 sb.append("=====================");
1174 return sb.toString();
1178 * Remove the given mapping
1182 public void deregisterMapping(AlignedCodonFrame acf)
1186 boolean removed = seqmappings.remove(acf);
1187 if (removed && seqmappings.isEmpty())
1189 System.out.println("All mappings removed");
1195 * Add each of the given codonFrames to the stored set, if not aready present.
1199 public void registerMappings(List<AlignedCodonFrame> mappings)
1201 if (mappings != null)
1203 for (AlignedCodonFrame acf : mappings)
1205 registerMapping(acf);
1211 * Add the given mapping to the stored set, unless already stored.
1213 public void registerMapping(AlignedCodonFrame acf)
1217 if (!seqmappings.contains(acf))
1219 seqmappings.add(acf);
1225 * Resets this object to its initial state by removing all registered
1226 * listeners, codon mappings, PDB file mappings
1228 public void resetAll()
1230 if (mappings != null)
1234 if (seqmappings != null)
1236 seqmappings.clear();
1238 if (sel_listeners != null)
1240 sel_listeners.clear();
1242 if (listeners != null)
1246 if (commandListeners != null)
1248 commandListeners.clear();
1250 if (view_listeners != null)
1252 view_listeners.clear();
1254 if (pdbFileNameId != null)
1256 pdbFileNameId.clear();
1258 if (pdbIdFileName != null)
1260 pdbIdFileName.clear();
1264 public void addSelectionListener(SelectionListener selecter)
1266 if (!sel_listeners.contains(selecter))
1268 sel_listeners.add(selecter);
1272 public void removeSelectionListener(SelectionListener toremove)
1274 if (sel_listeners.contains(toremove))
1276 sel_listeners.remove(toremove);
1280 public synchronized void sendSelection(
1281 jalview.datamodel.SequenceGroup selection,
1282 jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
1283 SelectionSource source)
1285 for (SelectionListener slis : sel_listeners)
1289 slis.selection(selection, colsel, hidden, source);
1294 Vector<AlignmentViewPanelListener> view_listeners = new Vector<>();
1296 public synchronized void sendViewPosition(
1297 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1298 int startSeq, int endSeq)
1301 if (view_listeners != null && view_listeners.size() > 0)
1303 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1305 while (listeners.hasMoreElements())
1307 AlignmentViewPanelListener slis = listeners.nextElement();
1310 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1318 * release all references associated with this manager provider
1320 * @param jalviewLite
1322 public static void release(StructureSelectionManagerProvider jalviewLite)
1324 // synchronized (instances)
1326 if (instances == null)
1330 StructureSelectionManager mnger = (instances.get(jalviewLite));
1333 instances.remove(jalviewLite);
1337 } catch (Throwable x)
1344 public void registerPDBEntry(PDBEntry pdbentry)
1346 if (pdbentry.getFile() != null
1347 && pdbentry.getFile().trim().length() > 0)
1349 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1353 public void addCommandListener(CommandListener cl)
1355 if (!commandListeners.contains(cl))
1357 commandListeners.add(cl);
1361 public boolean hasCommandListener(CommandListener cl)
1363 return this.commandListeners.contains(cl);
1366 public boolean removeCommandListener(CommandListener l)
1368 return commandListeners.remove(l);
1372 * Forward a command to any command listeners (except for the command's
1376 * the command to be broadcast (in its form after being performed)
1378 * if true, the command was being 'undone'
1381 public void commandPerformed(CommandI command, boolean undo,
1382 VamsasSource source)
1384 for (CommandListener listener : commandListeners)
1386 listener.mirrorCommand(command, undo, this, source);
1391 * Returns a new CommandI representing the given command as mapped to the
1392 * given sequences. If no mapping could be made, or the command is not of a
1393 * mappable kind, returns null.
1401 public CommandI mapCommand(CommandI command, boolean undo,
1402 final AlignmentI mapTo, char gapChar)
1404 if (command instanceof EditCommand)
1406 return MappingUtils.mapEditCommand((EditCommand) command, undo, mapTo,
1407 gapChar, seqmappings);
1409 else if (command instanceof OrderCommand)
1411 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1412 mapTo, seqmappings);
1417 public List<AlignedCodonFrame> getSequenceMappings()