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(false, pdbFile, sourceType);
402 pdb.addSettings(parseSecStr, parseSecStr, parseSecStr);
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 (instances == null)
1338 StructureSelectionManager mnger = (instances.get(jalviewLite));
1341 instances.remove(jalviewLite);
1345 } catch (Throwable x)
1352 public void registerPDBEntry(PDBEntry pdbentry)
1354 if (pdbentry.getFile() != null
1355 && pdbentry.getFile().trim().length() > 0)
1357 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1361 public void addCommandListener(CommandListener cl)
1363 if (!commandListeners.contains(cl))
1365 commandListeners.add(cl);
1369 public boolean hasCommandListener(CommandListener cl)
1371 return this.commandListeners.contains(cl);
1374 public boolean removeCommandListener(CommandListener l)
1376 return commandListeners.remove(l);
1380 * Forward a command to any command listeners (except for the command's
1384 * the command to be broadcast (in its form after being performed)
1386 * if true, the command was being 'undone'
1389 public void commandPerformed(CommandI command, boolean undo,
1390 VamsasSource source)
1392 for (CommandListener listener : commandListeners)
1394 listener.mirrorCommand(command, undo, this, source);
1399 * Returns a new CommandI representing the given command as mapped to the
1400 * given sequences. If no mapping could be made, or the command is not of a
1401 * mappable kind, returns null.
1409 public CommandI mapCommand(CommandI command, boolean undo,
1410 final AlignmentI mapTo, char gapChar)
1412 if (command instanceof EditCommand)
1414 return MappingUtils.mapEditCommand((EditCommand) command, undo, mapTo,
1415 gapChar, seqmappings);
1417 else if (command instanceof OrderCommand)
1419 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1420 mapTo, seqmappings);
1425 public List<AlignedCodonFrame> getSequenceMappings()