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 mc_view.PDBChain;
61 import mc_view.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(false, pdbFile, sourceType);
402 pdb.addSettings(parseSecStr && processSecondaryStructure,
403 parseSecStr && addTempFacAnnot,
404 parseSecStr && secStructServices);
406 if (pdb.getId() != null && pdb.getId().trim().length() > 0
407 && DataSourceType.FILE == sourceType)
409 registerPDBFile(pdb.getId().trim(), pdbFile);
411 // if PDBId is unavailable then skip SIFTS mapping execution path
412 isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable();
414 } catch (Exception ex)
416 ex.printStackTrace();
420 * sifts client - non null if SIFTS mappings are to be used
422 SiftsClient siftsClient = null;
427 siftsClient = new SiftsClient(pdb);
429 } catch (SiftsException e)
431 isMapUsingSIFTs = false;
436 String targetChainId;
437 for (int s = 0; s < sequenceArray.length; s++)
439 boolean infChain = true;
440 final SequenceI seq = sequenceArray[s];
442 while (ds.getDatasetSequence() != null)
444 ds = ds.getDatasetSequence();
447 if (targetChainIds != null && targetChainIds[s] != null)
450 targetChainId = targetChainIds[s];
452 else if (seq.getName().indexOf("|") > -1)
454 targetChainId = seq.getName()
455 .substring(seq.getName().lastIndexOf("|") + 1);
456 if (targetChainId.length() > 1)
458 if (targetChainId.trim().length() == 0)
464 // not a valid chain identifier
475 * Attempt pairwise alignment of the sequence with each chain in the PDB,
476 * and remember the highest scoring chain
479 AlignSeq maxAlignseq = null;
480 String maxChainId = " ";
481 PDBChain maxChain = null;
482 boolean first = true;
483 for (PDBChain chain : pdb.getChains())
485 if (targetChainId.length() > 0 && !targetChainId.equals(chain.id)
488 continue; // don't try to map chains don't match.
490 // TODO: correctly determine sequence type for mixed na/peptide
492 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
493 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
496 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
497 // as.calcScoreMatrix();
498 // as.traceAlignment();
500 if (first || as.maxscore > max
501 || (as.maxscore == max && chain.id.equals(targetChainId)))
507 maxChainId = chain.id;
510 if (maxChain == null)
515 if (sourceType == DataSourceType.PASTE)
517 pdbFile = "INLINE" + pdb.getId();
520 List<StructureMapping> seqToStrucMapping = new ArrayList<>();
521 if (isMapUsingSIFTs && seq.isProtein())
523 if (progress!=null) {
524 progress.setProgressBar(MessageManager
525 .getString("status.obtaining_mapping_with_sifts"),
528 jalview.datamodel.Mapping sqmpping = maxAlignseq
529 .getMappingFromS1(false);
530 if (targetChainId != null && !targetChainId.trim().isEmpty())
532 StructureMapping siftsMapping;
535 siftsMapping = getStructureMapping(seq, pdbFile, targetChainId,
536 pdb, maxChain, sqmpping, maxAlignseq, siftsClient);
537 seqToStrucMapping.add(siftsMapping);
538 maxChain.makeExactMapping(siftsMapping, seq);
539 maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
541 maxChain.transferResidueAnnotation(siftsMapping, null);
542 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
544 } catch (SiftsException e)
546 // fall back to NW alignment
547 System.err.println(e.getMessage());
548 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
549 targetChainId, maxChain, pdb, maxAlignseq);
550 seqToStrucMapping.add(nwMapping);
551 maxChain.makeExactMapping(maxAlignseq, seq);
552 maxChain.transferRESNUMFeatures(seq, "IEA:Jalview"); // FIXME: is
555 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
556 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
561 List<StructureMapping> foundSiftsMappings = new ArrayList<>();
562 for (PDBChain chain : pdb.getChains())
564 StructureMapping siftsMapping = null;
567 siftsMapping = getStructureMapping(seq,
568 pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq,
570 foundSiftsMappings.add(siftsMapping);
571 chain.makeExactMapping(siftsMapping, seq);
572 chain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
574 chain.transferResidueAnnotation(siftsMapping, null);
575 } catch (SiftsException e)
577 System.err.println(e.getMessage());
583 "Unexpected exception during SIFTS mapping - falling back to NW for this sequence/structure pair");
584 System.err.println(e.getMessage());
587 if (!foundSiftsMappings.isEmpty())
589 seqToStrucMapping.addAll(foundSiftsMappings);
590 ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
594 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
595 maxChainId, maxChain, pdb, maxAlignseq);
596 seqToStrucMapping.add(nwMapping);
597 maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
599 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
600 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
606 if (progress != null)
608 progress.setProgressBar(MessageManager
609 .getString("status.obtaining_mapping_with_nw_alignment"),
612 StructureMapping nwMapping = getNWMappings(seq, pdbFile, maxChainId,
613 maxChain, pdb, maxAlignseq);
614 seqToStrucMapping.add(nwMapping);
615 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
617 if (forStructureView)
619 for (StructureMapping sm : seqToStrucMapping)
621 addStructureMapping(sm); // not addAll!
624 if (progress != null)
626 progress.setProgressBar(null, progressSessionId);
633 * check if we need to extract secondary structure from given pdbFile and
634 * transfer to sequences
637 * @param sequenceArray
640 private boolean isStructureFileProcessed(String pdbFile,
641 SequenceI[] sequenceArray)
643 boolean parseSecStr = true;
644 if (isPDBFileRegistered(pdbFile))
646 for (SequenceI sq : sequenceArray)
649 while (ds.getDatasetSequence() != null)
651 ds = ds.getDatasetSequence();
654 if (ds.getAnnotation() != null)
656 for (AlignmentAnnotation ala : ds.getAnnotation())
658 // false if any annotation present from this structure
659 // JBPNote this fails for jmol/chimera view because the *file* is
660 // passed, not the structure data ID -
661 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
672 public void addStructureMapping(StructureMapping sm)
674 if (!mappings.contains(sm))
681 * retrieve a mapping for seq from SIFTs using associated DBRefEntry for
686 * @param targetChainId
692 * client for retrieval of SIFTS mappings for this structure
694 * @throws SiftsException
696 private StructureMapping getStructureMapping(SequenceI seq,
697 String pdbFile, String targetChainId, StructureFile pdb,
698 PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
699 AlignSeq maxAlignseq, SiftsClient siftsClient) throws SiftsException
701 StructureMapping curChainMapping = siftsClient
702 .getSiftsStructureMapping(seq, pdbFile, targetChainId);
705 PDBChain chain = pdb.findChain(targetChainId);
708 chain.transferResidueAnnotation(curChainMapping, null);
710 } catch (Exception e)
714 return curChainMapping;
717 private StructureMapping getNWMappings(SequenceI seq, String pdbFile,
718 String maxChainId, PDBChain maxChain, StructureFile pdb,
719 AlignSeq maxAlignseq)
721 final StringBuilder mappingDetails = new StringBuilder(128);
722 mappingDetails.append(NEWLINE)
723 .append("Sequence \u27f7 Structure mapping details");
724 mappingDetails.append(NEWLINE);
726 .append("Method: inferred with Needleman & Wunsch alignment");
727 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
728 .append(NEWLINE).append("Sequence = ")
729 .append(maxChain.sequence.getSequenceAsString());
730 mappingDetails.append(NEWLINE).append("No of residues = ")
731 .append(maxChain.residues.size()).append(NEWLINE)
733 PrintStream ps = new PrintStream(System.out)
736 public void print(String x)
738 mappingDetails.append(x);
742 public void println()
744 mappingDetails.append(NEWLINE);
748 maxAlignseq.printAlignment(ps);
750 mappingDetails.append(NEWLINE).append("PDB start/end ");
751 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
753 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
754 mappingDetails.append(NEWLINE).append("SEQ start/end ");
757 .valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
759 mappingDetails.append(
760 String.valueOf(maxAlignseq.seq1end + (seq.getStart() - 1)));
761 mappingDetails.append(NEWLINE);
762 maxChain.makeExactMapping(maxAlignseq, seq);
763 jalview.datamodel.Mapping sqmpping = maxAlignseq
764 .getMappingFromS1(false);
765 maxChain.transferRESNUMFeatures(seq, null);
767 HashMap<Integer, int[]> mapping = new HashMap<>();
774 Atom tmp = maxChain.atoms.elementAt(index);
775 if ((resNum != tmp.resNumber || insCode != tmp.insCode)
776 && tmp.alignmentMapping != -1)
778 resNum = tmp.resNumber;
779 insCode = tmp.insCode;
780 if (tmp.alignmentMapping >= -1)
782 mapping.put(tmp.alignmentMapping + 1,
784 { tmp.resNumber, tmp.atomIndex });
789 } while (index < maxChain.atoms.size());
791 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
792 pdb.getId(), maxChainId, mapping, mappingDetails.toString());
793 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
797 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
799 listeners.removeElement(svl);
800 if (svl instanceof SequenceListener)
802 for (int i = 0; i < listeners.size(); i++)
804 if (listeners.elementAt(i) instanceof StructureListener)
806 ((StructureListener) listeners.elementAt(i))
807 .releaseReferences(svl);
812 if (pdbfiles == null)
818 * Remove mappings to the closed listener's PDB files, but first check if
819 * another listener is still interested
821 List<String> pdbs = new ArrayList<>(Arrays.asList(pdbfiles));
823 StructureListener sl;
824 for (int i = 0; i < listeners.size(); i++)
826 if (listeners.elementAt(i) instanceof StructureListener)
828 sl = (StructureListener) listeners.elementAt(i);
829 for (String pdbfile : sl.getStructureFiles())
831 pdbs.remove(pdbfile);
837 * Rebuild the mappings set, retaining only those which are for 'other' PDB
842 List<StructureMapping> tmp = new ArrayList<>();
843 for (StructureMapping sm : mappings)
845 if (!pdbs.contains(sm.pdbfile))
856 * Propagate mouseover of a single position in a structure
862 public void mouseOverStructure(int pdbResNum, String chain,
865 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
866 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
867 mouseOverStructure(atoms);
871 * Propagate mouseover or selection of multiple positions in a structure
875 public void mouseOverStructure(List<AtomSpec> atoms)
877 if (listeners == null)
879 // old or prematurely sent event
882 boolean hasSequenceListener = false;
883 for (int i = 0; i < listeners.size(); i++)
885 if (listeners.elementAt(i) instanceof SequenceListener)
887 hasSequenceListener = true;
890 if (!hasSequenceListener)
895 SearchResultsI results = findAlignmentPositionsForStructurePositions(
897 for (Object li : listeners)
899 if (li instanceof SequenceListener)
901 ((SequenceListener) li).highlightSequence(results);
907 * Constructs a SearchResults object holding regions (if any) in the Jalview
908 * alignment which have a mapping to the structure viewer positions in the
914 public SearchResultsI findAlignmentPositionsForStructurePositions(
915 List<AtomSpec> atoms)
917 SearchResultsI results = new SearchResults();
918 for (AtomSpec atom : atoms)
920 SequenceI lastseq = null;
922 for (StructureMapping sm : mappings)
924 if (sm.pdbfile.equals(atom.getPdbFile())
925 && sm.pdbchain.equals(atom.getChain()))
927 int indexpos = sm.getSeqPos(atom.getPdbResNum());
928 if (lastipos != indexpos || lastseq != sm.sequence)
930 results.addResult(sm.sequence, indexpos, indexpos);
932 lastseq = sm.sequence;
933 // construct highlighted sequence list
934 for (AlignedCodonFrame acf : seqmappings)
936 acf.markMappedRegion(sm.sequence, indexpos, results);
946 * highlight regions associated with a position (indexpos) in seq
949 * the sequence that the mouse over occurred on
951 * the absolute position being mouseovered in seq (0 to seq.length())
953 * the sequence position (if -1, seq.findPosition is called to
954 * resolve the residue number)
956 public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
959 boolean hasSequenceListeners = handlingVamsasMo
960 || !seqmappings.isEmpty();
961 SearchResultsI results = null;
964 seqPos = seq.findPosition(indexpos);
966 for (int i = 0; i < listeners.size(); i++)
968 Object listener = listeners.elementAt(i);
969 if (listener == source)
971 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
972 // Temporary fudge with SequenceListener.getVamsasSource()
975 if (listener instanceof StructureListener)
977 highlightStructure((StructureListener) listener, seq, seqPos);
981 if (listener instanceof SequenceListener)
983 final SequenceListener seqListener = (SequenceListener) listener;
984 if (hasSequenceListeners
985 && seqListener.getVamsasSource() != source)
987 if (relaySeqMappings)
991 results = MappingUtils.buildSearchResults(seq, seqPos,
994 if (handlingVamsasMo)
996 results.addResult(seq, seqPos, seqPos);
999 if (!results.isEmpty())
1001 seqListener.highlightSequence(results);
1006 else if (listener instanceof VamsasListener && !handlingVamsasMo)
1008 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
1011 else if (listener instanceof SecondaryStructureListener)
1013 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
1021 * Send suitable messages to a StructureListener to highlight atoms
1022 * corresponding to the given sequence position(s)
1028 public void highlightStructure(StructureListener sl, SequenceI seq,
1031 if (!sl.isListeningFor(seq))
1036 List<AtomSpec> atoms = new ArrayList<>();
1037 for (StructureMapping sm : mappings)
1039 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
1040 || (sm.sequence.getDatasetSequence() != null && sm.sequence
1041 .getDatasetSequence() == seq.getDatasetSequence()))
1043 for (int index : positions)
1045 atomNo = sm.getAtomNum(index);
1049 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
1050 sm.getPDBResNum(index), atomNo));
1055 sl.highlightAtoms(atoms);
1059 * true if a mouse over event from an external (ie Vamsas) source is being
1062 boolean handlingVamsasMo = false;
1067 * as mouseOverSequence but only route event to SequenceListeners
1071 * in an alignment sequence
1073 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
1074 VamsasSource source)
1076 handlingVamsasMo = true;
1077 long msg = sequenceI.hashCode() * (1 + position);
1081 mouseOverSequence(sequenceI, position, -1, source);
1083 handlingVamsasMo = false;
1086 public Annotation[] colourSequenceFromStructure(SequenceI seq,
1090 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
1091 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
1093 * Annotation [] annotations = new Annotation[seq.getLength()];
1095 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
1096 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
1097 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
1099 * for (int j = 0; j < mappings.length; j++) {
1101 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
1102 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
1103 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
1104 * "+mappings[j].pdbfile);
1106 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
1107 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
1109 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
1110 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
1111 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
1112 * mappings[j].pdbfile); }
1114 * annotations[index] = new Annotation("X",null,' ',0,col); } return
1115 * annotations; } } } }
1117 * return annotations;
1121 public void structureSelectionChanged()
1125 public void sequenceSelectionChanged()
1129 public void sequenceColoursChanged(Object source)
1131 StructureListener sl;
1132 for (int i = 0; i < listeners.size(); i++)
1134 if (listeners.elementAt(i) instanceof StructureListener)
1136 sl = (StructureListener) listeners.elementAt(i);
1137 sl.updateColours(source);
1142 public StructureMapping[] getMapping(String pdbfile)
1144 List<StructureMapping> tmp = new ArrayList<>();
1145 for (StructureMapping sm : mappings)
1147 if (sm.pdbfile.equals(pdbfile))
1152 return tmp.toArray(new StructureMapping[tmp.size()]);
1156 * Returns a readable description of all mappings for the given pdbfile to any
1157 * of the given sequences
1163 public String printMappings(String pdbfile, List<SequenceI> seqs)
1165 if (pdbfile == null || seqs == null || seqs.isEmpty())
1170 StringBuilder sb = new StringBuilder(64);
1171 for (StructureMapping sm : mappings)
1173 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
1175 sb.append(sm.mappingDetails);
1177 // separator makes it easier to read multiple mappings
1178 sb.append("=====================");
1184 return sb.toString();
1188 * Remove the given mapping
1192 public void deregisterMapping(AlignedCodonFrame acf)
1196 boolean removed = seqmappings.remove(acf);
1197 if (removed && seqmappings.isEmpty())
1199 System.out.println("All mappings removed");
1205 * Add each of the given codonFrames to the stored set, if not aready present.
1209 public void registerMappings(List<AlignedCodonFrame> mappings)
1211 if (mappings != null)
1213 for (AlignedCodonFrame acf : mappings)
1215 registerMapping(acf);
1221 * Add the given mapping to the stored set, unless already stored.
1223 public void registerMapping(AlignedCodonFrame acf)
1227 if (!seqmappings.contains(acf))
1229 seqmappings.add(acf);
1235 * Resets this object to its initial state by removing all registered
1236 * listeners, codon mappings, PDB file mappings
1238 public void resetAll()
1240 if (mappings != null)
1244 if (seqmappings != null)
1246 seqmappings.clear();
1248 if (sel_listeners != null)
1250 sel_listeners.clear();
1252 if (listeners != null)
1256 if (commandListeners != null)
1258 commandListeners.clear();
1260 if (view_listeners != null)
1262 view_listeners.clear();
1264 if (pdbFileNameId != null)
1266 pdbFileNameId.clear();
1268 if (pdbIdFileName != null)
1270 pdbIdFileName.clear();
1274 public void addSelectionListener(SelectionListener selecter)
1276 if (!sel_listeners.contains(selecter))
1278 sel_listeners.add(selecter);
1282 public void removeSelectionListener(SelectionListener toremove)
1284 if (sel_listeners.contains(toremove))
1286 sel_listeners.remove(toremove);
1290 public synchronized void sendSelection(
1291 jalview.datamodel.SequenceGroup selection,
1292 jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
1293 SelectionSource source)
1295 for (SelectionListener slis : sel_listeners)
1299 slis.selection(selection, colsel, hidden, source);
1304 Vector<AlignmentViewPanelListener> view_listeners = new Vector<>();
1306 public synchronized void sendViewPosition(
1307 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1308 int startSeq, int endSeq)
1311 if (view_listeners != null && view_listeners.size() > 0)
1313 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1315 while (listeners.hasMoreElements())
1317 AlignmentViewPanelListener slis = listeners.nextElement();
1320 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1328 * release all references associated with this manager provider
1330 * @param jalviewLite
1332 public static void release(StructureSelectionManagerProvider jalviewLite)
1334 // synchronized (instances)
1336 if (instances == null)
1340 StructureSelectionManager mnger = (instances.get(jalviewLite));
1343 instances.remove(jalviewLite);
1347 } catch (Throwable x)
1354 public void registerPDBEntry(PDBEntry pdbentry)
1356 if (pdbentry.getFile() != null
1357 && pdbentry.getFile().trim().length() > 0)
1359 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1363 public void addCommandListener(CommandListener cl)
1365 if (!commandListeners.contains(cl))
1367 commandListeners.add(cl);
1371 public boolean hasCommandListener(CommandListener cl)
1373 return this.commandListeners.contains(cl);
1376 public boolean removeCommandListener(CommandListener l)
1378 return commandListeners.remove(l);
1382 * Forward a command to any command listeners (except for the command's
1386 * the command to be broadcast (in its form after being performed)
1388 * if true, the command was being 'undone'
1391 public void commandPerformed(CommandI command, boolean undo,
1392 VamsasSource source)
1394 for (CommandListener listener : commandListeners)
1396 listener.mirrorCommand(command, undo, this, source);
1401 * Returns a new CommandI representing the given command as mapped to the
1402 * given sequences. If no mapping could be made, or the command is not of a
1403 * mappable kind, returns null.
1411 public CommandI mapCommand(CommandI command, boolean undo,
1412 final AlignmentI mapTo, char gapChar)
1414 if (command instanceof EditCommand)
1416 return MappingUtils.mapEditCommand((EditCommand) command, undo, mapTo,
1417 gapChar, seqmappings);
1419 else if (command instanceof OrderCommand)
1421 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1422 mapTo, seqmappings);
1427 public List<AlignedCodonFrame> getSequenceMappings()