2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.structure;
23 import jalview.analysis.AlignSeq;
24 import jalview.api.StructureSelectionManagerProvider;
25 import jalview.commands.CommandI;
26 import jalview.commands.EditCommand;
27 import jalview.commands.OrderCommand;
28 import jalview.datamodel.AlignedCodonFrame;
29 import jalview.datamodel.AlignmentAnnotation;
30 import jalview.datamodel.AlignmentI;
31 import jalview.datamodel.Annotation;
32 import jalview.datamodel.HiddenColumns;
33 import jalview.datamodel.PDBEntry;
34 import jalview.datamodel.SearchResults;
35 import jalview.datamodel.SearchResultsI;
36 import jalview.datamodel.SequenceI;
37 import jalview.ext.jmol.JmolParser;
38 import jalview.gui.IProgressIndicator;
39 import jalview.io.AppletFormatAdapter;
40 import jalview.io.DataSourceType;
41 import jalview.io.StructureFile;
42 import jalview.util.MappingUtils;
43 import jalview.util.MessageManager;
44 import jalview.ws.sifts.SiftsClient;
45 import jalview.ws.sifts.SiftsException;
46 import jalview.ws.sifts.SiftsSettings;
48 import java.io.PrintStream;
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.Collections;
52 import java.util.Enumeration;
53 import java.util.HashMap;
54 import java.util.IdentityHashMap;
55 import java.util.List;
57 import java.util.Vector;
60 import MCview.PDBChain;
61 import MCview.PDBfile;
63 public class StructureSelectionManager
65 public final static String NEWLINE = System.lineSeparator();
67 static IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> instances;
69 private List<StructureMapping> mappings = new ArrayList<>();
71 private boolean processSecondaryStructure = false;
73 private boolean secStructServices = false;
75 private boolean addTempFacAnnot = false;
77 private IProgressIndicator progressIndicator;
79 private SiftsClient siftsClient = null;
81 private long progressSessionId;
84 * Set of any registered mappings between (dataset) sequences.
86 private List<AlignedCodonFrame> seqmappings = new ArrayList<>();
88 private List<CommandListener> commandListeners = new ArrayList<>();
90 private List<SelectionListener> sel_listeners = new ArrayList<>();
93 * @return true if will try to use external services for processing secondary
96 public boolean isSecStructServices()
98 return secStructServices;
102 * control use of external services for processing secondary structure
104 * @param secStructServices
106 public void setSecStructServices(boolean secStructServices)
108 this.secStructServices = secStructServices;
112 * flag controlling addition of any kind of structural annotation
114 * @return true if temperature factor annotation will be added
116 public boolean isAddTempFacAnnot()
118 return addTempFacAnnot;
122 * set flag controlling addition of structural annotation
124 * @param addTempFacAnnot
126 public void setAddTempFacAnnot(boolean addTempFacAnnot)
128 this.addTempFacAnnot = addTempFacAnnot;
133 * @return if true, the structure manager will attempt to add secondary
134 * structure lines for unannotated sequences
137 public boolean isProcessSecondaryStructure()
139 return processSecondaryStructure;
143 * Control whether structure manager will try to annotate mapped sequences
144 * with secondary structure from PDB data.
148 public void setProcessSecondaryStructure(boolean enable)
150 processSecondaryStructure = enable;
154 * debug function - write all mappings to stdout
156 public void reportMapping()
158 if (mappings.isEmpty())
160 System.err.println("reportMapping: No PDB/Sequence mappings.");
165 "reportMapping: There are " + mappings.size() + " mappings.");
167 for (StructureMapping sm : mappings)
169 System.err.println("mapping " + i++ + " : " + sm.pdbfile);
175 * map between the PDB IDs (or structure identifiers) used by Jalview and the
176 * absolute filenames for PDB data that corresponds to it
178 Map<String, String> pdbIdFileName = new HashMap<>();
180 Map<String, String> pdbFileNameId = new HashMap<>();
182 public void registerPDBFile(String idForFile, String absoluteFile)
184 pdbIdFileName.put(idForFile, absoluteFile);
185 pdbFileNameId.put(absoluteFile, idForFile);
188 public String findIdForPDBFile(String idOrFile)
190 String id = pdbFileNameId.get(idOrFile);
194 public String findFileForPDBId(String idOrFile)
196 String id = pdbIdFileName.get(idOrFile);
200 public boolean isPDBFileRegistered(String idOrFile)
202 return pdbFileNameId.containsKey(idOrFile)
203 || pdbIdFileName.containsKey(idOrFile);
206 private static StructureSelectionManager nullProvider = null;
208 public static StructureSelectionManager getStructureSelectionManager(
209 StructureSelectionManagerProvider context)
213 if (nullProvider == null)
215 if (instances != null)
217 throw new Error(MessageManager.getString(
218 "error.implementation_error_structure_selection_manager_null"),
219 new NullPointerException(MessageManager
220 .getString("exception.ssm_context_is_null")));
224 nullProvider = new StructureSelectionManager();
229 if (instances == null)
231 instances = new java.util.IdentityHashMap<>();
233 StructureSelectionManager instance = instances.get(context);
234 if (instance == null)
236 if (nullProvider != null)
238 instance = nullProvider;
242 instance = new StructureSelectionManager();
244 instances.put(context, instance);
250 * flag controlling whether SeqMappings are relayed from received sequence
251 * mouse over events to other sequences
253 boolean relaySeqMappings = true;
256 * Enable or disable relay of seqMapping events to other sequences. You might
257 * want to do this if there are many sequence mappings and the host computer
262 public void setRelaySeqMappings(boolean relay)
264 relaySeqMappings = relay;
268 * get the state of the relay seqMappings flag.
270 * @return true if sequence mouse overs are being relayed to other mapped
273 public boolean isRelaySeqMappingsEnabled()
275 return relaySeqMappings;
278 Vector listeners = new Vector();
281 * register a listener for alignment sequence mouseover events
285 public void addStructureViewerListener(Object svl)
287 if (!listeners.contains(svl))
289 listeners.addElement(svl);
294 * Returns the file name for a mapped PDB id (or null if not mapped).
299 public String alreadyMappedToFile(String pdbid)
301 for (StructureMapping sm : mappings)
303 if (sm.getPdbId().equals(pdbid))
312 * Import structure data and register a structure mapping for broadcasting
313 * colouring, mouseovers and selection events (convenience wrapper).
316 * - one or more sequences to be mapped to pdbFile
317 * @param targetChains
318 * - optional chain specification for mapping each sequence to pdb
319 * (may be nill, individual elements may be nill)
321 * - structure data resource
323 * - how to resolve data from resource
324 * @return null or the structure data parsed as a pdb file
326 synchronized public StructureFile setMapping(SequenceI[] sequence,
327 String[] targetChains, String pdbFile, DataSourceType protocol)
329 return setMapping(true, sequence, targetChains, pdbFile, protocol);
333 * create sequence structure mappings between each sequence and the given
334 * pdbFile (retrieved via the given protocol).
336 * @param forStructureView
337 * when true, record the mapping for use in mouseOvers
339 * @param sequenceArray
340 * - one or more sequences to be mapped to pdbFile
341 * @param targetChainIds
342 * - optional chain specification for mapping each sequence to pdb
343 * (may be nill, individual elements may be nill) - JBPNote: JAL-2693
344 * - this should be List<List<String>>, empty lists indicate no
345 * predefined mappings
347 * - structure data resource
349 * - how to resolve data from resource
350 * @return null or the structure data parsed as a pdb file
352 synchronized public StructureFile setMapping(boolean forStructureView,
353 SequenceI[] sequenceArray, String[] targetChainIds,
354 String pdbFile, DataSourceType sourceType)
357 * There will be better ways of doing this in the future, for now we'll use
358 * the tried and tested MCview pdb mapping
360 boolean parseSecStr = processSecondaryStructure;
361 if (isPDBFileRegistered(pdbFile))
363 for (SequenceI sq : sequenceArray)
366 while (ds.getDatasetSequence() != null)
368 ds = ds.getDatasetSequence();
371 if (ds.getAnnotation() != null)
373 for (AlignmentAnnotation ala : ds.getAnnotation())
375 // false if any annotation present from this structure
376 // JBPNote this fails for jmol/chimera view because the *file* is
377 // passed, not the structure data ID -
378 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
386 StructureFile pdb = null;
387 boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
390 sourceType = AppletFormatAdapter.checkProtocol(pdbFile);
391 pdb = new JmolParser(pdbFile, sourceType);
393 if (pdb.getId() != null && pdb.getId().trim().length() > 0
394 && DataSourceType.FILE == sourceType)
396 registerPDBFile(pdb.getId().trim(), pdbFile);
398 // if PDBId is unavailable then skip SIFTS mapping execution path
399 isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable();
401 } catch (Exception ex)
403 ex.printStackTrace();
411 siftsClient = new SiftsClient(pdb);
413 } catch (SiftsException e)
415 isMapUsingSIFTs = false;
419 String targetChainId;
420 for (int s = 0; s < sequenceArray.length; s++)
422 boolean infChain = true;
423 final SequenceI seq = sequenceArray[s];
425 while (ds.getDatasetSequence() != null)
427 ds = ds.getDatasetSequence();
430 if (targetChainIds != null && targetChainIds[s] != null)
433 targetChainId = targetChainIds[s];
435 else if (seq.getName().indexOf("|") > -1)
437 targetChainId = seq.getName()
438 .substring(seq.getName().lastIndexOf("|") + 1);
439 if (targetChainId.length() > 1)
441 if (targetChainId.trim().length() == 0)
447 // not a valid chain identifier
458 * Attempt pairwise alignment of the sequence with each chain in the PDB,
459 * and remember the highest scoring chain
462 AlignSeq maxAlignseq = null;
463 String maxChainId = " ";
464 PDBChain maxChain = null;
465 boolean first = true;
466 List<PDBChain> maximalChain = new ArrayList<>();
467 List<AlignSeq> maximalAlignseqs = new ArrayList<>();
468 List<String> maximalChainIds = new ArrayList<>();
469 for (PDBChain chain : pdb.getChains())
471 if (targetChainId.length() > 0 && !targetChainId.equals(chain.id)
474 continue; // don't try to map chains don't match.
476 // TODO: correctly determine sequence type for mixed na/peptide
478 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
479 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
482 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
483 // as.calcScoreMatrix();
484 // as.traceAlignment();
486 if (targetChainId.length() > 0 && chain.id.equals(targetChainId))
488 // Don't care - just pick this chain as the mapping
492 maxChainId = chain.id;
493 // if targetChainId is specified then it is expected to be unique, so
494 // precisely one maximal chain will be added
495 maximalChainIds.add(chain.id);
496 maximalChain.add(chain);
497 maximalAlignseqs.add(as);
501 // select chains with maximal mappings to this sequence
502 if (first || as.maxscore > max)
504 // clear out old maximal mappings (if any)
506 maximalChain.clear();
510 maxChainId = chain.id;
513 if (as.maxscore == max)
515 maximalChainIds.add(chain.id);
516 maximalChain.add(chain);
517 maximalAlignseqs.add(as);
521 if (maxChain == null)
526 if (sourceType == DataSourceType.PASTE)
528 pdbFile = "INLINE" + pdb.getId();
531 List<StructureMapping> seqToStrucMapping = new ArrayList<>();
532 if (isMapUsingSIFTs && seq.isProtein())
534 setProgressBar(null);
535 setProgressBar(MessageManager
536 .getString("status.obtaining_mapping_with_sifts"));
537 jalview.datamodel.Mapping sqmpping = maxAlignseq
538 .getMappingFromS1(false);
539 if (targetChainId != null && !targetChainId.trim().isEmpty())
541 StructureMapping siftsMapping;
544 siftsMapping = getStructureMapping(seq, pdbFile, targetChainId,
545 pdb, maxChain, sqmpping, maxAlignseq);
546 seqToStrucMapping.add(siftsMapping);
547 maxChain.makeExactMapping(maxAlignseq, seq);
548 maxChain.transferRESNUMFeatures(seq, null);// FIXME: is this
550 maxChain.transferResidueAnnotation(siftsMapping, sqmpping);
551 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
553 } catch (SiftsException e)
555 // fall back to NW alignment
556 System.err.println(e.getMessage());
557 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
558 maximalChainIds, maximalChain, pdb, maximalAlignseqs)
560 seqToStrucMapping.add(nwMapping);
561 maxChain.makeExactMapping(maxAlignseq, seq);
562 maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
564 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
565 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
570 List<StructureMapping> foundSiftsMappings = new ArrayList<>();
571 for (PDBChain chain : pdb.getChains())
575 StructureMapping siftsMapping = getStructureMapping(seq,
576 pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq);
577 foundSiftsMappings.add(siftsMapping);
578 } catch (SiftsException e)
580 System.err.println(e.getMessage());
583 if (!foundSiftsMappings.isEmpty())
585 seqToStrucMapping.addAll(foundSiftsMappings);
586 maxChain.makeExactMapping(maxAlignseq, seq);
587 maxChain.transferRESNUMFeatures(seq, null);// FIXME: is this
589 maxChain.transferResidueAnnotation(foundSiftsMappings.get(0),
591 ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
595 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
596 maximalChainIds, maximalChain, pdb, maximalAlignseqs)
598 seqToStrucMapping.add(nwMapping);
599 maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
601 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
602 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
608 setProgressBar(null);
609 setProgressBar(MessageManager
610 .getString("status.obtaining_mapping_with_nw_alignment"));
611 List<StructureMapping> nwMapping = getNWMappings(seq, pdbFile,
612 maximalChainIds, maximalChain, pdb, maximalAlignseqs);
613 seqToStrucMapping.addAll(nwMapping);
614 for (PDBChain mc : maximalChain)
616 ds.addPDBId(mc.sequence.getAllPDBEntries().get(0));
622 if (forStructureView)
624 mappings.addAll(seqToStrucMapping);
630 public void addStructureMapping(StructureMapping sm)
636 * retrieve a mapping for seq from SIFTs using associated DBRefEntry for
641 * @param targetChainId
647 * @throws SiftsException
649 private StructureMapping getStructureMapping(SequenceI seq,
650 String pdbFile, String targetChainId, StructureFile pdb,
651 PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
652 AlignSeq maxAlignseq) throws SiftsException
654 StructureMapping curChainMapping = siftsClient
655 .getSiftsStructureMapping(seq, pdbFile, targetChainId);
658 PDBChain chain = pdb.findChain(targetChainId);
661 chain.transferResidueAnnotation(curChainMapping, sqmpping);
663 } catch (Exception e)
667 return curChainMapping;
670 private List<StructureMapping> getNWMappings(SequenceI seq,
672 List<String> maximalChainId, List<PDBChain> maximalChain,
673 StructureFile pdb, List<AlignSeq> maximalAlignseq)
675 List<StructureMapping> nwMappings = new ArrayList();
676 for (int ch = 0; ch < maximalChain.size(); ch++)
678 String maxChainId = maximalChainId.get(ch);
679 PDBChain maxChain = maximalChain.get(ch);
680 AlignSeq maxAlignseq = maximalAlignseq.get(ch);
681 final StringBuilder mappingDetails = new StringBuilder(128);
682 mappingDetails.append(NEWLINE)
683 .append("Sequence \u27f7 Structure mapping details");
684 mappingDetails.append(NEWLINE);
686 .append("Method: inferred with Needleman & Wunsch alignment");
687 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
688 .append(NEWLINE).append("Sequence = ")
689 .append(maxChain.sequence.getSequenceAsString());
690 mappingDetails.append(NEWLINE).append("No of residues = ")
691 .append(maxChain.residues.size()).append(NEWLINE)
693 PrintStream ps = new PrintStream(System.out)
696 public void print(String x)
698 mappingDetails.append(x);
702 public void println()
704 mappingDetails.append(NEWLINE);
708 maxAlignseq.printAlignment(ps);
710 mappingDetails.append(NEWLINE).append("PDB start/end ");
711 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
713 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
714 mappingDetails.append(NEWLINE).append("SEQ start/end ");
717 .valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
719 mappingDetails.append(
720 String.valueOf(maxAlignseq.seq1end + (seq.getStart() - 1)));
721 mappingDetails.append(NEWLINE);
722 maxChain.makeExactMapping(maxAlignseq, seq);
723 jalview.datamodel.Mapping sqmpping = maxAlignseq
724 .getMappingFromS1(false);
725 maxChain.transferRESNUMFeatures(seq, null);
727 HashMap<Integer, int[]> mapping = new HashMap<>();
734 Atom tmp = maxChain.atoms.elementAt(index);
735 if ((resNum != tmp.resNumber || insCode != tmp.insCode)
736 && tmp.alignmentMapping != -1)
738 resNum = tmp.resNumber;
739 insCode = tmp.insCode;
740 if (tmp.alignmentMapping >= -1)
742 mapping.put(tmp.alignmentMapping + 1,
744 { tmp.resNumber, tmp.atomIndex });
749 } while (index < maxChain.atoms.size());
751 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
752 pdb.getId(), maxChainId, mapping, mappingDetails.toString());
753 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
754 nwMappings.add(nwMapping);
759 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
761 listeners.removeElement(svl);
762 if (svl instanceof SequenceListener)
764 for (int i = 0; i < listeners.size(); i++)
766 if (listeners.elementAt(i) instanceof StructureListener)
768 ((StructureListener) listeners.elementAt(i))
769 .releaseReferences(svl);
774 if (pdbfiles == null)
780 * Remove mappings to the closed listener's PDB files, but first check if
781 * another listener is still interested
783 List<String> pdbs = new ArrayList<>(Arrays.asList(pdbfiles));
785 StructureListener sl;
786 for (int i = 0; i < listeners.size(); i++)
788 if (listeners.elementAt(i) instanceof StructureListener)
790 sl = (StructureListener) listeners.elementAt(i);
791 for (String pdbfile : sl.getStructureFiles())
793 pdbs.remove(pdbfile);
799 * Rebuild the mappings set, retaining only those which are for 'other' PDB
804 List<StructureMapping> tmp = new ArrayList<>();
805 for (StructureMapping sm : mappings)
807 if (!pdbs.contains(sm.pdbfile))
818 * Propagate mouseover of a single position in a structure
824 public void mouseOverStructure(int pdbResNum, String chain,
827 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
828 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
829 mouseOverStructure(atoms);
833 * Propagate mouseover or selection of multiple positions in a structure
837 public void mouseOverStructure(List<AtomSpec> atoms)
839 if (listeners == null)
841 // old or prematurely sent event
844 boolean hasSequenceListener = false;
845 for (int i = 0; i < listeners.size(); i++)
847 if (listeners.elementAt(i) instanceof SequenceListener)
849 hasSequenceListener = true;
852 if (!hasSequenceListener)
857 SearchResultsI results = findAlignmentPositionsForStructurePositions(
859 for (Object li : listeners)
861 if (li instanceof SequenceListener)
863 ((SequenceListener) li).highlightSequence(results);
869 * Constructs a SearchResults object holding regions (if any) in the Jalview
870 * alignment which have a mapping to the structure viewer positions in the
876 public SearchResultsI findAlignmentPositionsForStructurePositions(
877 List<AtomSpec> atoms)
879 SearchResultsI results = new SearchResults();
880 for (AtomSpec atom : atoms)
882 SequenceI lastseq = null;
884 for (StructureMapping sm : mappings)
886 if (sm.pdbfile.equals(atom.getPdbFile())
887 && sm.pdbchain.equals(atom.getChain()))
889 int indexpos = sm.getSeqPos(atom.getPdbResNum());
890 if (lastipos != indexpos && lastseq != sm.sequence)
892 results.addResult(sm.sequence, indexpos, indexpos);
894 lastseq = sm.sequence;
895 // construct highlighted sequence list
896 for (AlignedCodonFrame acf : seqmappings)
898 acf.markMappedRegion(sm.sequence, indexpos, results);
908 * highlight regions associated with a position (indexpos) in seq
911 * the sequence that the mouse over occurred on
913 * the absolute position being mouseovered in seq (0 to seq.length())
915 * the sequence position (if -1, seq.findPosition is called to
916 * resolve the residue number)
918 public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
921 boolean hasSequenceListeners = handlingVamsasMo
922 || !seqmappings.isEmpty();
923 SearchResultsI results = null;
926 seqPos = seq.findPosition(indexpos);
928 for (int i = 0; i < listeners.size(); i++)
930 Object listener = listeners.elementAt(i);
931 if (listener == source)
933 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
934 // Temporary fudge with SequenceListener.getVamsasSource()
937 if (listener instanceof StructureListener)
939 highlightStructure((StructureListener) listener, seq, seqPos);
943 if (listener instanceof SequenceListener)
945 final SequenceListener seqListener = (SequenceListener) listener;
946 if (hasSequenceListeners
947 && seqListener.getVamsasSource() != source)
949 if (relaySeqMappings)
953 results = MappingUtils.buildSearchResults(seq, seqPos,
956 if (handlingVamsasMo)
958 results.addResult(seq, seqPos, seqPos);
961 if (!results.isEmpty())
963 seqListener.highlightSequence(results);
968 else if (listener instanceof VamsasListener && !handlingVamsasMo)
970 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
973 else if (listener instanceof SecondaryStructureListener)
975 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
983 * Send suitable messages to a StructureListener to highlight atoms
984 * corresponding to the given sequence position(s)
990 public void highlightStructure(StructureListener sl, SequenceI seq,
993 if (!sl.isListeningFor(seq))
998 List<AtomSpec> atoms = new ArrayList<>();
999 for (StructureMapping sm : mappings)
1001 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
1002 || (sm.sequence.getDatasetSequence() != null && sm.sequence
1003 .getDatasetSequence() == seq.getDatasetSequence()))
1005 for (int index : positions)
1007 atomNo = sm.getAtomNum(index);
1011 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
1012 sm.getPDBResNum(index), atomNo));
1017 sl.highlightAtoms(atoms);
1021 * true if a mouse over event from an external (ie Vamsas) source is being
1024 boolean handlingVamsasMo = false;
1029 * as mouseOverSequence but only route event to SequenceListeners
1033 * in an alignment sequence
1035 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
1036 VamsasSource source)
1038 handlingVamsasMo = true;
1039 long msg = sequenceI.hashCode() * (1 + position);
1043 mouseOverSequence(sequenceI, position, -1, source);
1045 handlingVamsasMo = false;
1048 public Annotation[] colourSequenceFromStructure(SequenceI seq,
1052 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
1053 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
1055 * Annotation [] annotations = new Annotation[seq.getLength()];
1057 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
1058 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
1059 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
1061 * for (int j = 0; j < mappings.length; j++) {
1063 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
1064 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
1065 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
1066 * "+mappings[j].pdbfile);
1068 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
1069 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
1071 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
1072 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
1073 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
1074 * mappings[j].pdbfile); }
1076 * annotations[index] = new Annotation("X",null,' ',0,col); } return
1077 * annotations; } } } }
1079 * return annotations;
1083 public void structureSelectionChanged()
1087 public void sequenceSelectionChanged()
1091 public void sequenceColoursChanged(Object source)
1093 StructureListener sl;
1094 for (int i = 0; i < listeners.size(); i++)
1096 if (listeners.elementAt(i) instanceof StructureListener)
1098 sl = (StructureListener) listeners.elementAt(i);
1099 sl.updateColours(source);
1104 public StructureMapping[] getMapping(String pdbfile)
1106 List<StructureMapping> tmp = new ArrayList<>();
1107 for (StructureMapping sm : mappings)
1109 if (sm.pdbfile.equals(pdbfile))
1114 return tmp.toArray(new StructureMapping[tmp.size()]);
1118 * Returns a readable description of all mappings for the given pdbfile to any
1119 * of the given sequences
1125 public String printMappings(String pdbfile, List<SequenceI> seqs)
1127 if (pdbfile == null || seqs == null || seqs.isEmpty())
1132 StringBuilder sb = new StringBuilder(64);
1133 for (StructureMapping sm : mappings)
1135 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
1137 sb.append(sm.mappingDetails);
1139 // separator makes it easier to read multiple mappings
1140 sb.append("=====================");
1146 return sb.toString();
1150 * Remove the given mapping
1154 public void deregisterMapping(AlignedCodonFrame acf)
1158 boolean removed = seqmappings.remove(acf);
1159 if (removed && seqmappings.isEmpty())
1161 System.out.println("All mappings removed");
1167 * Add each of the given codonFrames to the stored set, if not aready present.
1171 public void registerMappings(List<AlignedCodonFrame> mappings)
1173 if (mappings != null)
1175 for (AlignedCodonFrame acf : mappings)
1177 registerMapping(acf);
1183 * Add the given mapping to the stored set, unless already stored.
1185 public void registerMapping(AlignedCodonFrame acf)
1189 if (!seqmappings.contains(acf))
1191 seqmappings.add(acf);
1197 * Resets this object to its initial state by removing all registered
1198 * listeners, codon mappings, PDB file mappings
1200 public void resetAll()
1202 if (mappings != null)
1206 if (seqmappings != null)
1208 seqmappings.clear();
1210 if (sel_listeners != null)
1212 sel_listeners.clear();
1214 if (listeners != null)
1218 if (commandListeners != null)
1220 commandListeners.clear();
1222 if (view_listeners != null)
1224 view_listeners.clear();
1226 if (pdbFileNameId != null)
1228 pdbFileNameId.clear();
1230 if (pdbIdFileName != null)
1232 pdbIdFileName.clear();
1236 public void addSelectionListener(SelectionListener selecter)
1238 if (!sel_listeners.contains(selecter))
1240 sel_listeners.add(selecter);
1244 public void removeSelectionListener(SelectionListener toremove)
1246 if (sel_listeners.contains(toremove))
1248 sel_listeners.remove(toremove);
1252 public synchronized void sendSelection(
1253 jalview.datamodel.SequenceGroup selection,
1254 jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
1255 SelectionSource source)
1257 for (SelectionListener slis : sel_listeners)
1261 slis.selection(selection, colsel, hidden, source);
1266 Vector<AlignmentViewPanelListener> view_listeners = new Vector<>();
1268 public synchronized void sendViewPosition(
1269 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1270 int startSeq, int endSeq)
1273 if (view_listeners != null && view_listeners.size() > 0)
1275 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1277 while (listeners.hasMoreElements())
1279 AlignmentViewPanelListener slis = listeners.nextElement();
1282 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1290 * release all references associated with this manager provider
1292 * @param jalviewLite
1294 public static void release(StructureSelectionManagerProvider jalviewLite)
1296 // synchronized (instances)
1298 if (instances == null)
1302 StructureSelectionManager mnger = (instances.get(jalviewLite));
1305 instances.remove(jalviewLite);
1309 } catch (Throwable x)
1316 public void registerPDBEntry(PDBEntry pdbentry)
1318 if (pdbentry.getFile() != null
1319 && pdbentry.getFile().trim().length() > 0)
1321 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1325 public void addCommandListener(CommandListener cl)
1327 if (!commandListeners.contains(cl))
1329 commandListeners.add(cl);
1333 public boolean hasCommandListener(CommandListener cl)
1335 return this.commandListeners.contains(cl);
1338 public boolean removeCommandListener(CommandListener l)
1340 return commandListeners.remove(l);
1344 * Forward a command to any command listeners (except for the command's
1348 * the command to be broadcast (in its form after being performed)
1350 * if true, the command was being 'undone'
1353 public void commandPerformed(CommandI command, boolean undo,
1354 VamsasSource source)
1356 for (CommandListener listener : commandListeners)
1358 listener.mirrorCommand(command, undo, this, source);
1363 * Returns a new CommandI representing the given command as mapped to the
1364 * given sequences. If no mapping could be made, or the command is not of a
1365 * mappable kind, returns null.
1373 public CommandI mapCommand(CommandI command, boolean undo,
1374 final AlignmentI mapTo, char gapChar)
1376 if (command instanceof EditCommand)
1378 return MappingUtils.mapEditCommand((EditCommand) command, undo, mapTo,
1379 gapChar, seqmappings);
1381 else if (command instanceof OrderCommand)
1383 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1384 mapTo, seqmappings);
1389 public IProgressIndicator getProgressIndicator()
1391 return progressIndicator;
1394 public void setProgressIndicator(IProgressIndicator progressIndicator)
1396 this.progressIndicator = progressIndicator;
1399 public long getProgressSessionId()
1401 return progressSessionId;
1404 public void setProgressSessionId(long progressSessionId)
1406 this.progressSessionId = progressSessionId;
1409 public void setProgressBar(String message)
1411 if (progressIndicator == null)
1415 progressIndicator.setProgressBar(message, progressSessionId);
1418 public List<AlignedCodonFrame> getSequenceMappings()
1424 * utilty method - transform array of chain characters
1427 * @return array of lists with a chain in each
1429 public static List<String>[] perChainList(String[] chains)
1431 List<String>[] chainsL = new List[chains.length];
1433 for (String ch : chains)
1435 chainsL[p] = new ArrayList();
1436 chainsL[p++].add(ch);