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;
39 import java.io.PrintStream;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Collections;
43 import java.util.Enumeration;
44 import java.util.HashMap;
45 import java.util.IdentityHashMap;
46 import java.util.List;
48 import java.util.Vector;
51 import MCview.PDBChain;
52 import MCview.PDBfile;
54 public class StructureSelectionManager
56 public final static String NEWLINE = System.lineSeparator();
58 static IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> instances;
60 private List<StructureMapping> mappings = new ArrayList<StructureMapping>();
62 private boolean processSecondaryStructure = false;
64 private boolean secStructServices = false;
66 private boolean addTempFacAnnot = false;
69 * Set of any registered mappings between (dataset) sequences.
71 private List<AlignedCodonFrame> seqmappings = new ArrayList<AlignedCodonFrame>();
73 private List<CommandListener> commandListeners = new ArrayList<CommandListener>();
75 private List<SelectionListener> sel_listeners = new ArrayList<SelectionListener>();
78 * @return true if will try to use external services for processing secondary
81 public boolean isSecStructServices()
83 return secStructServices;
87 * control use of external services for processing secondary structure
89 * @param secStructServices
91 public void setSecStructServices(boolean secStructServices)
93 this.secStructServices = secStructServices;
97 * flag controlling addition of any kind of structural annotation
99 * @return true if temperature factor annotation will be added
101 public boolean isAddTempFacAnnot()
103 return addTempFacAnnot;
107 * set flag controlling addition of structural annotation
109 * @param addTempFacAnnot
111 public void setAddTempFacAnnot(boolean addTempFacAnnot)
113 this.addTempFacAnnot = addTempFacAnnot;
118 * @return if true, the structure manager will attempt to add secondary
119 * structure lines for unannotated sequences
122 public boolean isProcessSecondaryStructure()
124 return processSecondaryStructure;
128 * Control whether structure manager will try to annotate mapped sequences
129 * with secondary structure from PDB data.
133 public void setProcessSecondaryStructure(boolean enable)
135 processSecondaryStructure = enable;
139 * debug function - write all mappings to stdout
141 public void reportMapping()
143 if (mappings.isEmpty())
145 System.err.println("reportMapping: No PDB/Sequence mappings.");
149 System.err.println("reportMapping: There are " + mappings.size()
152 for (StructureMapping sm : mappings)
154 System.err.println("mapping " + i++ + " : " + sm.pdbfile);
160 * map between the PDB IDs (or structure identifiers) used by Jalview and the
161 * absolute filenames for PDB data that corresponds to it
163 Map<String, String> pdbIdFileName = new HashMap<String, String>();
165 Map<String, String> pdbFileNameId = new HashMap<String, String>();
167 public void registerPDBFile(String idForFile, String absoluteFile)
169 pdbIdFileName.put(idForFile, absoluteFile);
170 pdbFileNameId.put(absoluteFile, idForFile);
173 public String findIdForPDBFile(String idOrFile)
175 String id = pdbFileNameId.get(idOrFile);
179 public String findFileForPDBId(String idOrFile)
181 String id = pdbIdFileName.get(idOrFile);
185 public boolean isPDBFileRegistered(String idOrFile)
187 return pdbFileNameId.containsKey(idOrFile)
188 || pdbIdFileName.containsKey(idOrFile);
191 private static StructureSelectionManager nullProvider = null;
193 public static StructureSelectionManager getStructureSelectionManager(
194 StructureSelectionManagerProvider context)
198 if (nullProvider == null)
200 if (instances != null)
204 .getString("error.implementation_error_structure_selection_manager_null"),
205 new NullPointerException(MessageManager
206 .getString("exception.ssm_context_is_null")));
210 nullProvider = new StructureSelectionManager();
215 if (instances == null)
217 instances = new java.util.IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager>();
219 StructureSelectionManager instance = instances.get(context);
220 if (instance == null)
222 if (nullProvider != null)
224 instance = nullProvider;
228 instance = new StructureSelectionManager();
230 instances.put(context, instance);
236 * flag controlling whether SeqMappings are relayed from received sequence
237 * mouse over events to other sequences
239 boolean relaySeqMappings = true;
242 * Enable or disable relay of seqMapping events to other sequences. You might
243 * want to do this if there are many sequence mappings and the host computer
248 public void setRelaySeqMappings(boolean relay)
250 relaySeqMappings = relay;
254 * get the state of the relay seqMappings flag.
256 * @return true if sequence mouse overs are being relayed to other mapped
259 public boolean isRelaySeqMappingsEnabled()
261 return relaySeqMappings;
264 Vector listeners = new Vector();
267 * register a listener for alignment sequence mouseover events
271 public void addStructureViewerListener(Object svl)
273 if (!listeners.contains(svl))
275 listeners.addElement(svl);
280 * Returns the file name for a mapped PDB id (or null if not mapped).
285 public String alreadyMappedToFile(String pdbid)
287 for (StructureMapping sm : mappings)
289 if (sm.getPdbId().equals(pdbid))
298 * Import structure data and register a structure mapping for broadcasting
299 * colouring, mouseovers and selection events (convenience wrapper).
302 * - one or more sequences to be mapped to pdbFile
303 * @param targetChains
304 * - optional chain specification for mapping each sequence to pdb
305 * (may be nill, individual elements may be nill)
307 * - structure data resource
309 * - how to resolve data from resource
310 * @return null or the structure data parsed as a pdb file
312 synchronized public PDBfile setMapping(SequenceI[] sequence,
313 String[] targetChains, String pdbFile, String protocol)
315 return setMapping(true, sequence, targetChains, pdbFile, protocol);
319 * create sequence structure mappings between each sequence and the given
320 * pdbFile (retrieved via the given protocol).
322 * @param forStructureView
323 * when true, record the mapping for use in mouseOvers
326 * - one or more sequences to be mapped to pdbFile
327 * @param targetChains
328 * - optional chain specification for mapping each sequence to pdb
329 * (may be nill, individual elements may be nill)
331 * - structure data resource
333 * - how to resolve data from resource
334 * @return null or the structure data parsed as a pdb file
336 synchronized public PDBfile setMapping(boolean forStructureView,
337 SequenceI[] sequence, String[] targetChains, String pdbFile,
341 * There will be better ways of doing this in the future, for now we'll use
342 * the tried and tested MCview pdb mapping
344 boolean parseSecStr = processSecondaryStructure;
345 if (isPDBFileRegistered(pdbFile))
347 for (SequenceI sq : sequence)
350 while (ds.getDatasetSequence() != null)
352 ds = ds.getDatasetSequence();
355 if (ds.getAnnotation() != null)
357 for (AlignmentAnnotation ala : ds.getAnnotation())
359 // false if any annotation present from this structure
360 // JBPNote this fails for jmol/chimera view because the *file* is
361 // passed, not the structure data ID -
362 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
373 pdb = new PDBfile(addTempFacAnnot, parseSecStr, secStructServices,
375 if (pdb.id != null && pdb.id.trim().length() > 0
376 && AppletFormatAdapter.FILE.equals(protocol))
378 registerPDBFile(pdb.id.trim(), pdbFile);
380 } catch (Exception ex)
382 ex.printStackTrace();
387 for (int s = 0; s < sequence.length; s++)
389 boolean infChain = true;
390 final SequenceI seq = sequence[s];
391 if (targetChains != null && targetChains[s] != null)
394 targetChain = targetChains[s];
396 else if (seq.getName().indexOf("|") > -1)
398 targetChain = seq.getName().substring(
399 seq.getName().lastIndexOf("|") + 1);
400 if (targetChain.length() > 1)
402 if (targetChain.trim().length() == 0)
408 // not a valid chain identifier
419 * Attempt pairwise alignment of the sequence with each chain in the PDB,
420 * and remember the highest scoring chain
423 AlignSeq maxAlignseq = null;
424 String maxChainId = " ";
425 PDBChain maxChain = null;
426 boolean first = true;
427 for (PDBChain chain : pdb.chains)
429 if (targetChain.length() > 0 && !targetChain.equals(chain.id)
432 continue; // don't try to map chains don't match.
434 // TODO: correctly determine sequence type for mixed na/peptide
436 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
437 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
440 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
441 // as.calcScoreMatrix();
442 // as.traceAlignment();
444 if (first || as.maxscore > max
445 || (as.maxscore == max && chain.id.equals(targetChain)))
451 maxChainId = chain.id;
454 if (maxChain == null)
458 final StringBuilder mappingDetails = new StringBuilder(128);
459 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
460 .append(NEWLINE).append("Sequence = ")
461 .append(maxChain.sequence.getSequenceAsString());
462 mappingDetails.append(NEWLINE).append("No of residues = ")
463 .append(maxChain.residues.size()).append(NEWLINE)
465 PrintStream ps = new PrintStream(System.out)
468 public void print(String x)
470 mappingDetails.append(x);
474 public void println()
476 mappingDetails.append(NEWLINE);
480 maxAlignseq.printAlignment(ps);
482 mappingDetails.append(NEWLINE).append("PDB start/end ");
483 mappingDetails.append(String.valueOf(maxAlignseq.seq2start)).append(
485 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
487 mappingDetails.append(NEWLINE).append("SEQ start/end ");
488 mappingDetails.append(
489 String.valueOf(maxAlignseq.seq1start + seq.getStart() - 1))
491 mappingDetails.append(String.valueOf(maxAlignseq.seq1end
492 + seq.getEnd() - 1));
494 maxChain.makeExactMapping(maxAlignseq, seq);
495 jalview.datamodel.Mapping sqmpping = maxAlignseq
496 .getMappingFromS1(false);
497 jalview.datamodel.Mapping omap = new jalview.datamodel.Mapping(
498 sqmpping.getMap().getInverse());
499 maxChain.transferRESNUMFeatures(seq, null);
501 // allocate enough slots to store the mapping from positions in
502 // sequence[s] to the associated chain
503 int[][] mapping = new int[seq.findPosition(seq.getLength()) + 2][2];
509 Atom tmp = maxChain.atoms.elementAt(index);
510 if (resNum != tmp.resNumber && tmp.alignmentMapping != -1)
512 resNum = tmp.resNumber;
513 if (tmp.alignmentMapping >= -1)
515 // TODO (JAL-1836) address root cause: negative residue no in PDB
517 mapping[tmp.alignmentMapping + 1][0] = tmp.resNumber;
518 mapping[tmp.alignmentMapping + 1][1] = tmp.atomIndex;
523 } while (index < maxChain.atoms.size());
525 if (protocol.equals(jalview.io.AppletFormatAdapter.PASTE))
527 pdbFile = "INLINE" + pdb.id;
529 StructureMapping newMapping = new StructureMapping(seq, pdbFile,
530 pdb.id, maxChainId, mapping, mappingDetails.toString());
531 if (forStructureView)
533 mappings.add(newMapping);
535 maxChain.transferResidueAnnotation(newMapping, sqmpping);
542 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
544 listeners.removeElement(svl);
545 if (svl instanceof SequenceListener)
547 for (int i = 0; i < listeners.size(); i++)
549 if (listeners.elementAt(i) instanceof StructureListener)
551 ((StructureListener) listeners.elementAt(i))
552 .releaseReferences(svl);
557 if (pdbfiles == null)
563 * Remove mappings to the closed listener's PDB files, but first check if
564 * another listener is still interested
566 List<String> pdbs = new ArrayList<String>(Arrays.asList(pdbfiles));
568 StructureListener sl;
569 for (int i = 0; i < listeners.size(); i++)
571 if (listeners.elementAt(i) instanceof StructureListener)
573 sl = (StructureListener) listeners.elementAt(i);
574 for (String pdbfile : sl.getPdbFile())
576 pdbs.remove(pdbfile);
582 * Rebuild the mappings set, retaining only those which are for 'other' PDB
587 List<StructureMapping> tmp = new ArrayList<StructureMapping>();
588 for (StructureMapping sm : mappings)
590 if (!pdbs.contains(sm.pdbfile))
601 * Propagate mouseover of a single position in a structure
607 public void mouseOverStructure(int pdbResNum, String chain, String pdbfile)
609 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
610 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
611 mouseOverStructure(atoms);
615 * Propagate mouseover or selection of multiple positions in a structure
619 public void mouseOverStructure(List<AtomSpec> atoms)
621 if (listeners == null)
623 // old or prematurely sent event
626 boolean hasSequenceListener = false;
627 for (int i = 0; i < listeners.size(); i++)
629 if (listeners.elementAt(i) instanceof SequenceListener)
631 hasSequenceListener = true;
634 if (!hasSequenceListener)
639 SearchResults results = new SearchResults();
640 for (AtomSpec atom : atoms)
642 SequenceI lastseq = null;
644 for (StructureMapping sm : mappings)
646 if (sm.pdbfile.equals(atom.getPdbFile())
647 && sm.pdbchain.equals(atom.getChain()))
649 int indexpos = sm.getSeqPos(atom.getPdbResNum());
650 if (lastipos != indexpos && lastseq != sm.sequence)
652 results.addResult(sm.sequence, indexpos, indexpos);
654 lastseq = sm.sequence;
655 // construct highlighted sequence list
656 for (AlignedCodonFrame acf : seqmappings)
658 acf.markMappedRegion(sm.sequence, indexpos, results);
664 for (Object li : listeners)
666 if (li instanceof SequenceListener)
668 ((SequenceListener) li).highlightSequence(results);
674 * highlight regions associated with a position (indexpos) in seq
677 * the sequence that the mouse over occurred on
679 * the absolute position being mouseovered in seq (0 to seq.length())
681 * the sequence position (if -1, seq.findPosition is called to
682 * resolve the residue number)
684 public void mouseOverSequence(SequenceI seq, int indexpos, int index,
687 boolean hasSequenceListeners = handlingVamsasMo
688 || !seqmappings.isEmpty();
689 SearchResults results = null;
692 index = seq.findPosition(indexpos);
694 for (int i = 0; i < listeners.size(); i++)
696 Object listener = listeners.elementAt(i);
697 if (listener == source)
699 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
700 // Temporary fudge with SequenceListener.getVamsasSource()
703 if (listener instanceof StructureListener)
705 highlightStructure((StructureListener) listener, seq, index);
709 if (listener instanceof SequenceListener)
711 final SequenceListener seqListener = (SequenceListener) listener;
712 if (hasSequenceListeners
713 && seqListener.getVamsasSource() != source)
715 if (relaySeqMappings)
719 results = MappingUtils.buildSearchResults(seq, index,
722 if (handlingVamsasMo)
724 results.addResult(seq, index, index);
727 if (!results.isEmpty())
729 seqListener.highlightSequence(results);
734 else if (listener instanceof VamsasListener && !handlingVamsasMo)
736 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
739 else if (listener instanceof SecondaryStructureListener)
741 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
749 * Send suitable messages to a StructureListener to highlight atoms
750 * corresponding to the given sequence position.
756 protected void highlightStructure(StructureListener sl, SequenceI seq,
759 if (!sl.isListeningFor(seq))
764 List<AtomSpec> atoms = new ArrayList<AtomSpec>();
765 for (StructureMapping sm : mappings)
767 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence())
769 atomNo = sm.getAtomNum(index);
773 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain, sm
774 .getPDBResNum(index), atomNo));
778 sl.highlightAtoms(atoms);
782 * true if a mouse over event from an external (ie Vamsas) source is being
785 boolean handlingVamsasMo = false;
790 * as mouseOverSequence but only route event to SequenceListeners
794 * in an alignment sequence
796 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
799 handlingVamsasMo = true;
800 long msg = sequenceI.hashCode() * (1 + position);
804 mouseOverSequence(sequenceI, position, -1, source);
806 handlingVamsasMo = false;
809 public Annotation[] colourSequenceFromStructure(SequenceI seq,
813 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
814 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
816 * Annotation [] annotations = new Annotation[seq.getLength()];
818 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
819 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
820 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
822 * for (int j = 0; j < mappings.length; j++) {
824 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
825 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
826 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
827 * "+mappings[j].pdbfile);
829 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
830 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
832 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
833 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
834 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
835 * mappings[j].pdbfile); }
837 * annotations[index] = new Annotation("X",null,' ',0,col); } return
838 * annotations; } } } }
840 * return annotations;
844 public void structureSelectionChanged()
848 public void sequenceSelectionChanged()
852 public void sequenceColoursChanged(Object source)
854 StructureListener sl;
855 for (int i = 0; i < listeners.size(); i++)
857 if (listeners.elementAt(i) instanceof StructureListener)
859 sl = (StructureListener) listeners.elementAt(i);
860 sl.updateColours(source);
865 public StructureMapping[] getMapping(String pdbfile)
867 List<StructureMapping> tmp = new ArrayList<StructureMapping>();
868 for (StructureMapping sm : mappings)
870 if (sm.pdbfile.equals(pdbfile))
875 return tmp.toArray(new StructureMapping[tmp.size()]);
879 * Returns a readable description of all mappings for the given pdbfile to any
880 * of the given sequences
886 public String printMappings(String pdbfile, List<SequenceI> seqs)
888 if (pdbfile == null || seqs == null || seqs.isEmpty())
893 StringBuilder sb = new StringBuilder(64);
894 for (StructureMapping sm : mappings)
896 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
898 sb.append(sm.mappingDetails);
900 // separator makes it easier to read multiple mappings
901 sb.append("=====================");
907 return sb.toString();
911 * Remove the given mapping
915 public void deregisterMapping(AlignedCodonFrame acf)
919 boolean removed = seqmappings.remove(acf);
920 if (removed && seqmappings.isEmpty())
922 System.out.println("All mappings removed");
928 * Add each of the given codonFrames to the stored set, if not aready present.
932 public void registerMappings(List<AlignedCodonFrame> mappings)
934 if (mappings != null)
936 for (AlignedCodonFrame acf : mappings)
938 registerMapping(acf);
944 * Add the given mapping to the stored set, unless already stored.
946 public void registerMapping(AlignedCodonFrame acf)
950 if (!seqmappings.contains(acf))
952 seqmappings.add(acf);
958 * Resets this object to its initial state by removing all registered
959 * listeners, codon mappings, PDB file mappings
961 public void resetAll()
963 if (mappings != null)
967 if (seqmappings != null)
971 if (sel_listeners != null)
973 sel_listeners.clear();
975 if (listeners != null)
979 if (commandListeners != null)
981 commandListeners.clear();
983 if (view_listeners != null)
985 view_listeners.clear();
987 if (pdbFileNameId != null)
989 pdbFileNameId.clear();
991 if (pdbIdFileName != null)
993 pdbIdFileName.clear();
997 public void addSelectionListener(SelectionListener selecter)
999 if (!sel_listeners.contains(selecter))
1001 sel_listeners.add(selecter);
1005 public void removeSelectionListener(SelectionListener toremove)
1007 if (sel_listeners.contains(toremove))
1009 sel_listeners.remove(toremove);
1013 public synchronized void sendSelection(
1014 jalview.datamodel.SequenceGroup selection,
1015 jalview.datamodel.ColumnSelection colsel, SelectionSource source)
1017 for (SelectionListener slis : sel_listeners)
1021 slis.selection(selection, colsel, source);
1026 Vector<AlignmentViewPanelListener> view_listeners = new Vector<AlignmentViewPanelListener>();
1028 public synchronized void sendViewPosition(
1029 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1030 int startSeq, int endSeq)
1033 if (view_listeners != null && view_listeners.size() > 0)
1035 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1037 while (listeners.hasMoreElements())
1039 AlignmentViewPanelListener slis = listeners.nextElement();
1042 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1050 * release all references associated with this manager provider
1052 * @param jalviewLite
1054 public static void release(StructureSelectionManagerProvider jalviewLite)
1056 // synchronized (instances)
1058 if (instances == null)
1062 StructureSelectionManager mnger = (instances.get(jalviewLite));
1065 instances.remove(jalviewLite);
1069 } catch (Throwable x)
1076 public void registerPDBEntry(PDBEntry pdbentry)
1078 if (pdbentry.getFile() != null
1079 && pdbentry.getFile().trim().length() > 0)
1081 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1085 public void addCommandListener(CommandListener cl)
1087 if (!commandListeners.contains(cl))
1089 commandListeners.add(cl);
1093 public boolean hasCommandListener(CommandListener cl)
1095 return this.commandListeners.contains(cl);
1098 public boolean removeCommandListener(CommandListener l)
1100 return commandListeners.remove(l);
1104 * Forward a command to any command listeners (except for the command's
1108 * the command to be broadcast (in its form after being performed)
1110 * if true, the command was being 'undone'
1113 public void commandPerformed(CommandI command, boolean undo,
1114 VamsasSource source)
1116 for (CommandListener listener : commandListeners)
1118 listener.mirrorCommand(command, undo, this, source);
1123 * Returns a new CommandI representing the given command as mapped to the
1124 * given sequences. If no mapping could be made, or the command is not of a
1125 * mappable kind, returns null.
1133 public CommandI mapCommand(CommandI command, boolean undo,
1134 final AlignmentI mapTo, char gapChar)
1136 if (command instanceof EditCommand)
1138 return MappingUtils.mapEditCommand((EditCommand) command, undo,
1139 mapTo, gapChar, seqmappings);
1141 else if (command instanceof OrderCommand)
1143 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1144 mapTo, seqmappings);
1149 public List<AlignedCodonFrame> getSequenceMappings()