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.PDBEntry;
33 import jalview.datamodel.SearchResults;
34 import jalview.datamodel.SequenceI;
35 import jalview.io.AppletFormatAdapter;
36 import jalview.util.MappingUtils;
37 import jalview.util.MessageManager;
38 import jalview.ws.sifts.SiftsClient;
39 import jalview.ws.sifts.SiftsException;
41 import java.io.PrintStream;
42 import java.util.ArrayList;
43 import java.util.Arrays;
44 import java.util.Collections;
45 import java.util.Enumeration;
46 import java.util.HashMap;
47 import java.util.IdentityHashMap;
48 import java.util.LinkedHashSet;
49 import java.util.List;
52 import java.util.Vector;
55 import MCview.PDBChain;
56 import MCview.PDBfile;
58 public class StructureSelectionManager
60 public final static String NEWLINE = System.lineSeparator();
62 static IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> instances;
64 private List<StructureMapping> mappings = new ArrayList<StructureMapping>();
66 private boolean processSecondaryStructure = false;
68 private boolean secStructServices = false;
70 private boolean addTempFacAnnot = false;
73 * Set of any registered mappings between (dataset) sequences.
75 public Set<AlignedCodonFrame> seqmappings = new LinkedHashSet<AlignedCodonFrame>();
77 private List<CommandListener> commandListeners = new ArrayList<CommandListener>();
79 private List<SelectionListener> sel_listeners = new ArrayList<SelectionListener>();
82 * @return true if will try to use external services for processing secondary
85 public boolean isSecStructServices()
87 return secStructServices;
91 * control use of external services for processing secondary structure
93 * @param secStructServices
95 public void setSecStructServices(boolean secStructServices)
97 this.secStructServices = secStructServices;
101 * flag controlling addition of any kind of structural annotation
103 * @return true if temperature factor annotation will be added
105 public boolean isAddTempFacAnnot()
107 return addTempFacAnnot;
111 * set flag controlling addition of structural annotation
113 * @param addTempFacAnnot
115 public void setAddTempFacAnnot(boolean addTempFacAnnot)
117 this.addTempFacAnnot = addTempFacAnnot;
122 * @return if true, the structure manager will attempt to add secondary
123 * structure lines for unannotated sequences
126 public boolean isProcessSecondaryStructure()
128 return processSecondaryStructure;
132 * Control whether structure manager will try to annotate mapped sequences
133 * with secondary structure from PDB data.
137 public void setProcessSecondaryStructure(boolean enable)
139 processSecondaryStructure = enable;
143 * debug function - write all mappings to stdout
145 public void reportMapping()
147 if (mappings.isEmpty())
149 System.err.println("reportMapping: No PDB/Sequence mappings.");
153 System.err.println("reportMapping: There are " + mappings.size()
156 for (StructureMapping sm : mappings)
158 System.err.println("mapping " + i++ + " : " + sm.pdbfile);
164 * map between the PDB IDs (or structure identifiers) used by Jalview and the
165 * absolute filenames for PDB data that corresponds to it
167 Map<String, String> pdbIdFileName = new HashMap<String, String>();
169 Map<String, String> pdbFileNameId = new HashMap<String, String>();
171 public void registerPDBFile(String idForFile, String absoluteFile)
173 pdbIdFileName.put(idForFile, absoluteFile);
174 pdbFileNameId.put(absoluteFile, idForFile);
177 public String findIdForPDBFile(String idOrFile)
179 String id = pdbFileNameId.get(idOrFile);
183 public String findFileForPDBId(String idOrFile)
185 String id = pdbIdFileName.get(idOrFile);
189 public boolean isPDBFileRegistered(String idOrFile)
191 return pdbFileNameId.containsKey(idOrFile)
192 || pdbIdFileName.containsKey(idOrFile);
195 private static StructureSelectionManager nullProvider = null;
197 public static StructureSelectionManager getStructureSelectionManager(
198 StructureSelectionManagerProvider context)
202 if (nullProvider == null)
204 if (instances != null)
208 .getString("error.implementation_error_structure_selection_manager_null"),
209 new NullPointerException(MessageManager
210 .getString("exception.ssm_context_is_null")));
214 nullProvider = new StructureSelectionManager();
219 if (instances == null)
221 instances = new java.util.IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager>();
223 StructureSelectionManager instance = instances.get(context);
224 if (instance == null)
226 if (nullProvider != null)
228 instance = nullProvider;
232 instance = new StructureSelectionManager();
234 instances.put(context, instance);
240 * flag controlling whether SeqMappings are relayed from received sequence
241 * mouse over events to other sequences
243 boolean relaySeqMappings = true;
246 * Enable or disable relay of seqMapping events to other sequences. You might
247 * want to do this if there are many sequence mappings and the host computer
252 public void setRelaySeqMappings(boolean relay)
254 relaySeqMappings = relay;
258 * get the state of the relay seqMappings flag.
260 * @return true if sequence mouse overs are being relayed to other mapped
263 public boolean isRelaySeqMappingsEnabled()
265 return relaySeqMappings;
268 Vector listeners = new Vector();
271 * register a listener for alignment sequence mouseover events
275 public void addStructureViewerListener(Object svl)
277 if (!listeners.contains(svl))
279 listeners.addElement(svl);
284 * Returns the file name for a mapped PDB id (or null if not mapped).
289 public String alreadyMappedToFile(String pdbid)
291 for (StructureMapping sm : mappings)
293 if (sm.getPdbId().equals(pdbid))
302 * Import structure data and register a structure mapping for broadcasting
303 * colouring, mouseovers and selection events (convenience wrapper).
306 * - one or more sequences to be mapped to pdbFile
307 * @param targetChains
308 * - optional chain specification for mapping each sequence to pdb
309 * (may be nill, individual elements may be nill)
311 * - structure data resource
313 * - how to resolve data from resource
314 * @return null or the structure data parsed as a pdb file
316 synchronized public PDBfile setMapping(SequenceI[] sequence,
317 String[] targetChains, String pdbFile, String protocol)
319 return setMapping(true, sequence, targetChains, pdbFile, protocol);
323 * create sequence structure mappings between each sequence and the given
324 * pdbFile (retrieved via the given protocol).
326 * @param forStructureView
327 * when true, record the mapping for use in mouseOvers
330 * - one or more sequences to be mapped to pdbFile
331 * @param targetChains
332 * - optional chain specification for mapping each sequence to pdb
333 * (may be nill, individual elements may be nill)
335 * - structure data resource
337 * - how to resolve data from resource
338 * @return null or the structure data parsed as a pdb file
340 synchronized public PDBfile setMapping(boolean forStructureView,
341 SequenceI[] sequence, String[] targetChains, String pdbFile,
345 * There will be better ways of doing this in the future, for now we'll use
346 * the tried and tested MCview pdb mapping
348 boolean parseSecStr = processSecondaryStructure;
349 if (isPDBFileRegistered(pdbFile))
351 for (SequenceI sq : sequence)
354 while (ds.getDatasetSequence() != null)
356 ds = ds.getDatasetSequence();
359 if (ds.getAnnotation() != null)
361 for (AlignmentAnnotation ala : ds.getAnnotation())
363 // false if any annotation present from this structure
364 // JBPNote this fails for jmol/chimera view because the *file* is
365 // passed, not the structure data ID -
366 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
377 pdb = new PDBfile(addTempFacAnnot, parseSecStr, secStructServices,
379 if (pdb.id != null && pdb.id.trim().length() > 0
380 && AppletFormatAdapter.FILE.equals(protocol))
382 registerPDBFile(pdb.id.trim(), pdbFile);
384 } catch (Exception ex)
386 ex.printStackTrace();
391 for (int s = 0; s < sequence.length; s++)
393 boolean infChain = true;
394 final SequenceI seq = sequence[s];
395 if (targetChains != null && targetChains[s] != null)
398 targetChain = targetChains[s];
400 else if (seq.getName().indexOf("|") > -1)
402 targetChain = seq.getName().substring(
403 seq.getName().lastIndexOf("|") + 1);
404 if (targetChain.length() > 1)
406 if (targetChain.trim().length() == 0)
412 // not a valid chain identifier
423 * Attempt pairwise alignment of the sequence with each chain in the PDB,
424 * and remember the highest scoring chain
427 AlignSeq maxAlignseq = null;
428 String maxChainId = " ";
429 PDBChain maxChain = null;
430 boolean first = true;
431 for (PDBChain chain : pdb.chains)
433 if (targetChain.length() > 0 && !targetChain.equals(chain.id)
436 continue; // don't try to map chains don't match.
438 // TODO: correctly determine sequence type for mixed na/peptide
440 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
441 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
444 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
445 // as.calcScoreMatrix();
446 // as.traceAlignment();
448 if (first || as.maxscore > max
449 || (as.maxscore == max && chain.id.equals(targetChain)))
455 maxChainId = chain.id;
458 if (maxChain == null)
463 if (protocol.equals(jalview.io.AppletFormatAdapter.PASTE))
465 pdbFile = "INLINE" + pdb.id;
468 StructureMapping seqToStrucMapping = null;
469 boolean isMapViaSIFTs = Boolean.valueOf(jalview.bin.Cache.getDefault(
470 "MAP_WITH_SIFTS", "false"));
473 SiftsClient siftsClient = new SiftsClient(pdb.id);
476 seqToStrucMapping = siftsClient.getSiftsStructureMapping(seq,
477 pdbFile, maxChainId);
478 } catch (SiftsException e)
481 .println(">>>>>>> SIFTs mapping could not be obtained... Now mapping with NW alignment");
482 seqToStrucMapping = getNWMappings(seq, pdbFile, maxChainId,
483 maxChain, pdb, maxAlignseq);
488 seqToStrucMapping = getNWMappings(seq, pdbFile,
489 maxChainId, maxChain, pdb,
493 if (forStructureView)
495 mappings.add(seqToStrucMapping);
501 private StructureMapping getNWMappings(SequenceI seq, String pdbFile,
502 String maxChainId, PDBChain maxChain, PDBfile pdb,
503 AlignSeq maxAlignseq)
505 final StringBuilder mappingDetails = new StringBuilder(128);
506 mappingDetails.append(NEWLINE).append(
507 "Sequence \u27f7 Structure mapping details");
508 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
509 .append(NEWLINE).append("Sequence = ")
510 .append(maxChain.sequence.getSequenceAsString());
511 mappingDetails.append(NEWLINE).append("No of residues = ")
512 .append(maxChain.residues.size()).append(NEWLINE)
514 PrintStream ps = new PrintStream(System.out)
517 public void print(String x)
519 mappingDetails.append(x);
523 public void println()
525 mappingDetails.append(NEWLINE);
529 maxAlignseq.printAlignment(ps);
531 mappingDetails.append(NEWLINE).append("PDB start/end ");
532 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
534 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
535 mappingDetails.append(NEWLINE).append("SEQ start/end ");
536 mappingDetails.append(
537 String.valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
539 mappingDetails.append(String.valueOf(maxAlignseq.seq1end
540 + (seq.getStart() - 1)));
541 mappingDetails.append(NEWLINE);
543 .append("Mapping inferred with Needleman & Wunsch alignment");
544 mappingDetails.append(NEWLINE);
545 maxChain.makeExactMapping(maxAlignseq, seq);
546 jalview.datamodel.Mapping sqmpping = maxAlignseq
547 .getMappingFromS1(false);
548 maxChain.transferRESNUMFeatures(seq, null);
550 // allocate enough slots to store the mapping from positions in
551 // sequence[s] to the associated chain
552 int[][] mapping = new int[seq.findPosition(seq.getLength()) + 2][2];
558 Atom tmp = maxChain.atoms.elementAt(index);
559 if (resNum != tmp.resNumber && tmp.alignmentMapping != -1)
561 resNum = tmp.resNumber;
562 if (tmp.alignmentMapping >= -1)
564 // TODO (JAL-1836) address root cause: negative residue no in PDB
566 mapping[tmp.alignmentMapping + 1][0] = tmp.resNumber;
567 mapping[tmp.alignmentMapping + 1][1] = tmp.atomIndex;
572 } while (index < maxChain.atoms.size());
574 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
575 pdb.id, maxChainId, mapping, mappingDetails.toString());
576 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
580 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
582 listeners.removeElement(svl);
583 if (svl instanceof SequenceListener)
585 for (int i = 0; i < listeners.size(); i++)
587 if (listeners.elementAt(i) instanceof StructureListener)
589 ((StructureListener) listeners.elementAt(i))
590 .releaseReferences(svl);
595 if (pdbfiles == null)
601 * Remove mappings to the closed listener's PDB files, but first check if
602 * another listener is still interested
604 List<String> pdbs = new ArrayList<String>(Arrays.asList(pdbfiles));
606 StructureListener sl;
607 for (int i = 0; i < listeners.size(); i++)
609 if (listeners.elementAt(i) instanceof StructureListener)
611 sl = (StructureListener) listeners.elementAt(i);
612 for (String pdbfile : sl.getPdbFile())
614 pdbs.remove(pdbfile);
620 * Rebuild the mappings set, retaining only those which are for 'other' PDB
625 List<StructureMapping> tmp = new ArrayList<StructureMapping>();
626 for (StructureMapping sm : mappings)
628 if (!pdbs.contains(sm.pdbfile))
639 * Propagate mouseover of a single position in a structure
645 public void mouseOverStructure(int pdbResNum, String chain, String pdbfile)
647 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
648 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
649 mouseOverStructure(atoms);
653 * Propagate mouseover or selection of multiple positions in a structure
657 public void mouseOverStructure(List<AtomSpec> atoms)
659 if (listeners == null)
661 // old or prematurely sent event
664 boolean hasSequenceListener = false;
665 for (int i = 0; i < listeners.size(); i++)
667 if (listeners.elementAt(i) instanceof SequenceListener)
669 hasSequenceListener = true;
672 if (!hasSequenceListener)
677 SearchResults results = new SearchResults();
678 for (AtomSpec atom : atoms)
680 SequenceI lastseq = null;
682 for (StructureMapping sm : mappings)
684 if (sm.pdbfile.equals(atom.getPdbFile())
685 && sm.pdbchain.equals(atom.getChain()))
687 int indexpos = sm.getSeqPos(atom.getPdbResNum());
688 if (lastipos != indexpos && lastseq != sm.sequence)
690 results.addResult(sm.sequence, indexpos, indexpos);
692 lastseq = sm.sequence;
693 // construct highlighted sequence list
694 for (AlignedCodonFrame acf : seqmappings)
696 acf.markMappedRegion(sm.sequence, indexpos, results);
702 for (Object li : listeners)
704 if (li instanceof SequenceListener)
706 ((SequenceListener) li).highlightSequence(results);
712 * highlight regions associated with a position (indexpos) in seq
715 * the sequence that the mouse over occurred on
717 * the absolute position being mouseovered in seq (0 to seq.length())
719 * the sequence position (if -1, seq.findPosition is called to
720 * resolve the residue number)
722 public void mouseOverSequence(SequenceI seq, int indexpos, int index,
725 boolean hasSequenceListeners = handlingVamsasMo
726 || !seqmappings.isEmpty();
727 SearchResults results = null;
730 index = seq.findPosition(indexpos);
732 for (int i = 0; i < listeners.size(); i++)
734 Object listener = listeners.elementAt(i);
735 if (listener == source)
737 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
738 // Temporary fudge with SequenceListener.getVamsasSource()
741 if (listener instanceof StructureListener)
743 highlightStructure((StructureListener) listener, seq, index);
747 if (listener instanceof SequenceListener)
749 final SequenceListener seqListener = (SequenceListener) listener;
750 if (hasSequenceListeners
751 && seqListener.getVamsasSource() != source)
753 if (relaySeqMappings)
757 results = MappingUtils.buildSearchResults(seq, index,
760 if (handlingVamsasMo)
762 results.addResult(seq, index, index);
765 if (!results.isEmpty())
767 seqListener.highlightSequence(results);
772 else if (listener instanceof VamsasListener && !handlingVamsasMo)
774 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
777 else if (listener instanceof SecondaryStructureListener)
779 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
787 * Send suitable messages to a StructureListener to highlight atoms
788 * corresponding to the given sequence position.
794 protected void highlightStructure(StructureListener sl, SequenceI seq,
797 if (!sl.isListeningFor(seq))
802 List<AtomSpec> atoms = new ArrayList<AtomSpec>();
803 for (StructureMapping sm : mappings)
805 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence())
807 atomNo = sm.getAtomNum(index);
811 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain, sm
812 .getPDBResNum(index), atomNo));
816 sl.highlightAtoms(atoms);
820 * true if a mouse over event from an external (ie Vamsas) source is being
823 boolean handlingVamsasMo = false;
828 * as mouseOverSequence but only route event to SequenceListeners
832 * in an alignment sequence
834 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
837 handlingVamsasMo = true;
838 long msg = sequenceI.hashCode() * (1 + position);
842 mouseOverSequence(sequenceI, position, -1, source);
844 handlingVamsasMo = false;
847 public Annotation[] colourSequenceFromStructure(SequenceI seq,
851 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
852 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
854 * Annotation [] annotations = new Annotation[seq.getLength()];
856 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
857 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
858 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
860 * for (int j = 0; j < mappings.length; j++) {
862 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
863 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
864 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
865 * "+mappings[j].pdbfile);
867 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
868 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
870 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
871 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
872 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
873 * mappings[j].pdbfile); }
875 * annotations[index] = new Annotation("X",null,' ',0,col); } return
876 * annotations; } } } }
878 * return annotations;
882 public void structureSelectionChanged()
886 public void sequenceSelectionChanged()
890 public void sequenceColoursChanged(Object source)
892 StructureListener sl;
893 for (int i = 0; i < listeners.size(); i++)
895 if (listeners.elementAt(i) instanceof StructureListener)
897 sl = (StructureListener) listeners.elementAt(i);
898 sl.updateColours(source);
903 public StructureMapping[] getMapping(String pdbfile)
905 List<StructureMapping> tmp = new ArrayList<StructureMapping>();
906 for (StructureMapping sm : mappings)
908 if (sm.pdbfile.equals(pdbfile))
913 return tmp.toArray(new StructureMapping[tmp.size()]);
917 * Returns a readable description of all mappings for the given pdbfile to any
918 * of the given sequences
924 public String printMappings(String pdbfile, List<SequenceI> seqs)
926 if (pdbfile == null || seqs == null || seqs.isEmpty())
931 StringBuilder sb = new StringBuilder(64);
932 for (StructureMapping sm : mappings)
934 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
936 sb.append(sm.mappingDetails);
938 // separator makes it easier to read multiple mappings
939 sb.append("=====================");
945 return sb.toString();
949 * Remove the given mapping
953 public void deregisterMapping(AlignedCodonFrame acf)
957 boolean removed = seqmappings.remove(acf);
958 if (removed && seqmappings.isEmpty())
960 System.out.println("All mappings removed");
966 * Add each of the given codonFrames to the stored set, if not aready present.
970 public void registerMappings(Set<AlignedCodonFrame> set)
974 for (AlignedCodonFrame acf : set)
976 registerMapping(acf);
982 * Add the given mapping to the stored set, unless already stored.
984 public void registerMapping(AlignedCodonFrame acf)
988 if (!seqmappings.contains(acf))
990 seqmappings.add(acf);
996 * Resets this object to its initial state by removing all registered
997 * listeners, codon mappings, PDB file mappings
999 public void resetAll()
1001 if (mappings != null)
1005 if (seqmappings != null)
1007 seqmappings.clear();
1009 if (sel_listeners != null)
1011 sel_listeners.clear();
1013 if (listeners != null)
1017 if (commandListeners != null)
1019 commandListeners.clear();
1021 if (view_listeners != null)
1023 view_listeners.clear();
1025 if (pdbFileNameId != null)
1027 pdbFileNameId.clear();
1029 if (pdbIdFileName != null)
1031 pdbIdFileName.clear();
1035 public void addSelectionListener(SelectionListener selecter)
1037 if (!sel_listeners.contains(selecter))
1039 sel_listeners.add(selecter);
1043 public void removeSelectionListener(SelectionListener toremove)
1045 if (sel_listeners.contains(toremove))
1047 sel_listeners.remove(toremove);
1051 public synchronized void sendSelection(
1052 jalview.datamodel.SequenceGroup selection,
1053 jalview.datamodel.ColumnSelection colsel, SelectionSource source)
1055 for (SelectionListener slis : sel_listeners)
1059 slis.selection(selection, colsel, source);
1064 Vector<AlignmentViewPanelListener> view_listeners = new Vector<AlignmentViewPanelListener>();
1066 public synchronized void sendViewPosition(
1067 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1068 int startSeq, int endSeq)
1071 if (view_listeners != null && view_listeners.size() > 0)
1073 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1075 while (listeners.hasMoreElements())
1077 AlignmentViewPanelListener slis = listeners.nextElement();
1080 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1088 * release all references associated with this manager provider
1090 * @param jalviewLite
1092 public static void release(StructureSelectionManagerProvider jalviewLite)
1094 // synchronized (instances)
1096 if (instances == null)
1100 StructureSelectionManager mnger = (instances.get(jalviewLite));
1103 instances.remove(jalviewLite);
1107 } catch (Throwable x)
1114 public void registerPDBEntry(PDBEntry pdbentry)
1116 if (pdbentry.getFile() != null
1117 && pdbentry.getFile().trim().length() > 0)
1119 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1123 public void addCommandListener(CommandListener cl)
1125 if (!commandListeners.contains(cl))
1127 commandListeners.add(cl);
1131 public boolean hasCommandListener(CommandListener cl)
1133 return this.commandListeners.contains(cl);
1136 public boolean removeCommandListener(CommandListener l)
1138 return commandListeners.remove(l);
1142 * Forward a command to any command listeners (except for the command's
1146 * the command to be broadcast (in its form after being performed)
1148 * if true, the command was being 'undone'
1151 public void commandPerformed(CommandI command, boolean undo,
1152 VamsasSource source)
1154 for (CommandListener listener : commandListeners)
1156 listener.mirrorCommand(command, undo, this, source);
1161 * Returns a new CommandI representing the given command as mapped to the
1162 * given sequences. If no mapping could be made, or the command is not of a
1163 * mappable kind, returns null.
1171 public CommandI mapCommand(CommandI command, boolean undo,
1172 final AlignmentI mapTo, char gapChar)
1174 if (command instanceof EditCommand)
1176 return MappingUtils.mapEditCommand((EditCommand) command, undo,
1177 mapTo, gapChar, seqmappings);
1179 else if (command instanceof OrderCommand)
1181 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1182 mapTo, seqmappings);