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());
576 if (!foundSiftsMappings.isEmpty())
578 seqToStrucMapping.addAll(foundSiftsMappings);
579 ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
583 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
584 maxChainId, maxChain, pdb, maxAlignseq);
585 seqToStrucMapping.add(nwMapping);
586 maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
588 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
589 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
595 if (progress != null)
597 progress.setProgressBar(MessageManager
598 .getString("status.obtaining_mapping_with_nw_alignment"),
601 StructureMapping nwMapping = getNWMappings(seq, pdbFile, maxChainId,
602 maxChain, pdb, maxAlignseq);
603 seqToStrucMapping.add(nwMapping);
604 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
606 if (forStructureView)
608 mappings.addAll(seqToStrucMapping);
610 if (progress != null)
612 progress.setProgressBar(null, progressSessionId);
619 * check if we need to extract secondary structure from given pdbFile and
620 * transfer to sequences
623 * @param sequenceArray
626 private boolean isStructureFileProcessed(String pdbFile,
627 SequenceI[] sequenceArray)
629 boolean parseSecStr = true;
630 if (isPDBFileRegistered(pdbFile))
632 for (SequenceI sq : sequenceArray)
635 while (ds.getDatasetSequence() != null)
637 ds = ds.getDatasetSequence();
640 if (ds.getAnnotation() != null)
642 for (AlignmentAnnotation ala : ds.getAnnotation())
644 // false if any annotation present from this structure
645 // JBPNote this fails for jmol/chimera view because the *file* is
646 // passed, not the structure data ID -
647 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
658 public void addStructureMapping(StructureMapping sm)
664 * retrieve a mapping for seq from SIFTs using associated DBRefEntry for
669 * @param targetChainId
675 * client for retrieval of SIFTS mappings for this structure
677 * @throws SiftsException
679 private StructureMapping getStructureMapping(SequenceI seq,
680 String pdbFile, String targetChainId, StructureFile pdb,
681 PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
682 AlignSeq maxAlignseq, SiftsClient siftsClient) throws SiftsException
684 StructureMapping curChainMapping = siftsClient
685 .getSiftsStructureMapping(seq, pdbFile, targetChainId);
688 PDBChain chain = pdb.findChain(targetChainId);
691 chain.transferResidueAnnotation(curChainMapping, null);
693 } catch (Exception e)
697 return curChainMapping;
700 private StructureMapping getNWMappings(SequenceI seq, String pdbFile,
701 String maxChainId, PDBChain maxChain, StructureFile pdb,
702 AlignSeq maxAlignseq)
704 final StringBuilder mappingDetails = new StringBuilder(128);
705 mappingDetails.append(NEWLINE)
706 .append("Sequence \u27f7 Structure mapping details");
707 mappingDetails.append(NEWLINE);
709 .append("Method: inferred with Needleman & Wunsch alignment");
710 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
711 .append(NEWLINE).append("Sequence = ")
712 .append(maxChain.sequence.getSequenceAsString());
713 mappingDetails.append(NEWLINE).append("No of residues = ")
714 .append(maxChain.residues.size()).append(NEWLINE)
716 PrintStream ps = new PrintStream(System.out)
719 public void print(String x)
721 mappingDetails.append(x);
725 public void println()
727 mappingDetails.append(NEWLINE);
731 maxAlignseq.printAlignment(ps);
733 mappingDetails.append(NEWLINE).append("PDB start/end ");
734 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
736 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
737 mappingDetails.append(NEWLINE).append("SEQ start/end ");
740 .valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
742 mappingDetails.append(
743 String.valueOf(maxAlignseq.seq1end + (seq.getStart() - 1)));
744 mappingDetails.append(NEWLINE);
745 maxChain.makeExactMapping(maxAlignseq, seq);
746 jalview.datamodel.Mapping sqmpping = maxAlignseq
747 .getMappingFromS1(false);
748 maxChain.transferRESNUMFeatures(seq, null);
750 HashMap<Integer, int[]> mapping = new HashMap<>();
757 Atom tmp = maxChain.atoms.elementAt(index);
758 if ((resNum != tmp.resNumber || insCode != tmp.insCode)
759 && tmp.alignmentMapping != -1)
761 resNum = tmp.resNumber;
762 insCode = tmp.insCode;
763 if (tmp.alignmentMapping >= -1)
765 mapping.put(tmp.alignmentMapping + 1,
767 { tmp.resNumber, tmp.atomIndex });
772 } while (index < maxChain.atoms.size());
774 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
775 pdb.getId(), maxChainId, mapping, mappingDetails.toString());
776 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
780 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
782 listeners.removeElement(svl);
783 if (svl instanceof SequenceListener)
785 for (int i = 0; i < listeners.size(); i++)
787 if (listeners.elementAt(i) instanceof StructureListener)
789 ((StructureListener) listeners.elementAt(i))
790 .releaseReferences(svl);
795 if (pdbfiles == null)
801 * Remove mappings to the closed listener's PDB files, but first check if
802 * another listener is still interested
804 List<String> pdbs = new ArrayList<>(Arrays.asList(pdbfiles));
806 StructureListener sl;
807 for (int i = 0; i < listeners.size(); i++)
809 if (listeners.elementAt(i) instanceof StructureListener)
811 sl = (StructureListener) listeners.elementAt(i);
812 for (String pdbfile : sl.getStructureFiles())
814 pdbs.remove(pdbfile);
820 * Rebuild the mappings set, retaining only those which are for 'other' PDB
825 List<StructureMapping> tmp = new ArrayList<>();
826 for (StructureMapping sm : mappings)
828 if (!pdbs.contains(sm.pdbfile))
839 * Propagate mouseover of a single position in a structure
845 public void mouseOverStructure(int pdbResNum, String chain,
848 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
849 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
850 mouseOverStructure(atoms);
854 * Propagate mouseover or selection of multiple positions in a structure
858 public void mouseOverStructure(List<AtomSpec> atoms)
860 if (listeners == null)
862 // old or prematurely sent event
865 boolean hasSequenceListener = false;
866 for (int i = 0; i < listeners.size(); i++)
868 if (listeners.elementAt(i) instanceof SequenceListener)
870 hasSequenceListener = true;
873 if (!hasSequenceListener)
878 SearchResultsI results = findAlignmentPositionsForStructurePositions(
880 for (Object li : listeners)
882 if (li instanceof SequenceListener)
884 ((SequenceListener) li).highlightSequence(results);
890 * Constructs a SearchResults object holding regions (if any) in the Jalview
891 * alignment which have a mapping to the structure viewer positions in the
897 public SearchResultsI findAlignmentPositionsForStructurePositions(
898 List<AtomSpec> atoms)
900 SearchResultsI results = new SearchResults();
901 for (AtomSpec atom : atoms)
903 SequenceI lastseq = null;
905 for (StructureMapping sm : mappings)
907 if (sm.pdbfile.equals(atom.getPdbFile())
908 && sm.pdbchain.equals(atom.getChain()))
910 int indexpos = sm.getSeqPos(atom.getPdbResNum());
911 if (lastipos != indexpos || lastseq != sm.sequence)
913 results.addResult(sm.sequence, indexpos, indexpos);
915 lastseq = sm.sequence;
916 // construct highlighted sequence list
917 for (AlignedCodonFrame acf : seqmappings)
919 acf.markMappedRegion(sm.sequence, indexpos, results);
929 * highlight regions associated with a position (indexpos) in seq
932 * the sequence that the mouse over occurred on
934 * the absolute position being mouseovered in seq (0 to seq.length())
936 * the sequence position (if -1, seq.findPosition is called to
937 * resolve the residue number)
939 public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
942 boolean hasSequenceListeners = handlingVamsasMo
943 || !seqmappings.isEmpty();
944 SearchResultsI results = null;
947 seqPos = seq.findPosition(indexpos);
949 for (int i = 0; i < listeners.size(); i++)
951 Object listener = listeners.elementAt(i);
952 if (listener == source)
954 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
955 // Temporary fudge with SequenceListener.getVamsasSource()
958 if (listener instanceof StructureListener)
960 highlightStructure((StructureListener) listener, seq, seqPos);
964 if (listener instanceof SequenceListener)
966 final SequenceListener seqListener = (SequenceListener) listener;
967 if (hasSequenceListeners
968 && seqListener.getVamsasSource() != source)
970 if (relaySeqMappings)
974 results = MappingUtils.buildSearchResults(seq, seqPos,
977 if (handlingVamsasMo)
979 results.addResult(seq, seqPos, seqPos);
982 if (!results.isEmpty())
984 seqListener.highlightSequence(results);
989 else if (listener instanceof VamsasListener && !handlingVamsasMo)
991 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
994 else if (listener instanceof SecondaryStructureListener)
996 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
1004 * Send suitable messages to a StructureListener to highlight atoms
1005 * corresponding to the given sequence position(s)
1011 public void highlightStructure(StructureListener sl, SequenceI seq,
1014 if (!sl.isListeningFor(seq))
1019 List<AtomSpec> atoms = new ArrayList<>();
1020 for (StructureMapping sm : mappings)
1022 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
1023 || (sm.sequence.getDatasetSequence() != null && sm.sequence
1024 .getDatasetSequence() == seq.getDatasetSequence()))
1026 for (int index : positions)
1028 atomNo = sm.getAtomNum(index);
1032 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
1033 sm.getPDBResNum(index), atomNo));
1038 sl.highlightAtoms(atoms);
1042 * true if a mouse over event from an external (ie Vamsas) source is being
1045 boolean handlingVamsasMo = false;
1050 * as mouseOverSequence but only route event to SequenceListeners
1054 * in an alignment sequence
1056 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
1057 VamsasSource source)
1059 handlingVamsasMo = true;
1060 long msg = sequenceI.hashCode() * (1 + position);
1064 mouseOverSequence(sequenceI, position, -1, source);
1066 handlingVamsasMo = false;
1069 public Annotation[] colourSequenceFromStructure(SequenceI seq,
1073 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
1074 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
1076 * Annotation [] annotations = new Annotation[seq.getLength()];
1078 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
1079 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
1080 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
1082 * for (int j = 0; j < mappings.length; j++) {
1084 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
1085 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
1086 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
1087 * "+mappings[j].pdbfile);
1089 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
1090 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
1092 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
1093 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
1094 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
1095 * mappings[j].pdbfile); }
1097 * annotations[index] = new Annotation("X",null,' ',0,col); } return
1098 * annotations; } } } }
1100 * return annotations;
1104 public void structureSelectionChanged()
1108 public void sequenceSelectionChanged()
1112 public void sequenceColoursChanged(Object source)
1114 StructureListener sl;
1115 for (int i = 0; i < listeners.size(); i++)
1117 if (listeners.elementAt(i) instanceof StructureListener)
1119 sl = (StructureListener) listeners.elementAt(i);
1120 sl.updateColours(source);
1125 public StructureMapping[] getMapping(String pdbfile)
1127 List<StructureMapping> tmp = new ArrayList<>();
1128 for (StructureMapping sm : mappings)
1130 if (sm.pdbfile.equals(pdbfile))
1135 return tmp.toArray(new StructureMapping[tmp.size()]);
1139 * Returns a readable description of all mappings for the given pdbfile to any
1140 * of the given sequences
1146 public String printMappings(String pdbfile, List<SequenceI> seqs)
1148 if (pdbfile == null || seqs == null || seqs.isEmpty())
1153 StringBuilder sb = new StringBuilder(64);
1154 for (StructureMapping sm : mappings)
1156 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
1158 sb.append(sm.mappingDetails);
1160 // separator makes it easier to read multiple mappings
1161 sb.append("=====================");
1167 return sb.toString();
1171 * Remove the given mapping
1175 public void deregisterMapping(AlignedCodonFrame acf)
1179 boolean removed = seqmappings.remove(acf);
1180 if (removed && seqmappings.isEmpty())
1182 System.out.println("All mappings removed");
1188 * Add each of the given codonFrames to the stored set, if not aready present.
1192 public void registerMappings(List<AlignedCodonFrame> mappings)
1194 if (mappings != null)
1196 for (AlignedCodonFrame acf : mappings)
1198 registerMapping(acf);
1204 * Add the given mapping to the stored set, unless already stored.
1206 public void registerMapping(AlignedCodonFrame acf)
1210 if (!seqmappings.contains(acf))
1212 seqmappings.add(acf);
1218 * Resets this object to its initial state by removing all registered
1219 * listeners, codon mappings, PDB file mappings
1221 public void resetAll()
1223 if (mappings != null)
1227 if (seqmappings != null)
1229 seqmappings.clear();
1231 if (sel_listeners != null)
1233 sel_listeners.clear();
1235 if (listeners != null)
1239 if (commandListeners != null)
1241 commandListeners.clear();
1243 if (view_listeners != null)
1245 view_listeners.clear();
1247 if (pdbFileNameId != null)
1249 pdbFileNameId.clear();
1251 if (pdbIdFileName != null)
1253 pdbIdFileName.clear();
1257 public void addSelectionListener(SelectionListener selecter)
1259 if (!sel_listeners.contains(selecter))
1261 sel_listeners.add(selecter);
1265 public void removeSelectionListener(SelectionListener toremove)
1267 if (sel_listeners.contains(toremove))
1269 sel_listeners.remove(toremove);
1273 public synchronized void sendSelection(
1274 jalview.datamodel.SequenceGroup selection,
1275 jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
1276 SelectionSource source)
1278 for (SelectionListener slis : sel_listeners)
1282 slis.selection(selection, colsel, hidden, source);
1287 Vector<AlignmentViewPanelListener> view_listeners = new Vector<>();
1289 public synchronized void sendViewPosition(
1290 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1291 int startSeq, int endSeq)
1294 if (view_listeners != null && view_listeners.size() > 0)
1296 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1298 while (listeners.hasMoreElements())
1300 AlignmentViewPanelListener slis = listeners.nextElement();
1303 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1311 * release all references associated with this manager provider
1313 * @param jalviewLite
1315 public static void release(StructureSelectionManagerProvider jalviewLite)
1317 // synchronized (instances)
1319 if (instances == null)
1323 StructureSelectionManager mnger = (instances.get(jalviewLite));
1326 instances.remove(jalviewLite);
1330 } catch (Throwable x)
1337 public void registerPDBEntry(PDBEntry pdbentry)
1339 if (pdbentry.getFile() != null
1340 && pdbentry.getFile().trim().length() > 0)
1342 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1346 public void addCommandListener(CommandListener cl)
1348 if (!commandListeners.contains(cl))
1350 commandListeners.add(cl);
1354 public boolean hasCommandListener(CommandListener cl)
1356 return this.commandListeners.contains(cl);
1359 public boolean removeCommandListener(CommandListener l)
1361 return commandListeners.remove(l);
1365 * Forward a command to any command listeners (except for the command's
1369 * the command to be broadcast (in its form after being performed)
1371 * if true, the command was being 'undone'
1374 public void commandPerformed(CommandI command, boolean undo,
1375 VamsasSource source)
1377 for (CommandListener listener : commandListeners)
1379 listener.mirrorCommand(command, undo, this, source);
1384 * Returns a new CommandI representing the given command as mapped to the
1385 * given sequences. If no mapping could be made, or the command is not of a
1386 * mappable kind, returns null.
1394 public CommandI mapCommand(CommandI command, boolean undo,
1395 final AlignmentI mapTo, char gapChar)
1397 if (command instanceof EditCommand)
1399 return MappingUtils.mapEditCommand((EditCommand) command, undo, mapTo,
1400 gapChar, seqmappings);
1402 else if (command instanceof OrderCommand)
1404 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1405 mapTo, seqmappings);
1410 public List<AlignedCodonFrame> getSequenceMappings()