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.Jalview;
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.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 private List<StructureMapping> mappings = new ArrayList<>();
69 private boolean processSecondaryStructure = false;
71 private boolean secStructServices = false;
73 private boolean addTempFacAnnot = false;
76 * Set of any registered mappings between (dataset) sequences.
78 private List<AlignedCodonFrame> seqmappings = new ArrayList<>();
80 private List<CommandListener> commandListeners = new ArrayList<>();
82 private List<SelectionListener> sel_listeners = new ArrayList<>();
85 * @return true if will try to use external services for processing secondary
88 public boolean isSecStructServices()
90 return secStructServices;
94 * control use of external services for processing secondary structure
96 * @param secStructServices
98 public void setSecStructServices(boolean secStructServices)
100 this.secStructServices = secStructServices;
104 * flag controlling addition of any kind of structural annotation
106 * @return true if temperature factor annotation will be added
108 public boolean isAddTempFacAnnot()
110 return addTempFacAnnot;
114 * set flag controlling addition of structural annotation
116 * @param addTempFacAnnot
118 public void setAddTempFacAnnot(boolean addTempFacAnnot)
120 this.addTempFacAnnot = addTempFacAnnot;
125 * @return if true, the structure manager will attempt to add secondary
126 * structure lines for unannotated sequences
129 public boolean isProcessSecondaryStructure()
131 return processSecondaryStructure;
135 * Control whether structure manager will try to annotate mapped sequences
136 * with secondary structure from PDB data.
140 public void setProcessSecondaryStructure(boolean enable)
142 processSecondaryStructure = enable;
146 * debug function - write all mappings to stdout
148 public void reportMapping()
150 if (mappings.isEmpty())
152 System.err.println("reportMapping: No PDB/Sequence mappings.");
157 "reportMapping: There are " + mappings.size() + " mappings.");
159 for (StructureMapping sm : mappings)
161 System.err.println("mapping " + i++ + " : " + sm.pdbfile);
167 * map between the PDB IDs (or structure identifiers) used by Jalview and the
168 * absolute filenames for PDB data that corresponds to it
170 Map<String, String> pdbIdFileName = new HashMap<>();
172 Map<String, String> pdbFileNameId = new HashMap<>();
174 public void registerPDBFile(String idForFile, String absoluteFile)
176 pdbIdFileName.put(idForFile, absoluteFile);
177 pdbFileNameId.put(absoluteFile, idForFile);
180 public String findIdForPDBFile(String idOrFile)
182 String id = pdbFileNameId.get(idOrFile);
186 public String findFileForPDBId(String idOrFile)
188 String id = pdbIdFileName.get(idOrFile);
192 public boolean isPDBFileRegistered(String idOrFile)
194 return pdbFileNameId.containsKey(idOrFile)
195 || pdbIdFileName.containsKey(idOrFile);
198 public static StructureSelectionManager getStructureSelectionManager(
199 StructureSelectionManagerProvider context)
201 Jalview j = Jalview.getInstance();
204 if (j.nullProvider == null)
206 if (j.structureSelections != null)
208 throw new Error(MessageManager.getString(
209 "error.implementation_error_structure_selection_manager_null"),
210 new NullPointerException(MessageManager
211 .getString("exception.ssm_context_is_null")));
215 j.nullProvider = new StructureSelectionManager();
217 return j.nullProvider;
220 if (j.structureSelections == null)
222 j.structureSelections = new java.util.IdentityHashMap<>();
224 StructureSelectionManager instance = Jalview
225 .getInstance().structureSelections.get(context);
226 if (instance == null)
228 if (j.nullProvider != null)
230 instance = j.nullProvider;
234 instance = new StructureSelectionManager();
236 j.structureSelections.put(context, instance);
242 * flag controlling whether SeqMappings are relayed from received sequence
243 * mouse over events to other sequences
245 boolean relaySeqMappings = true;
248 * Enable or disable relay of seqMapping events to other sequences. You might
249 * want to do this if there are many sequence mappings and the host computer
254 public void setRelaySeqMappings(boolean relay)
256 relaySeqMappings = relay;
260 * get the state of the relay seqMappings flag.
262 * @return true if sequence mouse overs are being relayed to other mapped
265 public boolean isRelaySeqMappingsEnabled()
267 return relaySeqMappings;
270 Vector<Object> listeners = new Vector<>();
273 * register a listener for alignment sequence mouseover events
277 public void addStructureViewerListener(Object svl)
279 if (!listeners.contains(svl))
281 listeners.addElement(svl);
286 * Returns the filename the PDB id is already mapped to if known, or null if
292 public String alreadyMappedToFile(String pdbid)
294 for (StructureMapping sm : mappings)
296 if (sm.getPdbId().equalsIgnoreCase(pdbid))
305 * Import structure data and register a structure mapping for broadcasting
306 * colouring, mouseovers and selection events (convenience wrapper).
309 * - one or more sequences to be mapped to pdbFile
310 * @param targetChains
311 * - optional chain specification for mapping each sequence to pdb
312 * (may be nill, individual elements may be nill)
314 * - structure data resource
316 * - how to resolve data from resource
317 * @return null or the structure data parsed as a pdb file
319 synchronized public StructureFile setMapping(SequenceI[] sequence,
320 String[] targetChains, String pdbFile, DataSourceType protocol,
321 IProgressIndicator progress)
323 return computeMapping(true, sequence, targetChains, pdbFile, protocol,
328 * Import a single structure file and register sequence structure mappings for
329 * broadcasting colouring, mouseovers and selection events (convenience
332 * @param forStructureView
333 * when true, record the mapping for use in mouseOvers
335 * - one or more sequences to be mapped to pdbFile
336 * @param targetChains
337 * - optional chain specification for mapping each sequence to pdb
338 * (may be nill, individual elements may be nill)
340 * - structure data resource
342 * - how to resolve data from resource
343 * @return null or the structure data parsed as a pdb file
345 synchronized public StructureFile setMapping(boolean forStructureView,
346 SequenceI[] sequenceArray, String[] targetChainIds,
347 String pdbFile, DataSourceType sourceType)
349 return computeMapping(forStructureView, sequenceArray, targetChainIds,
350 pdbFile, sourceType, null);
354 * create sequence structure mappings between each sequence and the given
355 * pdbFile (retrieved via the given protocol). Either constructs a mapping
356 * using NW alignment or derives one from any available SIFTS mapping data.
358 * @param forStructureView
359 * when true, record the mapping for use in mouseOvers
361 * @param sequenceArray
362 * - one or more sequences to be mapped to pdbFile
363 * @param targetChainIds
364 * - optional chain specification for mapping each sequence to pdb
365 * (may be nill, individual elements may be nill) - JBPNote: JAL-2693
366 * - this should be List<List<String>>, empty lists indicate no
367 * predefined mappings
369 * - structure data resource
371 * - how to resolve data from resource
372 * @param IProgressIndicator
373 * reference to UI component that maintains a progress bar for the
375 * @return null or the structure data parsed as a pdb file
377 synchronized public StructureFile computeMapping(
378 boolean forStructureView, SequenceI[] sequenceArray,
379 String[] targetChainIds, String pdbFile, DataSourceType sourceType,
380 IProgressIndicator progress)
382 long progressSessionId = System.currentTimeMillis() * 3;
385 * do we extract and transfer annotation from 3D data ?
387 // FIXME: possibly should just delete
389 boolean parseSecStr = processSecondaryStructure
390 ? isStructureFileProcessed(pdbFile, sequenceArray)
393 StructureFile pdb = null;
394 boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
397 // FIXME if sourceType is not null, we've lost data here
398 sourceType = AppletFormatAdapter.checkProtocol(pdbFile);
399 pdb = new JmolParser(false, pdbFile, sourceType);
400 pdb.addSettings(parseSecStr && processSecondaryStructure,
401 parseSecStr && addTempFacAnnot,
402 parseSecStr && secStructServices);
404 if (pdb.getId() != null && pdb.getId().trim().length() > 0
405 && DataSourceType.FILE == sourceType)
407 registerPDBFile(pdb.getId().trim(), pdbFile);
409 // if PDBId is unavailable then skip SIFTS mapping execution path
410 isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable();
412 } catch (Exception ex)
414 ex.printStackTrace();
418 * sifts client - non null if SIFTS mappings are to be used
420 SiftsClient siftsClient = null;
425 siftsClient = new SiftsClient(pdb);
427 } catch (SiftsException e)
429 isMapUsingSIFTs = false;
434 String targetChainId;
435 for (int s = 0; s < sequenceArray.length; s++)
437 boolean infChain = true;
438 final SequenceI seq = sequenceArray[s];
440 while (ds.getDatasetSequence() != null)
442 ds = ds.getDatasetSequence();
445 if (targetChainIds != null && targetChainIds[s] != null)
448 targetChainId = targetChainIds[s];
450 else if (seq.getName().indexOf("|") > -1)
452 targetChainId = seq.getName()
453 .substring(seq.getName().lastIndexOf("|") + 1);
454 if (targetChainId.length() > 1)
456 if (targetChainId.trim().length() == 0)
462 // not a valid chain identifier
473 * Attempt pairwise alignment of the sequence with each chain in the PDB,
474 * and remember the highest scoring chain
477 AlignSeq maxAlignseq = null;
478 String maxChainId = " ";
479 PDBChain maxChain = null;
480 boolean first = true;
481 for (PDBChain chain : pdb.getChains())
483 if (targetChainId.length() > 0 && !targetChainId.equals(chain.id)
486 continue; // don't try to map chains don't match.
488 // TODO: correctly determine sequence type for mixed na/peptide
490 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
491 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
494 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
495 // as.calcScoreMatrix();
496 // as.traceAlignment();
498 if (first || as.maxscore > max
499 || (as.maxscore == max && chain.id.equals(targetChainId)))
505 maxChainId = chain.id;
508 if (maxChain == null)
513 if (sourceType == DataSourceType.PASTE)
515 pdbFile = "INLINE" + pdb.getId();
518 List<StructureMapping> seqToStrucMapping = new ArrayList<>();
519 if (isMapUsingSIFTs && seq.isProtein())
521 if (progress!=null) {
522 progress.setProgressBar(MessageManager
523 .getString("status.obtaining_mapping_with_sifts"),
526 jalview.datamodel.Mapping sqmpping = maxAlignseq
527 .getMappingFromS1(false);
528 if (targetChainId != null && !targetChainId.trim().isEmpty())
530 StructureMapping siftsMapping;
533 siftsMapping = getStructureMapping(seq, pdbFile, targetChainId,
534 pdb, maxChain, sqmpping, maxAlignseq, siftsClient);
535 seqToStrucMapping.add(siftsMapping);
536 maxChain.makeExactMapping(siftsMapping, seq);
537 maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
539 maxChain.transferResidueAnnotation(siftsMapping, null);
540 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
542 } catch (SiftsException e)
544 // fall back to NW alignment
545 System.err.println(e.getMessage());
546 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
547 targetChainId, maxChain, pdb, maxAlignseq);
548 seqToStrucMapping.add(nwMapping);
549 maxChain.makeExactMapping(maxAlignseq, seq);
550 maxChain.transferRESNUMFeatures(seq, "IEA:Jalview"); // FIXME: is
553 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
554 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
559 List<StructureMapping> foundSiftsMappings = new ArrayList<>();
560 for (PDBChain chain : pdb.getChains())
562 StructureMapping siftsMapping = null;
565 siftsMapping = getStructureMapping(seq,
566 pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq,
568 foundSiftsMappings.add(siftsMapping);
569 chain.makeExactMapping(siftsMapping, seq);
570 chain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
572 chain.transferResidueAnnotation(siftsMapping, null);
573 } catch (SiftsException e)
575 System.err.println(e.getMessage());
581 "Unexpected exception during SIFTS mapping - falling back to NW for this sequence/structure pair");
582 System.err.println(e.getMessage());
585 if (!foundSiftsMappings.isEmpty())
587 seqToStrucMapping.addAll(foundSiftsMappings);
588 ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
592 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
593 maxChainId, maxChain, pdb, maxAlignseq);
594 seqToStrucMapping.add(nwMapping);
595 maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
597 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
598 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
604 if (progress != null)
606 progress.setProgressBar(MessageManager
607 .getString("status.obtaining_mapping_with_nw_alignment"),
610 StructureMapping nwMapping = getNWMappings(seq, pdbFile, maxChainId,
611 maxChain, pdb, maxAlignseq);
612 seqToStrucMapping.add(nwMapping);
613 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
615 if (forStructureView)
617 for (StructureMapping sm : seqToStrucMapping)
619 addStructureMapping(sm); // not addAll!
622 if (progress != null)
624 progress.setProgressBar(null, progressSessionId);
631 * check if we need to extract secondary structure from given pdbFile and
632 * transfer to sequences
635 * @param sequenceArray
638 private boolean isStructureFileProcessed(String pdbFile,
639 SequenceI[] sequenceArray)
641 boolean parseSecStr = true;
642 if (isPDBFileRegistered(pdbFile))
644 for (SequenceI sq : sequenceArray)
647 while (ds.getDatasetSequence() != null)
649 ds = ds.getDatasetSequence();
652 if (ds.getAnnotation() != null)
654 for (AlignmentAnnotation ala : ds.getAnnotation())
656 // false if any annotation present from this structure
657 // JBPNote this fails for jmol/chimera view because the *file* is
658 // passed, not the structure data ID -
659 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
670 public void addStructureMapping(StructureMapping sm)
672 if (!mappings.contains(sm))
679 * retrieve a mapping for seq from SIFTs using associated DBRefEntry for
684 * @param targetChainId
690 * client for retrieval of SIFTS mappings for this structure
692 * @throws SiftsException
694 private StructureMapping getStructureMapping(SequenceI seq,
695 String pdbFile, String targetChainId, StructureFile pdb,
696 PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
697 AlignSeq maxAlignseq, SiftsClient siftsClient) throws SiftsException
699 StructureMapping curChainMapping = siftsClient
700 .getSiftsStructureMapping(seq, pdbFile, targetChainId);
703 PDBChain chain = pdb.findChain(targetChainId);
706 chain.transferResidueAnnotation(curChainMapping, null);
708 } catch (Exception e)
712 return curChainMapping;
715 private StructureMapping getNWMappings(SequenceI seq, String pdbFile,
716 String maxChainId, PDBChain maxChain, StructureFile pdb,
717 AlignSeq maxAlignseq)
719 final StringBuilder mappingDetails = new StringBuilder(128);
720 mappingDetails.append(NEWLINE)
721 .append("Sequence \u27f7 Structure mapping details");
722 mappingDetails.append(NEWLINE);
724 .append("Method: inferred with Needleman & Wunsch alignment");
725 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
726 .append(NEWLINE).append("Sequence = ")
727 .append(maxChain.sequence.getSequenceAsString());
728 mappingDetails.append(NEWLINE).append("No of residues = ")
729 .append(maxChain.residues.size()).append(NEWLINE)
731 PrintStream ps = new PrintStream(System.out)
734 public void print(String x)
736 mappingDetails.append(x);
740 public void println()
742 mappingDetails.append(NEWLINE);
746 maxAlignseq.printAlignment(ps);
748 mappingDetails.append(NEWLINE).append("PDB start/end ");
749 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
751 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
752 mappingDetails.append(NEWLINE).append("SEQ start/end ");
755 .valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
757 mappingDetails.append(
758 String.valueOf(maxAlignseq.seq1end + (seq.getStart() - 1)));
759 mappingDetails.append(NEWLINE);
760 maxChain.makeExactMapping(maxAlignseq, seq);
761 jalview.datamodel.Mapping sqmpping = maxAlignseq
762 .getMappingFromS1(false);
763 maxChain.transferRESNUMFeatures(seq, null);
765 HashMap<Integer, int[]> mapping = new HashMap<>();
772 Atom tmp = maxChain.atoms.elementAt(index);
773 if ((resNum != tmp.resNumber || insCode != tmp.insCode)
774 && tmp.alignmentMapping != -1)
776 resNum = tmp.resNumber;
777 insCode = tmp.insCode;
778 if (tmp.alignmentMapping >= -1)
780 mapping.put(tmp.alignmentMapping + 1,
782 { tmp.resNumber, tmp.atomIndex });
787 } while (index < maxChain.atoms.size());
789 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
790 pdb.getId(), maxChainId, mapping, mappingDetails.toString());
791 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
795 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
797 listeners.removeElement(svl);
798 if (svl instanceof SequenceListener)
800 for (int i = 0; i < listeners.size(); i++)
802 if (listeners.elementAt(i) instanceof StructureListener)
804 ((StructureListener) listeners.elementAt(i))
805 .releaseReferences(svl);
810 if (pdbfiles == null)
816 * Remove mappings to the closed listener's PDB files, but first check if
817 * another listener is still interested
819 List<String> pdbs = new ArrayList<>(Arrays.asList(pdbfiles));
821 StructureListener sl;
822 for (int i = 0; i < listeners.size(); i++)
824 if (listeners.elementAt(i) instanceof StructureListener)
826 sl = (StructureListener) listeners.elementAt(i);
827 for (String pdbfile : sl.getStructureFiles())
829 pdbs.remove(pdbfile);
835 * Rebuild the mappings set, retaining only those which are for 'other' PDB
840 List<StructureMapping> tmp = new ArrayList<>();
841 for (StructureMapping sm : mappings)
843 if (!pdbs.contains(sm.pdbfile))
854 * Propagate mouseover of a single position in a structure
860 public void mouseOverStructure(int pdbResNum, String chain,
863 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
864 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
865 mouseOverStructure(atoms);
869 * Propagate mouseover or selection of multiple positions in a structure
873 public void mouseOverStructure(List<AtomSpec> atoms)
875 if (listeners == null)
877 // old or prematurely sent event
880 boolean hasSequenceListener = false;
881 for (int i = 0; i < listeners.size(); i++)
883 if (listeners.elementAt(i) instanceof SequenceListener)
885 hasSequenceListener = true;
888 if (!hasSequenceListener)
893 SearchResultsI results = findAlignmentPositionsForStructurePositions(
895 for (Object li : listeners)
897 if (li instanceof SequenceListener)
899 ((SequenceListener) li).highlightSequence(results);
905 * Constructs a SearchResults object holding regions (if any) in the Jalview
906 * alignment which have a mapping to the structure viewer positions in the
912 public SearchResultsI findAlignmentPositionsForStructurePositions(
913 List<AtomSpec> atoms)
915 SearchResultsI results = new SearchResults();
916 for (AtomSpec atom : atoms)
918 SequenceI lastseq = null;
920 for (StructureMapping sm : mappings)
922 if (sm.pdbfile.equals(atom.getPdbFile())
923 && sm.pdbchain.equals(atom.getChain()))
925 int indexpos = sm.getSeqPos(atom.getPdbResNum());
926 if (lastipos != indexpos || lastseq != sm.sequence)
928 results.addResult(sm.sequence, indexpos, indexpos);
930 lastseq = sm.sequence;
931 // construct highlighted sequence list
932 for (AlignedCodonFrame acf : seqmappings)
934 acf.markMappedRegion(sm.sequence, indexpos, results);
944 * highlight regions associated with a position (indexpos) in seq
947 * the sequence that the mouse over occurred on
949 * the absolute position being mouseovered in seq (0 to seq.length())
951 * the sequence position (if -1, seq.findPosition is called to
952 * resolve the residue number)
954 public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
957 boolean hasSequenceListeners = handlingVamsasMo
958 || !seqmappings.isEmpty();
959 SearchResultsI results = null;
962 seqPos = seq.findPosition(indexpos);
964 for (int i = 0; i < listeners.size(); i++)
966 Object listener = listeners.elementAt(i);
967 if (listener == source)
969 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
970 // Temporary fudge with SequenceListener.getVamsasSource()
973 if (listener instanceof StructureListener)
975 highlightStructure((StructureListener) listener, seq, seqPos);
979 if (listener instanceof SequenceListener)
981 final SequenceListener seqListener = (SequenceListener) listener;
982 if (hasSequenceListeners
983 && seqListener.getVamsasSource() != source)
985 if (relaySeqMappings)
989 results = MappingUtils.buildSearchResults(seq, seqPos,
992 if (handlingVamsasMo)
994 results.addResult(seq, seqPos, seqPos);
997 if (!results.isEmpty())
999 seqListener.highlightSequence(results);
1004 else if (listener instanceof VamsasListener && !handlingVamsasMo)
1006 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
1009 else if (listener instanceof SecondaryStructureListener)
1011 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
1019 * Send suitable messages to a StructureListener to highlight atoms
1020 * corresponding to the given sequence position(s)
1026 public void highlightStructure(StructureListener sl, SequenceI seq,
1029 if (!sl.isListeningFor(seq))
1034 List<AtomSpec> atoms = new ArrayList<>();
1035 for (StructureMapping sm : mappings)
1037 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
1038 || (sm.sequence.getDatasetSequence() != null && sm.sequence
1039 .getDatasetSequence() == seq.getDatasetSequence()))
1041 for (int index : positions)
1043 atomNo = sm.getAtomNum(index);
1047 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
1048 sm.getPDBResNum(index), atomNo));
1053 sl.highlightAtoms(atoms);
1057 * true if a mouse over event from an external (ie Vamsas) source is being
1060 boolean handlingVamsasMo = false;
1065 * as mouseOverSequence but only route event to SequenceListeners
1069 * in an alignment sequence
1071 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
1072 VamsasSource source)
1074 handlingVamsasMo = true;
1075 long msg = sequenceI.hashCode() * (1 + position);
1079 mouseOverSequence(sequenceI, position, -1, source);
1081 handlingVamsasMo = false;
1084 public Annotation[] colourSequenceFromStructure(SequenceI seq,
1088 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
1089 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
1091 * Annotation [] annotations = new Annotation[seq.getLength()];
1093 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
1094 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
1095 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
1097 * for (int j = 0; j < mappings.length; j++) {
1099 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
1100 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
1101 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
1102 * "+mappings[j].pdbfile);
1104 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
1105 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
1107 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
1108 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
1109 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
1110 * mappings[j].pdbfile); }
1112 * annotations[index] = new Annotation("X",null,' ',0,col); } return
1113 * annotations; } } } }
1115 * return annotations;
1119 public void structureSelectionChanged()
1123 public void sequenceSelectionChanged()
1127 public void sequenceColoursChanged(Object source)
1129 StructureListener sl;
1130 for (int i = 0; i < listeners.size(); i++)
1132 if (listeners.elementAt(i) instanceof StructureListener)
1134 sl = (StructureListener) listeners.elementAt(i);
1135 sl.updateColours(source);
1140 public StructureMapping[] getMapping(String pdbfile)
1142 List<StructureMapping> tmp = new ArrayList<>();
1143 for (StructureMapping sm : mappings)
1145 if (sm.pdbfile.equals(pdbfile))
1150 return tmp.toArray(new StructureMapping[tmp.size()]);
1154 * Returns a readable description of all mappings for the given pdbfile to any
1155 * of the given sequences
1161 public String printMappings(String pdbfile, List<SequenceI> seqs)
1163 if (pdbfile == null || seqs == null || seqs.isEmpty())
1168 StringBuilder sb = new StringBuilder(64);
1169 for (StructureMapping sm : mappings)
1171 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
1173 sb.append(sm.mappingDetails);
1175 // separator makes it easier to read multiple mappings
1176 sb.append("=====================");
1182 return sb.toString();
1186 * Remove the given mapping
1190 public void deregisterMapping(AlignedCodonFrame acf)
1194 boolean removed = seqmappings.remove(acf);
1195 if (removed && seqmappings.isEmpty())
1197 System.out.println("All mappings removed");
1203 * Add each of the given codonFrames to the stored set, if not aready present.
1207 public void registerMappings(List<AlignedCodonFrame> mappings)
1209 if (mappings != null)
1211 for (AlignedCodonFrame acf : mappings)
1213 registerMapping(acf);
1219 * Add the given mapping to the stored set, unless already stored.
1221 public void registerMapping(AlignedCodonFrame acf)
1225 if (!seqmappings.contains(acf))
1227 seqmappings.add(acf);
1233 * Resets this object to its initial state by removing all registered
1234 * listeners, codon mappings, PDB file mappings
1236 public void resetAll()
1238 if (mappings != null)
1242 if (seqmappings != null)
1244 seqmappings.clear();
1246 if (sel_listeners != null)
1248 sel_listeners.clear();
1250 if (listeners != null)
1254 if (commandListeners != null)
1256 commandListeners.clear();
1258 if (view_listeners != null)
1260 view_listeners.clear();
1262 if (pdbFileNameId != null)
1264 pdbFileNameId.clear();
1266 if (pdbIdFileName != null)
1268 pdbIdFileName.clear();
1272 public void addSelectionListener(SelectionListener selecter)
1274 if (!sel_listeners.contains(selecter))
1276 sel_listeners.add(selecter);
1280 public void removeSelectionListener(SelectionListener toremove)
1282 if (sel_listeners.contains(toremove))
1284 sel_listeners.remove(toremove);
1288 public synchronized void sendSelection(
1289 jalview.datamodel.SequenceGroup selection,
1290 jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
1291 SelectionSource source)
1293 for (SelectionListener slis : sel_listeners)
1297 slis.selection(selection, colsel, hidden, source);
1302 Vector<AlignmentViewPanelListener> view_listeners = new Vector<>();
1304 public synchronized void sendViewPosition(
1305 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1306 int startSeq, int endSeq)
1309 if (view_listeners != null && view_listeners.size() > 0)
1311 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1313 while (listeners.hasMoreElements())
1315 AlignmentViewPanelListener slis = listeners.nextElement();
1318 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1326 * release all references associated with this manager provider
1328 * @param jalviewLite
1330 public static void release(StructureSelectionManagerProvider jalviewLite)
1332 // synchronized (instances)
1334 if (Jalview.getInstance().structureSelections == null)
1338 StructureSelectionManager mnger = (Jalview
1339 .getInstance().structureSelections.get(jalviewLite));
1342 Jalview.getInstance().structureSelections.remove(jalviewLite);
1346 } catch (Throwable x)
1353 public void registerPDBEntry(PDBEntry pdbentry)
1355 if (pdbentry.getFile() != null
1356 && pdbentry.getFile().trim().length() > 0)
1358 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1362 public void addCommandListener(CommandListener cl)
1364 if (!commandListeners.contains(cl))
1366 commandListeners.add(cl);
1370 public boolean hasCommandListener(CommandListener cl)
1372 return this.commandListeners.contains(cl);
1375 public boolean removeCommandListener(CommandListener l)
1377 return commandListeners.remove(l);
1381 * Forward a command to any command listeners (except for the command's
1385 * the command to be broadcast (in its form after being performed)
1387 * if true, the command was being 'undone'
1390 public void commandPerformed(CommandI command, boolean undo,
1391 VamsasSource source)
1393 for (CommandListener listener : commandListeners)
1395 listener.mirrorCommand(command, undo, this, source);
1400 * Returns a new CommandI representing the given command as mapped to the
1401 * given sequences. If no mapping could be made, or the command is not of a
1402 * mappable kind, returns null.
1410 public CommandI mapCommand(CommandI command, boolean undo,
1411 final AlignmentI mapTo, char gapChar)
1413 if (command instanceof EditCommand)
1415 return MappingUtils.mapEditCommand((EditCommand) command, undo, mapTo,
1416 gapChar, seqmappings);
1418 else if (command instanceof OrderCommand)
1420 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1421 mapTo, seqmappings);
1426 public List<AlignedCodonFrame> getSequenceMappings()