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.io.SiftsClient;
37 import jalview.util.MappingUtils;
38 import jalview.util.MessageManager;
40 import java.io.PrintStream;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.Collections;
44 import java.util.Enumeration;
45 import java.util.HashMap;
46 import java.util.IdentityHashMap;
47 import java.util.LinkedHashSet;
48 import java.util.List;
51 import java.util.Vector;
54 import MCview.PDBChain;
55 import MCview.PDBfile;
57 public class StructureSelectionManager
59 public final static String NEWLINE = System.lineSeparator();
61 static IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> instances;
63 private List<StructureMapping> mappings = new ArrayList<StructureMapping>();
65 private boolean processSecondaryStructure = false;
67 private boolean secStructServices = false;
69 private boolean addTempFacAnnot = false;
72 * Set of any registered mappings between (dataset) sequences.
74 public Set<AlignedCodonFrame> seqmappings = new LinkedHashSet<AlignedCodonFrame>();
76 private List<CommandListener> commandListeners = new ArrayList<CommandListener>();
78 private List<SelectionListener> sel_listeners = new ArrayList<SelectionListener>();
81 * @return true if will try to use external services for processing secondary
84 public boolean isSecStructServices()
86 return secStructServices;
90 * control use of external services for processing secondary structure
92 * @param secStructServices
94 public void setSecStructServices(boolean secStructServices)
96 this.secStructServices = secStructServices;
100 * flag controlling addition of any kind of structural annotation
102 * @return true if temperature factor annotation will be added
104 public boolean isAddTempFacAnnot()
106 return addTempFacAnnot;
110 * set flag controlling addition of structural annotation
112 * @param addTempFacAnnot
114 public void setAddTempFacAnnot(boolean addTempFacAnnot)
116 this.addTempFacAnnot = addTempFacAnnot;
121 * @return if true, the structure manager will attempt to add secondary
122 * structure lines for unannotated sequences
125 public boolean isProcessSecondaryStructure()
127 return processSecondaryStructure;
131 * Control whether structure manager will try to annotate mapped sequences
132 * with secondary structure from PDB data.
136 public void setProcessSecondaryStructure(boolean enable)
138 processSecondaryStructure = enable;
142 * debug function - write all mappings to stdout
144 public void reportMapping()
146 if (mappings.isEmpty())
148 System.err.println("reportMapping: No PDB/Sequence mappings.");
152 System.err.println("reportMapping: There are " + mappings.size()
155 for (StructureMapping sm : mappings)
157 System.err.println("mapping " + i++ + " : " + sm.pdbfile);
163 * map between the PDB IDs (or structure identifiers) used by Jalview and the
164 * absolute filenames for PDB data that corresponds to it
166 Map<String, String> pdbIdFileName = new HashMap<String, String>();
168 Map<String, String> pdbFileNameId = new HashMap<String, String>();
170 public void registerPDBFile(String idForFile, String absoluteFile)
172 pdbIdFileName.put(idForFile, absoluteFile);
173 pdbFileNameId.put(absoluteFile, idForFile);
176 public String findIdForPDBFile(String idOrFile)
178 String id = pdbFileNameId.get(idOrFile);
182 public String findFileForPDBId(String idOrFile)
184 String id = pdbIdFileName.get(idOrFile);
188 public boolean isPDBFileRegistered(String idOrFile)
190 return pdbFileNameId.containsKey(idOrFile)
191 || pdbIdFileName.containsKey(idOrFile);
194 private static StructureSelectionManager nullProvider = null;
196 public static StructureSelectionManager getStructureSelectionManager(
197 StructureSelectionManagerProvider context)
201 if (nullProvider == null)
203 if (instances != null)
207 .getString("error.implementation_error_structure_selection_manager_null"),
208 new NullPointerException(MessageManager
209 .getString("exception.ssm_context_is_null")));
213 nullProvider = new StructureSelectionManager();
218 if (instances == null)
220 instances = new java.util.IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager>();
222 StructureSelectionManager instance = instances.get(context);
223 if (instance == null)
225 if (nullProvider != null)
227 instance = nullProvider;
231 instance = new StructureSelectionManager();
233 instances.put(context, instance);
239 * flag controlling whether SeqMappings are relayed from received sequence
240 * mouse over events to other sequences
242 boolean relaySeqMappings = true;
245 * Enable or disable relay of seqMapping events to other sequences. You might
246 * want to do this if there are many sequence mappings and the host computer
251 public void setRelaySeqMappings(boolean relay)
253 relaySeqMappings = relay;
257 * get the state of the relay seqMappings flag.
259 * @return true if sequence mouse overs are being relayed to other mapped
262 public boolean isRelaySeqMappingsEnabled()
264 return relaySeqMappings;
267 Vector listeners = new Vector();
270 * register a listener for alignment sequence mouseover events
274 public void addStructureViewerListener(Object svl)
276 if (!listeners.contains(svl))
278 listeners.addElement(svl);
283 * Returns the file name for a mapped PDB id (or null if not mapped).
288 public String alreadyMappedToFile(String pdbid)
290 for (StructureMapping sm : mappings)
292 if (sm.getPdbId().equals(pdbid))
301 * Import structure data and register a structure mapping for broadcasting
302 * colouring, mouseovers and selection events (convenience wrapper).
305 * - one or more sequences to be mapped to pdbFile
306 * @param targetChains
307 * - optional chain specification for mapping each sequence to pdb
308 * (may be nill, individual elements may be nill)
310 * - structure data resource
312 * - how to resolve data from resource
313 * @return null or the structure data parsed as a pdb file
315 synchronized public PDBfile setMapping(SequenceI[] sequence,
316 String[] targetChains, String pdbFile, String protocol)
318 return setMapping(true, sequence, targetChains, pdbFile, protocol);
322 * create sequence structure mappings between each sequence and the given
323 * pdbFile (retrieved via the given protocol).
325 * @param forStructureView
326 * when true, record the mapping for use in mouseOvers
329 * - one or more sequences to be mapped to pdbFile
330 * @param targetChains
331 * - optional chain specification for mapping each sequence to pdb
332 * (may be nill, individual elements may be nill)
334 * - structure data resource
336 * - how to resolve data from resource
337 * @return null or the structure data parsed as a pdb file
339 synchronized public PDBfile setMapping(boolean forStructureView,
340 SequenceI[] sequence, String[] targetChains, String pdbFile,
344 * There will be better ways of doing this in the future, for now we'll use
345 * the tried and tested MCview pdb mapping
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 (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
376 pdb = new PDBfile(addTempFacAnnot, parseSecStr, secStructServices,
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 final SequenceI seq = sequence[s];
394 if (targetChains != null && targetChains[s] != null)
397 targetChain = targetChains[s];
399 else if (seq.getName().indexOf("|") > -1)
401 targetChain = seq.getName().substring(
402 seq.getName().lastIndexOf("|") + 1);
403 if (targetChain.length() > 1)
405 if (targetChain.trim().length() == 0)
411 // not a valid chain identifier
422 * Attempt pairwise alignment of the sequence with each chain in the PDB,
423 * and remember the highest scoring chain
426 AlignSeq maxAlignseq = null;
427 String maxChainId = " ";
428 PDBChain maxChain = null;
429 boolean first = true;
430 for (PDBChain chain : pdb.chains)
432 if (targetChain.length() > 0 && !targetChain.equals(chain.id)
435 continue; // don't try to map chains don't match.
437 // TODO: correctly determine sequence type for mixed na/peptide
439 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
440 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
443 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
444 // as.calcScoreMatrix();
445 // as.traceAlignment();
447 if (first || as.maxscore > max
448 || (as.maxscore == max && chain.id.equals(targetChain)))
454 maxChainId = chain.id;
457 if (maxChain == null)
462 if (protocol.equals(jalview.io.AppletFormatAdapter.PASTE))
464 pdbFile = "INLINE" + pdb.id;
467 StructureMapping seqToStrucMapping = null;
468 boolean isMapViaSIFTs = Boolean.valueOf(jalview.bin.Cache.getDefault(
469 "MAP_WITH_SIFTS", "false"));
472 SiftsClient siftsClient = new SiftsClient(pdb.id);
473 seqToStrucMapping = siftsClient.getSiftsStructureMapping(seq,
474 pdbFile, maxChainId);
475 // TODO if SIFTs mapping fails.. then fallback to NW alignment
479 seqToStrucMapping = getNWMappings(seq, pdbFile,
480 maxChainId, maxChain, pdb,
484 if (forStructureView)
486 mappings.add(seqToStrucMapping);
492 private StructureMapping getNWMappings(SequenceI seq, String pdbFile,
493 String maxChainId, PDBChain maxChain, PDBfile pdb,
494 AlignSeq maxAlignseq)
496 final StringBuilder mappingDetails = new StringBuilder(128);
497 PrintStream ps = new PrintStream(System.out)
500 public void print(String x)
502 mappingDetails.append(x);
506 public void println()
508 mappingDetails.append(NEWLINE);
512 maxAlignseq.printAlignment(ps);
513 maxChain.makeExactMapping(maxAlignseq, seq);
514 jalview.datamodel.Mapping sqmpping = maxAlignseq
515 .getMappingFromS1(false);
516 maxChain.transferRESNUMFeatures(seq, null);
518 // allocate enough slots to store the mapping from positions in
519 // sequence[s] to the associated chain
520 int[][] mapping = new int[seq.findPosition(seq.getLength()) + 2][2];
526 Atom tmp = maxChain.atoms.elementAt(index);
527 if (resNum != tmp.resNumber && tmp.alignmentMapping != -1)
529 resNum = tmp.resNumber;
530 if (tmp.alignmentMapping >= -1)
532 // TODO (JAL-1836) address root cause: negative residue no in PDB
534 mapping[tmp.alignmentMapping + 1][0] = tmp.resNumber;
535 mapping[tmp.alignmentMapping + 1][1] = tmp.atomIndex;
540 } while (index < maxChain.atoms.size());
542 StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
543 pdb.id, maxChainId, mapping, mappingDetails.toString());
544 maxChain.transferResidueAnnotation(nwMapping, sqmpping);
548 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
550 listeners.removeElement(svl);
551 if (svl instanceof SequenceListener)
553 for (int i = 0; i < listeners.size(); i++)
555 if (listeners.elementAt(i) instanceof StructureListener)
557 ((StructureListener) listeners.elementAt(i))
558 .releaseReferences(svl);
563 if (pdbfiles == null)
569 * Remove mappings to the closed listener's PDB files, but first check if
570 * another listener is still interested
572 List<String> pdbs = new ArrayList<String>(Arrays.asList(pdbfiles));
574 StructureListener sl;
575 for (int i = 0; i < listeners.size(); i++)
577 if (listeners.elementAt(i) instanceof StructureListener)
579 sl = (StructureListener) listeners.elementAt(i);
580 for (String pdbfile : sl.getPdbFile())
582 pdbs.remove(pdbfile);
588 * Rebuild the mappings set, retaining only those which are for 'other' PDB
593 List<StructureMapping> tmp = new ArrayList<StructureMapping>();
594 for (StructureMapping sm : mappings)
596 if (!pdbs.contains(sm.pdbfile))
607 * Propagate mouseover of a single position in a structure
613 public void mouseOverStructure(int pdbResNum, String chain, String pdbfile)
615 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
616 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
617 mouseOverStructure(atoms);
621 * Propagate mouseover or selection of multiple positions in a structure
625 public void mouseOverStructure(List<AtomSpec> atoms)
627 if (listeners == null)
629 // old or prematurely sent event
632 boolean hasSequenceListener = false;
633 for (int i = 0; i < listeners.size(); i++)
635 if (listeners.elementAt(i) instanceof SequenceListener)
637 hasSequenceListener = true;
640 if (!hasSequenceListener)
645 SearchResults results = new SearchResults();
646 for (AtomSpec atom : atoms)
648 SequenceI lastseq = null;
650 for (StructureMapping sm : mappings)
652 if (sm.pdbfile.equals(atom.getPdbFile())
653 && sm.pdbchain.equals(atom.getChain()))
655 int indexpos = sm.getSeqPos(atom.getPdbResNum());
656 if (lastipos != indexpos && lastseq != sm.sequence)
658 results.addResult(sm.sequence, indexpos, indexpos);
660 lastseq = sm.sequence;
661 // construct highlighted sequence list
662 for (AlignedCodonFrame acf : seqmappings)
664 acf.markMappedRegion(sm.sequence, indexpos, results);
670 for (Object li : listeners)
672 if (li instanceof SequenceListener)
674 ((SequenceListener) li).highlightSequence(results);
680 * highlight regions associated with a position (indexpos) in seq
683 * the sequence that the mouse over occurred on
685 * the absolute position being mouseovered in seq (0 to seq.length())
687 * the sequence position (if -1, seq.findPosition is called to
688 * resolve the residue number)
690 public void mouseOverSequence(SequenceI seq, int indexpos, int index,
693 boolean hasSequenceListeners = handlingVamsasMo
694 || !seqmappings.isEmpty();
695 SearchResults results = null;
698 index = seq.findPosition(indexpos);
700 for (int i = 0; i < listeners.size(); i++)
702 Object listener = listeners.elementAt(i);
703 if (listener == source)
705 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
706 // Temporary fudge with SequenceListener.getVamsasSource()
709 if (listener instanceof StructureListener)
711 highlightStructure((StructureListener) listener, seq, index);
715 if (listener instanceof SequenceListener)
717 final SequenceListener seqListener = (SequenceListener) listener;
718 if (hasSequenceListeners
719 && seqListener.getVamsasSource() != source)
721 if (relaySeqMappings)
725 results = MappingUtils.buildSearchResults(seq, index,
728 if (handlingVamsasMo)
730 results.addResult(seq, index, index);
733 if (!results.isEmpty())
735 seqListener.highlightSequence(results);
740 else if (listener instanceof VamsasListener && !handlingVamsasMo)
742 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
745 else if (listener instanceof SecondaryStructureListener)
747 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
755 * Send suitable messages to a StructureListener to highlight atoms
756 * corresponding to the given sequence position.
762 protected void highlightStructure(StructureListener sl, SequenceI seq,
765 if (!sl.isListeningFor(seq))
770 List<AtomSpec> atoms = new ArrayList<AtomSpec>();
771 for (StructureMapping sm : mappings)
773 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence())
775 atomNo = sm.getAtomNum(index);
779 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain, sm
780 .getPDBResNum(index), atomNo));
784 sl.highlightAtoms(atoms);
788 * true if a mouse over event from an external (ie Vamsas) source is being
791 boolean handlingVamsasMo = false;
796 * as mouseOverSequence but only route event to SequenceListeners
800 * in an alignment sequence
802 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
805 handlingVamsasMo = true;
806 long msg = sequenceI.hashCode() * (1 + position);
810 mouseOverSequence(sequenceI, position, -1, source);
812 handlingVamsasMo = false;
815 public Annotation[] colourSequenceFromStructure(SequenceI seq,
819 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
820 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
822 * Annotation [] annotations = new Annotation[seq.getLength()];
824 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
825 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
826 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
828 * for (int j = 0; j < mappings.length; j++) {
830 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
831 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
832 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
833 * "+mappings[j].pdbfile);
835 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
836 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
838 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
839 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
840 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
841 * mappings[j].pdbfile); }
843 * annotations[index] = new Annotation("X",null,' ',0,col); } return
844 * annotations; } } } }
846 * return annotations;
850 public void structureSelectionChanged()
854 public void sequenceSelectionChanged()
858 public void sequenceColoursChanged(Object source)
860 StructureListener sl;
861 for (int i = 0; i < listeners.size(); i++)
863 if (listeners.elementAt(i) instanceof StructureListener)
865 sl = (StructureListener) listeners.elementAt(i);
866 sl.updateColours(source);
871 public StructureMapping[] getMapping(String pdbfile)
873 List<StructureMapping> tmp = new ArrayList<StructureMapping>();
874 for (StructureMapping sm : mappings)
876 if (sm.pdbfile.equals(pdbfile))
881 return tmp.toArray(new StructureMapping[tmp.size()]);
885 * Returns a readable description of all mappings for the given pdbfile to any
886 * of the given sequences
892 public String printMappings(String pdbfile, List<SequenceI> seqs)
894 if (pdbfile == null || seqs == null || seqs.isEmpty())
899 StringBuilder sb = new StringBuilder(64);
900 for (StructureMapping sm : mappings)
902 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
904 sb.append(sm.mappingDetails);
906 // separator makes it easier to read multiple mappings
907 sb.append("=====================");
913 return sb.toString();
917 * Remove the given mapping
921 public void deregisterMapping(AlignedCodonFrame acf)
925 boolean removed = seqmappings.remove(acf);
926 if (removed && seqmappings.isEmpty())
928 System.out.println("All mappings removed");
934 * Add each of the given codonFrames to the stored set, if not aready present.
938 public void registerMappings(Set<AlignedCodonFrame> set)
942 for (AlignedCodonFrame acf : set)
944 registerMapping(acf);
950 * Add the given mapping to the stored set, unless already stored.
952 public void registerMapping(AlignedCodonFrame acf)
956 if (!seqmappings.contains(acf))
958 seqmappings.add(acf);
964 * Resets this object to its initial state by removing all registered
965 * listeners, codon mappings, PDB file mappings
967 public void resetAll()
969 if (mappings != null)
973 if (seqmappings != null)
977 if (sel_listeners != null)
979 sel_listeners.clear();
981 if (listeners != null)
985 if (commandListeners != null)
987 commandListeners.clear();
989 if (view_listeners != null)
991 view_listeners.clear();
993 if (pdbFileNameId != null)
995 pdbFileNameId.clear();
997 if (pdbIdFileName != null)
999 pdbIdFileName.clear();
1003 public void addSelectionListener(SelectionListener selecter)
1005 if (!sel_listeners.contains(selecter))
1007 sel_listeners.add(selecter);
1011 public void removeSelectionListener(SelectionListener toremove)
1013 if (sel_listeners.contains(toremove))
1015 sel_listeners.remove(toremove);
1019 public synchronized void sendSelection(
1020 jalview.datamodel.SequenceGroup selection,
1021 jalview.datamodel.ColumnSelection colsel, SelectionSource source)
1023 for (SelectionListener slis : sel_listeners)
1027 slis.selection(selection, colsel, source);
1032 Vector<AlignmentViewPanelListener> view_listeners = new Vector<AlignmentViewPanelListener>();
1034 public synchronized void sendViewPosition(
1035 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1036 int startSeq, int endSeq)
1039 if (view_listeners != null && view_listeners.size() > 0)
1041 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1043 while (listeners.hasMoreElements())
1045 AlignmentViewPanelListener slis = listeners.nextElement();
1048 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1056 * release all references associated with this manager provider
1058 * @param jalviewLite
1060 public static void release(StructureSelectionManagerProvider jalviewLite)
1062 // synchronized (instances)
1064 if (instances == null)
1068 StructureSelectionManager mnger = (instances.get(jalviewLite));
1071 instances.remove(jalviewLite);
1075 } catch (Throwable x)
1082 public void registerPDBEntry(PDBEntry pdbentry)
1084 if (pdbentry.getFile() != null
1085 && pdbentry.getFile().trim().length() > 0)
1087 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1091 public void addCommandListener(CommandListener cl)
1093 if (!commandListeners.contains(cl))
1095 commandListeners.add(cl);
1099 public boolean hasCommandListener(CommandListener cl)
1101 return this.commandListeners.contains(cl);
1104 public boolean removeCommandListener(CommandListener l)
1106 return commandListeners.remove(l);
1110 * Forward a command to any command listeners (except for the command's
1114 * the command to be broadcast (in its form after being performed)
1116 * if true, the command was being 'undone'
1119 public void commandPerformed(CommandI command, boolean undo,
1120 VamsasSource source)
1122 for (CommandListener listener : commandListeners)
1124 listener.mirrorCommand(command, undo, this, source);
1129 * Returns a new CommandI representing the given command as mapped to the
1130 * given sequences. If no mapping could be made, or the command is not of a
1131 * mappable kind, returns null.
1139 public CommandI mapCommand(CommandI command, boolean undo,
1140 final AlignmentI mapTo, char gapChar)
1142 if (command instanceof EditCommand)
1144 return MappingUtils.mapEditCommand((EditCommand) command, undo,
1145 mapTo, gapChar, seqmappings);
1147 else if (command instanceof OrderCommand)
1149 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1150 mapTo, seqmappings);