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 java.io.PrintStream;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collections;
27 import java.util.Enumeration;
28 import java.util.HashMap;
29 import java.util.IdentityHashMap;
30 import java.util.LinkedHashSet;
31 import java.util.List;
34 import java.util.Vector;
37 import MCview.PDBChain;
38 import MCview.PDBfile;
40 import jalview.analysis.AlignSeq;
41 import jalview.api.StructureSelectionManagerProvider;
42 import jalview.commands.CommandI;
43 import jalview.commands.EditCommand;
44 import jalview.commands.OrderCommand;
45 import jalview.datamodel.AlignedCodonFrame;
46 import jalview.datamodel.AlignmentAnnotation;
47 import jalview.datamodel.AlignmentI;
48 import jalview.datamodel.Annotation;
49 import jalview.datamodel.PDBEntry;
50 import jalview.datamodel.SearchResults;
51 import jalview.datamodel.SequenceI;
52 import jalview.io.AppletFormatAdapter;
53 import jalview.util.MappingUtils;
54 import jalview.util.MessageManager;
56 public class StructureSelectionManager
58 public final static String NEWLINE = System.lineSeparator();
60 static IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> instances;
62 private List<StructureMapping> mappings = new ArrayList<StructureMapping>();
64 private boolean processSecondaryStructure = false;
66 private boolean secStructServices = false;
68 private boolean addTempFacAnnot = false;
71 * Set of any registered mappings between (dataset) sequences.
73 Set<AlignedCodonFrame> seqmappings = new LinkedHashSet<AlignedCodonFrame>();
76 * Reference counters for the above mappings. Remove mappings when ref count
79 Map<AlignedCodonFrame, Integer> seqMappingRefCounts = new HashMap<AlignedCodonFrame, Integer>();
81 private List<CommandListener> commandListeners = new ArrayList<CommandListener>();
83 private List<SelectionListener> sel_listeners = new ArrayList<SelectionListener>();
86 * @return true if will try to use external services for processing secondary
89 public boolean isSecStructServices()
91 return secStructServices;
95 * control use of external services for processing secondary structure
97 * @param secStructServices
99 public void setSecStructServices(boolean secStructServices)
101 this.secStructServices = secStructServices;
105 * flag controlling addition of any kind of structural annotation
107 * @return true if temperature factor annotation will be added
109 public boolean isAddTempFacAnnot()
111 return addTempFacAnnot;
115 * set flag controlling addition of structural annotation
117 * @param addTempFacAnnot
119 public void setAddTempFacAnnot(boolean addTempFacAnnot)
121 this.addTempFacAnnot = addTempFacAnnot;
126 * @return if true, the structure manager will attempt to add secondary
127 * structure lines for unannotated sequences
130 public boolean isProcessSecondaryStructure()
132 return processSecondaryStructure;
136 * Control whether structure manager will try to annotate mapped sequences
137 * with secondary structure from PDB data.
141 public void setProcessSecondaryStructure(boolean enable)
143 processSecondaryStructure = enable;
147 * debug function - write all mappings to stdout
149 public void reportMapping()
151 if (mappings.isEmpty())
153 System.err.println("reportMapping: No PDB/Sequence mappings.");
157 System.err.println("reportMapping: There are " + mappings.size()
160 for (StructureMapping sm : mappings)
162 System.err.println("mapping " + i++ + " : " + sm.pdbfile);
168 * map between the PDB IDs (or structure identifiers) used by Jalview and the
169 * absolute filenames for PDB data that corresponds to it
171 Map<String, String> pdbIdFileName = new HashMap<String, String>();
173 Map<String, String> pdbFileNameId = new HashMap<String, String>();
175 public void registerPDBFile(String idForFile, String absoluteFile)
177 pdbIdFileName.put(idForFile, absoluteFile);
178 pdbFileNameId.put(absoluteFile, idForFile);
181 public String findIdForPDBFile(String idOrFile)
183 String id = pdbFileNameId.get(idOrFile);
187 public String findFileForPDBId(String idOrFile)
189 String id = pdbIdFileName.get(idOrFile);
193 public boolean isPDBFileRegistered(String idOrFile)
195 return pdbFileNameId.containsKey(idOrFile)
196 || pdbIdFileName.containsKey(idOrFile);
199 private static StructureSelectionManager nullProvider = null;
201 public static StructureSelectionManager getStructureSelectionManager(
202 StructureSelectionManagerProvider context)
206 if (nullProvider == null)
208 if (instances != null)
212 .getString("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<StructureSelectionManagerProvider, StructureSelectionManager>();
227 StructureSelectionManager instance = instances.get(context);
228 if (instance == null)
230 if (nullProvider != null)
232 instance = nullProvider;
236 instance = new StructureSelectionManager();
238 instances.put(context, instance);
244 * flag controlling whether SeqMappings are relayed from received sequence
245 * mouse over events to other sequences
247 boolean relaySeqMappings = true;
250 * Enable or disable relay of seqMapping events to other sequences. You might
251 * want to do this if there are many sequence mappings and the host computer
256 public void setRelaySeqMappings(boolean relay)
258 relaySeqMappings = relay;
262 * get the state of the relay seqMappings flag.
264 * @return true if sequence mouse overs are being relayed to other mapped
267 public boolean isRelaySeqMappingsEnabled()
269 return relaySeqMappings;
272 Vector listeners = new Vector();
275 * register a listener for alignment sequence mouseover events
279 public void addStructureViewerListener(Object svl)
281 if (!listeners.contains(svl))
283 listeners.addElement(svl);
288 * Returns the file name for a mapped PDB id (or null if not mapped).
293 public String alreadyMappedToFile(String pdbid)
295 for (StructureMapping sm : mappings)
297 if (sm.getPdbId().equals(pdbid))
306 * Import structure data and register a structure mapping for broadcasting
307 * colouring, mouseovers and selection events (convenience wrapper).
310 * - one or more sequences to be mapped to pdbFile
311 * @param targetChains
312 * - optional chain specification for mapping each sequence to pdb
313 * (may be nill, individual elements may be nill)
315 * - structure data resource
317 * - how to resolve data from resource
318 * @return null or the structure data parsed as a pdb file
320 synchronized public PDBfile setMapping(SequenceI[] sequence,
321 String[] targetChains, String pdbFile, String protocol)
323 return setMapping(true, sequence, targetChains, pdbFile, protocol);
327 * create sequence structure mappings between each sequence and the given
328 * pdbFile (retrieved via the given protocol).
330 * @param forStructureView
331 * when true, record the mapping for use in mouseOvers
334 * - one or more sequences to be mapped to pdbFile
335 * @param targetChains
336 * - optional chain specification for mapping each sequence to pdb
337 * (may be nill, individual elements may be nill)
339 * - structure data resource
341 * - how to resolve data from resource
342 * @return null or the structure data parsed as a pdb file
344 synchronized public PDBfile setMapping(boolean forStructureView,
345 SequenceI[] sequence, String[] targetChains, String pdbFile,
349 * There will be better ways of doing this in the future, for now we'll use
350 * the tried and tested MCview pdb mapping
352 boolean parseSecStr = processSecondaryStructure;
353 if (isPDBFileRegistered(pdbFile))
355 for (SequenceI sq : sequence)
358 while (ds.getDatasetSequence() != null)
360 ds = ds.getDatasetSequence();
363 if (ds.getAnnotation() != null)
365 for (AlignmentAnnotation ala : ds.getAnnotation())
367 // false if any annotation present from this structure
368 // JBPNote this fails for jmol/chimera view because the *file* is
369 // passed, not the structure data ID -
370 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
381 pdb = new PDBfile(addTempFacAnnot, parseSecStr, secStructServices,
383 if (pdb.id != null && pdb.id.trim().length() > 0
384 && AppletFormatAdapter.FILE.equals(protocol))
386 registerPDBFile(pdb.id.trim(), pdbFile);
388 } catch (Exception ex)
390 ex.printStackTrace();
395 for (int s = 0; s < sequence.length; s++)
397 boolean infChain = true;
398 final SequenceI seq = sequence[s];
399 if (targetChains != null && targetChains[s] != null)
402 targetChain = targetChains[s];
404 else if (seq.getName().indexOf("|") > -1)
406 targetChain = seq.getName().substring(
407 seq.getName().lastIndexOf("|") + 1);
408 if (targetChain.length() > 1)
410 if (targetChain.trim().length() == 0)
416 // not a valid chain identifier
427 * Attempt pairwise alignment of the sequence with each chain in the PDB,
428 * and remember the highest scoring chain
431 AlignSeq maxAlignseq = null;
432 String maxChainId = " ";
433 PDBChain maxChain = null;
434 boolean first = true;
435 for (PDBChain chain : pdb.chains)
437 if (targetChain.length() > 0 && !targetChain.equals(chain.id)
440 continue; // don't try to map chains don't match.
442 // TODO: correctly determine sequence type for mixed na/peptide
444 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
445 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
448 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
449 // as.calcScoreMatrix();
450 // as.traceAlignment();
452 if (first || as.maxscore > max
453 || (as.maxscore == max && chain.id.equals(targetChain)))
459 maxChainId = chain.id;
462 if (maxChain == null)
466 final StringBuilder mappingDetails = new StringBuilder(128);
467 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
468 .append(NEWLINE).append("Sequence = ")
469 .append(maxChain.sequence.getSequenceAsString());
470 mappingDetails.append(NEWLINE).append("No of residues = ")
471 .append(maxChain.residues.size()).append(NEWLINE)
473 PrintStream ps = new PrintStream(System.out)
476 public void print(String x)
478 mappingDetails.append(x);
482 public void println()
484 mappingDetails.append(NEWLINE);
488 maxAlignseq.printAlignment(ps);
490 mappingDetails.append(NEWLINE).append("PDB start/end ");
491 mappingDetails.append(String.valueOf(maxAlignseq.seq2start)).append(
493 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
495 mappingDetails.append(NEWLINE).append("SEQ start/end ");
496 mappingDetails.append(
497 String.valueOf(maxAlignseq.seq1start + seq.getStart() - 1))
499 mappingDetails.append(String.valueOf(maxAlignseq.seq1end
500 + seq.getEnd() - 1));
502 maxChain.makeExactMapping(maxAlignseq, seq);
503 jalview.datamodel.Mapping sqmpping = maxAlignseq
504 .getMappingFromS1(false);
505 jalview.datamodel.Mapping omap = new jalview.datamodel.Mapping(
506 sqmpping.getMap().getInverse());
507 maxChain.transferRESNUMFeatures(seq, null);
509 // allocate enough slots to store the mapping from positions in
510 // sequence[s] to the associated chain
511 int[][] mapping = new int[seq.findPosition(seq.getLength()) + 2][2];
517 Atom tmp = maxChain.atoms.elementAt(index);
518 if (resNum != tmp.resNumber && tmp.alignmentMapping != -1)
520 resNum = tmp.resNumber;
521 mapping[tmp.alignmentMapping + 1][0] = tmp.resNumber;
522 mapping[tmp.alignmentMapping + 1][1] = tmp.atomIndex;
526 } while (index < maxChain.atoms.size());
528 if (protocol.equals(jalview.io.AppletFormatAdapter.PASTE))
530 pdbFile = "INLINE" + pdb.id;
532 StructureMapping newMapping = new StructureMapping(seq, pdbFile,
533 pdb.id, maxChainId, mapping, mappingDetails.toString());
534 if (forStructureView)
536 mappings.add(newMapping);
538 maxChain.transferResidueAnnotation(newMapping, sqmpping);
545 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
547 listeners.removeElement(svl);
548 if (svl instanceof SequenceListener)
550 for (int i = 0; i < listeners.size(); i++)
552 if (listeners.elementAt(i) instanceof StructureListener)
554 ((StructureListener) listeners.elementAt(i))
555 .releaseReferences(svl);
560 if (pdbfiles == null)
566 * Remove mappings to the closed listener's PDB files, but first check if
567 * another listener is still interested
569 List<String> pdbs = new ArrayList<String>(Arrays.asList(pdbfiles));
571 StructureListener sl;
572 for (int i = 0; i < listeners.size(); i++)
574 if (listeners.elementAt(i) instanceof StructureListener)
576 sl = (StructureListener) listeners.elementAt(i);
577 for (String pdbfile : sl.getPdbFile())
579 pdbs.remove(pdbfile);
585 * Rebuild the mappings set, retaining only those which are for 'other' PDB
590 List<StructureMapping> tmp = new ArrayList<StructureMapping>();
591 for (StructureMapping sm : mappings)
593 if (!pdbs.contains(sm.pdbfile))
604 * Propagate mouseover of a single position in a structure
610 public void mouseOverStructure(int pdbResNum, String chain, String pdbfile)
612 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
613 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
614 mouseOverStructure(atoms);
618 * Propagate mouseover or selection of multiple positions in a structure
622 public void mouseOverStructure(List<AtomSpec> atoms)
624 if (listeners == null)
626 // old or prematurely sent event
629 boolean hasSequenceListener = false;
630 for (int i = 0; i < listeners.size(); i++)
632 if (listeners.elementAt(i) instanceof SequenceListener)
634 hasSequenceListener = true;
637 if (!hasSequenceListener)
642 SearchResults results = new SearchResults();
643 for (AtomSpec atom : atoms)
645 SequenceI lastseq = null;
647 for (StructureMapping sm : mappings)
649 if (sm.pdbfile.equals(atom.getPdbFile())
650 && sm.pdbchain.equals(atom.getChain()))
652 int indexpos = sm.getSeqPos(atom.getPdbResNum());
653 if (lastipos != indexpos && lastseq != sm.sequence)
655 results.addResult(sm.sequence, indexpos, indexpos);
657 lastseq = sm.sequence;
658 // construct highlighted sequence list
659 for (AlignedCodonFrame acf : seqmappings)
661 acf.markMappedRegion(sm.sequence, indexpos, results);
667 for (Object li : listeners)
669 if (li instanceof SequenceListener)
671 ((SequenceListener) li).highlightSequence(results);
677 * highlight regions associated with a position (indexpos) in seq
680 * the sequence that the mouse over occurred on
682 * the absolute position being mouseovered in seq (0 to seq.length())
684 * the sequence position (if -1, seq.findPosition is called to
685 * resolve the residue number)
687 public void mouseOverSequence(SequenceI seq, int indexpos, int index,
690 boolean hasSequenceListeners = handlingVamsasMo
691 || !seqmappings.isEmpty();
692 SearchResults results = null;
695 index = seq.findPosition(indexpos);
697 for (int i = 0; i < listeners.size(); i++)
699 Object listener = listeners.elementAt(i);
700 if (listener == source)
702 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
703 // Temporary fudge with SequenceListener.getVamsasSource()
706 if (listener instanceof StructureListener)
708 highlightStructure((StructureListener) listener, seq, index);
712 if (listener instanceof SequenceListener)
714 final SequenceListener seqListener = (SequenceListener) listener;
715 if (hasSequenceListeners
716 && seqListener.getVamsasSource() != source)
718 if (relaySeqMappings)
722 results = MappingUtils.buildSearchResults(seq, index,
725 if (handlingVamsasMo)
727 results.addResult(seq, index, index);
730 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 * Decrement the reference counter for each of the given mappings, and remove
912 * it entirely if its reference counter reduces to zero.
916 public void removeMappings(Set<AlignedCodonFrame> set)
920 for (AlignedCodonFrame acf : set)
928 * Decrement the reference counter for the given mapping, and remove it
929 * entirely if its reference counter reduces to zero.
933 public void removeMapping(AlignedCodonFrame acf)
935 if (acf != null && seqmappings.contains(acf))
937 int count = seqMappingRefCounts.get(acf);
941 seqMappingRefCounts.put(acf, count);
945 seqmappings.remove(acf);
946 seqMappingRefCounts.remove(acf);
952 * Add each of the given codonFrames to the stored set. If not aready present,
953 * increments its reference count instead.
957 public void addMappings(Set<AlignedCodonFrame> set)
961 for (AlignedCodonFrame acf : set)
969 * Add the given mapping to the stored set, or if already stored, increment
970 * its reference counter.
972 public void addMapping(AlignedCodonFrame acf)
976 if (seqmappings.contains(acf))
978 seqMappingRefCounts.put(acf, seqMappingRefCounts.get(acf) + 1);
982 seqmappings.add(acf);
983 seqMappingRefCounts.put(acf, 1);
988 public void addSelectionListener(SelectionListener selecter)
990 if (!sel_listeners.contains(selecter))
992 sel_listeners.add(selecter);
996 public void removeSelectionListener(SelectionListener toremove)
998 if (sel_listeners.contains(toremove))
1000 sel_listeners.remove(toremove);
1004 public synchronized void sendSelection(
1005 jalview.datamodel.SequenceGroup selection,
1006 jalview.datamodel.ColumnSelection colsel, SelectionSource source)
1008 for (SelectionListener slis : sel_listeners)
1012 slis.selection(selection, colsel, source);
1017 Vector<AlignmentViewPanelListener> view_listeners = new Vector<AlignmentViewPanelListener>();
1019 public synchronized void sendViewPosition(
1020 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1021 int startSeq, int endSeq)
1024 if (view_listeners != null && view_listeners.size() > 0)
1026 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1028 while (listeners.hasMoreElements())
1030 AlignmentViewPanelListener slis = listeners.nextElement();
1033 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1041 * release all references associated with this manager provider
1043 * @param jalviewLite
1045 public static void release(StructureSelectionManagerProvider jalviewLite)
1047 // synchronized (instances)
1049 if (instances == null)
1053 StructureSelectionManager mnger = (instances.get(jalviewLite));
1056 instances.remove(jalviewLite);
1060 } catch (Throwable x)
1067 public void registerPDBEntry(PDBEntry pdbentry)
1069 if (pdbentry.getFile() != null
1070 && pdbentry.getFile().trim().length() > 0)
1072 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1076 public void addCommandListener(CommandListener cl)
1078 if (!commandListeners.contains(cl))
1080 commandListeners.add(cl);
1084 public boolean hasCommandListener(CommandListener cl)
1086 return this.commandListeners.contains(cl);
1089 public boolean removeCommandListener(CommandListener l)
1091 return commandListeners.remove(l);
1095 * Forward a command to any command listeners (except for the command's
1099 * the command to be broadcast (in its form after being performed)
1101 * if true, the command was being 'undone'
1104 public void commandPerformed(CommandI command, boolean undo,
1105 VamsasSource source)
1107 for (CommandListener listener : commandListeners)
1109 listener.mirrorCommand(command, undo, this, source);
1114 * Returns a new CommandI representing the given command as mapped to the
1115 * given sequences. If no mapping could be made, or the command is not of a
1116 * mappable kind, returns null.
1124 public CommandI mapCommand(CommandI command, boolean undo,
1125 final AlignmentI mapTo, char gapChar)
1127 if (command instanceof EditCommand)
1129 return MappingUtils.mapEditCommand((EditCommand) command, undo,
1130 mapTo, gapChar, seqmappings);
1132 else if (command instanceof OrderCommand)
1134 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1135 mapTo, seqmappings);