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 file name for a mapped PDB id (or null if not mapped).
293 public String alreadyMappedToFile(String pdbid)
295 for (StructureMapping sm : mappings)
297 if (sm.getPdbId().equals(pdbid))
306 * Import structure data and register a structure mapping for broadcasting
307 * colouring, mouseovers and selection events (convenience wrapper).
310 * - one or more sequences to be mapped to pdbFile
311 * @param targetChains
312 * - optional chain specification for mapping each sequence to pdb
313 * (may be nill, individual elements may be nill)
315 * - structure data resource
317 * - how to resolve data from resource
318 * @return null or the structure data parsed as a pdb file
320 synchronized public StructureFile setMapping(SequenceI[] sequence,
321 String[] targetChains, String pdbFile, DataSourceType protocol,
322 IProgressIndicator progress)
324 return computeMapping(true, sequence, targetChains, pdbFile, protocol,
329 * Import a single structure file and register sequence structure mappings for
330 * broadcasting colouring, mouseovers and selection events (convenience
333 * @param forStructureView
334 * when true, record the mapping for use in mouseOvers
336 * - one or more sequences to be mapped to pdbFile
337 * @param targetChains
338 * - optional chain specification for mapping each sequence to pdb
339 * (may be nill, individual elements may be nill)
341 * - structure data resource
343 * - how to resolve data from resource
344 * @return null or the structure data parsed as a pdb file
346 synchronized public StructureFile setMapping(boolean forStructureView,
347 SequenceI[] sequenceArray, String[] targetChainIds,
348 String pdbFile, DataSourceType sourceType)
350 return computeMapping(forStructureView, sequenceArray, targetChainIds,
351 pdbFile, sourceType, null);
355 * create sequence structure mappings between each sequence and the given
356 * pdbFile (retrieved via the given protocol). Either constructs a mapping
357 * using NW alignment or derives one from any available SIFTS mapping data.
359 * @param forStructureView
360 * when true, record the mapping for use in mouseOvers
362 * @param sequenceArray
363 * - one or more sequences to be mapped to pdbFile
364 * @param targetChainIds
365 * - optional chain specification for mapping each sequence to pdb
366 * (may be nill, individual elements may be nill) - JBPNote: JAL-2693
367 * - this should be List<List<String>>, empty lists indicate no
368 * predefined mappings
370 * - structure data resource
372 * - how to resolve data from resource
373 * @param IProgressIndicator
374 * reference to UI component that maintains a progress bar for the
376 * @return null or the structure data parsed as a pdb file
378 synchronized public StructureFile computeMapping(
379 boolean forStructureView, SequenceI[] sequenceArray,
380 String[] targetChainIds, String pdbFile, DataSourceType sourceType,
381 IProgressIndicator progress)
383 long progressSessionId = System.currentTimeMillis() * 3;
386 * do we extract and transfer annotation from 3D data ?
388 // FIXME: possibly should just delete
390 boolean parseSecStr = processSecondaryStructure
391 ? isStructureFileProcessed(pdbFile, sequenceArray)
394 StructureFile pdb = null;
395 boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
398 // FIXME if sourceType is not null, we've lost data here
399 sourceType = AppletFormatAdapter.checkProtocol(pdbFile);
400 pdb = new JmolParser(pdbFile, sourceType);
402 if (pdb.getId() != null && pdb.getId().trim().length() > 0
403 && DataSourceType.FILE == sourceType)
405 registerPDBFile(pdb.getId().trim(), pdbFile);
407 // if PDBId is unavailable then skip SIFTS mapping execution path
408 isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable();
410 } catch (Exception ex)
412 ex.printStackTrace();
416 * sifts client - non null if SIFTS mappings are to be used
418 SiftsClient siftsClient = null;
423 siftsClient = new SiftsClient(pdb);
425 } catch (SiftsException e)
427 isMapUsingSIFTs = false;
431 String targetChainId;
432 for (int s = 0; s < sequenceArray.length; s++)
434 boolean infChain = true;
435 final SequenceI seq = sequenceArray[s];
437 while (ds.getDatasetSequence() != null)
439 ds = ds.getDatasetSequence();
442 if (targetChainIds != null && targetChainIds[s] != null)
445 targetChainId = targetChainIds[s];
447 else if (seq.getName().indexOf("|") > -1)
449 targetChainId = seq.getName()
450 .substring(seq.getName().lastIndexOf("|") + 1);
451 if (targetChainId.length() > 1)
453 if (targetChainId.trim().length() == 0)
459 // not a valid chain identifier
470 * Attempt pairwise alignment of the sequence with each chain in the PDB,
471 * and remember the highest scoring chain
474 AlignSeq maxAlignseq = null;
475 String maxChainId = " ";
476 PDBChain maxChain = null;
477 boolean first = true;
478 for (PDBChain chain : pdb.getChains())
480 if (targetChainId.length() > 0 && !targetChainId.equals(chain.id)
483 continue; // don't try to map chains don't match.
485 // TODO: correctly determine sequence type for mixed na/peptide
487 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
488 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
491 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
492 // as.calcScoreMatrix();
493 // as.traceAlignment();
495 if (first || as.maxscore > max
496 || (as.maxscore == max && chain.id.equals(targetChainId)))
502 maxChainId = chain.id;
505 if (maxChain == null)
510 if (sourceType == DataSourceType.PASTE)
512 pdbFile = "INLINE" + pdb.getId();
515 List<StructureMapping> seqToStrucMapping = new ArrayList<>();
516 if (isMapUsingSIFTs && seq.isProtein())
518 if (progress!=null) {
519 progress.setProgressBar(MessageManager
520 .getString("status.obtaining_mapping_with_sifts"),
523 jalview.datamodel.Mapping sqmpping = maxAlignseq
524 .getMappingFromS1(false);
525 if (targetChainId != null && !targetChainId.trim().isEmpty())
527 StructureMapping siftsMapping;
530 siftsMapping = getStructureMapping(seq, pdbFile, targetChainId,
531 pdb, maxChain, sqmpping, maxAlignseq, siftsClient);
532 seqToStrucMapping.add(siftsMapping);
533 maxChain.makeExactMapping(siftsMapping, seq);
534 maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
536 maxChain.transferResidueAnnotation(siftsMapping, null);
537 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
539 } catch (SiftsException e)
541 // fall back to NW alignment
542 System.err.println(e.getMessage());
543 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
544 targetChainId, maxChain, pdb, maxAlignseq);
545 seqToStrucMapping.add(nwMapping);
546 maxChain.makeExactMapping(maxAlignseq, seq);
547 maxChain.transferRESNUMFeatures(seq, "IEA:Jalview"); // FIXME: is
550 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
551 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
556 List<StructureMapping> foundSiftsMappings = new ArrayList<>();
557 for (PDBChain chain : pdb.getChains())
559 StructureMapping siftsMapping = null;
562 siftsMapping = getStructureMapping(seq,
563 pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq,
565 foundSiftsMappings.add(siftsMapping);
566 chain.makeExactMapping(siftsMapping, seq);
567 chain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
569 chain.transferResidueAnnotation(siftsMapping, null);
570 } catch (SiftsException e)
572 System.err.println(e.getMessage());
575 if (!foundSiftsMappings.isEmpty())
577 seqToStrucMapping.addAll(foundSiftsMappings);
578 ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
582 StructureMapping nwMapping = getNWMappings(seq, pdbFile,
583 maxChainId, maxChain, pdb, maxAlignseq);
584 seqToStrucMapping.add(nwMapping);
585 maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
587 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
588 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
594 if (progress != null)
596 progress.setProgressBar(MessageManager
597 .getString("status.obtaining_mapping_with_nw_alignment"),
600 StructureMapping nwMapping = getNWMappings(seq, pdbFile, maxChainId,
601 maxChain, pdb, maxAlignseq);
602 seqToStrucMapping.add(nwMapping);
603 ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
605 if (forStructureView)
607 mappings.addAll(seqToStrucMapping);
609 if (progress != null)
611 progress.setProgressBar(null, progressSessionId);
618 * check if we need to extract secondary structure from given pdbFile and
619 * transfer to sequences
622 * @param sequenceArray
625 private boolean isStructureFileProcessed(String pdbFile,
626 SequenceI[] sequenceArray)
628 boolean parseSecStr = true;
629 if (isPDBFileRegistered(pdbFile))
631 for (SequenceI sq : sequenceArray)
634 while (ds.getDatasetSequence() != null)
636 ds = ds.getDatasetSequence();
639 if (ds.getAnnotation() != null)
641 for (AlignmentAnnotation ala : ds.getAnnotation())
643 // false if any annotation present from this structure
644 // JBPNote this fails for jmol/chimera view because the *file* is
645 // passed, not the structure data ID -
646 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
657 public void addStructureMapping(StructureMapping sm)
663 * retrieve a mapping for seq from SIFTs using associated DBRefEntry for
668 * @param targetChainId
674 * client for retrieval of SIFTS mappings for this structure
676 * @throws SiftsException
678 private StructureMapping getStructureMapping(SequenceI seq,
679 String pdbFile, String targetChainId, StructureFile pdb,
680 PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
681 AlignSeq maxAlignseq, SiftsClient siftsClient) throws SiftsException
683 StructureMapping curChainMapping = siftsClient
684 .getSiftsStructureMapping(seq, pdbFile, targetChainId);
687 PDBChain chain = pdb.findChain(targetChainId);
690 chain.transferResidueAnnotation(curChainMapping, null);
692 } catch (Exception e)
696 return curChainMapping;
699 private StructureMapping getNWMappings(SequenceI seq, String pdbFile,
700 String maxChainId, PDBChain maxChain, StructureFile pdb,
701 AlignSeq maxAlignseq)
703 final StringBuilder mappingDetails = new StringBuilder(128);
704 mappingDetails.append(NEWLINE)
705 .append("Sequence \u27f7 Structure mapping details");
706 mappingDetails.append(NEWLINE);
708 .append("Method: inferred with Needleman & Wunsch alignment");
709 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
710 .append(NEWLINE).append("Sequence = ")
711 .append(maxChain.sequence.getSequenceAsString());
712 mappingDetails.append(NEWLINE).append("No of residues = ")
713 .append(maxChain.residues.size()).append(NEWLINE)
715 PrintStream ps = new PrintStream(System.out)
718 public void print(String x)
720 mappingDetails.append(x);
724 public void println()
726 mappingDetails.append(NEWLINE);
730 maxAlignseq.printAlignment(ps);
732 mappingDetails.append(NEWLINE).append("PDB start/end ");
733 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
735 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
736 mappingDetails.append(NEWLINE).append("SEQ start/end ");
739 .valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
741 mappingDetails.append(
742 String.valueOf(maxAlignseq.seq1end + (seq.getStart() - 1)));
743 mappingDetails.append(NEWLINE);
744 maxChain.makeExactMapping(maxAlignseq, seq);
745 jalview.datamodel.Mapping sqmpping = maxAlignseq
746 .getMappingFromS1(false);
747 maxChain.transferRESNUMFeatures(seq, null);
749 HashMap<Integer, int[]> mapping = new HashMap<>();
756 Atom tmp = maxChain.atoms.elementAt(index);
757 if ((resNum != tmp.resNumber || insCode != tmp.insCode)
758 && tmp.alignmentMapping != -1)
760 resNum = tmp.resNumber;
761 insCode = tmp.insCode;
762 if (tmp.alignmentMapping >= -1)
764 mapping.put(tmp.alignmentMapping + 1,
766 { tmp.resNumber, tmp.atomIndex });
771 } while (index < maxChain.atoms.size());
773 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
774 pdb.getId(), maxChainId, mapping, mappingDetails.toString());
775 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
779 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
781 listeners.removeElement(svl);
782 if (svl instanceof SequenceListener)
784 for (int i = 0; i < listeners.size(); i++)
786 if (listeners.elementAt(i) instanceof StructureListener)
788 ((StructureListener) listeners.elementAt(i))
789 .releaseReferences(svl);
794 if (pdbfiles == null)
800 * Remove mappings to the closed listener's PDB files, but first check if
801 * another listener is still interested
803 List<String> pdbs = new ArrayList<>(Arrays.asList(pdbfiles));
805 StructureListener sl;
806 for (int i = 0; i < listeners.size(); i++)
808 if (listeners.elementAt(i) instanceof StructureListener)
810 sl = (StructureListener) listeners.elementAt(i);
811 for (String pdbfile : sl.getStructureFiles())
813 pdbs.remove(pdbfile);
819 * Rebuild the mappings set, retaining only those which are for 'other' PDB
824 List<StructureMapping> tmp = new ArrayList<>();
825 for (StructureMapping sm : mappings)
827 if (!pdbs.contains(sm.pdbfile))
838 * Propagate mouseover of a single position in a structure
844 public void mouseOverStructure(int pdbResNum, String chain,
847 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
848 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
849 mouseOverStructure(atoms);
853 * Propagate mouseover or selection of multiple positions in a structure
857 public void mouseOverStructure(List<AtomSpec> atoms)
859 if (listeners == null)
861 // old or prematurely sent event
864 boolean hasSequenceListener = false;
865 for (int i = 0; i < listeners.size(); i++)
867 if (listeners.elementAt(i) instanceof SequenceListener)
869 hasSequenceListener = true;
872 if (!hasSequenceListener)
877 SearchResultsI results = findAlignmentPositionsForStructurePositions(
879 for (Object li : listeners)
881 if (li instanceof SequenceListener)
883 ((SequenceListener) li).highlightSequence(results);
889 * Constructs a SearchResults object holding regions (if any) in the Jalview
890 * alignment which have a mapping to the structure viewer positions in the
896 public SearchResultsI findAlignmentPositionsForStructurePositions(
897 List<AtomSpec> atoms)
899 SearchResultsI results = new SearchResults();
900 for (AtomSpec atom : atoms)
902 SequenceI lastseq = null;
904 for (StructureMapping sm : mappings)
906 if (sm.pdbfile.equals(atom.getPdbFile())
907 && sm.pdbchain.equals(atom.getChain()))
909 int indexpos = sm.getSeqPos(atom.getPdbResNum());
910 if (lastipos != indexpos || lastseq != sm.sequence)
912 results.addResult(sm.sequence, indexpos, indexpos);
914 lastseq = sm.sequence;
915 // construct highlighted sequence list
916 for (AlignedCodonFrame acf : seqmappings)
918 acf.markMappedRegion(sm.sequence, indexpos, results);
928 * highlight regions associated with a position (indexpos) in seq
931 * the sequence that the mouse over occurred on
933 * the absolute position being mouseovered in seq (0 to seq.length())
935 * the sequence position (if -1, seq.findPosition is called to
936 * resolve the residue number)
938 public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
941 boolean hasSequenceListeners = handlingVamsasMo
942 || !seqmappings.isEmpty();
943 SearchResultsI results = null;
946 seqPos = seq.findPosition(indexpos);
948 for (int i = 0; i < listeners.size(); i++)
950 Object listener = listeners.elementAt(i);
951 if (listener == source)
953 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
954 // Temporary fudge with SequenceListener.getVamsasSource()
957 if (listener instanceof StructureListener)
959 highlightStructure((StructureListener) listener, seq, seqPos);
963 if (listener instanceof SequenceListener)
965 final SequenceListener seqListener = (SequenceListener) listener;
966 if (hasSequenceListeners
967 && seqListener.getVamsasSource() != source)
969 if (relaySeqMappings)
973 results = MappingUtils.buildSearchResults(seq, seqPos,
976 if (handlingVamsasMo)
978 results.addResult(seq, seqPos, seqPos);
981 if (!results.isEmpty())
983 seqListener.highlightSequence(results);
988 else if (listener instanceof VamsasListener && !handlingVamsasMo)
990 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
993 else if (listener instanceof SecondaryStructureListener)
995 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
1003 * Send suitable messages to a StructureListener to highlight atoms
1004 * corresponding to the given sequence position(s)
1010 public void highlightStructure(StructureListener sl, SequenceI seq,
1013 if (!sl.isListeningFor(seq))
1018 List<AtomSpec> atoms = new ArrayList<>();
1019 for (StructureMapping sm : mappings)
1021 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
1022 || (sm.sequence.getDatasetSequence() != null && sm.sequence
1023 .getDatasetSequence() == seq.getDatasetSequence()))
1025 for (int index : positions)
1027 atomNo = sm.getAtomNum(index);
1031 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain,
1032 sm.getPDBResNum(index), atomNo));
1037 sl.highlightAtoms(atoms);
1041 * true if a mouse over event from an external (ie Vamsas) source is being
1044 boolean handlingVamsasMo = false;
1049 * as mouseOverSequence but only route event to SequenceListeners
1053 * in an alignment sequence
1055 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
1056 VamsasSource source)
1058 handlingVamsasMo = true;
1059 long msg = sequenceI.hashCode() * (1 + position);
1063 mouseOverSequence(sequenceI, position, -1, source);
1065 handlingVamsasMo = false;
1068 public Annotation[] colourSequenceFromStructure(SequenceI seq,
1072 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
1073 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
1075 * Annotation [] annotations = new Annotation[seq.getLength()];
1077 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
1078 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
1079 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
1081 * for (int j = 0; j < mappings.length; j++) {
1083 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
1084 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
1085 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
1086 * "+mappings[j].pdbfile);
1088 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
1089 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
1091 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
1092 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
1093 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
1094 * mappings[j].pdbfile); }
1096 * annotations[index] = new Annotation("X",null,' ',0,col); } return
1097 * annotations; } } } }
1099 * return annotations;
1103 public void structureSelectionChanged()
1107 public void sequenceSelectionChanged()
1111 public void sequenceColoursChanged(Object source)
1113 StructureListener sl;
1114 for (int i = 0; i < listeners.size(); i++)
1116 if (listeners.elementAt(i) instanceof StructureListener)
1118 sl = (StructureListener) listeners.elementAt(i);
1119 sl.updateColours(source);
1124 public StructureMapping[] getMapping(String pdbfile)
1126 List<StructureMapping> tmp = new ArrayList<>();
1127 for (StructureMapping sm : mappings)
1129 if (sm.pdbfile.equals(pdbfile))
1134 return tmp.toArray(new StructureMapping[tmp.size()]);
1138 * Returns a readable description of all mappings for the given pdbfile to any
1139 * of the given sequences
1145 public String printMappings(String pdbfile, List<SequenceI> seqs)
1147 if (pdbfile == null || seqs == null || seqs.isEmpty())
1152 StringBuilder sb = new StringBuilder(64);
1153 for (StructureMapping sm : mappings)
1155 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
1157 sb.append(sm.mappingDetails);
1159 // separator makes it easier to read multiple mappings
1160 sb.append("=====================");
1166 return sb.toString();
1170 * Remove the given mapping
1174 public void deregisterMapping(AlignedCodonFrame acf)
1178 boolean removed = seqmappings.remove(acf);
1179 if (removed && seqmappings.isEmpty())
1181 System.out.println("All mappings removed");
1187 * Add each of the given codonFrames to the stored set, if not aready present.
1191 public void registerMappings(List<AlignedCodonFrame> mappings)
1193 if (mappings != null)
1195 for (AlignedCodonFrame acf : mappings)
1197 registerMapping(acf);
1203 * Add the given mapping to the stored set, unless already stored.
1205 public void registerMapping(AlignedCodonFrame acf)
1209 if (!seqmappings.contains(acf))
1211 seqmappings.add(acf);
1217 * Resets this object to its initial state by removing all registered
1218 * listeners, codon mappings, PDB file mappings
1220 public void resetAll()
1222 if (mappings != null)
1226 if (seqmappings != null)
1228 seqmappings.clear();
1230 if (sel_listeners != null)
1232 sel_listeners.clear();
1234 if (listeners != null)
1238 if (commandListeners != null)
1240 commandListeners.clear();
1242 if (view_listeners != null)
1244 view_listeners.clear();
1246 if (pdbFileNameId != null)
1248 pdbFileNameId.clear();
1250 if (pdbIdFileName != null)
1252 pdbIdFileName.clear();
1256 public void addSelectionListener(SelectionListener selecter)
1258 if (!sel_listeners.contains(selecter))
1260 sel_listeners.add(selecter);
1264 public void removeSelectionListener(SelectionListener toremove)
1266 if (sel_listeners.contains(toremove))
1268 sel_listeners.remove(toremove);
1272 public synchronized void sendSelection(
1273 jalview.datamodel.SequenceGroup selection,
1274 jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
1275 SelectionSource source)
1277 for (SelectionListener slis : sel_listeners)
1281 slis.selection(selection, colsel, hidden, source);
1286 Vector<AlignmentViewPanelListener> view_listeners = new Vector<>();
1288 public synchronized void sendViewPosition(
1289 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1290 int startSeq, int endSeq)
1293 if (view_listeners != null && view_listeners.size() > 0)
1295 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1297 while (listeners.hasMoreElements())
1299 AlignmentViewPanelListener slis = listeners.nextElement();
1302 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1310 * release all references associated with this manager provider
1312 * @param jalviewLite
1314 public static void release(StructureSelectionManagerProvider jalviewLite)
1316 // synchronized (instances)
1318 if (instances == null)
1322 StructureSelectionManager mnger = (instances.get(jalviewLite));
1325 instances.remove(jalviewLite);
1329 } catch (Throwable x)
1336 public void registerPDBEntry(PDBEntry pdbentry)
1338 if (pdbentry.getFile() != null
1339 && pdbentry.getFile().trim().length() > 0)
1341 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1345 public void addCommandListener(CommandListener cl)
1347 if (!commandListeners.contains(cl))
1349 commandListeners.add(cl);
1353 public boolean hasCommandListener(CommandListener cl)
1355 return this.commandListeners.contains(cl);
1358 public boolean removeCommandListener(CommandListener l)
1360 return commandListeners.remove(l);
1364 * Forward a command to any command listeners (except for the command's
1368 * the command to be broadcast (in its form after being performed)
1370 * if true, the command was being 'undone'
1373 public void commandPerformed(CommandI command, boolean undo,
1374 VamsasSource source)
1376 for (CommandListener listener : commandListeners)
1378 listener.mirrorCommand(command, undo, this, source);
1383 * Returns a new CommandI representing the given command as mapped to the
1384 * given sequences. If no mapping could be made, or the command is not of a
1385 * mappable kind, returns null.
1393 public CommandI mapCommand(CommandI command, boolean undo,
1394 final AlignmentI mapTo, char gapChar)
1396 if (command instanceof EditCommand)
1398 return MappingUtils.mapEditCommand((EditCommand) command, undo, mapTo,
1399 gapChar, seqmappings);
1401 else if (command instanceof OrderCommand)
1403 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1404 mapTo, seqmappings);
1409 public List<AlignedCodonFrame> getSequenceMappings()