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.Collections;
26 import java.util.Enumeration;
27 import java.util.HashMap;
28 import java.util.IdentityHashMap;
29 import java.util.LinkedHashSet;
30 import java.util.List;
33 import java.util.Vector;
36 import MCview.PDBChain;
38 import jalview.analysis.AlignSeq;
39 import jalview.api.StructureSelectionManagerProvider;
40 import jalview.commands.CommandI;
41 import jalview.commands.EditCommand;
42 import jalview.commands.OrderCommand;
43 import jalview.datamodel.AlignedCodonFrame;
44 import jalview.datamodel.AlignmentAnnotation;
45 import jalview.datamodel.AlignmentI;
46 import jalview.datamodel.Annotation;
47 import jalview.datamodel.PDBEntry;
48 import jalview.datamodel.SearchResults;
49 import jalview.datamodel.SequenceI;
50 import jalview.io.AppletFormatAdapter;
51 import jalview.util.MappingUtils;
52 import jalview.util.MessageManager;
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 Set<AlignedCodonFrame> seqmappings = new LinkedHashSet<AlignedCodonFrame>();
74 * Reference counters for the above mappings. Remove mappings when ref count
77 Map<AlignedCodonFrame, Integer> seqMappingRefCounts = new HashMap<AlignedCodonFrame, Integer>();
79 private List<CommandListener> commandListeners = new ArrayList<CommandListener>();
81 private List<SelectionListener> sel_listeners = new ArrayList<SelectionListener>();
84 * @return true if will try to use external services for processing secondary
87 public boolean isSecStructServices()
89 return secStructServices;
93 * control use of external services for processing secondary structure
95 * @param secStructServices
97 public void setSecStructServices(boolean secStructServices)
99 this.secStructServices = secStructServices;
103 * flag controlling addition of any kind of structural annotation
105 * @return true if temperature factor annotation will be added
107 public boolean isAddTempFacAnnot()
109 return addTempFacAnnot;
113 * set flag controlling addition of structural annotation
115 * @param addTempFacAnnot
117 public void setAddTempFacAnnot(boolean addTempFacAnnot)
119 this.addTempFacAnnot = addTempFacAnnot;
124 * @return if true, the structure manager will attempt to add secondary
125 * structure lines for unannotated sequences
128 public boolean isProcessSecondaryStructure()
130 return processSecondaryStructure;
134 * Control whether structure manager will try to annotate mapped sequences
135 * with secondary structure from PDB data.
139 public void setProcessSecondaryStructure(boolean enable)
141 processSecondaryStructure = enable;
145 * debug function - write all mappings to stdout
147 public void reportMapping()
149 if (mappings.isEmpty())
151 System.err.println("reportMapping: No PDB/Sequence mappings.");
155 System.err.println("reportMapping: There are " + mappings.size()
158 for (StructureMapping sm : mappings)
160 System.err.println("mapping " + i++ + " : " + sm.pdbfile);
166 * map between the PDB IDs (or structure identifiers) used by Jalview and the
167 * absolute filenames for PDB data that corresponds to it
169 HashMap<String, String> pdbIdFileName = new HashMap<String, String>(),
170 pdbFileNameId = new HashMap<String, String>();
172 public void registerPDBFile(String idForFile, String absoluteFile)
174 pdbIdFileName.put(idForFile, absoluteFile);
175 pdbFileNameId.put(absoluteFile, idForFile);
178 public String findIdForPDBFile(String idOrFile)
180 String id = pdbFileNameId.get(idOrFile);
184 public String findFileForPDBId(String idOrFile)
186 String id = pdbIdFileName.get(idOrFile);
190 public boolean isPDBFileRegistered(String idOrFile)
192 return pdbFileNameId.containsKey(idOrFile)
193 || pdbIdFileName.containsKey(idOrFile);
196 private static StructureSelectionManager nullProvider = null;
198 public static StructureSelectionManager getStructureSelectionManager(
199 StructureSelectionManagerProvider context)
203 if (nullProvider == null)
205 if (instances != null)
207 throw new Error(MessageManager.getString("error.implementation_error_structure_selection_manager_null"),
208 new NullPointerException(MessageManager.getString("exception.ssm_context_is_null")));
212 nullProvider = new StructureSelectionManager();
217 if (instances == null)
219 instances = new java.util.IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager>();
221 StructureSelectionManager instance = instances.get(context);
222 if (instance == null)
224 if (nullProvider != null)
226 instance = nullProvider;
230 instance = new StructureSelectionManager();
232 instances.put(context, instance);
238 * flag controlling whether SeqMappings are relayed from received sequence
239 * mouse over events to other sequences
241 boolean relaySeqMappings = true;
244 * Enable or disable relay of seqMapping events to other sequences. You might
245 * want to do this if there are many sequence mappings and the host computer
250 public void setRelaySeqMappings(boolean relay)
252 relaySeqMappings = relay;
256 * get the state of the relay seqMappings flag.
258 * @return true if sequence mouse overs are being relayed to other mapped
261 public boolean isRelaySeqMappingsEnabled()
263 return relaySeqMappings;
266 Vector listeners = new Vector();
269 * register a listener for alignment sequence mouseover events
273 public void addStructureViewerListener(Object svl)
275 if (!listeners.contains(svl))
277 listeners.addElement(svl);
282 * Returns the file name for a mapped PDB id (or null if not mapped).
287 public String alreadyMappedToFile(String pdbid)
289 for (StructureMapping sm : mappings)
291 if (sm.getPdbId().equals(pdbid))
300 * Import structure data and register a structure mapping for broadcasting
301 * colouring, mouseovers and selection events (convenience wrapper).
304 * - one or more sequences to be mapped to pdbFile
305 * @param targetChains
306 * - optional chain specification for mapping each sequence to pdb
307 * (may be nill, individual elements may be nill)
309 * - structure data resource
311 * - how to resolve data from resource
312 * @return null or the structure data parsed as a pdb file
314 synchronized public MCview.PDBfile setMapping(SequenceI[] sequence,
315 String[] targetChains, String pdbFile, String protocol)
317 return setMapping(true, sequence, targetChains, pdbFile, protocol);
321 * create sequence structure mappings between each sequence and the given
322 * pdbFile (retrieved via the given protocol).
324 * @param forStructureView
325 * when true, record the mapping for use in mouseOvers
328 * - one or more sequences to be mapped to pdbFile
329 * @param targetChains
330 * - optional chain specification for mapping each sequence to pdb
331 * (may be nill, individual elements may be nill)
333 * - structure data resource
335 * - how to resolve data from resource
336 * @return null or the structure data parsed as a pdb file
338 synchronized public MCview.PDBfile setMapping(boolean forStructureView,
339 SequenceI[] sequence,
340 String[] targetChains, String pdbFile, String protocol)
343 * There will be better ways of doing this in the future, for now we'll use
344 * the tried and tested MCview pdb mapping
346 MCview.PDBfile pdb = null;
347 boolean parseSecStr = processSecondaryStructure;
348 if (isPDBFileRegistered(pdbFile))
350 for (SequenceI sq : sequence)
353 while (ds.getDatasetSequence() != null)
355 ds = ds.getDatasetSequence();
358 if (ds.getAnnotation() != null)
360 for (AlignmentAnnotation ala : ds.getAnnotation())
362 // false if any annotation present from this structure
363 // JBPNote this fails for jmol/chimera view because the *file* is
364 // passed, not the structure data ID -
365 if (MCview.PDBfile.isCalcIdForFile(ala,
366 findIdForPDBFile(pdbFile)))
376 pdb = new MCview.PDBfile(addTempFacAnnot, parseSecStr,
377 secStructServices, pdbFile, protocol);
378 if (pdb.id != null && pdb.id.trim().length() > 0
379 && AppletFormatAdapter.FILE.equals(protocol))
381 registerPDBFile(pdb.id.trim(), pdbFile);
383 } catch (Exception ex)
385 ex.printStackTrace();
390 for (int s = 0; s < sequence.length; s++)
392 boolean infChain = true;
393 if (targetChains != null && targetChains[s] != null)
396 targetChain = targetChains[s];
398 else if (sequence[s].getName().indexOf("|") > -1)
400 targetChain = sequence[s].getName().substring(
401 sequence[s].getName().lastIndexOf("|") + 1);
402 if (targetChain.length() > 1)
404 if (targetChain.trim().length() == 0)
410 // not a valid chain identifier
421 AlignSeq maxAlignseq = null;
422 String maxChainId = " ";
423 PDBChain maxChain = null;
424 boolean first = true;
425 for (int i = 0; i < pdb.chains.size(); i++)
427 PDBChain chain = (pdb.chains.elementAt(i));
428 if (targetChain.length() > 0 && !targetChain.equals(chain.id)
431 continue; // don't try to map chains don't match.
433 // TODO: correctly determine sequence type for mixed na/peptide
435 AlignSeq as = new AlignSeq(sequence[s],
436 pdb.chains.elementAt(i).sequence,
437 pdb.chains.elementAt(i).isNa ? AlignSeq.DNA
439 as.calcScoreMatrix();
442 if (first || as.maxscore > max
443 || (as.maxscore == max && chain.id.equals(targetChain)))
449 maxChainId = chain.id;
452 if (maxChain == null)
456 final StringBuffer mappingDetails = new StringBuffer();
457 mappingDetails.append("\n\nPDB Sequence is :\nSequence = "
458 + maxChain.sequence.getSequenceAsString());
459 mappingDetails.append("\nNo of residues = "
460 + maxChain.residues.size() + "\n\n");
461 PrintStream ps = new PrintStream(System.out)
464 public void print(String x)
466 mappingDetails.append(x);
470 public void println()
472 mappingDetails.append("\n");
476 maxAlignseq.printAlignment(ps);
478 mappingDetails.append("\nPDB start/end " + maxAlignseq.seq2start
479 + " " + maxAlignseq.seq2end);
480 mappingDetails.append("\nSEQ start/end "
481 + (maxAlignseq.seq1start + sequence[s].getStart() - 1) + " "
482 + (maxAlignseq.seq1end + sequence[s].getEnd() - 1));
484 maxChain.makeExactMapping(maxAlignseq, sequence[s]);
485 jalview.datamodel.Mapping sqmpping = maxAlignseq
486 .getMappingFromS1(false);
487 jalview.datamodel.Mapping omap = new jalview.datamodel.Mapping(
488 sqmpping.getMap().getInverse());
489 maxChain.transferRESNUMFeatures(sequence[s], null);
491 // allocate enough slots to store the mapping from positions in
492 // sequence[s] to the associated chain
493 int[][] mapping = new int[sequence[s].findPosition(sequence[s]
494 .getLength()) + 2][2];
500 Atom tmp = maxChain.atoms.elementAt(index);
501 if (resNum != tmp.resNumber && tmp.alignmentMapping != -1)
503 resNum = tmp.resNumber;
504 mapping[tmp.alignmentMapping + 1][0] = tmp.resNumber;
505 mapping[tmp.alignmentMapping + 1][1] = tmp.atomIndex;
509 } while (index < maxChain.atoms.size());
511 if (protocol.equals(jalview.io.AppletFormatAdapter.PASTE))
513 pdbFile = "INLINE" + pdb.id;
515 StructureMapping newMapping = new StructureMapping(sequence[s],
516 pdbFile, pdb.id, maxChainId, mapping,
517 mappingDetails.toString());
518 if (forStructureView)
520 mappings.add(newMapping);
522 maxChain.transferResidueAnnotation(newMapping, sqmpping);
529 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
531 listeners.removeElement(svl);
532 if (svl instanceof SequenceListener)
534 for (int i = 0; i < listeners.size(); i++)
536 if (listeners.elementAt(i) instanceof StructureListener)
538 ((StructureListener) listeners.elementAt(i))
539 .releaseReferences(svl);
544 if (pdbfiles == null)
549 Vector pdbs = new Vector();
550 for (int i = 0; i < pdbfiles.length; pdbs.addElement(pdbfiles[i++]))
554 StructureListener sl;
555 for (int i = 0; i < listeners.size(); i++)
557 if (listeners.elementAt(i) instanceof StructureListener)
559 sl = (StructureListener) listeners.elementAt(i);
560 handlepdbs = sl.getPdbFile();
561 for (int j = 0; j < handlepdbs.length; j++)
563 if (pdbs.contains(handlepdbs[j]))
565 pdbs.removeElement(handlepdbs[j]);
574 List<StructureMapping> tmp = new ArrayList<StructureMapping>();
575 for (StructureMapping sm : mappings)
577 if (!pdbs.contains(sm.pdbfile))
588 * Propagate mouseover of a single position in a structure
594 public void mouseOverStructure(int pdbResNum, String chain, String pdbfile)
596 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
597 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
598 mouseOverStructure(atoms);
602 * Propagate mouseover or selection of multiple positions in a structure
606 public void mouseOverStructure(List<AtomSpec> atoms)
608 if (listeners == null)
610 // old or prematurely sent event
613 boolean hasSequenceListener = false;
614 for (int i = 0; i < listeners.size(); i++)
616 if (listeners.elementAt(i) instanceof SequenceListener)
618 hasSequenceListener = true;
621 if (!hasSequenceListener)
626 SearchResults results = new SearchResults();
627 for (AtomSpec atom : atoms)
629 SequenceI lastseq = null;
631 for (StructureMapping sm : mappings)
633 if (sm.pdbfile.equals(atom.getPdbFile())
634 && sm.pdbchain.equals(atom.getChain()))
636 int indexpos = sm.getSeqPos(atom.getPdbResNum());
637 if (lastipos != indexpos && lastseq != sm.sequence)
639 results.addResult(sm.sequence, indexpos, indexpos);
641 lastseq = sm.sequence;
642 // construct highlighted sequence list
643 for (AlignedCodonFrame acf : seqmappings)
645 acf.markMappedRegion(sm.sequence, indexpos, results);
651 for (Object li : listeners)
653 if (li instanceof SequenceListener)
655 ((SequenceListener) li).highlightSequence(results);
661 * highlight regions associated with a position (indexpos) in seq
664 * the sequence that the mouse over occurred on
666 * the absolute position being mouseovered in seq (0 to seq.length())
668 * the sequence position (if -1, seq.findPosition is called to
669 * resolve the residue number)
671 public void mouseOverSequence(SequenceI seq, int indexpos, int index,
674 boolean hasSequenceListeners = handlingVamsasMo
675 || !seqmappings.isEmpty();
676 SearchResults results = null;
679 index = seq.findPosition(indexpos);
681 for (int i = 0; i < listeners.size(); i++)
683 Object listener = listeners.elementAt(i);
684 if (listener == source)
686 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
687 // Temporary fudge with SequenceListener.getVamsasSource()
690 if (listener instanceof StructureListener)
692 highlightStructure((StructureListener) listener, seq, index);
696 if (listener instanceof SequenceListener)
698 final SequenceListener seqListener = (SequenceListener) listener;
699 if (hasSequenceListeners
700 && seqListener.getVamsasSource() != source)
702 if (relaySeqMappings)
706 results = MappingUtils.buildSearchResults(seq, index,
709 if (handlingVamsasMo)
711 results.addResult(seq, index, index);
714 seqListener.highlightSequence(results);
718 else if (listener instanceof VamsasListener && !handlingVamsasMo)
720 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
723 else if (listener instanceof SecondaryStructureListener)
725 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
733 * Send suitable messages to a StructureListener to highlight atoms
734 * corresponding to the given sequence position.
740 protected void highlightStructure(StructureListener sl, SequenceI seq,
744 List<AtomSpec> atoms = new ArrayList<AtomSpec>();
745 for (StructureMapping sm : mappings)
747 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence())
749 atomNo = sm.getAtomNum(index);
753 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain, sm
754 .getPDBResNum(index), atomNo));
758 sl.highlightAtoms(atoms);
762 * true if a mouse over event from an external (ie Vamsas) source is being
765 boolean handlingVamsasMo = false;
770 * as mouseOverSequence but only route event to SequenceListeners
774 * in an alignment sequence
776 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
779 handlingVamsasMo = true;
780 long msg = sequenceI.hashCode() * (1 + position);
784 mouseOverSequence(sequenceI, position, -1, source);
786 handlingVamsasMo = false;
789 public Annotation[] colourSequenceFromStructure(SequenceI seq,
793 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
794 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
796 * Annotation [] annotations = new Annotation[seq.getLength()];
798 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
799 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
800 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
802 * for (int j = 0; j < mappings.length; j++) {
804 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
805 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
806 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
807 * "+mappings[j].pdbfile);
809 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
810 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
812 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
813 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
814 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
815 * mappings[j].pdbfile); }
817 * annotations[index] = new Annotation("X",null,' ',0,col); } return
818 * annotations; } } } }
820 * return annotations;
824 public void structureSelectionChanged()
828 public void sequenceSelectionChanged()
832 public void sequenceColoursChanged(Object source)
834 StructureListener sl;
835 for (int i = 0; i < listeners.size(); i++)
837 if (listeners.elementAt(i) instanceof StructureListener)
839 sl = (StructureListener) listeners.elementAt(i);
840 sl.updateColours(source);
845 public StructureMapping[] getMapping(String pdbfile)
847 List<StructureMapping> tmp = new ArrayList<StructureMapping>();
848 for (StructureMapping sm : mappings)
850 if (sm.pdbfile.equals(pdbfile))
855 return tmp.toArray(new StructureMapping[tmp.size()]);
859 * Returns a readable description of all mappings for the given pdbfile to any
860 * of the given sequences
866 public String printMappings(String pdbfile, List<SequenceI> seqs)
868 if (pdbfile == null || seqs == null || seqs.isEmpty())
873 StringBuilder sb = new StringBuilder(64);
874 for (StructureMapping sm : mappings)
876 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
878 sb.append(sm.mappingDetails);
880 // separator makes it easier to read multiple mappings
881 sb.append("=====================");
887 return sb.toString();
891 * Decrement the reference counter for each of the given mappings, and remove
892 * it entirely if its reference counter reduces to zero.
896 public void removeMappings(Set<AlignedCodonFrame> set)
900 for (AlignedCodonFrame acf : set)
908 * Decrement the reference counter for the given mapping, and remove it
909 * entirely if its reference counter reduces to zero.
913 public void removeMapping(AlignedCodonFrame acf)
915 if (acf != null && seqmappings.contains(acf))
917 int count = seqMappingRefCounts.get(acf);
921 seqMappingRefCounts.put(acf, count);
925 seqmappings.remove(acf);
926 seqMappingRefCounts.remove(acf);
932 * Add each of the given codonFrames to the stored set. If not aready present,
933 * increments its reference count instead.
937 public void addMappings(Set<AlignedCodonFrame> set)
941 for (AlignedCodonFrame acf : set)
949 * Add the given mapping to the stored set, or if already stored, increment
950 * its reference counter.
952 public void addMapping(AlignedCodonFrame acf)
956 if (seqmappings.contains(acf))
958 seqMappingRefCounts.put(acf, seqMappingRefCounts.get(acf) + 1);
962 seqmappings.add(acf);
963 seqMappingRefCounts.put(acf, 1);
968 public void addSelectionListener(SelectionListener selecter)
970 if (!sel_listeners.contains(selecter))
972 sel_listeners.add(selecter);
976 public void removeSelectionListener(SelectionListener toremove)
978 if (sel_listeners.contains(toremove))
980 sel_listeners.remove(toremove);
984 public synchronized void sendSelection(
985 jalview.datamodel.SequenceGroup selection,
986 jalview.datamodel.ColumnSelection colsel, SelectionSource source)
988 for (SelectionListener slis : sel_listeners)
992 slis.selection(selection, colsel, source);
997 Vector<AlignmentViewPanelListener> view_listeners = new Vector<AlignmentViewPanelListener>();
999 public synchronized void sendViewPosition(
1000 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1001 int startSeq, int endSeq)
1004 if (view_listeners != null && view_listeners.size() > 0)
1006 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1008 while (listeners.hasMoreElements())
1010 AlignmentViewPanelListener slis = listeners.nextElement();
1013 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1021 * release all references associated with this manager provider
1023 * @param jalviewLite
1025 public static void release(StructureSelectionManagerProvider jalviewLite)
1027 // synchronized (instances)
1029 if (instances == null)
1033 StructureSelectionManager mnger = (instances.get(jalviewLite));
1036 instances.remove(jalviewLite);
1040 } catch (Throwable x)
1047 public void registerPDBEntry(PDBEntry pdbentry)
1049 if (pdbentry.getFile() != null
1050 && pdbentry.getFile().trim().length() > 0)
1052 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1056 public void addCommandListener(CommandListener cl)
1058 if (!commandListeners.contains(cl))
1060 commandListeners.add(cl);
1064 public boolean hasCommandListener(CommandListener cl)
1066 return this.commandListeners.contains(cl);
1069 public boolean removeCommandListener(CommandListener l)
1071 return commandListeners.remove(l);
1075 * Forward a command to any command listeners (except for the command's
1079 * the command to be broadcast (in its form after being performed)
1081 * if true, the command was being 'undone'
1084 public void commandPerformed(CommandI command, boolean undo,
1085 VamsasSource source)
1087 for (CommandListener listener : commandListeners)
1089 listener.mirrorCommand(command, undo, this, source);
1094 * Returns a new CommandI representing the given command as mapped to the
1095 * given sequences. If no mapping could be made, or the command is not of a
1096 * mappable kind, returns null.
1104 public CommandI mapCommand(CommandI command, boolean undo,
1105 final AlignmentI mapTo, char gapChar)
1107 if (command instanceof EditCommand)
1109 return MappingUtils.mapEditCommand((EditCommand) command, undo,
1110 mapTo, gapChar, seqmappings);
1112 else if (command instanceof OrderCommand)
1114 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1115 mapTo, seqmappings);