2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.structure;
23 import jalview.analysis.AlignSeq;
24 import jalview.api.StructureSelectionManagerProvider;
25 import jalview.commands.CommandI;
26 import jalview.commands.EditCommand;
27 import jalview.commands.OrderCommand;
28 import jalview.datamodel.AlignedCodonFrame;
29 import jalview.datamodel.AlignmentAnnotation;
30 import jalview.datamodel.AlignmentI;
31 import jalview.datamodel.Annotation;
32 import jalview.datamodel.HiddenColumns;
33 import jalview.datamodel.PDBEntry;
34 import jalview.datamodel.SearchResults;
35 import jalview.datamodel.SearchResultsI;
36 import jalview.datamodel.SequenceI;
37 import jalview.ext.jmol.JmolParser;
38 import jalview.gui.IProgressIndicator;
39 import jalview.io.AppletFormatAdapter;
40 import jalview.io.DataSourceType;
41 import jalview.io.StructureFile;
42 import jalview.util.MappingUtils;
43 import jalview.util.MessageManager;
44 import jalview.ws.sifts.SiftsClient;
45 import jalview.ws.sifts.SiftsException;
46 import jalview.ws.sifts.SiftsSettings;
48 import java.io.PrintStream;
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.Collections;
52 import java.util.Enumeration;
53 import java.util.HashMap;
54 import java.util.IdentityHashMap;
55 import java.util.List;
57 import java.util.Vector;
60 import MCview.PDBChain;
61 import MCview.PDBfile;
63 public class StructureSelectionManager
65 public final static String NEWLINE = System.lineSeparator();
67 static IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> instances;
69 private List<StructureMapping> mappings = new ArrayList<>();
71 private boolean processSecondaryStructure = false;
73 private boolean secStructServices = false;
75 private boolean addTempFacAnnot = false;
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(pdbFile, sourceType);
403 if (pdb.getId() != null && pdb.getId().trim().length() > 0
404 && DataSourceType.FILE == sourceType)
406 registerPDBFile(pdb.getId().trim(), pdbFile);
408 // if PDBId is unavailable then skip SIFTS mapping execution path
409 isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable();
411 } catch (Exception ex)
413 ex.printStackTrace();
417 * sifts client - non null if SIFTS mappings are to be used
419 SiftsClient siftsClient = null;
424 siftsClient = new SiftsClient(pdb);
426 } catch (SiftsException e)
428 isMapUsingSIFTs = false;
433 String targetChainId;
434 for (int s = 0; s < sequenceArray.length; s++)
436 boolean infChain = true;
437 final SequenceI seq = sequenceArray[s];
439 while (ds.getDatasetSequence() != null)
441 ds = ds.getDatasetSequence();
444 if (targetChainIds != null && targetChainIds[s] != null)
447 targetChainId = targetChainIds[s];
449 else if (seq.getName().indexOf("|") > -1)
451 targetChainId = seq.getName()
452 .substring(seq.getName().lastIndexOf("|") + 1);
453 if (targetChainId.length() > 1)
455 if (targetChainId.trim().length() == 0)
461 // not a valid chain identifier
472 * Attempt pairwise alignment of the sequence with each chain in the PDB,
473 * and remember the highest scoring chain
476 AlignSeq maxAlignseq = null;
477 String maxChainId = " ";
478 PDBChain maxChain = null;
479 boolean first = true;
480 for (PDBChain chain : pdb.getChains())
482 if (targetChainId.length() > 0 && !targetChainId.equals(chain.id)
485 continue; // don't try to map chains don't match.
487 // TODO: correctly determine sequence type for mixed na/peptide
489 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
490 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
493 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
494 // as.calcScoreMatrix();
495 // as.traceAlignment();
497 if (first || as.maxscore > max
498 || (as.maxscore == max && chain.id.equals(targetChainId)))
504 maxChainId = chain.id;
507 if (maxChain == null)
512 if (sourceType == DataSourceType.PASTE)
514 pdbFile = "INLINE" + pdb.getId();
517 List<StructureMapping> seqToStrucMapping = new ArrayList<>();
518 if (isMapUsingSIFTs && seq.isProtein())
520 if (progress!=null) {
521 progress.setProgressBar(MessageManager
522 .getString("status.obtaining_mapping_with_sifts"),
525 jalview.datamodel.Mapping sqmpping = maxAlignseq
526 .getMappingFromS1(false);
527 if (targetChainId != null && !targetChainId.trim().isEmpty())
529 StructureMapping siftsMapping;
532 siftsMapping = getStructureMapping(seq, pdbFile, targetChainId,
533 pdb, maxChain, sqmpping, maxAlignseq, siftsClient);
534 seqToStrucMapping.add(siftsMapping);
535 maxChain.makeExactMapping(siftsMapping, seq);
536 maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
538 maxChain.transferResidueAnnotation(siftsMapping, null);
539 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
541 } catch (SiftsException e)
543 // fall back to NW alignment
544 System.err.println(e.getMessage());
545 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
546 targetChainId, maxChain, pdb, maxAlignseq);
547 seqToStrucMapping.add(nwMapping);
548 maxChain.makeExactMapping(maxAlignseq, seq);
549 maxChain.transferRESNUMFeatures(seq, "IEA:Jalview"); // FIXME: is
552 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
553 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
558 List<StructureMapping> foundSiftsMappings = new ArrayList<>();
559 for (PDBChain chain : pdb.getChains())
561 StructureMapping siftsMapping = null;
564 siftsMapping = getStructureMapping(seq,
565 pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq,
567 foundSiftsMappings.add(siftsMapping);
568 chain.makeExactMapping(siftsMapping, seq);
569 chain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
571 chain.transferResidueAnnotation(siftsMapping, null);
572 } catch (SiftsException e)
574 System.err.println(e.getMessage());
580 "Unexpected exception during SIFTS mapping - falling back to NW for this sequence/structure pair");
581 System.err.println(e.getMessage());
584 if (!foundSiftsMappings.isEmpty())
586 seqToStrucMapping.addAll(foundSiftsMappings);
587 ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
591 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
592 maxChainId, maxChain, pdb, maxAlignseq);
593 seqToStrucMapping.add(nwMapping);
594 maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
596 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
597 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
603 if (progress != null)
605 progress.setProgressBar(MessageManager
606 .getString("status.obtaining_mapping_with_nw_alignment"),
609 StructureMapping nwMapping = getNWMappings(seq, pdbFile, maxChainId,
610 maxChain, pdb, maxAlignseq);
611 seqToStrucMapping.add(nwMapping);
612 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
614 if (forStructureView)
616 for (StructureMapping sm : seqToStrucMapping)
618 addStructureMapping(sm); // not addAll!
621 if (progress != null)
623 progress.setProgressBar(null, progressSessionId);
630 * check if we need to extract secondary structure from given pdbFile and
631 * transfer to sequences
634 * @param sequenceArray
637 private boolean isStructureFileProcessed(String pdbFile,
638 SequenceI[] sequenceArray)
640 boolean parseSecStr = true;
641 if (isPDBFileRegistered(pdbFile))
643 for (SequenceI sq : sequenceArray)
646 while (ds.getDatasetSequence() != null)
648 ds = ds.getDatasetSequence();
651 if (ds.getAnnotation() != null)
653 for (AlignmentAnnotation ala : ds.getAnnotation())
655 // false if any annotation present from this structure
656 // JBPNote this fails for jmol/chimera view because the *file* is
657 // passed, not the structure data ID -
658 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
669 public void addStructureMapping(StructureMapping sm)
671 if (!mappings.contains(sm))
678 * retrieve a mapping for seq from SIFTs using associated DBRefEntry for
683 * @param targetChainId
689 * client for retrieval of SIFTS mappings for this structure
691 * @throws SiftsException
693 private StructureMapping getStructureMapping(SequenceI seq,
694 String pdbFile, String targetChainId, StructureFile pdb,
695 PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
696 AlignSeq maxAlignseq, SiftsClient siftsClient) throws SiftsException
698 StructureMapping curChainMapping = siftsClient
699 .getSiftsStructureMapping(seq, pdbFile, targetChainId);
702 PDBChain chain = pdb.findChain(targetChainId);
705 chain.transferResidueAnnotation(curChainMapping, null);
707 } catch (Exception e)
711 return curChainMapping;
714 private StructureMapping getNWMappings(SequenceI seq, String pdbFile,
715 String maxChainId, PDBChain maxChain, StructureFile pdb,
716 AlignSeq maxAlignseq)
718 final StringBuilder mappingDetails = new StringBuilder(128);
719 mappingDetails.append(NEWLINE)
720 .append("Sequence \u27f7 Structure mapping details");
721 mappingDetails.append(NEWLINE);
723 .append("Method: inferred with Needleman & Wunsch alignment");
724 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
725 .append(NEWLINE).append("Sequence = ")
726 .append(maxChain.sequence.getSequenceAsString());
727 mappingDetails.append(NEWLINE).append("No of residues = ")
728 .append(maxChain.residues.size()).append(NEWLINE)
730 PrintStream ps = new PrintStream(System.out)
733 public void print(String x)
735 mappingDetails.append(x);
739 public void println()
741 mappingDetails.append(NEWLINE);
745 maxAlignseq.printAlignment(ps);
747 mappingDetails.append(NEWLINE).append("PDB start/end ");
748 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
750 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
751 mappingDetails.append(NEWLINE).append("SEQ start/end ");
754 .valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
756 mappingDetails.append(
757 String.valueOf(maxAlignseq.seq1end + (seq.getStart() - 1)));
758 mappingDetails.append(NEWLINE);
759 maxChain.makeExactMapping(maxAlignseq, seq);
760 jalview.datamodel.Mapping sqmpping = maxAlignseq
761 .getMappingFromS1(false);
762 maxChain.transferRESNUMFeatures(seq, null);
764 HashMap<Integer, int[]> mapping = new HashMap<>();
771 Atom tmp = maxChain.atoms.elementAt(index);
772 if ((resNum != tmp.resNumber || insCode != tmp.insCode)
773 && tmp.alignmentMapping != -1)
775 resNum = tmp.resNumber;
776 insCode = tmp.insCode;
777 if (tmp.alignmentMapping >= -1)
779 mapping.put(tmp.alignmentMapping + 1,
781 { tmp.resNumber, tmp.atomIndex });
786 } while (index < maxChain.atoms.size());
788 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
789 pdb.getId(), maxChainId, mapping, mappingDetails.toString());
790 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
794 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
796 listeners.removeElement(svl);
797 if (svl instanceof SequenceListener)
799 for (int i = 0; i < listeners.size(); i++)
801 if (listeners.elementAt(i) instanceof StructureListener)
803 ((StructureListener) listeners.elementAt(i))
804 .releaseReferences(svl);
809 if (pdbfiles == null)
815 * Remove mappings to the closed listener's PDB files, but first check if
816 * another listener is still interested
818 List<String> pdbs = new ArrayList<>(Arrays.asList(pdbfiles));
820 StructureListener sl;
821 for (int i = 0; i < listeners.size(); i++)
823 if (listeners.elementAt(i) instanceof StructureListener)
825 sl = (StructureListener) listeners.elementAt(i);
826 for (String pdbfile : sl.getStructureFiles())
828 pdbs.remove(pdbfile);
834 * Rebuild the mappings set, retaining only those which are for 'other' PDB
839 List<StructureMapping> tmp = new ArrayList<>();
840 for (StructureMapping sm : mappings)
842 if (!pdbs.contains(sm.pdbfile))
853 * Propagate mouseover of a single position in a structure
859 public void mouseOverStructure(int pdbResNum, String chain,
862 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
863 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
864 mouseOverStructure(atoms);
868 * Propagate mouseover or selection of multiple positions in a structure
872 public void mouseOverStructure(List<AtomSpec> atoms)
874 if (listeners == null)
876 // old or prematurely sent event
879 boolean hasSequenceListener = false;
880 for (int i = 0; i < listeners.size(); i++)
882 if (listeners.elementAt(i) instanceof SequenceListener)
884 hasSequenceListener = true;
887 if (!hasSequenceListener)
892 SearchResultsI results = findAlignmentPositionsForStructurePositions(
894 for (Object li : listeners)
896 if (li instanceof SequenceListener)
898 ((SequenceListener) li).highlightSequence(results);
904 * Constructs a SearchResults object holding regions (if any) in the Jalview
905 * alignment which have a mapping to the structure viewer positions in the
911 public SearchResultsI findAlignmentPositionsForStructurePositions(
912 List<AtomSpec> atoms)
914 SearchResultsI results = new SearchResults();
915 for (AtomSpec atom : atoms)
917 SequenceI lastseq = null;
919 for (StructureMapping sm : mappings)
921 if (sm.pdbfile.equals(atom.getPdbFile())
922 && sm.pdbchain.equals(atom.getChain()))
924 int indexpos = sm.getSeqPos(atom.getPdbResNum());
925 if (lastipos != indexpos || lastseq != sm.sequence)
927 results.addResult(sm.sequence, indexpos, indexpos);
929 lastseq = sm.sequence;
930 // construct highlighted sequence list
931 for (AlignedCodonFrame acf : seqmappings)
933 acf.markMappedRegion(sm.sequence, indexpos, results);
943 * highlight regions associated with a position (indexpos) in seq
946 * the sequence that the mouse over occurred on
948 * the absolute position being mouseovered in seq (0 to seq.length())
950 * the sequence position (if -1, seq.findPosition is called to
951 * resolve the residue number)
953 public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
956 boolean hasSequenceListeners = handlingVamsasMo
957 || !seqmappings.isEmpty();
958 SearchResultsI results = null;
961 seqPos = seq.findPosition(indexpos);
963 for (int i = 0; i < listeners.size(); i++)
965 Object listener = listeners.elementAt(i);
966 if (listener == source)
968 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
969 // Temporary fudge with SequenceListener.getVamsasSource()
972 if (listener instanceof StructureListener)
974 highlightStructure((StructureListener) listener, seq, seqPos);
978 if (listener instanceof SequenceListener)
980 final SequenceListener seqListener = (SequenceListener) listener;
981 if (hasSequenceListeners
982 && seqListener.getVamsasSource() != source)
984 if (relaySeqMappings)
988 results = MappingUtils.buildSearchResults(seq, seqPos,
991 if (handlingVamsasMo)
993 results.addResult(seq, seqPos, seqPos);
996 if (!results.isEmpty())
998 seqListener.highlightSequence(results);
1003 else if (listener instanceof VamsasListener && !handlingVamsasMo)
1005 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
1008 else if (listener instanceof SecondaryStructureListener)
1010 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
1018 * Send suitable messages to a StructureListener to highlight atoms
1019 * corresponding to the given sequence position(s)
1025 public void highlightStructure(StructureListener sl, SequenceI seq,
1028 if (!sl.isListeningFor(seq))
1033 List<AtomSpec> atoms = new ArrayList<>();
1034 for (StructureMapping sm : mappings)
1036 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
1037 || (sm.sequence.getDatasetSequence() != null && sm.sequence
1038 .getDatasetSequence() == seq.getDatasetSequence()))
1040 for (int index : positions)
1042 atomNo = sm.getAtomNum(index);
1046 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
1047 sm.getPDBResNum(index), atomNo));
1052 sl.highlightAtoms(atoms);
1056 * true if a mouse over event from an external (ie Vamsas) source is being
1059 boolean handlingVamsasMo = false;
1064 * as mouseOverSequence but only route event to SequenceListeners
1068 * in an alignment sequence
1070 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
1071 VamsasSource source)
1073 handlingVamsasMo = true;
1074 long msg = sequenceI.hashCode() * (1 + position);
1078 mouseOverSequence(sequenceI, position, -1, source);
1080 handlingVamsasMo = false;
1083 public Annotation[] colourSequenceFromStructure(SequenceI seq,
1087 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
1088 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
1090 * Annotation [] annotations = new Annotation[seq.getLength()];
1092 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
1093 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
1094 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
1096 * for (int j = 0; j < mappings.length; j++) {
1098 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
1099 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
1100 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
1101 * "+mappings[j].pdbfile);
1103 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
1104 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
1106 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
1107 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
1108 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
1109 * mappings[j].pdbfile); }
1111 * annotations[index] = new Annotation("X",null,' ',0,col); } return
1112 * annotations; } } } }
1114 * return annotations;
1118 public void structureSelectionChanged()
1122 public void sequenceSelectionChanged()
1126 public void sequenceColoursChanged(Object source)
1128 StructureListener sl;
1129 for (int i = 0; i < listeners.size(); i++)
1131 if (listeners.elementAt(i) instanceof StructureListener)
1133 sl = (StructureListener) listeners.elementAt(i);
1134 sl.updateColours(source);
1139 public StructureMapping[] getMapping(String pdbfile)
1141 List<StructureMapping> tmp = new ArrayList<>();
1142 for (StructureMapping sm : mappings)
1144 if (sm.pdbfile.equals(pdbfile))
1149 return tmp.toArray(new StructureMapping[tmp.size()]);
1153 * Returns a readable description of all mappings for the given pdbfile to any
1154 * of the given sequences
1160 public String printMappings(String pdbfile, List<SequenceI> seqs)
1162 if (pdbfile == null || seqs == null || seqs.isEmpty())
1167 StringBuilder sb = new StringBuilder(64);
1168 for (StructureMapping sm : mappings)
1170 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
1172 sb.append(sm.mappingDetails);
1174 // separator makes it easier to read multiple mappings
1175 sb.append("=====================");
1181 return sb.toString();
1185 * Remove the given mapping
1189 public void deregisterMapping(AlignedCodonFrame acf)
1193 boolean removed = seqmappings.remove(acf);
1194 if (removed && seqmappings.isEmpty())
1196 System.out.println("All mappings removed");
1202 * Add each of the given codonFrames to the stored set, if not aready present.
1206 public void registerMappings(List<AlignedCodonFrame> mappings)
1208 if (mappings != null)
1210 for (AlignedCodonFrame acf : mappings)
1212 registerMapping(acf);
1218 * Add the given mapping to the stored set, unless already stored.
1220 public void registerMapping(AlignedCodonFrame acf)
1224 if (!seqmappings.contains(acf))
1226 seqmappings.add(acf);
1232 * Resets this object to its initial state by removing all registered
1233 * listeners, codon mappings, PDB file mappings
1235 public void resetAll()
1237 if (mappings != null)
1241 if (seqmappings != null)
1243 seqmappings.clear();
1245 if (sel_listeners != null)
1247 sel_listeners.clear();
1249 if (listeners != null)
1253 if (commandListeners != null)
1255 commandListeners.clear();
1257 if (view_listeners != null)
1259 view_listeners.clear();
1261 if (pdbFileNameId != null)
1263 pdbFileNameId.clear();
1265 if (pdbIdFileName != null)
1267 pdbIdFileName.clear();
1271 public void addSelectionListener(SelectionListener selecter)
1273 if (!sel_listeners.contains(selecter))
1275 sel_listeners.add(selecter);
1279 public void removeSelectionListener(SelectionListener toremove)
1281 if (sel_listeners.contains(toremove))
1283 sel_listeners.remove(toremove);
1287 public synchronized void sendSelection(
1288 jalview.datamodel.SequenceGroup selection,
1289 jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
1290 SelectionSource source)
1292 for (SelectionListener slis : sel_listeners)
1296 slis.selection(selection, colsel, hidden, source);
1301 Vector<AlignmentViewPanelListener> view_listeners = new Vector<>();
1303 public synchronized void sendViewPosition(
1304 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1305 int startSeq, int endSeq)
1308 if (view_listeners != null && view_listeners.size() > 0)
1310 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1312 while (listeners.hasMoreElements())
1314 AlignmentViewPanelListener slis = listeners.nextElement();
1317 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1325 * release all references associated with this manager provider
1327 * @param jalviewLite
1329 public static void release(StructureSelectionManagerProvider jalviewLite)
1331 // synchronized (instances)
1333 if (instances == null)
1337 StructureSelectionManager mnger = (instances.get(jalviewLite));
1340 instances.remove(jalviewLite);
1344 } catch (Throwable x)
1351 public void registerPDBEntry(PDBEntry pdbentry)
1353 if (pdbentry.getFile() != null
1354 && pdbentry.getFile().trim().length() > 0)
1356 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1360 public void addCommandListener(CommandListener cl)
1362 if (!commandListeners.contains(cl))
1364 commandListeners.add(cl);
1368 public boolean hasCommandListener(CommandListener cl)
1370 return this.commandListeners.contains(cl);
1373 public boolean removeCommandListener(CommandListener l)
1375 return commandListeners.remove(l);
1379 * Forward a command to any command listeners (except for the command's
1383 * the command to be broadcast (in its form after being performed)
1385 * if true, the command was being 'undone'
1388 public void commandPerformed(CommandI command, boolean undo,
1389 VamsasSource source)
1391 for (CommandListener listener : commandListeners)
1393 listener.mirrorCommand(command, undo, this, source);
1398 * Returns a new CommandI representing the given command as mapped to the
1399 * given sequences. If no mapping could be made, or the command is not of a
1400 * mappable kind, returns null.
1408 public CommandI mapCommand(CommandI command, boolean undo,
1409 final AlignmentI mapTo, char gapChar)
1411 if (command instanceof EditCommand)
1413 return MappingUtils.mapEditCommand((EditCommand) command, undo, mapTo,
1414 gapChar, seqmappings);
1416 else if (command instanceof OrderCommand)
1418 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1419 mapTo, seqmappings);
1424 public List<AlignedCodonFrame> getSequenceMappings()