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.bin.Instance;
26 import jalview.commands.CommandI;
27 import jalview.commands.EditCommand;
28 import jalview.commands.OrderCommand;
29 import jalview.datamodel.AlignedCodonFrame;
30 import jalview.datamodel.AlignmentAnnotation;
31 import jalview.datamodel.AlignmentI;
32 import jalview.datamodel.Annotation;
33 import jalview.datamodel.HiddenColumns;
34 import jalview.datamodel.PDBEntry;
35 import jalview.datamodel.SearchResults;
36 import jalview.datamodel.SearchResultsI;
37 import jalview.datamodel.SequenceI;
38 import jalview.ext.jmol.JmolParser;
39 import jalview.gui.IProgressIndicator;
40 import jalview.io.AppletFormatAdapter;
41 import jalview.io.DataSourceType;
42 import jalview.io.StructureFile;
43 import jalview.util.MappingUtils;
44 import jalview.util.MessageManager;
45 import jalview.ws.sifts.SiftsClient;
46 import jalview.ws.sifts.SiftsException;
47 import jalview.ws.sifts.SiftsSettings;
49 import java.io.PrintStream;
50 import java.util.ArrayList;
51 import java.util.Arrays;
52 import java.util.Collections;
53 import java.util.Enumeration;
54 import java.util.HashMap;
55 import java.util.IdentityHashMap;
56 import java.util.List;
58 import java.util.Vector;
61 import mc_view.PDBChain;
62 import mc_view.PDBfile;
64 public class StructureSelectionManager
67 public static StructureSelectionManager getStructureSelectionManager(
68 StructureSelectionManagerProvider context)
70 IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> map = Instance
71 .getInstance().structureSelections;
76 .getInstance().structureSelections = new IdentityHashMap<>();
78 StructureSelectionManager instance = map.get(context);
81 // BH: actually, not possible except for coding error; this is an attempt
83 if (context == null && !map.isEmpty())
85 throw new Error(MessageManager.getString(
86 "error.implementation_error_structure_selection_manager_null"),
87 new NullPointerException(MessageManager
88 .getString("exception.ssm_context_is_null")));
90 map.put(context, instance = new StructureSelectionManager());
96 * release all references associated with this manager provider
101 public static void release(StructureSelectionManagerProvider provider)
103 IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> map = Instance
104 .getInstance().structureSelections;
107 map.remove(provider);
111 public StructureSelectionManager()
115 public final static String NEWLINE = System.lineSeparator();
117 // BH unnecessary; IdentityHashMap can handle this
118 // private static StructureSelectionManager nullProvider;
120 private List<StructureMapping> mappings = new ArrayList<>();
122 private boolean processSecondaryStructure = false;
124 private boolean secStructServices = false;
126 private boolean addTempFacAnnot = false;
129 * Set of any registered mappings between (dataset) sequences.
131 private List<AlignedCodonFrame> seqmappings = new ArrayList<>();
133 private List<CommandListener> commandListeners = new ArrayList<>();
135 private List<SelectionListener> sel_listeners = new ArrayList<>();
138 * @return true if will try to use external services for processing secondary
141 public boolean isSecStructServices()
143 return secStructServices;
147 * control use of external services for processing secondary structure
149 * @param secStructServices
151 public void setSecStructServices(boolean secStructServices)
153 this.secStructServices = secStructServices;
157 * flag controlling addition of any kind of structural annotation
159 * @return true if temperature factor annotation will be added
161 public boolean isAddTempFacAnnot()
163 return addTempFacAnnot;
167 * set flag controlling addition of structural annotation
169 * @param addTempFacAnnot
171 public void setAddTempFacAnnot(boolean addTempFacAnnot)
173 this.addTempFacAnnot = addTempFacAnnot;
178 * @return if true, the structure manager will attempt to add secondary
179 * structure lines for unannotated sequences
182 public boolean isProcessSecondaryStructure()
184 return processSecondaryStructure;
188 * Control whether structure manager will try to annotate mapped sequences
189 * with secondary structure from PDB data.
193 public void setProcessSecondaryStructure(boolean enable)
195 processSecondaryStructure = enable;
199 * debug function - write all mappings to stdout
201 public void reportMapping()
203 if (mappings.isEmpty())
205 System.err.println("reportMapping: No PDB/Sequence mappings.");
210 "reportMapping: There are " + mappings.size() + " mappings.");
212 for (StructureMapping sm : mappings)
214 System.err.println("mapping " + i++ + " : " + sm.pdbfile);
220 * map between the PDB IDs (or structure identifiers) used by Jalview and the
221 * absolute filenames for PDB data that corresponds to it
223 Map<String, String> pdbIdFileName = new HashMap<>();
225 Map<String, String> pdbFileNameId = new HashMap<>();
227 public void registerPDBFile(String idForFile, String absoluteFile)
229 pdbIdFileName.put(idForFile, absoluteFile);
230 pdbFileNameId.put(absoluteFile, idForFile);
233 public String findIdForPDBFile(String idOrFile)
235 String id = pdbFileNameId.get(idOrFile);
239 public String findFileForPDBId(String idOrFile)
241 String id = pdbIdFileName.get(idOrFile);
245 public boolean isPDBFileRegistered(String idOrFile)
247 return pdbFileNameId.containsKey(idOrFile)
248 || pdbIdFileName.containsKey(idOrFile);
252 * flag controlling whether SeqMappings are relayed from received sequence
253 * mouse over events to other sequences
255 boolean relaySeqMappings = true;
258 * Enable or disable relay of seqMapping events to other sequences. You might
259 * want to do this if there are many sequence mappings and the host computer
264 public void setRelaySeqMappings(boolean relay)
266 relaySeqMappings = relay;
270 * get the state of the relay seqMappings flag.
272 * @return true if sequence mouse overs are being relayed to other mapped
275 public boolean isRelaySeqMappingsEnabled()
277 return relaySeqMappings;
280 Vector<Object> listeners = new Vector<>();
283 * register a listener for alignment sequence mouseover events
287 public void addStructureViewerListener(Object svl)
289 if (!listeners.contains(svl))
291 listeners.addElement(svl);
296 * Returns the filename the PDB id is already mapped to if known, or null if
302 public String alreadyMappedToFile(String pdbid)
304 for (StructureMapping sm : mappings)
306 if (sm.getPdbId().equalsIgnoreCase(pdbid))
315 * Import structure data and register a structure mapping for broadcasting
316 * colouring, mouseovers and selection events (convenience wrapper).
318 * This is the standard entry point.
321 * - one or more sequences to be mapped to pdbFile
322 * @param targetChains
323 * - optional chain specification for mapping each sequence to pdb
324 * (may be nill, individual elements may be nill)
326 * - structure data resource
328 * - how to resolve data from resource
329 * @return null or the structure data parsed as a pdb file
331 synchronized public StructureFile setMapping(SequenceI[] sequence,
332 String[] targetChains, String pdbFile, DataSourceType protocol,
333 IProgressIndicator progress)
335 return computeMapping(true, sequence, targetChains, pdbFile, protocol,
340 * Import a single structure file and register sequence structure mappings for
341 * broadcasting colouring, mouseovers and selection events (convenience
346 * @param forStructureView
347 * when true (testng only), record the mapping for use in mouseOvers
350 * - one or more sequences to be mapped to pdbFile
351 * @param targetChains
352 * - optional chain specification for mapping each sequence to pdb
353 * (may be nill, individual elements may be nill)
355 * - structure data resource
357 * - how to resolve data from resource
358 * @return null or the structure data parsed as a pdb file
360 synchronized public StructureFile setMapping(boolean forStructureView,
361 SequenceI[] sequenceArray, String[] targetChainIds,
362 String pdbFile, DataSourceType sourceType)
364 return computeMapping(forStructureView, sequenceArray, targetChainIds,
365 pdbFile, sourceType, null);
369 * create sequence structure mappings between each sequence and the given
370 * pdbFile (retrieved via the given protocol). Either constructs a mapping
371 * using NW alignment or derives one from any available SIFTS mapping data.
373 * @param forStructureView
374 * when true, record the mapping for use in mouseOvers
376 * @param sequenceArray
377 * - one or more sequences to be mapped to pdbFile
378 * @param targetChainIds
379 * - optional chain specification for mapping each sequence to pdb
380 * (may be nill, individual elements may be nill) - JBPNote: JAL-2693
381 * - this should be List<List<String>>, empty lists indicate no
382 * predefined mappings
384 * - structure data resource
386 * - how to resolve data from resource
387 * @param IProgressIndicator
388 * reference to UI component that maintains a progress bar for the
390 * @return null or the structure data parsed as a pdb file
392 synchronized private StructureFile computeMapping(
393 boolean forStructureView, SequenceI[] sequenceArray,
394 String[] targetChainIds, String pdbFile, DataSourceType sourceType,
395 IProgressIndicator progress)
397 long progressSessionId = System.currentTimeMillis() * 3;
400 * do we extract and transfer annotation from 3D data ?
402 // FIXME: possibly should just delete
404 boolean parseSecStr = processSecondaryStructure
405 ? isStructureFileProcessed(pdbFile, sequenceArray)
408 StructureFile pdb = null;
409 boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
412 // FIXME if sourceType is not null, we've lost data here
413 sourceType = AppletFormatAdapter.checkProtocol(pdbFile);
414 pdb = new JmolParser(false, pdbFile, sourceType);
415 pdb.addSettings(parseSecStr && processSecondaryStructure,
416 parseSecStr && addTempFacAnnot,
417 parseSecStr && secStructServices);
419 if (pdb.getId() != null && pdb.getId().trim().length() > 0
420 && DataSourceType.FILE == sourceType)
422 registerPDBFile(pdb.getId().trim(), pdbFile);
424 // if PDBId is unavailable then skip SIFTS mapping execution path
425 isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable();
427 } catch (Exception ex)
429 ex.printStackTrace();
433 * sifts client - non null if SIFTS mappings are to be used
435 SiftsClient siftsClient = null;
440 siftsClient = new SiftsClient(pdb);
442 } catch (SiftsException e)
444 isMapUsingSIFTs = false;
449 String targetChainId;
450 for (int s = 0; s < sequenceArray.length; s++)
452 boolean infChain = true;
453 final SequenceI seq = sequenceArray[s];
455 while (ds.getDatasetSequence() != null)
457 ds = ds.getDatasetSequence();
460 if (targetChainIds != null && targetChainIds[s] != null)
463 targetChainId = targetChainIds[s];
465 else if (seq.getName().indexOf("|") > -1)
467 targetChainId = seq.getName()
468 .substring(seq.getName().lastIndexOf("|") + 1);
469 if (targetChainId.length() > 1)
471 if (targetChainId.trim().length() == 0)
477 // not a valid chain identifier
488 * Attempt pairwise alignment of the sequence with each chain in the PDB,
489 * and remember the highest scoring chain
492 AlignSeq maxAlignseq = null;
493 String maxChainId = " ";
494 PDBChain maxChain = null;
495 boolean first = true;
496 for (PDBChain chain : pdb.getChains())
498 if (targetChainId.length() > 0 && !targetChainId.equals(chain.id)
501 continue; // don't try to map chains don't match.
503 // TODO: correctly determine sequence type for mixed na/peptide
505 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
506 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
509 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
510 // as.calcScoreMatrix();
511 // as.traceAlignment();
513 if (first || as.maxscore > max
514 || (as.maxscore == max && chain.id.equals(targetChainId)))
520 maxChainId = chain.id;
523 if (maxChain == null)
528 if (sourceType == DataSourceType.PASTE)
530 pdbFile = "INLINE" + pdb.getId();
533 List<StructureMapping> seqToStrucMapping = new ArrayList<>();
534 if (isMapUsingSIFTs && seq.isProtein())
536 if (progress!=null) {
537 progress.setProgressBar(MessageManager
538 .getString("status.obtaining_mapping_with_sifts"),
541 jalview.datamodel.Mapping sqmpping = maxAlignseq
542 .getMappingFromS1(false);
543 if (targetChainId != null && !targetChainId.trim().isEmpty())
545 StructureMapping siftsMapping;
548 siftsMapping = getStructureMapping(seq, pdbFile, targetChainId,
549 pdb, maxChain, sqmpping, maxAlignseq, siftsClient);
550 seqToStrucMapping.add(siftsMapping);
551 maxChain.makeExactMapping(siftsMapping, seq);
552 maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
554 maxChain.transferResidueAnnotation(siftsMapping, null);
555 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
557 } catch (SiftsException e)
559 // fall back to NW alignment
560 System.err.println(e.getMessage());
561 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
562 targetChainId, maxChain, pdb, maxAlignseq);
563 seqToStrucMapping.add(nwMapping);
564 maxChain.makeExactMapping(maxAlignseq, seq);
565 maxChain.transferRESNUMFeatures(seq, "IEA:Jalview"); // FIXME: is
568 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
569 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
574 List<StructureMapping> foundSiftsMappings = new ArrayList<>();
575 for (PDBChain chain : pdb.getChains())
577 StructureMapping siftsMapping = null;
580 siftsMapping = getStructureMapping(seq,
581 pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq,
583 foundSiftsMappings.add(siftsMapping);
584 chain.makeExactMapping(siftsMapping, seq);
585 chain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
587 chain.transferResidueAnnotation(siftsMapping, null);
588 } catch (SiftsException e)
590 System.err.println(e.getMessage());
596 "Unexpected exception during SIFTS mapping - falling back to NW for this sequence/structure pair");
597 System.err.println(e.getMessage());
600 if (!foundSiftsMappings.isEmpty())
602 seqToStrucMapping.addAll(foundSiftsMappings);
603 ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
607 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
608 maxChainId, maxChain, pdb, maxAlignseq);
609 seqToStrucMapping.add(nwMapping);
610 maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
612 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
613 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
619 if (progress != null)
621 progress.setProgressBar(MessageManager
622 .getString("status.obtaining_mapping_with_nw_alignment"),
625 StructureMapping nwMapping = getNWMappings(seq, pdbFile, maxChainId,
626 maxChain, pdb, maxAlignseq);
627 seqToStrucMapping.add(nwMapping);
628 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
630 if (forStructureView)
632 for (StructureMapping sm : seqToStrucMapping)
634 addStructureMapping(sm); // not addAll!
637 if (progress != null)
639 progress.setProgressBar(null, progressSessionId);
646 * check if we need to extract secondary structure from given pdbFile and
647 * transfer to sequences
650 * @param sequenceArray
653 private boolean isStructureFileProcessed(String pdbFile,
654 SequenceI[] sequenceArray)
656 boolean parseSecStr = true;
657 if (isPDBFileRegistered(pdbFile))
659 for (SequenceI sq : sequenceArray)
662 while (ds.getDatasetSequence() != null)
664 ds = ds.getDatasetSequence();
667 if (ds.getAnnotation() != null)
669 for (AlignmentAnnotation ala : ds.getAnnotation())
671 // false if any annotation present from this structure
672 // JBPNote this fails for jmol/chimera view because the *file* is
673 // passed, not the structure data ID -
674 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
685 public void addStructureMapping(StructureMapping sm)
687 if (!mappings.contains(sm))
694 * retrieve a mapping for seq from SIFTs using associated DBRefEntry for
699 * @param targetChainId
705 * client for retrieval of SIFTS mappings for this structure
707 * @throws SiftsException
709 private StructureMapping getStructureMapping(SequenceI seq,
710 String pdbFile, String targetChainId, StructureFile pdb,
711 PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
712 AlignSeq maxAlignseq, SiftsClient siftsClient) throws SiftsException
714 StructureMapping curChainMapping = siftsClient
715 .getSiftsStructureMapping(seq, pdbFile, targetChainId);
718 PDBChain chain = pdb.findChain(targetChainId);
721 chain.transferResidueAnnotation(curChainMapping, null);
723 } catch (Exception e)
727 return curChainMapping;
730 private StructureMapping getNWMappings(SequenceI seq, String pdbFile,
731 String maxChainId, PDBChain maxChain, StructureFile pdb,
732 AlignSeq maxAlignseq)
734 final StringBuilder mappingDetails = new StringBuilder(128);
735 mappingDetails.append(NEWLINE)
736 .append("Sequence \u27f7 Structure mapping details");
737 mappingDetails.append(NEWLINE);
739 .append("Method: inferred with Needleman & Wunsch alignment");
740 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
741 .append(NEWLINE).append("Sequence = ")
742 .append(maxChain.sequence.getSequenceAsString());
743 mappingDetails.append(NEWLINE).append("No of residues = ")
744 .append(maxChain.residues.size()).append(NEWLINE)
746 PrintStream ps = new PrintStream(System.out)
749 public void print(String x)
751 mappingDetails.append(x);
755 public void println()
757 mappingDetails.append(NEWLINE);
761 maxAlignseq.printAlignment(ps);
763 mappingDetails.append(NEWLINE).append("PDB start/end ");
764 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
766 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
767 mappingDetails.append(NEWLINE).append("SEQ start/end ");
770 .valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
772 mappingDetails.append(
773 String.valueOf(maxAlignseq.seq1end + (seq.getStart() - 1)));
774 mappingDetails.append(NEWLINE);
775 maxChain.makeExactMapping(maxAlignseq, seq);
776 jalview.datamodel.Mapping sqmpping = maxAlignseq
777 .getMappingFromS1(false);
778 maxChain.transferRESNUMFeatures(seq, null);
780 HashMap<Integer, int[]> mapping = new HashMap<>();
787 Atom tmp = maxChain.atoms.elementAt(index);
788 if ((resNum != tmp.resNumber || insCode != tmp.insCode)
789 && tmp.alignmentMapping != -1)
791 resNum = tmp.resNumber;
792 insCode = tmp.insCode;
793 if (tmp.alignmentMapping >= -1)
795 mapping.put(tmp.alignmentMapping + 1,
797 { tmp.resNumber, tmp.atomIndex });
802 } while (index < maxChain.atoms.size());
804 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
805 pdb.getId(), maxChainId, mapping, mappingDetails.toString());
806 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
810 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
812 listeners.removeElement(svl);
813 if (svl instanceof SequenceListener)
815 for (int i = 0; i < listeners.size(); i++)
817 if (listeners.elementAt(i) instanceof StructureListener)
819 ((StructureListener) listeners.elementAt(i))
820 .releaseReferences(svl);
825 if (pdbfiles == null)
831 * Remove mappings to the closed listener's PDB files, but first check if
832 * another listener is still interested
834 List<String> pdbs = new ArrayList<>(Arrays.asList(pdbfiles));
836 StructureListener sl;
837 for (int i = 0; i < listeners.size(); i++)
839 if (listeners.elementAt(i) instanceof StructureListener)
841 sl = (StructureListener) listeners.elementAt(i);
842 for (String pdbfile : sl.getStructureFiles())
844 pdbs.remove(pdbfile);
850 * Rebuild the mappings set, retaining only those which are for 'other' PDB
855 List<StructureMapping> tmp = new ArrayList<>();
856 for (StructureMapping sm : mappings)
858 if (!pdbs.contains(sm.pdbfile))
869 * Propagate mouseover of a single position in a structure
875 public void mouseOverStructure(int pdbResNum, String chain,
878 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
879 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
880 mouseOverStructure(atoms);
884 * Propagate mouseover or selection of multiple positions in a structure
888 public void mouseOverStructure(List<AtomSpec> atoms)
890 if (listeners == null)
892 // old or prematurely sent event
895 boolean hasSequenceListener = false;
896 for (int i = 0; i < listeners.size(); i++)
898 if (listeners.elementAt(i) instanceof SequenceListener)
900 hasSequenceListener = true;
903 if (!hasSequenceListener)
908 SearchResultsI results = findAlignmentPositionsForStructurePositions(
910 for (Object li : listeners)
912 if (li instanceof SequenceListener)
914 ((SequenceListener) li).highlightSequence(results);
920 * Constructs a SearchResults object holding regions (if any) in the Jalview
921 * alignment which have a mapping to the structure viewer positions in the
927 public SearchResultsI findAlignmentPositionsForStructurePositions(
928 List<AtomSpec> atoms)
930 SearchResultsI results = new SearchResults();
931 for (AtomSpec atom : atoms)
933 SequenceI lastseq = null;
935 for (StructureMapping sm : mappings)
937 if (sm.pdbfile.equals(atom.getPdbFile())
938 && sm.pdbchain.equals(atom.getChain()))
940 int indexpos = sm.getSeqPos(atom.getPdbResNum());
941 if (lastipos != indexpos || lastseq != sm.sequence)
943 results.addResult(sm.sequence, indexpos, indexpos);
945 lastseq = sm.sequence;
946 // construct highlighted sequence list
947 for (AlignedCodonFrame acf : seqmappings)
949 acf.markMappedRegion(sm.sequence, indexpos, results);
959 * highlight regions associated with a position (indexpos) in seq
962 * the sequence that the mouse over occurred on
964 * the absolute position being mouseovered in seq (0 to seq.length())
966 * the sequence position (if -1, seq.findPosition is called to
967 * resolve the residue number)
969 public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
972 boolean hasSequenceListeners = handlingVamsasMo
973 || !seqmappings.isEmpty();
974 SearchResultsI results = null;
977 seqPos = seq.findPosition(indexpos);
979 for (int i = 0; i < listeners.size(); i++)
981 Object listener = listeners.elementAt(i);
982 if (listener == source)
984 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
985 // Temporary fudge with SequenceListener.getVamsasSource()
988 if (listener instanceof StructureListener)
990 highlightStructure((StructureListener) listener, seq, seqPos);
994 if (listener instanceof SequenceListener)
996 final SequenceListener seqListener = (SequenceListener) listener;
997 if (hasSequenceListeners
998 && seqListener.getVamsasSource() != source)
1000 if (relaySeqMappings)
1002 if (results == null)
1004 results = MappingUtils.buildSearchResults(seq, seqPos,
1007 if (handlingVamsasMo)
1009 results.addResult(seq, seqPos, seqPos);
1012 if (!results.isEmpty())
1014 seqListener.highlightSequence(results);
1019 else if (listener instanceof VamsasListener && !handlingVamsasMo)
1021 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
1024 else if (listener instanceof SecondaryStructureListener)
1026 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
1034 * Send suitable messages to a StructureListener to highlight atoms
1035 * corresponding to the given sequence position(s)
1041 public void highlightStructure(StructureListener sl, SequenceI seq,
1044 if (!sl.isListeningFor(seq))
1049 List<AtomSpec> atoms = new ArrayList<>();
1050 for (StructureMapping sm : mappings)
1052 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
1053 || (sm.sequence.getDatasetSequence() != null && sm.sequence
1054 .getDatasetSequence() == seq.getDatasetSequence()))
1056 for (int index : positions)
1058 atomNo = sm.getAtomNum(index);
1062 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
1063 sm.getPDBResNum(index), atomNo));
1068 sl.highlightAtoms(atoms);
1072 * true if a mouse over event from an external (ie Vamsas) source is being
1075 boolean handlingVamsasMo = false;
1080 * as mouseOverSequence but only route event to SequenceListeners
1084 * in an alignment sequence
1086 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
1087 VamsasSource source)
1089 handlingVamsasMo = true;
1090 long msg = sequenceI.hashCode() * (1 + position);
1094 mouseOverSequence(sequenceI, position, -1, source);
1096 handlingVamsasMo = false;
1099 public Annotation[] colourSequenceFromStructure(SequenceI seq,
1103 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
1104 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
1106 * Annotation [] annotations = new Annotation[seq.getLength()];
1108 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
1109 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
1110 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
1112 * for (int j = 0; j < mappings.length; j++) {
1114 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
1115 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
1116 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
1117 * "+mappings[j].pdbfile);
1119 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
1120 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
1122 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
1123 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
1124 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
1125 * mappings[j].pdbfile); }
1127 * annotations[index] = new Annotation("X",null,' ',0,col); } return
1128 * annotations; } } } }
1130 * return annotations;
1134 public void structureSelectionChanged()
1138 public void sequenceSelectionChanged()
1142 public void sequenceColoursChanged(Object source)
1144 StructureListener sl;
1145 for (int i = 0; i < listeners.size(); i++)
1147 if (listeners.elementAt(i) instanceof StructureListener)
1149 sl = (StructureListener) listeners.elementAt(i);
1150 sl.updateColours(source);
1155 public StructureMapping[] getMapping(String pdbfile)
1157 List<StructureMapping> tmp = new ArrayList<>();
1158 for (StructureMapping sm : mappings)
1160 if (sm.pdbfile.equals(pdbfile))
1165 return tmp.toArray(new StructureMapping[tmp.size()]);
1169 * Returns a readable description of all mappings for the given pdbfile to any
1170 * of the given sequences
1176 public String printMappings(String pdbfile, List<SequenceI> seqs)
1178 if (pdbfile == null || seqs == null || seqs.isEmpty())
1183 StringBuilder sb = new StringBuilder(64);
1184 for (StructureMapping sm : mappings)
1186 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
1188 sb.append(sm.mappingDetails);
1190 // separator makes it easier to read multiple mappings
1191 sb.append("=====================");
1197 return sb.toString();
1201 * Remove the given mapping
1205 public void deregisterMapping(AlignedCodonFrame acf)
1209 boolean removed = seqmappings.remove(acf);
1210 if (removed && seqmappings.isEmpty())
1212 System.out.println("All mappings removed");
1218 * Add each of the given codonFrames to the stored set, if not aready present.
1222 public void registerMappings(List<AlignedCodonFrame> mappings)
1224 if (mappings != null)
1226 for (AlignedCodonFrame acf : mappings)
1228 registerMapping(acf);
1234 * Add the given mapping to the stored set, unless already stored.
1236 public void registerMapping(AlignedCodonFrame acf)
1240 if (!seqmappings.contains(acf))
1242 seqmappings.add(acf);
1248 * Reset this object to its initial state by removing all registered
1249 * listeners, codon mappings, PDB file mappings.
1251 * Called only by Desktop and testng.
1254 public void resetAll()
1257 seqmappings.clear();
1258 sel_listeners.clear();
1260 commandListeners.clear();
1261 view_listeners.clear();
1262 pdbFileNameId.clear();
1263 pdbIdFileName.clear();
1266 public void addSelectionListener(SelectionListener selecter)
1268 if (!sel_listeners.contains(selecter))
1270 sel_listeners.add(selecter);
1274 public void removeSelectionListener(SelectionListener toremove)
1276 if (sel_listeners.contains(toremove))
1278 sel_listeners.remove(toremove);
1282 public synchronized void sendSelection(
1283 jalview.datamodel.SequenceGroup selection,
1284 jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
1285 SelectionSource source)
1287 for (SelectionListener slis : sel_listeners)
1291 slis.selection(selection, colsel, hidden, source);
1296 Vector<AlignmentViewPanelListener> view_listeners = new Vector<>();
1298 public synchronized void sendViewPosition(
1299 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1300 int startSeq, int endSeq)
1303 if (view_listeners != null && view_listeners.size() > 0)
1305 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1307 while (listeners.hasMoreElements())
1309 AlignmentViewPanelListener slis = listeners.nextElement();
1312 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1319 public void registerPDBEntry(PDBEntry pdbentry)
1321 if (pdbentry.getFile() != null
1322 && pdbentry.getFile().trim().length() > 0)
1324 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1328 public void addCommandListener(CommandListener cl)
1330 if (!commandListeners.contains(cl))
1332 commandListeners.add(cl);
1336 public boolean hasCommandListener(CommandListener cl)
1338 return this.commandListeners.contains(cl);
1341 public boolean removeCommandListener(CommandListener l)
1343 return commandListeners.remove(l);
1347 * Forward a command to any command listeners (except for the command's
1351 * the command to be broadcast (in its form after being performed)
1353 * if true, the command was being 'undone'
1356 public void commandPerformed(CommandI command, boolean undo,
1357 VamsasSource source)
1359 for (CommandListener listener : commandListeners)
1361 listener.mirrorCommand(command, undo, this, source);
1366 * Returns a new CommandI representing the given command as mapped to the
1367 * given sequences. If no mapping could be made, or the command is not of a
1368 * mappable kind, returns null.
1376 public CommandI mapCommand(CommandI command, boolean undo,
1377 final AlignmentI mapTo, char gapChar)
1379 if (command instanceof EditCommand)
1381 return MappingUtils.mapEditCommand((EditCommand) command, undo, mapTo,
1382 gapChar, seqmappings);
1384 else if (command instanceof OrderCommand)
1386 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1387 mapTo, seqmappings);
1392 public List<AlignedCodonFrame> getSequenceMappings()