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 filename the PDB id is already mapped to if known, or null if
294 public String alreadyMappedToFile(String pdbid)
296 for (StructureMapping sm : mappings)
298 if (sm.getPdbId().equalsIgnoreCase(pdbid))
307 * Import structure data and register a structure mapping for broadcasting
308 * colouring, mouseovers and selection events (convenience wrapper).
311 * - one or more sequences to be mapped to pdbFile
312 * @param targetChains
313 * - optional chain specification for mapping each sequence to pdb
314 * (may be nill, individual elements may be nill)
316 * - structure data resource
318 * - how to resolve data from resource
319 * @return null or the structure data parsed as a pdb file
321 synchronized public StructureFile setMapping(SequenceI[] sequence,
322 String[] targetChains, String pdbFile, DataSourceType protocol,
323 IProgressIndicator progress)
325 return computeMapping(true, sequence, targetChains, pdbFile, protocol,
330 * Import a single structure file and register sequence structure mappings for
331 * broadcasting colouring, mouseovers and selection events (convenience
334 * @param forStructureView
335 * when true, record the mapping for use in mouseOvers
337 * - one or more sequences to be mapped to pdbFile
338 * @param targetChains
339 * - optional chain specification for mapping each sequence to pdb
340 * (may be nill, individual elements may be nill)
342 * - structure data resource
344 * - how to resolve data from resource
345 * @return null or the structure data parsed as a pdb file
347 synchronized public StructureFile setMapping(boolean forStructureView,
348 SequenceI[] sequenceArray, String[] targetChainIds,
349 String pdbFile, DataSourceType sourceType)
351 return computeMapping(forStructureView, sequenceArray, targetChainIds,
352 pdbFile, sourceType, null);
356 * create sequence structure mappings between each sequence and the given
357 * pdbFile (retrieved via the given protocol). Either constructs a mapping
358 * using NW alignment or derives one from any available SIFTS mapping data.
360 * @param forStructureView
361 * when true, record the mapping for use in mouseOvers
363 * @param sequenceArray
364 * - one or more sequences to be mapped to pdbFile
365 * @param targetChainIds
366 * - optional chain specification for mapping each sequence to pdb
367 * (may be nill, individual elements may be nill) - JBPNote: JAL-2693
368 * - this should be List<List<String>>, empty lists indicate no
369 * predefined mappings
371 * - structure data resource
373 * - how to resolve data from resource
374 * @param IProgressIndicator
375 * reference to UI component that maintains a progress bar for the
377 * @return null or the structure data parsed as a pdb file
379 synchronized public StructureFile computeMapping(
380 boolean forStructureView, SequenceI[] sequenceArray,
381 String[] targetChainIds, String pdbFile, DataSourceType sourceType,
382 IProgressIndicator progress)
384 long progressSessionId = System.currentTimeMillis() * 3;
387 * do we extract and transfer annotation from 3D data ?
389 // FIXME: possibly should just delete
391 boolean parseSecStr = processSecondaryStructure
392 ? isStructureFileProcessed(pdbFile, sequenceArray)
395 StructureFile pdb = null;
396 boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
399 // FIXME if sourceType is not null, we've lost data here
400 sourceType = AppletFormatAdapter.checkProtocol(pdbFile);
401 pdb = new JmolParser(pdbFile, sourceType);
403 if (pdb.getId() != null && pdb.getId().trim().length() > 0
404 && DataSourceType.FILE == sourceType)
406 registerPDBFile(pdb.getId().trim(), pdbFile);
408 // if PDBId is unavailable then skip SIFTS mapping execution path
409 isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable();
411 } catch (Exception ex)
413 ex.printStackTrace();
417 * sifts client - non null if SIFTS mappings are to be used
419 SiftsClient siftsClient = null;
424 siftsClient = new SiftsClient(pdb);
426 } catch (SiftsException e)
428 isMapUsingSIFTs = false;
433 String targetChainId;
434 for (int s = 0; s < sequenceArray.length; s++)
436 boolean infChain = true;
437 final SequenceI seq = sequenceArray[s];
439 while (ds.getDatasetSequence() != null)
441 ds = ds.getDatasetSequence();
444 if (targetChainIds != null && targetChainIds[s] != null)
447 targetChainId = targetChainIds[s];
449 else if (seq.getName().indexOf("|") > -1)
451 targetChainId = seq.getName()
452 .substring(seq.getName().lastIndexOf("|") + 1);
453 if (targetChainId.length() > 1)
455 if (targetChainId.trim().length() == 0)
461 // not a valid chain identifier
472 * Attempt pairwise alignment of the sequence with each chain in the PDB,
473 * and remember the highest scoring chain
476 AlignSeq maxAlignseq = null;
477 String maxChainId = " ";
478 PDBChain maxChain = null;
479 boolean first = true;
480 for (PDBChain chain : pdb.getChains())
482 if (targetChainId.length() > 0 && !targetChainId.equals(chain.id)
485 continue; // don't try to map chains don't match.
487 // TODO: correctly determine sequence type for mixed na/peptide
489 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
490 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
493 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
494 // as.calcScoreMatrix();
495 // as.traceAlignment();
497 if (first || as.maxscore > max
498 || (as.maxscore == max && chain.id.equals(targetChainId)))
504 maxChainId = chain.id;
507 if (maxChain == null)
512 if (sourceType == DataSourceType.PASTE)
514 pdbFile = "INLINE" + pdb.getId();
517 List<StructureMapping> seqToStrucMapping = new ArrayList<>();
518 if (isMapUsingSIFTs && seq.isProtein())
520 if (progress!=null) {
521 progress.setProgressBar(MessageManager
522 .getString("status.obtaining_mapping_with_sifts"),
525 jalview.datamodel.Mapping sqmpping = maxAlignseq
526 .getMappingFromS1(false);
527 if (targetChainId != null && !targetChainId.trim().isEmpty())
529 StructureMapping siftsMapping;
532 siftsMapping = getStructureMapping(seq, pdbFile, targetChainId,
533 pdb, maxChain, sqmpping, maxAlignseq, siftsClient);
534 seqToStrucMapping.add(siftsMapping);
535 maxChain.makeExactMapping(siftsMapping, seq);
536 maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
538 maxChain.transferResidueAnnotation(siftsMapping, null);
539 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
541 } catch (SiftsException e)
543 // fall back to NW alignment
544 System.err.println(e.getMessage());
545 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
546 targetChainId, maxChain, pdb, maxAlignseq);
547 seqToStrucMapping.add(nwMapping);
548 maxChain.makeExactMapping(maxAlignseq, seq);
549 maxChain.transferRESNUMFeatures(seq, "IEA:Jalview"); // FIXME: is
552 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
553 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
558 List<StructureMapping> foundSiftsMappings = new ArrayList<>();
559 for (PDBChain chain : pdb.getChains())
561 StructureMapping siftsMapping = null;
564 siftsMapping = getStructureMapping(seq,
565 pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq,
567 foundSiftsMappings.add(siftsMapping);
568 chain.makeExactMapping(siftsMapping, seq);
569 chain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
571 chain.transferResidueAnnotation(siftsMapping, null);
572 } catch (SiftsException e)
574 System.err.println(e.getMessage());
577 if (!foundSiftsMappings.isEmpty())
579 seqToStrucMapping.addAll(foundSiftsMappings);
580 ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
584 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
585 maxChainId, maxChain, pdb, maxAlignseq);
586 seqToStrucMapping.add(nwMapping);
587 maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
589 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
590 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
596 if (progress != null)
598 progress.setProgressBar(MessageManager
599 .getString("status.obtaining_mapping_with_nw_alignment"),
602 StructureMapping nwMapping = getNWMappings(seq, pdbFile, maxChainId,
603 maxChain, pdb, maxAlignseq);
604 seqToStrucMapping.add(nwMapping);
605 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
607 if (forStructureView)
609 mappings.addAll(seqToStrucMapping);
611 if (progress != null)
613 progress.setProgressBar(null, progressSessionId);
620 * check if we need to extract secondary structure from given pdbFile and
621 * transfer to sequences
624 * @param sequenceArray
627 private boolean isStructureFileProcessed(String pdbFile,
628 SequenceI[] sequenceArray)
630 boolean parseSecStr = true;
631 if (isPDBFileRegistered(pdbFile))
633 for (SequenceI sq : sequenceArray)
636 while (ds.getDatasetSequence() != null)
638 ds = ds.getDatasetSequence();
641 if (ds.getAnnotation() != null)
643 for (AlignmentAnnotation ala : ds.getAnnotation())
645 // false if any annotation present from this structure
646 // JBPNote this fails for jmol/chimera view because the *file* is
647 // passed, not the structure data ID -
648 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
659 public void addStructureMapping(StructureMapping sm)
665 * retrieve a mapping for seq from SIFTs using associated DBRefEntry for
670 * @param targetChainId
676 * client for retrieval of SIFTS mappings for this structure
678 * @throws SiftsException
680 private StructureMapping getStructureMapping(SequenceI seq,
681 String pdbFile, String targetChainId, StructureFile pdb,
682 PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
683 AlignSeq maxAlignseq, SiftsClient siftsClient) throws SiftsException
685 StructureMapping curChainMapping = siftsClient
686 .getSiftsStructureMapping(seq, pdbFile, targetChainId);
689 PDBChain chain = pdb.findChain(targetChainId);
692 chain.transferResidueAnnotation(curChainMapping, null);
694 } catch (Exception e)
698 return curChainMapping;
701 private StructureMapping getNWMappings(SequenceI seq, String pdbFile,
702 String maxChainId, PDBChain maxChain, StructureFile pdb,
703 AlignSeq maxAlignseq)
705 final StringBuilder mappingDetails = new StringBuilder(128);
706 mappingDetails.append(NEWLINE)
707 .append("Sequence \u27f7 Structure mapping details");
708 mappingDetails.append(NEWLINE);
710 .append("Method: inferred with Needleman & Wunsch alignment");
711 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
712 .append(NEWLINE).append("Sequence = ")
713 .append(maxChain.sequence.getSequenceAsString());
714 mappingDetails.append(NEWLINE).append("No of residues = ")
715 .append(maxChain.residues.size()).append(NEWLINE)
717 PrintStream ps = new PrintStream(System.out)
720 public void print(String x)
722 mappingDetails.append(x);
726 public void println()
728 mappingDetails.append(NEWLINE);
732 maxAlignseq.printAlignment(ps);
734 mappingDetails.append(NEWLINE).append("PDB start/end ");
735 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
737 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
738 mappingDetails.append(NEWLINE).append("SEQ start/end ");
741 .valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
743 mappingDetails.append(
744 String.valueOf(maxAlignseq.seq1end + (seq.getStart() - 1)));
745 mappingDetails.append(NEWLINE);
746 maxChain.makeExactMapping(maxAlignseq, seq);
747 jalview.datamodel.Mapping sqmpping = maxAlignseq
748 .getMappingFromS1(false);
749 maxChain.transferRESNUMFeatures(seq, null);
751 HashMap<Integer, int[]> mapping = new HashMap<>();
758 Atom tmp = maxChain.atoms.elementAt(index);
759 if ((resNum != tmp.resNumber || insCode != tmp.insCode)
760 && tmp.alignmentMapping != -1)
762 resNum = tmp.resNumber;
763 insCode = tmp.insCode;
764 if (tmp.alignmentMapping >= -1)
766 mapping.put(tmp.alignmentMapping + 1,
768 { tmp.resNumber, tmp.atomIndex });
773 } while (index < maxChain.atoms.size());
775 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
776 pdb.getId(), maxChainId, mapping, mappingDetails.toString());
777 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
781 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
783 listeners.removeElement(svl);
784 if (svl instanceof SequenceListener)
786 for (int i = 0; i < listeners.size(); i++)
788 if (listeners.elementAt(i) instanceof StructureListener)
790 ((StructureListener) listeners.elementAt(i))
791 .releaseReferences(svl);
796 if (pdbfiles == null)
802 * Remove mappings to the closed listener's PDB files, but first check if
803 * another listener is still interested
805 List<String> pdbs = new ArrayList<>(Arrays.asList(pdbfiles));
807 StructureListener sl;
808 for (int i = 0; i < listeners.size(); i++)
810 if (listeners.elementAt(i) instanceof StructureListener)
812 sl = (StructureListener) listeners.elementAt(i);
813 for (String pdbfile : sl.getStructureFiles())
815 pdbs.remove(pdbfile);
821 * Rebuild the mappings set, retaining only those which are for 'other' PDB
826 List<StructureMapping> tmp = new ArrayList<>();
827 for (StructureMapping sm : mappings)
829 if (!pdbs.contains(sm.pdbfile))
840 * Propagate mouseover of a single position in a structure
846 public void mouseOverStructure(int pdbResNum, String chain,
849 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
850 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
851 mouseOverStructure(atoms);
855 * Propagate mouseover or selection of multiple positions in a structure
859 public void mouseOverStructure(List<AtomSpec> atoms)
861 if (listeners == null)
863 // old or prematurely sent event
866 boolean hasSequenceListener = false;
867 for (int i = 0; i < listeners.size(); i++)
869 if (listeners.elementAt(i) instanceof SequenceListener)
871 hasSequenceListener = true;
874 if (!hasSequenceListener)
879 SearchResultsI results = findAlignmentPositionsForStructurePositions(
881 for (Object li : listeners)
883 if (li instanceof SequenceListener)
885 ((SequenceListener) li).highlightSequence(results);
891 * Constructs a SearchResults object holding regions (if any) in the Jalview
892 * alignment which have a mapping to the structure viewer positions in the
898 public SearchResultsI findAlignmentPositionsForStructurePositions(
899 List<AtomSpec> atoms)
901 SearchResultsI results = new SearchResults();
902 for (AtomSpec atom : atoms)
904 SequenceI lastseq = null;
906 for (StructureMapping sm : mappings)
908 if (sm.pdbfile.equals(atom.getPdbFile())
909 && sm.pdbchain.equals(atom.getChain()))
911 int indexpos = sm.getSeqPos(atom.getPdbResNum());
912 if (lastipos != indexpos || lastseq != sm.sequence)
914 results.addResult(sm.sequence, indexpos, indexpos);
916 lastseq = sm.sequence;
917 // construct highlighted sequence list
918 for (AlignedCodonFrame acf : seqmappings)
920 acf.markMappedRegion(sm.sequence, indexpos, results);
930 * highlight regions associated with a position (indexpos) in seq
933 * the sequence that the mouse over occurred on
935 * the absolute position being mouseovered in seq (0 to seq.length())
937 * the sequence position (if -1, seq.findPosition is called to
938 * resolve the residue number)
940 public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
943 boolean hasSequenceListeners = handlingVamsasMo
944 || !seqmappings.isEmpty();
945 SearchResultsI results = null;
948 seqPos = seq.findPosition(indexpos);
950 for (int i = 0; i < listeners.size(); i++)
952 Object listener = listeners.elementAt(i);
953 if (listener == source)
955 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
956 // Temporary fudge with SequenceListener.getVamsasSource()
959 if (listener instanceof StructureListener)
961 highlightStructure((StructureListener) listener, seq, seqPos);
965 if (listener instanceof SequenceListener)
967 final SequenceListener seqListener = (SequenceListener) listener;
968 if (hasSequenceListeners
969 && seqListener.getVamsasSource() != source)
971 if (relaySeqMappings)
975 results = MappingUtils.buildSearchResults(seq, seqPos,
978 if (handlingVamsasMo)
980 results.addResult(seq, seqPos, seqPos);
983 if (!results.isEmpty())
985 seqListener.highlightSequence(results);
990 else if (listener instanceof VamsasListener && !handlingVamsasMo)
992 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
995 else if (listener instanceof SecondaryStructureListener)
997 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
1005 * Send suitable messages to a StructureListener to highlight atoms
1006 * corresponding to the given sequence position(s)
1012 public void highlightStructure(StructureListener sl, SequenceI seq,
1015 if (!sl.isListeningFor(seq))
1020 List<AtomSpec> atoms = new ArrayList<>();
1021 for (StructureMapping sm : mappings)
1023 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
1024 || (sm.sequence.getDatasetSequence() != null && sm.sequence
1025 .getDatasetSequence() == seq.getDatasetSequence()))
1027 for (int index : positions)
1029 atomNo = sm.getAtomNum(index);
1033 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
1034 sm.getPDBResNum(index), atomNo));
1039 sl.highlightAtoms(atoms);
1043 * true if a mouse over event from an external (ie Vamsas) source is being
1046 boolean handlingVamsasMo = false;
1051 * as mouseOverSequence but only route event to SequenceListeners
1055 * in an alignment sequence
1057 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
1058 VamsasSource source)
1060 handlingVamsasMo = true;
1061 long msg = sequenceI.hashCode() * (1 + position);
1065 mouseOverSequence(sequenceI, position, -1, source);
1067 handlingVamsasMo = false;
1070 public Annotation[] colourSequenceFromStructure(SequenceI seq,
1074 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
1075 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
1077 * Annotation [] annotations = new Annotation[seq.getLength()];
1079 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
1080 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
1081 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
1083 * for (int j = 0; j < mappings.length; j++) {
1085 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
1086 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
1087 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
1088 * "+mappings[j].pdbfile);
1090 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
1091 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
1093 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
1094 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
1095 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
1096 * mappings[j].pdbfile); }
1098 * annotations[index] = new Annotation("X",null,' ',0,col); } return
1099 * annotations; } } } }
1101 * return annotations;
1105 public void structureSelectionChanged()
1109 public void sequenceSelectionChanged()
1113 public void sequenceColoursChanged(Object source)
1115 StructureListener sl;
1116 for (int i = 0; i < listeners.size(); i++)
1118 if (listeners.elementAt(i) instanceof StructureListener)
1120 sl = (StructureListener) listeners.elementAt(i);
1121 sl.updateColours(source);
1126 public StructureMapping[] getMapping(String pdbfile)
1128 List<StructureMapping> tmp = new ArrayList<>();
1129 for (StructureMapping sm : mappings)
1131 if (sm.pdbfile.equals(pdbfile))
1136 return tmp.toArray(new StructureMapping[tmp.size()]);
1140 * Returns a readable description of all mappings for the given pdbfile to any
1141 * of the given sequences
1147 public String printMappings(String pdbfile, List<SequenceI> seqs)
1149 if (pdbfile == null || seqs == null || seqs.isEmpty())
1154 StringBuilder sb = new StringBuilder(64);
1155 for (StructureMapping sm : mappings)
1157 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
1159 sb.append(sm.mappingDetails);
1161 // separator makes it easier to read multiple mappings
1162 sb.append("=====================");
1168 return sb.toString();
1172 * Remove the given mapping
1176 public void deregisterMapping(AlignedCodonFrame acf)
1180 boolean removed = seqmappings.remove(acf);
1181 if (removed && seqmappings.isEmpty())
1183 System.out.println("All mappings removed");
1189 * Add each of the given codonFrames to the stored set, if not aready present.
1193 public void registerMappings(List<AlignedCodonFrame> mappings)
1195 if (mappings != null)
1197 for (AlignedCodonFrame acf : mappings)
1199 registerMapping(acf);
1205 * Add the given mapping to the stored set, unless already stored.
1207 public void registerMapping(AlignedCodonFrame acf)
1211 if (!seqmappings.contains(acf))
1213 seqmappings.add(acf);
1219 * Resets this object to its initial state by removing all registered
1220 * listeners, codon mappings, PDB file mappings
1222 public void resetAll()
1224 if (mappings != null)
1228 if (seqmappings != null)
1230 seqmappings.clear();
1232 if (sel_listeners != null)
1234 sel_listeners.clear();
1236 if (listeners != null)
1240 if (commandListeners != null)
1242 commandListeners.clear();
1244 if (view_listeners != null)
1246 view_listeners.clear();
1248 if (pdbFileNameId != null)
1250 pdbFileNameId.clear();
1252 if (pdbIdFileName != null)
1254 pdbIdFileName.clear();
1258 public void addSelectionListener(SelectionListener selecter)
1260 if (!sel_listeners.contains(selecter))
1262 sel_listeners.add(selecter);
1266 public void removeSelectionListener(SelectionListener toremove)
1268 if (sel_listeners.contains(toremove))
1270 sel_listeners.remove(toremove);
1274 public synchronized void sendSelection(
1275 jalview.datamodel.SequenceGroup selection,
1276 jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
1277 SelectionSource source)
1279 for (SelectionListener slis : sel_listeners)
1283 slis.selection(selection, colsel, hidden, source);
1288 Vector<AlignmentViewPanelListener> view_listeners = new Vector<>();
1290 public synchronized void sendViewPosition(
1291 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1292 int startSeq, int endSeq)
1295 if (view_listeners != null && view_listeners.size() > 0)
1297 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1299 while (listeners.hasMoreElements())
1301 AlignmentViewPanelListener slis = listeners.nextElement();
1304 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1312 * release all references associated with this manager provider
1314 * @param jalviewLite
1316 public static void release(StructureSelectionManagerProvider jalviewLite)
1318 // synchronized (instances)
1320 if (instances == null)
1324 StructureSelectionManager mnger = (instances.get(jalviewLite));
1327 instances.remove(jalviewLite);
1331 } catch (Throwable x)
1338 public void registerPDBEntry(PDBEntry pdbentry)
1340 if (pdbentry.getFile() != null
1341 && pdbentry.getFile().trim().length() > 0)
1343 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1347 public void addCommandListener(CommandListener cl)
1349 if (!commandListeners.contains(cl))
1351 commandListeners.add(cl);
1355 public boolean hasCommandListener(CommandListener cl)
1357 return this.commandListeners.contains(cl);
1360 public boolean removeCommandListener(CommandListener l)
1362 return commandListeners.remove(l);
1366 * Forward a command to any command listeners (except for the command's
1370 * the command to be broadcast (in its form after being performed)
1372 * if true, the command was being 'undone'
1375 public void commandPerformed(CommandI command, boolean undo,
1376 VamsasSource source)
1378 for (CommandListener listener : commandListeners)
1380 listener.mirrorCommand(command, undo, this, source);
1385 * Returns a new CommandI representing the given command as mapped to the
1386 * given sequences. If no mapping could be made, or the command is not of a
1387 * mappable kind, returns null.
1395 public CommandI mapCommand(CommandI command, boolean undo,
1396 final AlignmentI mapTo, char gapChar)
1398 if (command instanceof EditCommand)
1400 return MappingUtils.mapEditCommand((EditCommand) command, undo, mapTo,
1401 gapChar, seqmappings);
1403 else if (command instanceof OrderCommand)
1405 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1406 mapTo, seqmappings);
1411 public List<AlignedCodonFrame> getSequenceMappings()