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.PDBEntry;
33 import jalview.datamodel.SearchResults;
34 import jalview.datamodel.SearchResultsI;
35 import jalview.datamodel.SequenceI;
36 import jalview.ext.jmol.JmolParser;
37 import jalview.gui.IProgressIndicator;
38 import jalview.io.DataSourceType;
39 import jalview.io.StructureFile;
40 import jalview.util.MappingUtils;
41 import jalview.util.MessageManager;
42 import jalview.ws.phyre2.Phyre2Client;
43 import jalview.ws.sifts.SiftsClient;
44 import jalview.ws.sifts.SiftsException;
45 import jalview.ws.sifts.SiftsSettings;
47 import java.io.PrintStream;
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.Collections;
51 import java.util.Enumeration;
52 import java.util.HashMap;
53 import java.util.Hashtable;
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<StructureMapping>();
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;
85 * Set of any registered mappings between (dataset) sequences.
87 private List<AlignedCodonFrame> seqmappings = new ArrayList<AlignedCodonFrame>();
89 private List<CommandListener> commandListeners = new ArrayList<CommandListener>();
91 private List<SelectionListener> sel_listeners = new ArrayList<SelectionListener>();
93 private Map<String, String> phyre2ModelTemplates = new Hashtable<String, String>();
96 * @return true if will try to use external services for processing secondary
99 public boolean isSecStructServices()
101 return secStructServices;
105 * control use of external services for processing secondary structure
107 * @param secStructServices
109 public void setSecStructServices(boolean secStructServices)
111 this.secStructServices = secStructServices;
115 * flag controlling addition of any kind of structural annotation
117 * @return true if temperature factor annotation will be added
119 public boolean isAddTempFacAnnot()
121 return addTempFacAnnot;
125 * set flag controlling addition of structural annotation
127 * @param addTempFacAnnot
129 public void setAddTempFacAnnot(boolean addTempFacAnnot)
131 this.addTempFacAnnot = addTempFacAnnot;
136 * @return if true, the structure manager will attempt to add secondary
137 * structure lines for unannotated sequences
140 public boolean isProcessSecondaryStructure()
142 return processSecondaryStructure;
146 * Control whether structure manager will try to annotate mapped sequences
147 * with secondary structure from PDB data.
151 public void setProcessSecondaryStructure(boolean enable)
153 processSecondaryStructure = enable;
157 * debug function - write all mappings to stdout
159 public void reportMapping()
161 if (mappings.isEmpty())
163 System.err.println("reportMapping: No PDB/Sequence mappings.");
167 System.err.println("reportMapping: There are " + mappings.size()
170 for (StructureMapping sm : mappings)
172 System.err.println("mapping " + i++ + " : " + sm.pdbfile);
178 * map between the PDB IDs (or structure identifiers) used by Jalview and the
179 * absolute filenames for PDB data that corresponds to it
181 Map<String, String> pdbIdFileName = new HashMap<String, String>();
183 Map<String, String> pdbFileNameId = new HashMap<String, String>();
185 public void registerPDBFile(String idForFile, String absoluteFile)
187 pdbIdFileName.put(idForFile, absoluteFile);
188 pdbFileNameId.put(absoluteFile, idForFile);
191 public String findIdForPDBFile(String idOrFile)
193 String id = pdbFileNameId.get(idOrFile);
197 public String findFileForPDBId(String idOrFile)
199 String id = pdbIdFileName.get(idOrFile);
203 public boolean isPDBFileRegistered(String idOrFile)
205 return pdbFileNameId.containsKey(idOrFile)
206 || pdbIdFileName.containsKey(idOrFile);
209 private static StructureSelectionManager nullProvider = null;
211 public static StructureSelectionManager getStructureSelectionManager(
212 StructureSelectionManagerProvider context)
216 if (nullProvider == null)
218 if (instances != null)
222 .getString("error.implementation_error_structure_selection_manager_null"),
223 new NullPointerException(MessageManager
224 .getString("exception.ssm_context_is_null")));
228 nullProvider = new StructureSelectionManager();
233 if (instances == null)
235 instances = new java.util.IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager>();
237 StructureSelectionManager instance = instances.get(context);
238 if (instance == null)
240 if (nullProvider != null)
242 instance = nullProvider;
246 instance = new StructureSelectionManager();
248 instances.put(context, instance);
254 * flag controlling whether SeqMappings are relayed from received sequence
255 * mouse over events to other sequences
257 boolean relaySeqMappings = true;
260 * Enable or disable relay of seqMapping events to other sequences. You might
261 * want to do this if there are many sequence mappings and the host computer
266 public void setRelaySeqMappings(boolean relay)
268 relaySeqMappings = relay;
272 * get the state of the relay seqMappings flag.
274 * @return true if sequence mouse overs are being relayed to other mapped
277 public boolean isRelaySeqMappingsEnabled()
279 return relaySeqMappings;
282 Vector listeners = new Vector();
285 * register a listener for alignment sequence mouseover events
289 public void addStructureViewerListener(Object svl)
291 if (!listeners.contains(svl))
293 listeners.addElement(svl);
298 * Returns the file name for a mapped PDB id (or null if not mapped).
303 public String alreadyMappedToFile(String pdbid)
305 for (StructureMapping sm : mappings)
307 if (sm.getPdbId().equals(pdbid))
316 * Import structure data and register a structure mapping for broadcasting
317 * colouring, mouseovers and selection events (convenience wrapper).
320 * - one or more sequences to be mapped to pdbFile
321 * @param targetChains
322 * - optional chain specification for mapping each sequence to pdb
323 * (may be nill, individual elements may be nill)
325 * - structure data resource
327 * - how to resolve data from resource
328 * @return null or the structure data parsed as a pdb file
330 synchronized public StructureFile setMapping(SequenceI[] sequence,
331 String[] targetChains, String pdbFile, DataSourceType protocol,
332 IProgressIndicator progress)
334 return computeMapping(true, sequence, targetChains, pdbFile, protocol,
340 * create sequence structure mappings between each sequence and the given
341 * pdbFile (retrieved via the given protocol).
343 * @param forStructureView
344 * when true, record the mapping for use in mouseOvers
346 * @param sequenceArray
347 * - one or more sequences to be mapped to pdbFile
348 * @param targetChainIds
349 * - optional chain specification for mapping each sequence to pdb
350 * (may be null, individual elements may be null)
352 * - structure data resource
354 * - how to resolve data from resource
355 * @return null or the structure data parsed as a pdb file
357 synchronized public StructureFile setMapping(boolean forStructureView,
358 SequenceI[] sequenceArray, String[] targetChainIds,
359 String pdbFile, DataSourceType protocol)
361 return computeMapping(forStructureView, sequenceArray, targetChainIds,
362 pdbFile, protocol, null);
365 synchronized public StructureFile computeMapping(
366 boolean forStructureView, SequenceI[] sequenceArray,
367 String[] targetChainIds, String pdbFile, DataSourceType protocol,
368 IProgressIndicator progress)
370 long progressSessionId = System.currentTimeMillis() * 3;
372 * There will be better ways of doing this in the future, for now we'll use
373 * the tried and tested MCview pdb mapping
375 boolean parseSecStr = processSecondaryStructure;
376 if (isPDBFileRegistered(pdbFile))
378 for (SequenceI sq : sequenceArray)
381 while (ds.getDatasetSequence() != null)
383 ds = ds.getDatasetSequence();
386 if (ds.getAnnotation() != null)
388 for (AlignmentAnnotation ala : ds.getAnnotation())
390 // false if any annotation present from this structure
391 // JBPNote this fails for jmol/chimera view because the *file* is
392 // passed, not the structure data ID -
393 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
401 StructureFile pdb = null;
402 boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
405 pdb = new JmolParser(pdbFile, protocol);
407 if (pdb.getId() != null && pdb.getId().trim().length() > 0
408 && DataSourceType.FILE == protocol)
410 registerPDBFile(pdb.getId().trim(), pdbFile);
412 // if PDBId is unavailable then skip SIFTS mapping execution path
413 isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable();
415 } catch (Exception ex)
417 ex.printStackTrace();
425 siftsClient = new SiftsClient(pdb);
427 } catch (SiftsException e)
429 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().substring(
452 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 (protocol.equals(DataSourceType.PASTE))
514 pdbFile = "INLINE" + pdb.getId();
516 boolean phyre2Template = isPhyre2Template(pdbFile);
517 List<StructureMapping> seqToStrucMapping = new ArrayList<StructureMapping>();
518 if (!phyre2Template && 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);
534 seqToStrucMapping.add(siftsMapping);
535 maxChain.makeExactMapping(maxAlignseq, seq);
536 maxChain.transferRESNUMFeatures(seq, null);// FIXME: is this
538 maxChain.transferResidueAnnotation(siftsMapping, sqmpping);
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, null); // FIXME: is this
551 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
552 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
553 } catch (Exception e)
560 List<StructureMapping> foundSiftsMappings = new ArrayList<StructureMapping>();
561 for (PDBChain chain : pdb.getChains())
565 StructureMapping siftsMapping = getStructureMapping(seq,
566 pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq);
567 foundSiftsMappings.add(siftsMapping);
568 } catch (SiftsException e)
570 System.err.println(e.getMessage());
571 } catch (Exception e)
576 if (!foundSiftsMappings.isEmpty())
578 seqToStrucMapping.addAll(foundSiftsMappings);
579 maxChain.makeExactMapping(maxAlignseq, seq);
580 maxChain.transferRESNUMFeatures(seq, null);// FIXME: is this
582 maxChain.transferResidueAnnotation(foundSiftsMappings.get(0),
584 ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
588 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
589 maxChainId, maxChain, pdb, maxAlignseq);
590 seqToStrucMapping.add(nwMapping);
591 maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
593 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
594 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
598 else if (phyre2Template)
600 setProgressBar(null);
601 setProgressBar(MessageManager
602 .getString("status.obtaining_mapping_with_phyre2_template_alignment"));
603 String fastaFile = getPhyre2FastaFileFor(pdbFile);
604 StructureMapping phyre2ModelMapping = new Phyre2Client(pdb)
605 .getStructureMapping(seq, pdbFile, fastaFile, " ");
606 seqToStrucMapping.add(phyre2ModelMapping);
607 maxChain.makeExactMapping(maxAlignseq, seq);
608 maxChain.transferRESNUMFeatures(seq, null);
609 jalview.datamodel.Mapping sqmpping = maxAlignseq
610 .getMappingFromS1(false);
611 maxChain.transferResidueAnnotation(phyre2ModelMapping, sqmpping);
612 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
616 if (progress != null)
618 progress.setProgressBar(MessageManager
619 .getString("status.obtaining_mapping_with_nw_alignment"),
622 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
623 maxChainId, maxChain, pdb, maxAlignseq);
624 seqToStrucMapping.add(nwMapping);
625 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
629 if (forStructureView)
631 mappings.addAll(seqToStrucMapping);
637 public void registerPhyre2Template(String phyre2Template,
638 String fastaMappingFile)
640 phyre2ModelTemplates.put(phyre2Template, fastaMappingFile);
644 * retrieve a mapping for seq from SIFTs using associated DBRefEntry for
649 * @param targetChainId
655 * @throws SiftsException
657 private StructureMapping getStructureMapping(SequenceI seq,
658 String pdbFile, String targetChainId, StructureFile pdb,
659 PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
660 AlignSeq maxAlignseq) throws Exception
662 StructureMapping curChainMapping = siftsClient
663 .getStructureMapping(seq, pdbFile, targetChainId);
666 PDBChain chain = pdb.findChain(targetChainId);
669 chain.transferResidueAnnotation(curChainMapping, sqmpping);
671 } catch (Exception e)
675 return curChainMapping;
678 private StructureMapping getNWMappings(SequenceI seq, String pdbFile,
679 String maxChainId, PDBChain maxChain, StructureFile pdb,
680 AlignSeq maxAlignseq)
682 final StringBuilder mappingDetails = new StringBuilder(128);
683 mappingDetails.append(NEWLINE).append(
684 "Sequence \u27f7 Structure mapping details");
685 mappingDetails.append(NEWLINE);
687 .append("Method: inferred with Needleman & Wunsch alignment");
688 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
689 .append(NEWLINE).append("Sequence = ")
690 .append(maxChain.sequence.getSequenceAsString());
691 mappingDetails.append(NEWLINE).append("No of residues = ")
692 .append(maxChain.residues.size()).append(NEWLINE)
694 PrintStream ps = new PrintStream(System.out)
697 public void print(String x)
699 mappingDetails.append(x);
703 public void println()
705 mappingDetails.append(NEWLINE);
709 maxAlignseq.printAlignment(ps);
711 mappingDetails.append(NEWLINE).append("PDB start/end ");
712 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
714 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
715 mappingDetails.append(NEWLINE).append("SEQ start/end ");
716 mappingDetails.append(
717 String.valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
719 mappingDetails.append(String.valueOf(maxAlignseq.seq1end
720 + (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<Integer, int[]>();
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, new int[] { tmp.resNumber,
748 } while (index < maxChain.atoms.size());
750 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
751 pdb.getId(), maxChainId, mapping, mappingDetails.toString());
752 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
756 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
758 listeners.removeElement(svl);
759 if (svl instanceof SequenceListener)
761 for (int i = 0; i < listeners.size(); i++)
763 if (listeners.elementAt(i) instanceof StructureListener)
765 ((StructureListener) listeners.elementAt(i))
766 .releaseReferences(svl);
771 if (pdbfiles == null)
777 * Remove mappings to the closed listener's PDB files, but first check if
778 * another listener is still interested
780 List<String> pdbs = new ArrayList<String>(Arrays.asList(pdbfiles));
782 StructureListener sl;
783 for (int i = 0; i < listeners.size(); i++)
785 if (listeners.elementAt(i) instanceof StructureListener)
787 sl = (StructureListener) listeners.elementAt(i);
788 for (String pdbfile : sl.getStructureFiles())
790 pdbs.remove(pdbfile);
796 * Rebuild the mappings set, retaining only those which are for 'other' PDB
801 List<StructureMapping> tmp = new ArrayList<StructureMapping>();
802 for (StructureMapping sm : mappings)
804 if (!pdbs.contains(sm.pdbfile))
815 * Propagate mouseover of a single position in a structure
821 public void mouseOverStructure(int pdbResNum, String chain, String pdbfile)
823 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
824 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
825 mouseOverStructure(atoms);
829 * Propagate mouseover or selection of multiple positions in a structure
833 public void mouseOverStructure(List<AtomSpec> atoms)
835 if (listeners == null)
837 // old or prematurely sent event
840 boolean hasSequenceListener = false;
841 for (int i = 0; i < listeners.size(); i++)
843 if (listeners.elementAt(i) instanceof SequenceListener)
845 hasSequenceListener = true;
848 if (!hasSequenceListener)
853 SearchResultsI results = findAlignmentPositionsForStructurePositions(atoms);
854 for (Object li : listeners)
856 if (li instanceof SequenceListener)
858 ((SequenceListener) li).highlightSequence(results);
864 * Constructs a SearchResults object holding regions (if any) in the Jalview
865 * alignment which have a mapping to the structure viewer positions in the
871 public SearchResultsI findAlignmentPositionsForStructurePositions(
872 List<AtomSpec> atoms)
874 SearchResultsI results = new SearchResults();
875 for (AtomSpec atom : atoms)
877 SequenceI lastseq = null;
879 for (StructureMapping sm : mappings)
881 if (sm.pdbfile.equals(atom.getPdbFile())
882 && sm.pdbchain.equals(atom.getChain()))
884 int indexpos = sm.getSeqPos(atom.getPdbResNum());
885 if (lastipos != indexpos && lastseq != sm.sequence)
887 results.addResult(sm.sequence, indexpos, indexpos);
889 lastseq = sm.sequence;
890 // construct highlighted sequence list
891 for (AlignedCodonFrame acf : seqmappings)
893 acf.markMappedRegion(sm.sequence, indexpos, results);
903 * highlight regions associated with a position (indexpos) in seq
906 * the sequence that the mouse over occurred on
908 * the absolute position being mouseovered in seq (0 to seq.length())
910 * the sequence position (if -1, seq.findPosition is called to
911 * resolve the residue number)
913 public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
916 boolean hasSequenceListeners = handlingVamsasMo
917 || !seqmappings.isEmpty();
918 SearchResultsI results = null;
921 seqPos = seq.findPosition(indexpos);
923 for (int i = 0; i < listeners.size(); i++)
925 Object listener = listeners.elementAt(i);
926 if (listener == source)
928 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
929 // Temporary fudge with SequenceListener.getVamsasSource()
932 if (listener instanceof StructureListener)
934 highlightStructure((StructureListener) listener, seq, seqPos);
938 if (listener instanceof SequenceListener)
940 final SequenceListener seqListener = (SequenceListener) listener;
941 if (hasSequenceListeners
942 && seqListener.getVamsasSource() != source)
944 if (relaySeqMappings)
948 results = MappingUtils.buildSearchResults(seq, seqPos,
951 if (handlingVamsasMo)
953 results.addResult(seq, seqPos, seqPos);
956 if (!results.isEmpty())
958 seqListener.highlightSequence(results);
963 else if (listener instanceof VamsasListener && !handlingVamsasMo)
965 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
968 else if (listener instanceof SecondaryStructureListener)
970 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
978 * Send suitable messages to a StructureListener to highlight atoms
979 * corresponding to the given sequence position(s)
985 public void highlightStructure(StructureListener sl, SequenceI seq,
988 if (!sl.isListeningFor(seq))
993 List<AtomSpec> atoms = new ArrayList<AtomSpec>();
994 for (StructureMapping sm : mappings)
996 if (sm.sequence == seq
997 || sm.sequence == seq.getDatasetSequence()
998 || (sm.sequence.getDatasetSequence() != null && sm.sequence
999 .getDatasetSequence() == seq.getDatasetSequence()))
1001 for (int index : positions)
1003 atomNo = sm.getAtomNum(index);
1007 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain, sm
1008 .getPDBResNum(index), atomNo));
1013 sl.highlightAtoms(atoms);
1017 * true if a mouse over event from an external (ie Vamsas) source is being
1020 boolean handlingVamsasMo = false;
1025 * as mouseOverSequence but only route event to SequenceListeners
1029 * in an alignment sequence
1031 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
1032 VamsasSource source)
1034 handlingVamsasMo = true;
1035 long msg = sequenceI.hashCode() * (1 + position);
1039 mouseOverSequence(sequenceI, position, -1, source);
1041 handlingVamsasMo = false;
1044 public Annotation[] colourSequenceFromStructure(SequenceI seq,
1048 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
1049 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
1051 * Annotation [] annotations = new Annotation[seq.getLength()];
1053 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
1054 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
1055 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
1057 * for (int j = 0; j < mappings.length; j++) {
1059 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
1060 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
1061 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
1062 * "+mappings[j].pdbfile);
1064 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
1065 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
1067 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
1068 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
1069 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
1070 * mappings[j].pdbfile); }
1072 * annotations[index] = new Annotation("X",null,' ',0,col); } return
1073 * annotations; } } } }
1075 * return annotations;
1079 public void structureSelectionChanged()
1083 public void sequenceSelectionChanged()
1087 public void sequenceColoursChanged(Object source)
1089 StructureListener sl;
1090 for (int i = 0; i < listeners.size(); i++)
1092 if (listeners.elementAt(i) instanceof StructureListener)
1094 sl = (StructureListener) listeners.elementAt(i);
1095 sl.updateColours(source);
1100 public StructureMapping[] getMapping(String pdbfile)
1102 List<StructureMapping> tmp = new ArrayList<StructureMapping>();
1103 for (StructureMapping sm : mappings)
1105 if (sm.pdbfile.equals(pdbfile))
1110 return tmp.toArray(new StructureMapping[tmp.size()]);
1114 * Returns a readable description of all mappings for the given pdbfile to any
1115 * of the given sequences
1121 public String printMappings(String pdbfile, List<SequenceI> seqs)
1123 if (pdbfile == null || seqs == null || seqs.isEmpty())
1128 StringBuilder sb = new StringBuilder(64);
1129 for (StructureMapping sm : mappings)
1131 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
1133 sb.append(sm.mappingDetails);
1135 // separator makes it easier to read multiple mappings
1136 sb.append("=====================");
1142 return sb.toString();
1146 * Remove the given mapping
1150 public void deregisterMapping(AlignedCodonFrame acf)
1154 boolean removed = seqmappings.remove(acf);
1155 if (removed && seqmappings.isEmpty())
1157 System.out.println("All mappings removed");
1163 * Add each of the given codonFrames to the stored set, if not aready present.
1167 public void registerMappings(List<AlignedCodonFrame> mappings)
1169 if (mappings != null)
1171 for (AlignedCodonFrame acf : mappings)
1173 registerMapping(acf);
1179 * Add the given mapping to the stored set, unless already stored.
1181 public void registerMapping(AlignedCodonFrame acf)
1185 if (!seqmappings.contains(acf))
1187 seqmappings.add(acf);
1193 * Resets this object to its initial state by removing all registered
1194 * listeners, codon mappings, PDB file mappings
1196 public void resetAll()
1198 if (mappings != null)
1202 if (seqmappings != null)
1204 seqmappings.clear();
1206 if (sel_listeners != null)
1208 sel_listeners.clear();
1210 if (listeners != null)
1214 if (commandListeners != null)
1216 commandListeners.clear();
1218 if (view_listeners != null)
1220 view_listeners.clear();
1222 if (pdbFileNameId != null)
1224 pdbFileNameId.clear();
1226 if (pdbIdFileName != null)
1228 pdbIdFileName.clear();
1232 public void addSelectionListener(SelectionListener selecter)
1234 if (!sel_listeners.contains(selecter))
1236 sel_listeners.add(selecter);
1240 public void removeSelectionListener(SelectionListener toremove)
1242 if (sel_listeners.contains(toremove))
1244 sel_listeners.remove(toremove);
1248 public synchronized void sendSelection(
1249 jalview.datamodel.SequenceGroup selection,
1250 jalview.datamodel.ColumnSelection colsel, SelectionSource source)
1252 for (SelectionListener slis : sel_listeners)
1256 slis.selection(selection, colsel, source);
1261 Vector<AlignmentViewPanelListener> view_listeners = new Vector<AlignmentViewPanelListener>();
1263 public synchronized void sendViewPosition(
1264 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1265 int startSeq, int endSeq)
1268 if (view_listeners != null && view_listeners.size() > 0)
1270 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1272 while (listeners.hasMoreElements())
1274 AlignmentViewPanelListener slis = listeners.nextElement();
1277 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1285 * release all references associated with this manager provider
1287 * @param jalviewLite
1289 public static void release(StructureSelectionManagerProvider jalviewLite)
1291 // synchronized (instances)
1293 if (instances == null)
1297 StructureSelectionManager mnger = (instances.get(jalviewLite));
1300 instances.remove(jalviewLite);
1304 } catch (Throwable x)
1311 public void registerPDBEntry(PDBEntry pdbentry)
1313 if (pdbentry.getFile() != null
1314 && pdbentry.getFile().trim().length() > 0)
1316 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1320 public void addCommandListener(CommandListener cl)
1322 if (!commandListeners.contains(cl))
1324 commandListeners.add(cl);
1328 public boolean hasCommandListener(CommandListener cl)
1330 return this.commandListeners.contains(cl);
1333 public boolean removeCommandListener(CommandListener l)
1335 return commandListeners.remove(l);
1339 * Forward a command to any command listeners (except for the command's
1343 * the command to be broadcast (in its form after being performed)
1345 * if true, the command was being 'undone'
1348 public void commandPerformed(CommandI command, boolean undo,
1349 VamsasSource source)
1351 for (CommandListener listener : commandListeners)
1353 listener.mirrorCommand(command, undo, this, source);
1358 * Returns a new CommandI representing the given command as mapped to the
1359 * given sequences. If no mapping could be made, or the command is not of a
1360 * mappable kind, returns null.
1368 public CommandI mapCommand(CommandI command, boolean undo,
1369 final AlignmentI mapTo, char gapChar)
1371 if (command instanceof EditCommand)
1373 return MappingUtils.mapEditCommand((EditCommand) command, undo,
1374 mapTo, gapChar, seqmappings);
1376 else if (command instanceof OrderCommand)
1378 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1379 mapTo, seqmappings);
1384 public IProgressIndicator getProgressIndicator()
1386 return progressIndicator;
1389 public void setProgressIndicator(IProgressIndicator progressIndicator)
1391 this.progressIndicator = progressIndicator;
1394 public long getProgressSessionId()
1396 return progressSessionId;
1399 public void setProgressSessionId(long progressSessionId)
1401 this.progressSessionId = progressSessionId;
1404 public void setProgressBar(String message)
1406 if (progressIndicator == null)
1410 progressIndicator.setProgressBar(message, progressSessionId);
1413 public List<AlignedCodonFrame> getSequenceMappings()
1418 public boolean isPhyre2Template(String structureFile)
1420 if (structureFile == null || phyre2ModelTemplates == null
1421 || phyre2ModelTemplates.isEmpty())
1425 return phyre2ModelTemplates.get(structureFile) != null
1426 && !phyre2ModelTemplates.get(structureFile).isEmpty();
1429 public String getPhyre2FastaFileFor(String structureFile)
1431 return phyre2ModelTemplates.get(structureFile);
1435 public static StructureSelectionManager getStructureSelectionManager()
1437 return instances.values().iterator().next();
1440 public void addStructureMapping(StructureMapping smapping)
1442 mappings.add(smapping);