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("PDB Sequence is :")
507 .append(NEWLINE).append("Sequence = ")
508 .append(maxChain.sequence.getSequenceAsString());
509 mappingDetails.append(NEWLINE).append("No of residues = ")
510 .append(maxChain.residues.size()).append(NEWLINE)
512 PrintStream ps = new PrintStream(System.out)
515 public void print(String x)
517 mappingDetails.append(x);
521 public void println()
523 mappingDetails.append(NEWLINE);
527 maxAlignseq.printAlignment(ps);
529 mappingDetails.append(NEWLINE).append("PDB start/end ");
530 mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
532 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
533 mappingDetails.append(NEWLINE).append("SEQ start/end ");
534 mappingDetails.append(
535 String.valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
537 mappingDetails.append(String.valueOf(maxAlignseq.seq1end
538 + (seq.getStart() - 1)));
539 mappingDetails.append(NEWLINE);
541 .append("Mapping inferred with Needleman & Wunsch alignment");
542 mappingDetails.append(NEWLINE);
543 maxChain.makeExactMapping(maxAlignseq, seq);
544 jalview.datamodel.Mapping sqmpping = maxAlignseq
545 .getMappingFromS1(false);
546 maxChain.transferRESNUMFeatures(seq, null);
548 // allocate enough slots to store the mapping from positions in
549 // sequence[s] to the associated chain
550 int[][] mapping = new int[seq.findPosition(seq.getLength()) + 2][2];
556 Atom tmp = maxChain.atoms.elementAt(index);
557 if (resNum != tmp.resNumber && tmp.alignmentMapping != -1)
559 resNum = tmp.resNumber;
560 if (tmp.alignmentMapping >= -1)
562 // TODO (JAL-1836) address root cause: negative residue no in PDB
564 mapping[tmp.alignmentMapping + 1][0] = tmp.resNumber;
565 mapping[tmp.alignmentMapping + 1][1] = tmp.atomIndex;
570 } while (index < maxChain.atoms.size());
572 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
573 pdb.id, maxChainId, mapping, mappingDetails.toString());
574 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
578 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
580 listeners.removeElement(svl);
581 if (svl instanceof SequenceListener)
583 for (int i = 0; i < listeners.size(); i++)
585 if (listeners.elementAt(i) instanceof StructureListener)
587 ((StructureListener) listeners.elementAt(i))
588 .releaseReferences(svl);
593 if (pdbfiles == null)
599 * Remove mappings to the closed listener's PDB files, but first check if
600 * another listener is still interested
602 List<String> pdbs = new ArrayList<String>(Arrays.asList(pdbfiles));
604 StructureListener sl;
605 for (int i = 0; i < listeners.size(); i++)
607 if (listeners.elementAt(i) instanceof StructureListener)
609 sl = (StructureListener) listeners.elementAt(i);
610 for (String pdbfile : sl.getPdbFile())
612 pdbs.remove(pdbfile);
618 * Rebuild the mappings set, retaining only those which are for 'other' PDB
623 List<StructureMapping> tmp = new ArrayList<StructureMapping>();
624 for (StructureMapping sm : mappings)
626 if (!pdbs.contains(sm.pdbfile))
637 * Propagate mouseover of a single position in a structure
643 public void mouseOverStructure(int pdbResNum, String chain, String pdbfile)
645 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
646 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
647 mouseOverStructure(atoms);
651 * Propagate mouseover or selection of multiple positions in a structure
655 public void mouseOverStructure(List<AtomSpec> atoms)
657 if (listeners == null)
659 // old or prematurely sent event
662 boolean hasSequenceListener = false;
663 for (int i = 0; i < listeners.size(); i++)
665 if (listeners.elementAt(i) instanceof SequenceListener)
667 hasSequenceListener = true;
670 if (!hasSequenceListener)
675 SearchResults results = new SearchResults();
676 for (AtomSpec atom : atoms)
678 SequenceI lastseq = null;
680 for (StructureMapping sm : mappings)
682 if (sm.pdbfile.equals(atom.getPdbFile())
683 && sm.pdbchain.equals(atom.getChain()))
685 int indexpos = sm.getSeqPos(atom.getPdbResNum());
686 if (lastipos != indexpos && lastseq != sm.sequence)
688 results.addResult(sm.sequence, indexpos, indexpos);
690 lastseq = sm.sequence;
691 // construct highlighted sequence list
692 for (AlignedCodonFrame acf : seqmappings)
694 acf.markMappedRegion(sm.sequence, indexpos, results);
700 for (Object li : listeners)
702 if (li instanceof SequenceListener)
704 ((SequenceListener) li).highlightSequence(results);
710 * highlight regions associated with a position (indexpos) in seq
713 * the sequence that the mouse over occurred on
715 * the absolute position being mouseovered in seq (0 to seq.length())
717 * the sequence position (if -1, seq.findPosition is called to
718 * resolve the residue number)
720 public void mouseOverSequence(SequenceI seq, int indexpos, int index,
723 boolean hasSequenceListeners = handlingVamsasMo
724 || !seqmappings.isEmpty();
725 SearchResults results = null;
728 index = seq.findPosition(indexpos);
730 for (int i = 0; i < listeners.size(); i++)
732 Object listener = listeners.elementAt(i);
733 if (listener == source)
735 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
736 // Temporary fudge with SequenceListener.getVamsasSource()
739 if (listener instanceof StructureListener)
741 highlightStructure((StructureListener) listener, seq, index);
745 if (listener instanceof SequenceListener)
747 final SequenceListener seqListener = (SequenceListener) listener;
748 if (hasSequenceListeners
749 && seqListener.getVamsasSource() != source)
751 if (relaySeqMappings)
755 results = MappingUtils.buildSearchResults(seq, index,
758 if (handlingVamsasMo)
760 results.addResult(seq, index, index);
763 if (!results.isEmpty())
765 seqListener.highlightSequence(results);
770 else if (listener instanceof VamsasListener && !handlingVamsasMo)
772 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
775 else if (listener instanceof SecondaryStructureListener)
777 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
785 * Send suitable messages to a StructureListener to highlight atoms
786 * corresponding to the given sequence position.
792 protected void highlightStructure(StructureListener sl, SequenceI seq,
795 if (!sl.isListeningFor(seq))
800 List<AtomSpec> atoms = new ArrayList<AtomSpec>();
801 for (StructureMapping sm : mappings)
803 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence())
805 atomNo = sm.getAtomNum(index);
809 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain, sm
810 .getPDBResNum(index), atomNo));
814 sl.highlightAtoms(atoms);
818 * true if a mouse over event from an external (ie Vamsas) source is being
821 boolean handlingVamsasMo = false;
826 * as mouseOverSequence but only route event to SequenceListeners
830 * in an alignment sequence
832 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
835 handlingVamsasMo = true;
836 long msg = sequenceI.hashCode() * (1 + position);
840 mouseOverSequence(sequenceI, position, -1, source);
842 handlingVamsasMo = false;
845 public Annotation[] colourSequenceFromStructure(SequenceI seq,
849 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
850 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
852 * Annotation [] annotations = new Annotation[seq.getLength()];
854 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
855 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
856 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
858 * for (int j = 0; j < mappings.length; j++) {
860 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
861 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
862 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
863 * "+mappings[j].pdbfile);
865 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
866 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
868 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
869 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
870 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
871 * mappings[j].pdbfile); }
873 * annotations[index] = new Annotation("X",null,' ',0,col); } return
874 * annotations; } } } }
876 * return annotations;
880 public void structureSelectionChanged()
884 public void sequenceSelectionChanged()
888 public void sequenceColoursChanged(Object source)
890 StructureListener sl;
891 for (int i = 0; i < listeners.size(); i++)
893 if (listeners.elementAt(i) instanceof StructureListener)
895 sl = (StructureListener) listeners.elementAt(i);
896 sl.updateColours(source);
901 public StructureMapping[] getMapping(String pdbfile)
903 List<StructureMapping> tmp = new ArrayList<StructureMapping>();
904 for (StructureMapping sm : mappings)
906 if (sm.pdbfile.equals(pdbfile))
911 return tmp.toArray(new StructureMapping[tmp.size()]);
915 * Returns a readable description of all mappings for the given pdbfile to any
916 * of the given sequences
922 public String printMappings(String pdbfile, List<SequenceI> seqs)
924 if (pdbfile == null || seqs == null || seqs.isEmpty())
929 StringBuilder sb = new StringBuilder(64);
930 for (StructureMapping sm : mappings)
932 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
934 sb.append(sm.mappingDetails);
936 // separator makes it easier to read multiple mappings
937 sb.append("=====================");
943 return sb.toString();
947 * Remove the given mapping
951 public void deregisterMapping(AlignedCodonFrame acf)
955 boolean removed = seqmappings.remove(acf);
956 if (removed && seqmappings.isEmpty())
958 System.out.println("All mappings removed");
964 * Add each of the given codonFrames to the stored set, if not aready present.
968 public void registerMappings(Set<AlignedCodonFrame> set)
972 for (AlignedCodonFrame acf : set)
974 registerMapping(acf);
980 * Add the given mapping to the stored set, unless already stored.
982 public void registerMapping(AlignedCodonFrame acf)
986 if (!seqmappings.contains(acf))
988 seqmappings.add(acf);
994 * Resets this object to its initial state by removing all registered
995 * listeners, codon mappings, PDB file mappings
997 public void resetAll()
999 if (mappings != null)
1003 if (seqmappings != null)
1005 seqmappings.clear();
1007 if (sel_listeners != null)
1009 sel_listeners.clear();
1011 if (listeners != null)
1015 if (commandListeners != null)
1017 commandListeners.clear();
1019 if (view_listeners != null)
1021 view_listeners.clear();
1023 if (pdbFileNameId != null)
1025 pdbFileNameId.clear();
1027 if (pdbIdFileName != null)
1029 pdbIdFileName.clear();
1033 public void addSelectionListener(SelectionListener selecter)
1035 if (!sel_listeners.contains(selecter))
1037 sel_listeners.add(selecter);
1041 public void removeSelectionListener(SelectionListener toremove)
1043 if (sel_listeners.contains(toremove))
1045 sel_listeners.remove(toremove);
1049 public synchronized void sendSelection(
1050 jalview.datamodel.SequenceGroup selection,
1051 jalview.datamodel.ColumnSelection colsel, SelectionSource source)
1053 for (SelectionListener slis : sel_listeners)
1057 slis.selection(selection, colsel, source);
1062 Vector<AlignmentViewPanelListener> view_listeners = new Vector<AlignmentViewPanelListener>();
1064 public synchronized void sendViewPosition(
1065 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1066 int startSeq, int endSeq)
1069 if (view_listeners != null && view_listeners.size() > 0)
1071 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1073 while (listeners.hasMoreElements())
1075 AlignmentViewPanelListener slis = listeners.nextElement();
1078 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1086 * release all references associated with this manager provider
1088 * @param jalviewLite
1090 public static void release(StructureSelectionManagerProvider jalviewLite)
1092 // synchronized (instances)
1094 if (instances == null)
1098 StructureSelectionManager mnger = (instances.get(jalviewLite));
1101 instances.remove(jalviewLite);
1105 } catch (Throwable x)
1112 public void registerPDBEntry(PDBEntry pdbentry)
1114 if (pdbentry.getFile() != null
1115 && pdbentry.getFile().trim().length() > 0)
1117 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1121 public void addCommandListener(CommandListener cl)
1123 if (!commandListeners.contains(cl))
1125 commandListeners.add(cl);
1129 public boolean hasCommandListener(CommandListener cl)
1131 return this.commandListeners.contains(cl);
1134 public boolean removeCommandListener(CommandListener l)
1136 return commandListeners.remove(l);
1140 * Forward a command to any command listeners (except for the command's
1144 * the command to be broadcast (in its form after being performed)
1146 * if true, the command was being 'undone'
1149 public void commandPerformed(CommandI command, boolean undo,
1150 VamsasSource source)
1152 for (CommandListener listener : commandListeners)
1154 listener.mirrorCommand(command, undo, this, source);
1159 * Returns a new CommandI representing the given command as mapped to the
1160 * given sequences. If no mapping could be made, or the command is not of a
1161 * mappable kind, returns null.
1169 public CommandI mapCommand(CommandI command, boolean undo,
1170 final AlignmentI mapTo, char gapChar)
1172 if (command instanceof EditCommand)
1174 return MappingUtils.mapEditCommand((EditCommand) command, undo,
1175 mapTo, gapChar, seqmappings);
1177 else if (command instanceof OrderCommand)
1179 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1180 mapTo, seqmappings);