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.commands;
23 import jalview.datamodel.AlignmentAnnotation;
24 import jalview.datamodel.AlignmentI;
25 import jalview.datamodel.Annotation;
26 import jalview.datamodel.Sequence;
27 import jalview.datamodel.SequenceFeature;
28 import jalview.datamodel.SequenceI;
29 import jalview.util.ReverseListIterator;
30 import jalview.util.StringUtils;
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.Hashtable;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.ListIterator;
47 * Description: Essential information for performing undo and redo for cut/paste
48 * insert/delete gap which can be stored in the HistoryList
52 * Copyright: Copyright (c) 2006
56 * Company: Dundee University
59 * @author not attributable
62 public class EditCommand implements CommandI
69 public Action getUndoAction()
77 public Action getUndoAction()
85 public Action getUndoAction()
93 public Action getUndoAction()
101 public Action getUndoAction()
109 public Action getUndoAction()
114 public abstract Action getUndoAction();
117 private List<Edit> edits = new ArrayList<Edit>();
125 public EditCommand(String description)
127 this.description = description;
130 public EditCommand(String description, Action command, SequenceI[] seqs,
131 int position, int number, AlignmentI al)
133 this.description = description;
134 if (command == Action.CUT || command == Action.PASTE)
136 setEdit(new Edit(command, seqs, position, number, al));
139 performEdit(0, null);
142 public EditCommand(String description, Action command, String replace,
143 SequenceI[] seqs, int position, int number, AlignmentI al)
145 this.description = description;
146 if (command == Action.REPLACE)
148 setEdit(new Edit(command, seqs, position, number, al, replace));
151 performEdit(0, null);
155 * Set the list of edits to the specified item (only).
159 protected void setEdit(Edit e)
166 * Add the given edit command to the stored list of commands. If simply
167 * expanding the range of the last command added, then modify it instead of
168 * adding a new command.
172 public void addEdit(Edit e)
174 if (!expandEdit(edits, e))
181 * Returns true if the new edit is incorporated by updating (expanding the
182 * range of) the last edit on the list, else false. We can 'expand' the last
183 * edit if the new one is the same action, on the same sequences, and acts on
184 * a contiguous range. This is the case where a mouse drag generates a series
185 * of contiguous gap insertions or deletions.
191 protected static boolean expandEdit(List<Edit> edits, Edit e)
193 if (edits == null || edits.isEmpty())
197 Edit lastEdit = edits.get(edits.size() - 1);
198 Action action = e.command;
199 if (lastEdit.command != action)
205 * Both commands must act on the same sequences - compare the underlying
206 * dataset sequences, rather than the aligned sequences, which change as
209 if (lastEdit.seqs.length != e.seqs.length)
213 for (int i = 0; i < e.seqs.length; i++)
215 if (lastEdit.seqs[i].getDatasetSequence() != e.seqs[i]
216 .getDatasetSequence())
223 * Check a contiguous edit; either
225 * <li>a new Insert <n> positions to the right of the last <insert n>,
227 * <li>a new Delete <n> gaps which is <n> positions to the left of the last
231 boolean contiguous = (action == Action.INSERT_GAP
232 && e.position == lastEdit.position + lastEdit.number)
233 || (action == Action.DELETE_GAP
234 && e.position + e.number == lastEdit.position);
238 * We are just expanding the range of the last edit. For delete gap, also
239 * moving the start position left.
241 lastEdit.number += e.number;
242 lastEdit.seqs = e.seqs;
243 if (action == Action.DELETE_GAP)
253 * Clear the list of stored edit commands.
256 protected void clearEdits()
262 * Returns the i'th stored Edit command.
267 protected Edit getEdit(int i)
269 if (i >= 0 && i < edits.size())
277 final public String getDescription()
289 * Return the alignment for the first edit (or null if no edit).
293 final public AlignmentI getAlignment()
295 return (edits.isEmpty() ? null : edits.get(0).al);
299 * append a new editCommand Note. this shouldn't be called if the edit is an
300 * operation affects more alignment objects than the one referenced in al (for
301 * example, cut or pasting whole sequences). Use the form with an additional
302 * AlignmentI[] views parameter.
311 final public void appendEdit(Action command, SequenceI[] seqs,
312 int position, int number, AlignmentI al, boolean performEdit)
314 appendEdit(command, seqs, position, number, al, performEdit, null);
318 * append a new edit command with a set of alignment views that may be
329 final public void appendEdit(Action command, SequenceI[] seqs,
330 int position, int number, AlignmentI al, boolean performEdit,
333 Edit edit = new Edit(command, seqs, position, number,
334 al.getGapCharacter());
335 if (al.getHeight() == seqs.length)
338 edit.fullAlignmentHeight = true;
345 performEdit(edit, views);
350 * Overloaded method that accepts an Edit object with additional parameters.
357 final public void appendEdit(Edit edit, AlignmentI al,
358 boolean performEdit, AlignmentI[] views)
360 if (al.getHeight() == edit.seqs.length)
363 edit.fullAlignmentHeight = true;
370 performEdit(edit, views);
375 * Execute all the edit commands, starting at the given commandIndex
377 * @param commandIndex
380 public final void performEdit(int commandIndex, AlignmentI[] views)
382 ListIterator<Edit> iterator = edits.listIterator(commandIndex);
383 while (iterator.hasNext())
385 Edit edit = iterator.next();
386 performEdit(edit, views);
391 * Execute one edit command in all the specified alignment views
396 protected static void performEdit(Edit edit, AlignmentI[] views)
398 switch (edit.command)
416 // TODO:add deleteNuc for UNDO
418 // insertNuc(edits[e]);
426 final public void doCommand(AlignmentI[] views)
428 performEdit(0, views);
432 * Undo the stored list of commands, in reverse order.
435 final public void undoCommand(AlignmentI[] views)
437 ListIterator<Edit> iterator = edits.listIterator(edits.size());
438 while (iterator.hasPrevious())
440 Edit e = iterator.previous();
468 * Insert gap(s) in sequences as specified by the command, and adjust
473 final private static void insertGap(Edit command)
476 for (int s = 0; s < command.seqs.length; s++)
478 command.seqs[s].insertCharAt(command.position, command.number,
480 // System.out.println("pos: "+command.position+" number:
481 // "+command.number);
484 adjustAnnotations(command, true, false, null);
488 // final void insertNuc(Edit command)
491 // for (int s = 0; s < command.seqs.length; s++)
493 // System.out.println("pos: "+command.position+" number: "+command.number);
494 // command.seqs[s].insertCharAt(command.position, command.number,'A');
497 // adjustAnnotations(command, true, false, null);
501 * Delete gap(s) in sequences as specified by the command, and adjust
506 final static private void deleteGap(Edit command)
508 for (int s = 0; s < command.seqs.length; s++)
510 command.seqs[s].deleteChars(command.position,
511 command.position + command.number);
514 adjustAnnotations(command, false, false, null);
518 * Carry out a Cut action. The cut characters are saved in case Undo is
524 static void cut(Edit command, AlignmentI[] views)
526 boolean seqDeleted = false;
527 command.string = new char[command.seqs.length][];
529 for (int i = 0; i < command.seqs.length; i++)
531 final SequenceI sequence = command.seqs[i];
532 if (sequence.getLength() > command.position)
534 command.string[i] = sequence.getSequence(command.position,
535 command.position + command.number);
536 SequenceI oldds = sequence.getDatasetSequence();
537 if (command.oldds != null && command.oldds[i] != null)
539 // we are redoing an undone cut.
540 sequence.setDatasetSequence(null);
542 sequence.deleteChars(command.position,
543 command.position + command.number);
544 if (command.oldds != null && command.oldds[i] != null)
546 // oldds entry contains the cut dataset sequence.
547 sequence.setDatasetSequence(command.oldds[i]);
548 command.oldds[i] = oldds;
552 // modify the oldds if necessary
553 if (oldds != sequence.getDatasetSequence()
554 || sequence.getSequenceFeatures() != null)
556 if (command.oldds == null)
558 command.oldds = new SequenceI[command.seqs.length];
560 command.oldds[i] = oldds;
561 adjustFeatures(command, i,
562 sequence.findPosition(command.position),
563 sequence.findPosition(
564 command.position + command.number),
570 if (sequence.getLength() < 1)
572 command.al.deleteSequence(sequence);
577 adjustAnnotations(command, false, seqDeleted, views);
581 * Perform the given Paste command. This may be to add cut or copied sequences
582 * to an alignment, or to undo a 'Cut' action on a region of the alignment.
587 static void paste(Edit command, AlignmentI[] views)
591 boolean newDSWasNeeded;
592 int newstart, newend;
593 boolean seqWasDeleted = false;
594 int start = 0, end = 0;
596 for (int i = 0; i < command.seqs.length; i++)
599 newDSWasNeeded = command.oldds != null && command.oldds[i] != null;
600 if (command.seqs[i].getLength() < 1)
602 // ie this sequence was deleted, we need to
603 // readd it to the alignment
604 if (command.alIndex[i] < command.al.getHeight())
606 List<SequenceI> sequences;
607 synchronized (sequences = command.al.getSequences())
609 if (!(command.alIndex[i] < 0))
611 sequences.add(command.alIndex[i], command.seqs[i]);
617 command.al.addSequence(command.seqs[i]);
619 seqWasDeleted = true;
621 newstart = command.seqs[i].getStart();
622 newend = command.seqs[i].getEnd();
624 tmp = new StringBuffer();
625 tmp.append(command.seqs[i].getSequence());
626 // Undo of a delete does not replace original dataset sequence on to
627 // alignment sequence.
629 if (command.string != null && command.string[i] != null)
631 if (command.position >= tmp.length())
633 // This occurs if padding is on, and residues
634 // are removed from end of alignment
635 int length = command.position - tmp.length();
638 tmp.append(command.gapChar);
642 tmp.insert(command.position, command.string[i]);
643 for (int s = 0; s < command.string[i].length; s++)
645 if (jalview.schemes.ResidueProperties.aaIndex[command.string[i][s]] != 23)
650 start = command.seqs[i].findPosition(command.position);
651 end = command.seqs[i]
652 .findPosition(command.position + command.number);
654 if (command.seqs[i].getStart() == start)
664 command.string[i] = null;
667 command.seqs[i].setSequence(tmp.toString());
668 command.seqs[i].setStart(newstart);
669 command.seqs[i].setEnd(newend);
672 if (command.seqs[i].getDatasetSequence() != null)
677 ds = command.oldds[i];
681 // make a new DS sequence
682 // use new ds mechanism here
683 ds = new Sequence(command.seqs[i].getName(),
684 jalview.analysis.AlignSeq.extractGaps(
685 jalview.util.Comparison.GapChars,
686 command.seqs[i].getSequenceAsString()),
687 command.seqs[i].getStart(), command.seqs[i].getEnd());
688 ds.setDescription(command.seqs[i].getDescription());
690 if (command.oldds == null)
692 command.oldds = new SequenceI[command.seqs.length];
694 command.oldds[i] = command.seqs[i].getDatasetSequence();
695 command.seqs[i].setDatasetSequence(ds);
697 adjustFeatures(command, i, start, end, true);
700 adjustAnnotations(command, true, seqWasDeleted, views);
702 command.string = null;
705 static void replace(Edit command)
709 int start = command.position;
710 int end = command.number;
711 // TODO TUTORIAL - Fix for replacement with different length of sequence (or
713 // TODO Jalview 2.4 bugfix change to an aggregate command - original
714 // sequence string is cut, new string is pasted in.
715 command.number = start + command.string[0].length;
716 for (int i = 0; i < command.seqs.length; i++)
718 boolean newDSWasNeeded = command.oldds != null
719 && command.oldds[i] != null;
722 * cut addHistoryItem(new EditCommand("Cut Sequences", EditCommand.CUT,
723 * cut, sg.getStartRes(), sg.getEndRes()-sg.getStartRes()+1,
724 * viewport.alignment));
728 * then addHistoryItem(new EditCommand( "Add sequences",
729 * EditCommand.PASTE, sequences, 0, alignment.getWidth(), alignment) );
732 oldstring = command.seqs[i].getSequenceAsString();
733 tmp = new StringBuffer(oldstring.substring(0, start));
734 tmp.append(command.string[i]);
735 String nogaprep = jalview.analysis.AlignSeq.extractGaps(
736 jalview.util.Comparison.GapChars,
737 new String(command.string[i]));
738 int ipos = command.seqs[i].findPosition(start)
739 - command.seqs[i].getStart();
740 tmp.append(oldstring.substring(end));
741 command.seqs[i].setSequence(tmp.toString());
742 command.string[i] = oldstring.substring(start, end).toCharArray();
743 String nogapold = jalview.analysis.AlignSeq.extractGaps(
744 jalview.util.Comparison.GapChars,
745 new String(command.string[i]));
746 if (!nogaprep.toLowerCase().equals(nogapold.toLowerCase()))
750 SequenceI oldds = command.seqs[i].getDatasetSequence();
751 command.seqs[i].setDatasetSequence(command.oldds[i]);
752 command.oldds[i] = oldds;
756 if (command.oldds == null)
758 command.oldds = new SequenceI[command.seqs.length];
760 command.oldds[i] = command.seqs[i].getDatasetSequence();
761 SequenceI newds = new Sequence(
762 command.seqs[i].getDatasetSequence());
763 String fullseq, osp = newds.getSequenceAsString();
764 fullseq = osp.substring(0, ipos) + nogaprep
765 + osp.substring(ipos + nogaprep.length());
766 newds.setSequence(fullseq.toUpperCase());
767 // TODO: JAL-1131 ensure newly created dataset sequence is added to
769 // dataset sequences associated with the alignment.
770 // TODO: JAL-1131 fix up any annotation associated with new dataset
771 // sequence to ensure that original sequence/annotation relationships
773 command.seqs[i].setDatasetSequence(newds);
782 final static void adjustAnnotations(Edit command, boolean insert,
783 boolean modifyVisibility, AlignmentI[] views)
785 AlignmentAnnotation[] annotations = null;
787 if (modifyVisibility && !insert)
789 // only occurs if a sequence was added or deleted.
790 command.deletedAnnotationRows = new Hashtable<SequenceI, AlignmentAnnotation[]>();
792 if (command.fullAlignmentHeight)
794 annotations = command.al.getAlignmentAnnotation();
799 AlignmentAnnotation[] tmp;
800 for (int s = 0; s < command.seqs.length; s++)
802 if (modifyVisibility)
804 // Rows are only removed or added to sequence object.
808 tmp = command.seqs[s].getAnnotation();
811 int alen = tmp.length;
812 for (int aa = 0; aa < tmp.length; aa++)
814 if (!command.al.deleteAnnotation(tmp[aa]))
816 // strip out annotation not in the current al (will be put
817 // back on insert in all views)
822 command.seqs[s].setAlignmentAnnotation(null);
823 if (alen != tmp.length)
825 // save the non-null annotation references only
826 AlignmentAnnotation[] saved = new AlignmentAnnotation[alen];
827 for (int aa = 0, aapos = 0; aa < tmp.length; aa++)
831 saved[aapos++] = tmp[aa];
836 command.deletedAnnotationRows.put(command.seqs[s], saved);
837 // and then remove any annotation in the other views
838 for (int alview = 0; views != null
839 && alview < views.length; alview++)
841 if (views[alview] != command.al)
843 AlignmentAnnotation[] toremove = views[alview]
844 .getAlignmentAnnotation();
845 if (toremove == null || toremove.length == 0)
849 // remove any alignment annotation on this sequence that's
850 // on that alignment view.
851 for (int aa = 0; aa < toremove.length; aa++)
853 if (toremove[aa].sequenceRef == command.seqs[s])
855 views[alview].deleteAnnotation(toremove[aa]);
863 // save all the annotation
864 command.deletedAnnotationRows.put(command.seqs[s], tmp);
871 if (command.deletedAnnotationRows != null
872 && command.deletedAnnotationRows
873 .containsKey(command.seqs[s]))
875 AlignmentAnnotation[] revealed = command.deletedAnnotationRows
876 .get(command.seqs[s]);
877 command.seqs[s].setAlignmentAnnotation(revealed);
878 if (revealed != null)
880 for (int aa = 0; aa < revealed.length; aa++)
882 // iterate through al adding original annotation
883 command.al.addAnnotation(revealed[aa]);
885 for (int aa = 0; aa < revealed.length; aa++)
887 command.al.setAnnotationIndex(revealed[aa], aa);
889 // and then duplicate added annotation on every other alignment
891 for (int vnum = 0; views != null
892 && vnum < views.length; vnum++)
894 if (views[vnum] != command.al)
896 int avwidth = views[vnum].getWidth() + 1;
897 // duplicate in this view
898 for (int a = 0; a < revealed.length; a++)
900 AlignmentAnnotation newann = new AlignmentAnnotation(
902 command.seqs[s].addAlignmentAnnotation(newann);
903 newann.padAnnotation(avwidth);
904 views[vnum].addAnnotation(newann);
905 views[vnum].setAnnotationIndex(newann, a);
915 if (command.seqs[s].getAnnotation() == null)
922 annotations = command.seqs[s].getAnnotation();
926 tmp = new AlignmentAnnotation[aSize
927 + command.seqs[s].getAnnotation().length];
929 System.arraycopy(annotations, 0, tmp, 0, aSize);
931 System.arraycopy(command.seqs[s].getAnnotation(), 0, tmp, aSize,
932 command.seqs[s].getAnnotation().length);
936 aSize = annotations.length;
940 if (annotations == null)
947 command.deletedAnnotations = new Hashtable<String, Annotation[]>();
952 for (int a = 0; a < annotations.length; a++)
954 if (annotations[a].autoCalculated
955 || annotations[a].annotations == null)
962 aSize = annotations[a].annotations.length;
965 temp = new Annotation[aSize + command.number];
966 if (annotations[a].padGaps)
968 for (int aa = 0; aa < temp.length; aa++)
970 temp[aa] = new Annotation(command.gapChar + "", null, ' ', 0);
976 if (command.position < aSize)
978 if (command.position + command.number >= aSize)
984 tSize = aSize - command.number;
996 temp = new Annotation[tSize];
1001 if (command.position < annotations[a].annotations.length)
1003 System.arraycopy(annotations[a].annotations, 0, temp, 0,
1006 if (command.deletedAnnotations != null
1007 && command.deletedAnnotations
1008 .containsKey(annotations[a].annotationId))
1010 Annotation[] restore = command.deletedAnnotations
1011 .get(annotations[a].annotationId);
1013 System.arraycopy(restore, 0, temp, command.position,
1018 System.arraycopy(annotations[a].annotations, command.position,
1019 temp, command.position + command.number,
1020 aSize - command.position);
1024 if (command.deletedAnnotations != null
1025 && command.deletedAnnotations
1026 .containsKey(annotations[a].annotationId))
1028 Annotation[] restore = command.deletedAnnotations
1029 .get(annotations[a].annotationId);
1031 temp = new Annotation[annotations[a].annotations.length
1033 System.arraycopy(annotations[a].annotations, 0, temp, 0,
1034 annotations[a].annotations.length);
1035 System.arraycopy(restore, 0, temp,
1036 annotations[a].annotations.length, restore.length);
1040 temp = annotations[a].annotations;
1046 if (tSize != aSize || command.position < 2)
1048 int copylen = Math.min(command.position,
1049 annotations[a].annotations.length);
1052 System.arraycopy(annotations[a].annotations, 0, temp, 0,
1053 copylen); // command.position);
1056 Annotation[] deleted = new Annotation[command.number];
1057 if (copylen >= command.position)
1059 copylen = Math.min(command.number,
1060 annotations[a].annotations.length - command.position);
1063 System.arraycopy(annotations[a].annotations, command.position,
1064 deleted, 0, copylen); // command.number);
1068 command.deletedAnnotations.put(annotations[a].annotationId,
1070 if (annotations[a].annotations.length > command.position
1073 System.arraycopy(annotations[a].annotations,
1074 command.position + command.number, temp,
1075 command.position, annotations[a].annotations.length
1076 - command.position - command.number); // aSize
1081 int dSize = aSize - command.position;
1085 Annotation[] deleted = new Annotation[command.number];
1086 System.arraycopy(annotations[a].annotations, command.position,
1089 command.deletedAnnotations.put(annotations[a].annotationId,
1092 tSize = Math.min(annotations[a].annotations.length,
1094 temp = new Annotation[tSize];
1095 System.arraycopy(annotations[a].annotations, 0, temp, 0, tSize);
1099 temp = annotations[a].annotations;
1104 annotations[a].annotations = temp;
1108 final static void adjustFeatures(Edit command, int index, int i, int j,
1111 SequenceI seq = command.seqs[index];
1112 SequenceI sequence = seq.getDatasetSequence();
1113 if (sequence == null)
1120 if (command.editedFeatures != null
1121 && command.editedFeatures.containsKey(seq))
1123 sequence.setSequenceFeatures(command.editedFeatures.get(seq));
1129 SequenceFeature[] sf = sequence.getSequenceFeatures();
1136 SequenceFeature[] oldsf = new SequenceFeature[sf.length];
1140 for (int s = 0; s < sf.length; s++)
1142 SequenceFeature copy = new SequenceFeature(sf[s]);
1146 if (sf[s].getEnd() < i)
1151 if (sf[s].getBegin() > j)
1153 sf[s].setBegin(copy.getBegin() - cSize);
1154 sf[s].setEnd(copy.getEnd() - cSize);
1158 if (sf[s].getBegin() >= i)
1163 if (sf[s].getEnd() < j)
1165 sf[s].setEnd(j - 1);
1168 sf[s].setEnd(sf[s].getEnd() - (cSize));
1170 if (sf[s].getBegin() > sf[s].getEnd())
1172 sequence.deleteFeature(sf[s]);
1176 if (command.editedFeatures == null)
1178 command.editedFeatures = new Hashtable<SequenceI, SequenceFeature[]>();
1181 command.editedFeatures.put(seq, oldsf);
1186 * Returns the list of edit commands wrapped by this object.
1190 public List<Edit> getEdits()
1196 * Returns a map whose keys are the dataset sequences, and values their
1197 * aligned sequences before the command edit list was applied. The aligned
1198 * sequences are copies, which may be updated without affecting the originals.
1200 * The command holds references to the aligned sequences (after editing). If
1201 * the command is an 'undo',then the prior state is simply the aligned state.
1202 * Otherwise, we have to derive the prior state by working backwards through
1203 * the edit list to infer the aligned sequences before editing.
1205 * Note: an alternative solution would be to cache the 'before' state of each
1206 * edit, but this would be expensive in space in the common case that the
1207 * original is never needed (edits are not mirrored).
1210 * @throws IllegalStateException
1211 * on detecting an edit command of a type that can't be unwound
1213 public Map<SequenceI, SequenceI> priorState(boolean forUndo)
1215 Map<SequenceI, SequenceI> result = new HashMap<SequenceI, SequenceI>();
1216 if (getEdits() == null)
1222 for (Edit e : getEdits())
1224 for (SequenceI seq : e.getSequences())
1226 SequenceI ds = seq.getDatasetSequence();
1227 // SequenceI preEdit = result.get(ds);
1228 if (!result.containsKey(ds))
1231 * copy sequence including start/end (but don't use copy constructor
1232 * as we don't need annotations)
1234 SequenceI preEdit = new Sequence("", seq.getSequenceAsString(),
1235 seq.getStart(), seq.getEnd());
1236 preEdit.setDatasetSequence(ds);
1237 result.put(ds, preEdit);
1245 * Work backwards through the edit list, deriving the sequences before each
1246 * was applied. The final result is the sequence set before any edits.
1248 Iterator<Edit> editList = new ReverseListIterator<Edit>(getEdits());
1249 while (editList.hasNext())
1251 Edit oldEdit = editList.next();
1252 Action action = oldEdit.getAction();
1253 int position = oldEdit.getPosition();
1254 int number = oldEdit.getNumber();
1255 final char gap = oldEdit.getGapCharacter();
1256 for (SequenceI seq : oldEdit.getSequences())
1258 SequenceI ds = seq.getDatasetSequence();
1259 SequenceI preEdit = result.get(ds);
1260 if (preEdit == null)
1262 preEdit = new Sequence("", seq.getSequenceAsString(),
1263 seq.getStart(), seq.getEnd());
1264 preEdit.setDatasetSequence(ds);
1265 result.put(ds, preEdit);
1268 * 'Undo' this edit action on the sequence (updating the value in the
1273 if (action == Action.DELETE_GAP)
1275 preEdit.setSequence(new String(StringUtils.insertCharAt(
1276 preEdit.getSequence(), position, number, gap)));
1278 else if (action == Action.INSERT_GAP)
1280 preEdit.setSequence(new String(StringUtils.deleteChars(
1281 preEdit.getSequence(), position, position + number)));
1285 System.err.println("Can't undo edit action " + action);
1286 // throw new IllegalStateException("Can't undo edit action " +
1297 public SequenceI[] oldds;
1299 boolean fullAlignmentHeight = false;
1301 Hashtable<SequenceI, AlignmentAnnotation[]> deletedAnnotationRows;
1303 Hashtable<String, Annotation[]> deletedAnnotations;
1305 Hashtable<SequenceI, SequenceFeature[]> editedFeatures;
1317 int position, number;
1321 public Edit(Action command, SequenceI[] seqs, int position, int number,
1324 this.command = command;
1326 this.position = position;
1327 this.number = number;
1328 this.gapChar = gapChar;
1331 Edit(Action command, SequenceI[] seqs, int position, int number,
1334 this.gapChar = al.getGapCharacter();
1335 this.command = command;
1337 this.position = position;
1338 this.number = number;
1341 alIndex = new int[seqs.length];
1342 for (int i = 0; i < seqs.length; i++)
1344 alIndex[i] = al.findIndex(seqs[i]);
1347 fullAlignmentHeight = (al.getHeight() == seqs.length);
1350 Edit(Action command, SequenceI[] seqs, int position, int number,
1351 AlignmentI al, String replace)
1353 this.command = command;
1355 this.position = position;
1356 this.number = number;
1358 this.gapChar = al.getGapCharacter();
1359 string = new char[seqs.length][];
1360 for (int i = 0; i < seqs.length; i++)
1362 string[i] = replace.toCharArray();
1365 fullAlignmentHeight = (al.getHeight() == seqs.length);
1368 public SequenceI[] getSequences()
1373 public int getPosition()
1378 public Action getAction()
1383 public int getNumber()
1388 public char getGapCharacter()
1395 * Returns an iterator over the list of edit commands which traverses the list
1396 * either forwards or backwards.
1401 public Iterator<Edit> getEditIterator(boolean forwards)
1405 return getEdits().iterator();
1409 return new ReverseListIterator<Edit>(getEdits());