JFAL-1594 fix Undo bug; enum EditCommand.Action; basic JUnit
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 25 Nov 2014 16:55:09 +0000 (16:55 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 25 Nov 2014 16:55:09 +0000 (16:55 +0000)
16 files changed:
src/jalview/appletgui/APopupMenu.java
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/RedundancyPanel.java
src/jalview/appletgui/SeqPanel.java
src/jalview/commands/EditCommand.java
src/jalview/commands/RemoveGapColCommand.java
src/jalview/commands/RemoveGapsCommand.java
src/jalview/commands/SlideSequencesCommand.java
src/jalview/commands/TrimRegionCommand.java
src/jalview/datamodel/ColumnSelection.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/RedundancyPanel.java
src/jalview/gui/SeqPanel.java
test/jalview/commands/EditCommandTest.java [new file with mode: 0644]

index eba1200..98a4a1c 100644 (file)
  */
 package jalview.appletgui;
 
-import java.util.*;
-
-import java.awt.*;
-import java.awt.event.*;
-
-import jalview.analysis.*;
-import jalview.commands.*;
-import jalview.datamodel.*;
-import jalview.schemes.*;
-import jalview.util.MessageManager;
-import jalview.util.UrlLink;
+import jalview.analysis.AAFrequency;
+import jalview.analysis.Conservation;
+import jalview.commands.ChangeCaseCommand;
+import jalview.commands.EditCommand;
+import jalview.commands.EditCommand.Action;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
 import jalview.io.AppletFormatAdapter;
 import jalview.io.SequenceAnnotationReport;
+import jalview.schemes.Blosum62ColourScheme;
+import jalview.schemes.BuriedColourScheme;
+import jalview.schemes.ClustalxColourScheme;
+import jalview.schemes.HelixColourScheme;
+import jalview.schemes.HydrophobicColourScheme;
+import jalview.schemes.NucleotideColourScheme;
+import jalview.schemes.PIDColourScheme;
+import jalview.schemes.ResidueProperties;
+import jalview.schemes.StrandColourScheme;
+import jalview.schemes.TaylorColourScheme;
+import jalview.schemes.TurnColourScheme;
+import jalview.schemes.ZappoColourScheme;
+import jalview.util.MessageManager;
+import jalview.util.UrlLink;
+
+import java.awt.CheckboxMenuItem;
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuItem;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.util.Vector;
 
 public class APopupMenu extends java.awt.PopupMenu implements
         ActionListener, ItemListener
@@ -549,7 +573,9 @@ public class APopupMenu extends java.awt.PopupMenu implements
       if (sg != null)
       {
         if (seq == null)
+        {
           seq = (Sequence) sg.getSequenceAt(0);
+        }
 
         EditNameDialog dialog = new EditNameDialog(seq.getSequenceAsString(
                 sg.getStartRes(), sg.getEndRes() + 1), null,
@@ -560,7 +586,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
         if (dialog.accept)
         {
           EditCommand editCommand = new EditCommand(MessageManager.getString("label.edit_sequences"),
-                  EditCommand.REPLACE, dialog.getName().replace(' ',
+                  Action.REPLACE, dialog.getName().replace(' ',
                           ap.av.getGapCharacter()),
                   sg.getSequencesAsArray(ap.av.getHiddenRepSequences()),
                   sg.getStartRes(), sg.getEndRes() + 1,
@@ -742,11 +768,15 @@ public class APopupMenu extends java.awt.PopupMenu implements
       PDBEntry entry = (PDBEntry) seq.getPDBId().firstElement();
 
       if (ap.av.applet.jmolAvailable)
+      {
         new jalview.appletgui.AppletJmol(entry, new Sequence[]
         { seq }, null, ap, AppletFormatAdapter.URL);
+      }
       else
+      {
         new MCview.AppletPDBViewer(entry, new Sequence[]
         { seq }, null, ap, AppletFormatAdapter.URL);
+      }
 
     }
     else
index 34ec2cf..ed64215 100644 (file)
@@ -27,6 +27,7 @@ import jalview.api.SequenceStructureBinding;
 import jalview.bin.JalviewLite;
 import jalview.commands.CommandI;
 import jalview.commands.EditCommand;
+import jalview.commands.EditCommand.Action;
 import jalview.commands.OrderCommand;
 import jalview.commands.RemoveGapColCommand;
 import jalview.commands.RemoveGapsCommand;
@@ -1833,7 +1834,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     }
 
     // !newAlignment
-    addHistoryItem(new EditCommand(MessageManager.getString("label.add_sequences"), EditCommand.PASTE,
+    addHistoryItem(new EditCommand(
+            MessageManager.getString("label.add_sequences"), Action.PASTE,
             seqs, 0, viewport.getAlignment().getWidth(),
             viewport.getAlignment()));
 
@@ -1883,8 +1885,9 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     /*
      * //ADD HISTORY ITEM
      */
-    addHistoryItem(new EditCommand(MessageManager.getString("label.cut_sequences"), EditCommand.CUT, cut,
-            sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
+    addHistoryItem(new EditCommand(
+            MessageManager.getString("label.cut_sequences"), Action.CUT,
+            cut, sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
             viewport.getAlignment()));
 
     viewport.setSelectionGroup(null);
index 1547862..8e364f0 100644 (file)
  */
 package jalview.appletgui;
 
-import java.util.*;
-import java.util.List;
-import java.awt.*;
-import java.awt.event.*;
-
 import jalview.analysis.AlignSeq;
-import jalview.commands.*;
-import jalview.datamodel.*;
+import jalview.commands.CommandI;
+import jalview.commands.EditCommand;
+import jalview.commands.EditCommand.Action;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
 import jalview.util.MessageManager;
 
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.AdjustmentEvent;
+import java.awt.event.AdjustmentListener;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+import java.util.Vector;
+
 public class RedundancyPanel extends SliderPanel implements Runnable,
         WindowListener
 {
@@ -197,7 +207,7 @@ public class RedundancyPanel extends SliderPanel implements Runnable,
       }
 
       EditCommand cut = new EditCommand(MessageManager.getString("action.remove_redundancy"),
-              EditCommand.CUT, deleted, 0, width, ap.av.getAlignment());
+              Action.CUT, deleted, 0, width, ap.av.getAlignment());
       AlignmentI alignment = ap.av.getAlignment();
       for (int i = 0; i < del.size(); i++)
       {
index de4d979..592fd4f 100644 (file)
  */
 package jalview.appletgui;
 
-import java.util.*;
-
-import java.awt.*;
-import java.awt.event.*;
-
-import jalview.commands.*;
-import jalview.datamodel.*;
-import jalview.schemes.*;
+import jalview.commands.EditCommand;
+import jalview.commands.EditCommand.Action;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.SearchResults;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.schemes.ResidueProperties;
 import jalview.structure.SelectionSource;
 import jalview.structure.SequenceListener;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 
+import java.awt.BorderLayout;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Panel;
+import java.awt.Point;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.util.Vector;
+
 public class SeqPanel extends Panel implements MouseMotionListener,
         MouseListener, SequenceListener
 {
@@ -147,7 +159,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
 
   void setCursorPosition()
   {
-    SequenceI sequence = (Sequence) av.getAlignment().getSequenceAt(
+    SequenceI sequence = av.getAlignment().getSequenceAt(
             seqCanvas.cursorY);
 
     seqCanvas.cursorX = sequence.findIndex(getKeyboardNo1()) - 1;
@@ -240,7 +252,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
 
   void setSelectionAreaAtCursor(boolean topLeft)
   {
-    SequenceI sequence = (Sequence) av.getAlignment().getSequenceAt(
+    SequenceI sequence = av.getAlignment().getSequenceAt(
             seqCanvas.cursorY);
 
     if (av.getSelectionGroup() != null)
@@ -648,7 +660,9 @@ public class SeqPanel extends Panel implements MouseMotionListener,
   {
     String tmp = sequence.hashCode() + index + "";
     if (lastMessage == null || !lastMessage.equals(tmp))
+    {
       ssm.mouseOverSequence(sequence, index, pos, av);
+    }
 
     lastMessage = tmp;
   }
@@ -698,7 +712,9 @@ public class SeqPanel extends Panel implements MouseMotionListener,
 
     int respos = sequence.findPosition(res);
     if (ssm != null)
+    {
       mouseOverSequence(sequence, res, respos);
+    }
 
     StringBuffer text = new StringBuffer("Sequence " + (seq + 1) + " ID: "
             + sequence.getName());
@@ -813,7 +829,9 @@ public class SeqPanel extends Panel implements MouseMotionListener,
                         .containsKey(features[i].featureGroup)
                 && !((Boolean) seqCanvas.fr.featureGroups
                         .get(features[i].featureGroup)).booleanValue())
+        {
           continue;
+        }
 
         if ((features[i].getBegin() <= res)
                 && (features[i].getEnd() >= res))
@@ -938,7 +956,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     {
       if (av.isHiddenRepSequence(seq))
       {
-        sg = (SequenceGroup) av.getRepresentedSequences(seq);
+        sg = av.getRepresentedSequences(seq);
         groupEditing = true;
       }
     }
@@ -1164,7 +1182,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         }
         else
         {
-          editCommand.appendEdit(EditCommand.INSERT_GAP, groupSeqs,
+          editCommand.appendEdit(Action.INSERT_GAP, groupSeqs,
                   startres, startres - lastres, av.getAlignment(), true);
         }
       }
@@ -1180,7 +1198,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         }
         else
         {
-          editCommand.appendEdit(EditCommand.DELETE_GAP, groupSeqs,
+          editCommand.appendEdit(Action.DELETE_GAP, groupSeqs,
                   startres, lastres - startres, av.getAlignment(), true);
         }
 
@@ -1202,7 +1220,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         }
         else
         {
-          editCommand.appendEdit(EditCommand.INSERT_GAP, new SequenceI[]
+          editCommand.appendEdit(Action.INSERT_GAP, new SequenceI[]
           { seq }, lastres, startres - lastres, av.getAlignment(), true);
         }
       }
@@ -1237,7 +1255,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
 
           if (max > 0)
           {
-            editCommand.appendEdit(EditCommand.DELETE_GAP, new SequenceI[]
+            editCommand.appendEdit(Action.DELETE_GAP, new SequenceI[]
             { seq }, startres, max, av.getAlignment(), true);
           }
         }
@@ -1273,10 +1291,10 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       }
     }
 
-    editCommand.appendEdit(EditCommand.DELETE_GAP, seq, blankColumn, 1,
+    editCommand.appendEdit(Action.DELETE_GAP, seq, blankColumn, 1,
             av.getAlignment(), true);
 
-    editCommand.appendEdit(EditCommand.INSERT_GAP, seq, j, 1,
+    editCommand.appendEdit(Action.INSERT_GAP, seq, j, 1,
             av.getAlignment(), true);
 
   }
@@ -1284,10 +1302,10 @@ public class SeqPanel extends Panel implements MouseMotionListener,
   void deleteChar(int j, SequenceI[] seq, int fixedColumn)
   {
 
-    editCommand.appendEdit(EditCommand.DELETE_GAP, seq, j, 1,
+    editCommand.appendEdit(Action.DELETE_GAP, seq, j, 1,
             av.getAlignment(), true);
 
-    editCommand.appendEdit(EditCommand.INSERT_GAP, seq, fixedColumn, 1,
+    editCommand.appendEdit(Action.INSERT_GAP, seq, fixedColumn, 1,
             av.getAlignment(), true);
   }
 
@@ -1312,7 +1330,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       return;
     }
 
-    SequenceI sequence = (Sequence) av.getAlignment().getSequenceAt(seq);
+    SequenceI sequence = av.getAlignment().getSequenceAt(seq);
 
     if (sequence == null || res > sequence.getLength())
     {
index 5c698a8..82de3b2 100644 (file)
@@ -27,8 +27,10 @@ import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 
+import java.util.ArrayList;
 import java.util.Hashtable;
 import java.util.List;
+import java.util.ListIterator;
 
 /**
  * 
@@ -54,19 +56,12 @@ import java.util.List;
  */
 public class EditCommand implements CommandI
 {
-  public static final int INSERT_GAP = 0;
-
-  public static final int DELETE_GAP = 1;
-
-  public static final int CUT = 2;
-
-  public static final int PASTE = 3;
-
-  public static final int REPLACE = 4;
-
-  public static final int INSERT_NUC = 5;
+  public enum Action
+  {
+    INSERT_GAP, DELETE_GAP, CUT, PASTE, REPLACE, INSERT_NUC
+  };
 
-  Edit[] edits;
+  private List<Edit> edits = new ArrayList<Edit>();
 
   String description;
 
@@ -79,32 +74,75 @@ public class EditCommand implements CommandI
     this.description = description;
   }
 
-  public EditCommand(String description, int command, SequenceI[] seqs,
+  public EditCommand(String description, Action command, SequenceI[] seqs,
           int position, int number, AlignmentI al)
   {
     this.description = description;
-    if (command == CUT || command == PASTE)
+    if (command == Action.CUT || command == Action.PASTE)
     {
-      edits = new Edit[]
-      { new Edit(command, seqs, position, number, al) };
+      setEdit(new Edit(command, seqs, position, number, al));
     }
 
     performEdit(0, null);
   }
 
-  public EditCommand(String description, int command, String replace,
+  public EditCommand(String description, Action command, String replace,
           SequenceI[] seqs, int position, int number, AlignmentI al)
   {
     this.description = description;
-    if (command == REPLACE)
+    if (command == Action.REPLACE)
     {
-      edits = new Edit[]
-      { new Edit(command, seqs, position, number, al, replace) };
+      setEdit(new Edit(command, seqs, position, number, al, replace));
     }
 
     performEdit(0, null);
   }
 
+  /**
+   * Set the list of edits to the specified item (only).
+   * 
+   * @param e
+   */
+  protected void setEdit(Edit e)
+  {
+    edits.clear();
+    edits.add(e);
+  }
+
+  /**
+   * Add the given edit command to the stored list of commands.
+   * 
+   * @param e
+   */
+  protected void addEdit(Edit e)
+  {
+    edits.add(e);
+  }
+
+  /**
+   * Clear the list of stored edit commands.
+   * 
+   */
+  protected void clearEdits()
+  {
+    edits.clear();
+  }
+
+  /**
+   * Returns the i'th stored Edit command.
+   * 
+   * @param i
+   * @return
+   */
+  protected Edit getEdit(int i)
+  {
+    if (i >= 0 && i < edits.size())
+    {
+      return edits.get(i);
+    }
+    return null;
+  }
+
   @Override
   final public String getDescription()
   {
@@ -114,12 +152,17 @@ public class EditCommand implements CommandI
   @Override
   public int getSize()
   {
-    return edits == null ? 0 : edits.length;
+    return edits.size();
   }
 
+  /**
+   * Return the alignment for the first edit (or null if no edit).
+   * 
+   * @return
+   */
   final public AlignmentI getAlignment()
   {
-    return edits[0].al;
+    return (edits.isEmpty() ? null : edits.get(0).al);
   }
 
   /**
@@ -135,7 +178,8 @@ public class EditCommand implements CommandI
    * @param al
    * @param performEdit
    */
-  final public void appendEdit(int command, SequenceI[] seqs, int position,
+  final public void appendEdit(Action command, SequenceI[] seqs,
+          int position,
           int number, AlignmentI al, boolean performEdit)
   {
     appendEdit(command, seqs, position, number, al, performEdit, null);
@@ -153,7 +197,8 @@ public class EditCommand implements CommandI
    * @param performEdit
    * @param views
    */
-  final public void appendEdit(int command, SequenceI[] seqs, int position,
+  final public void appendEdit(Action command, SequenceI[] seqs,
+          int position,
           int number, AlignmentI al, boolean performEdit, AlignmentI[] views)
   {
     Edit edit = new Edit(command, seqs, position, number,
@@ -164,52 +209,62 @@ public class EditCommand implements CommandI
       edit.fullAlignmentHeight = true;
     }
 
-    if (edits != null)
-    {
-      Edit[] temp = new Edit[edits.length + 1];
-      System.arraycopy(edits, 0, temp, 0, edits.length);
-      edits = temp;
-      edits[edits.length - 1] = edit;
-    }
-    else
-    {
-      edits = new Edit[]
-      { edit };
-    }
+    edits.add(edit);
 
     if (performEdit)
     {
-      performEdit(edits.length - 1, views);
+      performEdit(edit, views);
     }
   }
 
+  /**
+   * Execute all the edit commands, starting at the given commandIndex
+   * 
+   * @param commandIndex
+   * @param views
+   */
   final void performEdit(int commandIndex, AlignmentI[] views)
   {
-    int eSize = edits.length;
-    for (int e = commandIndex; e < eSize; e++)
+    ListIterator<Edit> iterator = edits.listIterator(commandIndex);
+    while (iterator.hasNext())
     {
-      switch (edits[e].command)
-      {
-      case INSERT_GAP:
-        insertGap(edits[e]);
-        break;
-      case DELETE_GAP:
-        deleteGap(edits[e]);
-        break;
-      case CUT:
-        cut(edits[e], views);
-        break;
-      case PASTE:
-        paste(edits[e], views);
-        break;
-      case REPLACE:
-        replace(edits[e]);
-        break;
+      Edit edit = iterator.next();
+      performEdit(edit, views);
+    }
+  }
+
+  /**
+   * Execute one edit command in all the specified alignment views
+   * 
+   * @param edit
+   * @param views
+   */
+  protected void performEdit(Edit edit, AlignmentI[] views)
+  {
+    switch (edit.command)
+    {
+    case INSERT_GAP:
+      insertGap(edit);
+      break;
+    case DELETE_GAP:
+      deleteGap(edit);
+      break;
+    case CUT:
+      cut(edit, views);
+      break;
+    case PASTE:
+      paste(edit, views);
+      break;
+    case REPLACE:
+      replace(edit);
+      break;
+    case INSERT_NUC:
       // TODO:add deleteNuc for UNDO
       // case INSERT_NUC:
       // insertNuc(edits[e]);
-      // break;
-      }
+      break;
+    default:
+      break;
     }
   }
 
@@ -219,32 +274,49 @@ public class EditCommand implements CommandI
     performEdit(0, views);
   }
 
+  /**
+   * Undo the stored list of commands, in reverse order.
+   */
   @Override
   final public void undoCommand(AlignmentI[] views)
   { 
-    for(Edit e : edits){
-       switch (e.command)
-        {
-        case INSERT_GAP:
-          deleteGap(e);
-          break;
-        case DELETE_GAP:
-          insertGap(e);
-          break;
-        case CUT:
-          paste(e, views);
-          break;
-        case PASTE:
-          cut(e, views);
-          break;
-        case REPLACE:
-          replace(e);
-          break;
-        }
+    ListIterator<Edit> iterator = edits.listIterator(edits.size());
+    while (iterator.hasPrevious())
+    {
+      Edit e = iterator.previous();
+      switch (e.command)
+      {
+      case INSERT_GAP:
+        deleteGap(e);
+        break;
+      case DELETE_GAP:
+        insertGap(e);
+        break;
+      case CUT:
+        paste(e, views);
+        break;
+      case PASTE:
+        cut(e, views);
+        break;
+      case REPLACE:
+        replace(e);
+        break;
+      case INSERT_NUC:
+        // not implemented
+        break;
+      default:
+        break;
+      }
     }
   }
 
-  final void insertGap(Edit command)
+  /**
+   * Insert gap(s) in sequences as specified by the command, and adjust
+   * annotations.
+   * 
+   * @param command
+   */
+  final private void insertGap(Edit command)
   {
 
     for (int s = 0; s < command.seqs.length; s++)
@@ -270,7 +342,13 @@ public class EditCommand implements CommandI
   // adjustAnnotations(command, true, false, null);
   // }
 
-  final void deleteGap(Edit command)
+  /**
+   * Delete gap(s) in sequences as specified by the command, and adjust
+   * annotations.
+   * 
+   * @param command
+   */
+  final private void deleteGap(Edit command)
   {
     for (int s = 0; s < command.seqs.length; s++)
     {
@@ -281,6 +359,13 @@ public class EditCommand implements CommandI
     adjustAnnotations(command, false, false, null);
   }
 
+  /**
+   * Carry out a Cut action. The cut characters are saved in case Undo is
+   * requested.
+   * 
+   * @param command
+   * @param views
+   */
   void cut(Edit command, AlignmentI[] views)
   {
     boolean seqDeleted = false;
@@ -288,29 +373,30 @@ public class EditCommand implements CommandI
 
     for (int i = 0; i < command.seqs.length; i++)
     {
-      if (command.seqs[i].getLength() > command.position)
+      final SequenceI sequence = command.seqs[i];
+      if (sequence.getLength() > command.position)
       {
-        command.string[i] = command.seqs[i].getSequence(command.position,
+        command.string[i] = sequence.getSequence(command.position,
                 command.position + command.number);
-        SequenceI oldds = command.seqs[i].getDatasetSequence();
+        SequenceI oldds = sequence.getDatasetSequence();
         if (command.oldds != null && command.oldds[i] != null)
         {
           // we are redoing an undone cut.
-          command.seqs[i].setDatasetSequence(null);
+          sequence.setDatasetSequence(null);
         }
-        command.seqs[i].deleteChars(command.position, command.position
+        sequence.deleteChars(command.position, command.position
                 + command.number);
         if (command.oldds != null && command.oldds[i] != null)
         {
           // oldds entry contains the cut dataset sequence.
-          command.seqs[i].setDatasetSequence(command.oldds[i]);
+          sequence.setDatasetSequence(command.oldds[i]);
           command.oldds[i] = oldds;
         }
         else
         {
           // modify the oldds if necessary
-          if (oldds != command.seqs[i].getDatasetSequence()
-                  || command.seqs[i].getSequenceFeatures() != null)
+          if (oldds != sequence.getDatasetSequence()
+                  || sequence.getSequenceFeatures() != null)
           {
             if (command.oldds == null)
             {
@@ -320,16 +406,16 @@ public class EditCommand implements CommandI
             adjustFeatures(
                     command,
                     i,
-                    command.seqs[i].findPosition(command.position),
-                    command.seqs[i].findPosition(command.position
+                    sequence.findPosition(command.position),
+                    sequence.findPosition(command.position
                             + command.number), false);
           }
         }
       }
 
-      if (command.seqs[i].getLength() < 1)
+      if (sequence.getLength() < 1)
       {
-        command.al.deleteSequence(command.seqs[i]);
+        command.al.deleteSequence(sequence);
         seqDeleted = true;
       }
     }
@@ -337,6 +423,13 @@ public class EditCommand implements CommandI
     adjustAnnotations(command, false, seqDeleted, views);
   }
 
+  /**
+   * Perform the given Paste command. This may be to add cut or copied sequences
+   * to an alignment, or to undo a 'Cut' action on a region of the alignment.
+   * 
+   * @param command
+   * @param views
+   */
   void paste(Edit command, AlignmentI[] views)
   {
     StringBuffer tmp;
@@ -540,7 +633,7 @@ public class EditCommand implements CommandI
     if (modifyVisibility && !insert)
     {
       // only occurs if a sequence was added or deleted.
-      command.deletedAnnotationRows = new Hashtable();
+      command.deletedAnnotationRows = new Hashtable<SequenceI, AlignmentAnnotation[]>();
     }
     if (command.fullAlignmentHeight)
     {
@@ -624,7 +717,7 @@ public class EditCommand implements CommandI
                     && command.deletedAnnotationRows
                             .containsKey(command.seqs[s]))
             {
-              AlignmentAnnotation[] revealed = (AlignmentAnnotation[]) command.deletedAnnotationRows
+              AlignmentAnnotation[] revealed = command.deletedAnnotationRows
                       .get(command.seqs[s]);
               command.seqs[s].setAlignmentAnnotation(revealed);
               if (revealed != null)
@@ -695,7 +788,7 @@ public class EditCommand implements CommandI
 
     if (!insert)
     {
-      command.deletedAnnotations = new Hashtable();
+      command.deletedAnnotations = new Hashtable<String, Annotation[]>();
     }
 
     int aSize;
@@ -758,7 +851,7 @@ public class EditCommand implements CommandI
                   && command.deletedAnnotations
                           .containsKey(annotations[a].annotationId))
           {
-            Annotation[] restore = (Annotation[]) command.deletedAnnotations
+            Annotation[] restore = command.deletedAnnotations
                     .get(annotations[a].annotationId);
 
             System.arraycopy(restore, 0, temp, command.position,
@@ -776,7 +869,7 @@ public class EditCommand implements CommandI
                   && command.deletedAnnotations
                           .containsKey(annotations[a].annotationId))
           {
-            Annotation[] restore = (Annotation[]) command.deletedAnnotations
+            Annotation[] restore = command.deletedAnnotations
                     .get(annotations[a].annotationId);
 
             temp = new Annotation[annotations[a].annotations.length
@@ -871,7 +964,7 @@ public class EditCommand implements CommandI
       if (command.editedFeatures != null
               && command.editedFeatures.containsKey(seq))
       {
-        sequence.setSequenceFeatures((SequenceFeature[]) command.editedFeatures
+        sequence.setSequenceFeatures(command.editedFeatures
                 .get(seq));
       }
 
@@ -927,7 +1020,7 @@ public class EditCommand implements CommandI
 
     if (command.editedFeatures == null)
     {
-      command.editedFeatures = new Hashtable();
+      command.editedFeatures = new Hashtable<SequenceI, SequenceFeature[]>();
     }
 
     command.editedFeatures.put(seq, oldsf);
@@ -940,15 +1033,15 @@ public class EditCommand implements CommandI
 
     boolean fullAlignmentHeight = false;
 
-    Hashtable deletedAnnotationRows;
+    Hashtable<SequenceI, AlignmentAnnotation[]> deletedAnnotationRows;
 
-    Hashtable deletedAnnotations;
+    Hashtable<String, Annotation[]> deletedAnnotations;
 
-    Hashtable editedFeatures;
+    Hashtable<SequenceI, SequenceFeature[]> editedFeatures;
 
     AlignmentI al;
 
-    int command;
+    Action command;
 
     char[][] string;
 
@@ -960,7 +1053,7 @@ public class EditCommand implements CommandI
 
     char gapChar;
 
-    Edit(int command, SequenceI[] seqs, int position, int number,
+    Edit(Action command, SequenceI[] seqs, int position, int number,
             char gapChar)
     {
       this.command = command;
@@ -970,7 +1063,7 @@ public class EditCommand implements CommandI
       this.gapChar = gapChar;
     }
 
-    Edit(int command, SequenceI[] seqs, int position, int number,
+    Edit(Action command, SequenceI[] seqs, int position, int number,
             AlignmentI al)
     {
       this.gapChar = al.getGapCharacter();
@@ -989,7 +1082,7 @@ public class EditCommand implements CommandI
       fullAlignmentHeight = (al.getHeight() == seqs.length);
     }
 
-    Edit(int command, SequenceI[] seqs, int position, int number,
+    Edit(Action command, SequenceI[] seqs, int position, int number,
             AlignmentI al, String replace)
     {
       this.command = command;
index 6172ce8..ac93d4e 100644 (file)
@@ -39,7 +39,8 @@ package jalview.commands;
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-import jalview.datamodel.*;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
 
 public class RemoveGapColCommand extends EditCommand
 {
@@ -55,7 +56,7 @@ public class RemoveGapColCommand extends EditCommand
     int startCol = -1, endCol = -1;
     columnsDeleted = 0;
 
-    edits = new Edit[0];
+    clearEdits();
 
     boolean delete = true;
     for (int i = start; i <= end; i++)
@@ -86,7 +87,8 @@ public class RemoveGapColCommand extends EditCommand
 
       if (!delete && startCol > -1)
       {
-        this.appendEdit(DELETE_GAP, seqs, startCol - columnsDeleted, endCol
+        this.appendEdit(Action.DELETE_GAP, seqs, startCol - columnsDeleted,
+                endCol
                 - startCol, al, false, null);
 
         columnsDeleted += (endCol - startCol);
@@ -100,7 +102,8 @@ public class RemoveGapColCommand extends EditCommand
       // This is for empty columns at the
       // end of the alignment
 
-      this.appendEdit(DELETE_GAP, seqs, startCol - columnsDeleted, end
+      this.appendEdit(Action.DELETE_GAP, seqs, startCol - columnsDeleted,
+              end
               - startCol + 1, al, false, null);
 
       columnsDeleted += (end - startCol + 1);
index 2e8d744..60d09f7 100644 (file)
@@ -39,7 +39,8 @@ package jalview.commands;
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-import jalview.datamodel.*;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
 
 public class RemoveGapsCommand extends EditCommand
 {
@@ -74,7 +75,7 @@ public class RemoveGapsCommand extends EditCommand
 
     int j, jSize;
 
-    edits = new Edit[0];
+    clearEdits();
 
     boolean delete = true;
     char[] sequence;
@@ -108,7 +109,7 @@ public class RemoveGapsCommand extends EditCommand
 
         if (!delete && startCol > -1)
         {
-          this.appendEdit(DELETE_GAP, new SequenceI[]
+          this.appendEdit(Action.DELETE_GAP, new SequenceI[]
           { seqs[s] }, start + startCol - deletedCols, endCol - startCol,
                   al, false, null);
 
@@ -119,7 +120,7 @@ public class RemoveGapsCommand extends EditCommand
       }
       if (delete && startCol > -1)
       {
-        this.appendEdit(DELETE_GAP, new SequenceI[]
+        this.appendEdit(Action.DELETE_GAP, new SequenceI[]
         { seqs[s] }, start + startCol - deletedCols, jSize - startCol, al,
                 false, null);
       }
index 1ad3d9e..382085c 100644 (file)
@@ -20,7 +20,7 @@
  */
 package jalview.commands;
 
-import jalview.datamodel.*;
+import jalview.datamodel.SequenceI;
 
 public class SlideSequencesCommand extends EditCommand
 {
@@ -37,21 +37,29 @@ public class SlideSequencesCommand extends EditCommand
     for (i = 0; i < lSize; i++)
     {
       for (j = 0; j < slideSize; j++)
+      {
         if (!jalview.util.Comparison.isGap(seqsLeft[i].getCharAt(j)))
         {
           gapsInsertedBegin = true;
           break;
         }
+      }
     }
 
+    Edit e = null;
+
     if (!gapsInsertedBegin)
-      edits = new Edit[]
-      { new Edit(DELETE_GAP, seqsLeft, 0, slideSize, gapChar) };
+    {
+      e = new Edit(Action.DELETE_GAP, seqsLeft, 0, slideSize, gapChar);
+      setEdit(e);
+    }
     else
-      edits = new Edit[]
-      { new Edit(INSERT_GAP, seqsRight, 0, slideSize, gapChar) };
+    {
+      e = new Edit(Action.INSERT_GAP, seqsRight, 0, slideSize, gapChar);
+      setEdit(e);
+    }
 
-    performEdit(0, null);
+    performEdit(e, null);
   }
 
   public boolean getGapsInsertedBegin()
@@ -63,12 +71,12 @@ public class SlideSequencesCommand extends EditCommand
   {
     boolean same = false;
 
-    if (command.edits[0].seqs.length == edits[0].seqs.length)
+    if (command.getEdit(0).seqs.length == getEdit(0).seqs.length)
     {
       same = true;
-      for (int i = 0; i < command.edits[0].seqs.length; i++)
+      for (int i = 0; i < command.getEdit(0).seqs.length; i++)
       {
-        if (edits[0].seqs[i] != command.edits[0].seqs[i])
+        if (getEdit(0).seqs[i] != command.getEdit(0).seqs[i])
         {
           same = false;
         }
@@ -77,10 +85,7 @@ public class SlideSequencesCommand extends EditCommand
 
     if (same)
     {
-      Edit[] temp = new Edit[command.edits.length + 1];
-      System.arraycopy(command.edits, 0, temp, 0, command.edits.length);
-      command.edits = temp;
-      command.edits[command.edits.length - 1] = edits[0];
+      command.addEdit(getEdit(0));
     }
 
     return same;
index a757d1a..ebbe827 100644 (file)
  */
 package jalview.commands;
 
-import java.util.*;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.util.ShiftList;
 
-import jalview.datamodel.*;
-import jalview.util.*;
+import java.util.List;
 
 public class TrimRegionCommand extends EditCommand
 {
@@ -39,7 +42,7 @@ public class TrimRegionCommand extends EditCommand
 
   SequenceGroup selectionGroup;
 
-  Vector deletedHiddenColumns;
+  List<int[]> deletedHiddenColumns;
 
   int columnsDeleted;
 
@@ -59,8 +62,7 @@ public class TrimRegionCommand extends EditCommand
 
       columnsDeleted = column;
 
-      edits = new Edit[]
-      { new Edit(CUT, seqs, 0, column, al) };
+      setEdit(new Edit(Action.CUT, seqs, 0, column, al));
     }
     else if (command.equalsIgnoreCase(TRIM_RIGHT))
     {
@@ -72,17 +74,16 @@ public class TrimRegionCommand extends EditCommand
 
       columnsDeleted = width - 1;
 
-      edits = new Edit[]
-      { new Edit(CUT, seqs, column + 1, width, al) };
+      setEdit(new Edit(Action.CUT, seqs, column + 1, width, al));
     }
 
     // We need to keep a record of the sequence start
     // in order to restore the state after a redo
-    int i, isize = edits[0].seqs.length;
+    int i, isize = getEdit(0).seqs.length;
     start = new int[isize];
     for (i = 0; i < isize; i++)
     {
-      start[i] = edits[0].seqs[i].getStart();
+      start[i] = getEdit(0).seqs[i].getStart();
     }
 
     performEdit(0, null);
@@ -160,7 +161,7 @@ public class TrimRegionCommand extends EditCommand
       int[] region;
       for (int i = 0; i < deletedHiddenColumns.size(); i++)
       {
-        region = (int[]) deletedHiddenColumns.elementAt(i);
+        region = deletedHiddenColumns.get(i);
         colSel.hideColumns(region[0], region[1]);
       }
     }
index 35d467a..f414d13 100644 (file)
  */
 package jalview.datamodel;
 
-import java.util.*;
+import jalview.util.ShiftList;
 
-import jalview.util.*;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Vector;
 
 /**
  * NOTE: Columns are zero based.
@@ -186,9 +189,9 @@ public class ColumnSelection
    * @param left
    *          shift in edit (+ve for removal, or -ve for inserts)
    */
-  public Vector compensateForEdit(int start, int change)
+  public List<int[]> compensateForEdit(int start, int change)
   {
-    Vector deletedHiddenColumns = null;
+    List<int[]> deletedHiddenColumns = null;
     for (int i = 0; i < size(); i++)
     {
       int temp = columnAt(i);
@@ -201,14 +204,14 @@ public class ColumnSelection
 
     if (hiddenColumns != null)
     {
-      deletedHiddenColumns = new Vector();
+      deletedHiddenColumns = new ArrayList<int[]>();
       int hSize = hiddenColumns.size();
       for (int i = 0; i < hSize; i++)
       {
         int[] region = (int[]) hiddenColumns.elementAt(i);
         if (region[0] > start && start + change > region[1])
         {
-          deletedHiddenColumns.addElement(hiddenColumns.elementAt(i));
+          deletedHiddenColumns.add(region);
 
           hiddenColumns.removeElementAt(i);
           i--;
@@ -752,6 +755,7 @@ public class ColumnSelection
   public boolean isVisible(int column)
   {
     if (hiddenColumns != null)
+    {
       for (int i = 0; i < hiddenColumns.size(); i++)
       {
         int[] region = (int[]) hiddenColumns.elementAt(i);
@@ -760,6 +764,7 @@ public class ColumnSelection
           return false;
         }
       }
+    }
 
     return true;
   }
@@ -1018,7 +1023,9 @@ public class ColumnSelection
         w += els.length;
       }
       if (w == 0)
+      {
         return;
+      }
       Enumeration e = annels.elements();
       alignmentAnnotation.annotations = new Annotation[w];
       w = 0;
index 03a3944..07c4a54 100644 (file)
@@ -34,6 +34,7 @@ import jalview.api.analysis.ScoreModelI;
 import jalview.bin.Cache;
 import jalview.commands.CommandI;
 import jalview.commands.EditCommand;
+import jalview.commands.EditCommand.Action;
 import jalview.commands.OrderCommand;
 import jalview.commands.RemoveGapColCommand;
 import jalview.commands.RemoveGapsCommand;
@@ -1410,7 +1411,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     if (viewport.historyList.size() > 0)
     {
       undoMenuItem.setEnabled(true);
-      CommandI command = (CommandI) viewport.historyList.peek();
+      CommandI command = viewport.historyList.peek();
       undoMenuItem.setText(MessageManager.formatMessage(
               "label.undo_command", new String[]
               { command.getDescription() }));
@@ -1425,7 +1426,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       redoMenuItem.setEnabled(true);
 
-      CommandI command = (CommandI) viewport.redoList.peek();
+      CommandI command = viewport.redoList.peek();
       redoMenuItem.setText(MessageManager.formatMessage(
               "label.redo_command", new String[]
               { command.getDescription() }));
@@ -1489,7 +1490,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       return;
     }
-    CommandI command = (CommandI) viewport.historyList.pop();
+    CommandI command = viewport.historyList.pop();
     viewport.redoList.push(command);
     command.undoCommand(getViewAlignments());
 
@@ -1528,7 +1529,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       return;
     }
 
-    CommandI command = (CommandI) viewport.redoList.pop();
+    CommandI command = viewport.redoList.pop();
     viewport.historyList.push(command);
     command.doCommand(getViewAlignments());
 
@@ -1990,7 +1991,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         // /////
         // ADD HISTORY ITEM
         //
-        addHistoryItem(new EditCommand(MessageManager.getString("label.add_sequences"), EditCommand.PASTE,
+        addHistoryItem(new EditCommand(
+                MessageManager.getString("label.add_sequences"),
+                Action.PASTE,
                 sequences, 0, alignment.getWidth(), alignment));
       }
       // Add any annotations attached to sequences
@@ -2261,8 +2264,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     /*
      * //ADD HISTORY ITEM
      */
-    addHistoryItem(new EditCommand(MessageManager.getString("label.cut_sequences"), EditCommand.CUT, cut,
-            sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
+    addHistoryItem(new EditCommand(
+            MessageManager.getString("label.cut_sequences"), Action.CUT,
+            cut, sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
             viewport.getAlignment()));
 
     viewport.setSelectionGroup(null);
index 5c383d8..c5d19e2 100644 (file)
@@ -42,6 +42,7 @@ import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.analysis.NJTree;
 import jalview.api.AlignViewportI;
 import jalview.bin.Cache;
+import jalview.commands.CommandI;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
@@ -140,9 +141,9 @@ public class AlignViewport extends AlignmentViewport implements
 
   boolean gatherViewsHere = false;
 
-  Stack historyList = new Stack();
+  Stack<CommandI> historyList = new Stack<CommandI>();
 
-  Stack redoList = new Stack();
+  Stack<CommandI> redoList = new Stack<CommandI>();
 
   int thresholdTextColour = 0;
 
index dc26a36..9976471 100644 (file)
@@ -25,6 +25,7 @@ import jalview.analysis.AlignmentAnnotationUtils;
 import jalview.analysis.Conservation;
 import jalview.commands.ChangeCaseCommand;
 import jalview.commands.EditCommand;
+import jalview.commands.EditCommand.Action;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.DBRefEntry;
@@ -2707,7 +2708,7 @@ public class PopupMenu extends JPopupMenu
       {
         EditCommand editCommand = new EditCommand(
                 MessageManager.getString("label.edit_sequences"),
-                EditCommand.REPLACE, dialog.getName().replace(' ',
+                Action.REPLACE, dialog.getName().replace(' ',
                         ap.av.getGapCharacter()),
                 sg.getSequencesAsArray(ap.av.getHiddenRepSequences()),
                 sg.getStartRes(), sg.getEndRes() + 1, ap.av.getAlignment());
index 0e55cf8..ab0a0b8 100755 (executable)
  */
 package jalview.gui;
 
-import java.util.*;
-
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.event.*;
-
 import jalview.analysis.AlignSeq;
-import jalview.commands.*;
-import jalview.datamodel.*;
-import jalview.jbgui.*;
+import jalview.commands.CommandI;
+import jalview.commands.EditCommand;
+import jalview.commands.EditCommand.Action;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.jbgui.GSliderPanel;
 import jalview.util.MessageManager;
 
+import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+import java.util.Vector;
+
+import javax.swing.JInternalFrame;
+import javax.swing.JProgressBar;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.InternalFrameAdapter;
+import javax.swing.event.InternalFrameEvent;
+
 /**
  * DOCUMENT ME!
  * 
@@ -44,7 +54,9 @@ public class RedundancyPanel extends GSliderPanel implements Runnable
 
   AlignmentPanel ap;
 
-  Stack historyList = new Stack(); // simpler than synching with alignFrame.
+  Stack<CommandI> historyList = new Stack<CommandI>();
+
+  // simpler than synching with alignFrame.
 
   float[] redundancy;
 
@@ -229,7 +241,7 @@ public class RedundancyPanel extends GSliderPanel implements Runnable
       }
 
       EditCommand cut = new EditCommand(MessageManager.getString("action.remove_redundancy"),
-              EditCommand.CUT, deleted, 0, width, ap.av.getAlignment());
+              Action.CUT, deleted, 0, width, ap.av.getAlignment());
 
       for (int i = 0; i < del.size(); i++)
       {
@@ -263,7 +275,7 @@ public class RedundancyPanel extends GSliderPanel implements Runnable
        return;
     }
     
-    CommandI command = (CommandI) historyList.pop();
+    CommandI command = historyList.pop();
     if (ap.av.historyList.contains(command))
     {
       command.undoCommand(af.getViewAlignments());
index 61782b4..3b41620 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.gui;
 
 import jalview.commands.EditCommand;
+import jalview.commands.EditCommand.Action;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.Sequence;
@@ -1190,7 +1191,7 @@ public class SeqPanel extends JPanel implements MouseListener,
         }
         else
         {
-          editCommand.appendEdit(EditCommand.INSERT_GAP, groupSeqs,
+          editCommand.appendEdit(Action.INSERT_GAP, groupSeqs,
                   startres, startres - lastres, av.getAlignment(), true);
         }
       }
@@ -1206,7 +1207,7 @@ public class SeqPanel extends JPanel implements MouseListener,
         }
         else
         {
-          editCommand.appendEdit(EditCommand.DELETE_GAP, groupSeqs,
+          editCommand.appendEdit(Action.DELETE_GAP, groupSeqs,
                   startres, lastres - startres, av.getAlignment(), true);
         }
 
@@ -1228,7 +1229,7 @@ public class SeqPanel extends JPanel implements MouseListener,
         }
         else
         {
-          editCommand.appendEdit(EditCommand.INSERT_GAP, new SequenceI[]
+          editCommand.appendEdit(Action.INSERT_GAP, new SequenceI[]
           { seq }, lastres, startres - lastres, av.getAlignment(), true);
         }
       }
@@ -1265,7 +1266,7 @@ public class SeqPanel extends JPanel implements MouseListener,
 
             if (max > 0)
             {
-              editCommand.appendEdit(EditCommand.DELETE_GAP,
+              editCommand.appendEdit(Action.DELETE_GAP,
                       new SequenceI[]
                       { seq }, startres, max, av.getAlignment(), true);
             }
@@ -1283,7 +1284,7 @@ public class SeqPanel extends JPanel implements MouseListener,
           }
           else
           {
-            editCommand.appendEdit(EditCommand.INSERT_NUC, new SequenceI[]
+            editCommand.appendEdit(Action.INSERT_NUC, new SequenceI[]
             { seq }, lastres, startres - lastres, av.getAlignment(), true);
           }
         }
@@ -1319,10 +1320,10 @@ public class SeqPanel extends JPanel implements MouseListener,
       }
     }
 
-    editCommand.appendEdit(EditCommand.DELETE_GAP, seq, blankColumn, 1,
+    editCommand.appendEdit(Action.DELETE_GAP, seq, blankColumn, 1,
             av.getAlignment(), true);
 
-    editCommand.appendEdit(EditCommand.INSERT_GAP, seq, j, 1,
+    editCommand.appendEdit(Action.INSERT_GAP, seq, j, 1,
             av.getAlignment(), true);
 
   }
@@ -1330,10 +1331,10 @@ public class SeqPanel extends JPanel implements MouseListener,
   void deleteChar(int j, SequenceI[] seq, int fixedColumn)
   {
 
-    editCommand.appendEdit(EditCommand.DELETE_GAP, seq, j, 1,
+    editCommand.appendEdit(Action.DELETE_GAP, seq, j, 1,
             av.getAlignment(), true);
 
-    editCommand.appendEdit(EditCommand.INSERT_GAP, seq, fixedColumn, 1,
+    editCommand.appendEdit(Action.INSERT_GAP, seq, fixedColumn, 1,
             av.getAlignment(), true);
   }
 
diff --git a/test/jalview/commands/EditCommandTest.java b/test/jalview/commands/EditCommandTest.java
new file mode 100644 (file)
index 0000000..fc821b9
--- /dev/null
@@ -0,0 +1,232 @@
+package jalview.commands;
+
+import static org.junit.Assert.assertEquals;
+import jalview.commands.EditCommand.Action;
+import jalview.commands.EditCommand.Edit;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Unit tests for EditCommand
+ * 
+ * @author gmcarstairs
+ *
+ */
+public class EditCommandTest
+{
+
+  private EditCommand testee;
+
+  private SequenceI[] seqs;
+
+  private Alignment al;
+
+  @Before
+  public void setUp()
+  {
+    testee = new EditCommand();
+    seqs = new SequenceI[4];
+    seqs[0] = new Sequence("seq0", "abcdefghjk");
+    seqs[1] = new Sequence("seq1", "fghjklmnopq");
+    seqs[2] = new Sequence("seq2", "qrstuvwxyz");
+    seqs[3] = new Sequence("seq3", "1234567890");
+    al = new Alignment(seqs);
+    al.setGapCharacter('?');
+  }
+
+  /**
+   * Test inserting gap characters
+   */
+  @Test
+  public void testAppendEdit_insertGap()
+  {
+    // set a non-standard gap character to prove it is actually used
+    testee.appendEdit(Action.INSERT_GAP, seqs, 4, 3, al, true);
+    assertEquals("abcd???efghjk", seqs[0].getSequenceAsString());
+    assertEquals("fghj???klmnopq", seqs[1].getSequenceAsString());
+    assertEquals("qrst???uvwxyz", seqs[2].getSequenceAsString());
+    assertEquals("1234???567890", seqs[3].getSequenceAsString());
+
+    // todo: test for handling out of range positions?
+  }
+
+  /**
+   * Test deleting characters from sequences. Note the deleteGap() action does
+   * not check that only gap characters are being removed.
+   */
+  @Test
+  public void testAppendEdit_deleteGap()
+  {
+    testee.appendEdit(Action.DELETE_GAP, seqs, 4, 3, al, true);
+    assertEquals("abcdhjk", seqs[0].getSequenceAsString());
+    assertEquals("fghjnopq", seqs[1].getSequenceAsString());
+    assertEquals("qrstxyz", seqs[2].getSequenceAsString());
+    assertEquals("1234890", seqs[3].getSequenceAsString());
+  }
+
+  /**
+   * Test a cut action. The command should store the cut characters to support
+   * undo.
+   */
+  @Test
+  public void testCut()
+  {
+    Edit ec = testee.new Edit(Action.CUT, seqs, 4, 3, al);
+    testee.cut(ec, new AlignmentI[]
+    { al });
+    assertEquals("abcdhjk", seqs[0].getSequenceAsString());
+    assertEquals("fghjnopq", seqs[1].getSequenceAsString());
+    assertEquals("qrstxyz", seqs[2].getSequenceAsString());
+    assertEquals("1234890", seqs[3].getSequenceAsString());
+
+    assertEquals("efg", new String(ec.string[0]));
+    assertEquals("klm", new String(ec.string[1]));
+    assertEquals("uvw", new String(ec.string[2]));
+    assertEquals("567", new String(ec.string[3]));
+    // TODO: case where whole sequence is deleted as nothing left; etc
+  }
+
+  /**
+   * Test a Paste action, where this adds sequences to an alignment.
+   */
+  @Test
+  @Ignore
+  // TODO fix so it works
+  public void testPaste_addToAlignment()
+  {
+    SequenceI[] newSeqs = new SequenceI[2];
+    newSeqs[0] = new Sequence("newseq0", "ACEFKL");
+    newSeqs[1] = new Sequence("newseq1", "JWMPDH");
+
+    Edit ec = testee.new Edit(Action.PASTE, newSeqs, 0, al.getWidth(), al);
+    testee.paste(ec, new AlignmentI[]
+    { al });
+    assertEquals(6, al.getSequences().size());
+    assertEquals("1234567890", seqs[3].getSequenceAsString());
+    assertEquals("ACEFKL", seqs[4].getSequenceAsString());
+    assertEquals("JWMPDH", seqs[5].getSequenceAsString());
+  }
+
+  /**
+   * Test insertGap followed by undo command
+   */
+  @Test
+  public void testUndo_insertGap()
+  {
+    // Edit ec = testee.new Edit(Action.INSERT_GAP, seqs, 4, 3, '?');
+    testee.appendEdit(Action.INSERT_GAP, seqs, 4, 3, al, true);
+    // check something changed
+    assertEquals("abcd???efghjk", seqs[0].getSequenceAsString());
+    testee.undoCommand(new AlignmentI[]
+    { al });
+    assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
+    assertEquals("fghjklmnopq", seqs[1].getSequenceAsString());
+    assertEquals("qrstuvwxyz", seqs[2].getSequenceAsString());
+    assertEquals("1234567890", seqs[3].getSequenceAsString());
+  }
+
+  /**
+   * Test deleteGap followed by undo command
+   */
+  @Test
+  public void testUndo_deleteGap()
+  {
+    testee.appendEdit(Action.DELETE_GAP, seqs, 4, 3, al, true);
+    // check something changed
+    assertEquals("abcdhjk", seqs[0].getSequenceAsString());
+    testee.undoCommand(new AlignmentI[]
+    { al });
+    // deleteGap doesn't 'remember' deleted characters, only gaps get put back
+    assertEquals("abcd???hjk", seqs[0].getSequenceAsString());
+    assertEquals("fghj???nopq", seqs[1].getSequenceAsString());
+    assertEquals("qrst???xyz", seqs[2].getSequenceAsString());
+    assertEquals("1234???890", seqs[3].getSequenceAsString());
+  }
+
+  /**
+   * Test several commands followed by an undo command
+   */
+  @Test
+  public void testUndo_multipleCommands()
+  {
+    // delete positions 3/4/5 (counting from 1)
+    testee.appendEdit(Action.DELETE_GAP, seqs, 2, 3, al, true);
+    assertEquals("abfghjk", seqs[0].getSequenceAsString());
+    assertEquals("1267890", seqs[3].getSequenceAsString());
+
+    // insert 2 gaps after the second residue
+    testee.appendEdit(Action.INSERT_GAP, seqs, 2, 2, al, true);
+    assertEquals("ab??fghjk", seqs[0].getSequenceAsString());
+    assertEquals("12??67890", seqs[3].getSequenceAsString());
+
+    // delete positions 4/5/6
+    testee.appendEdit(Action.DELETE_GAP, seqs, 3, 3, al, true);
+    assertEquals("ab?hjk", seqs[0].getSequenceAsString());
+    assertEquals("12?890", seqs[3].getSequenceAsString());
+
+    // undo edit commands
+    testee.undoCommand(new AlignmentI[]
+    { al });
+    assertEquals("ab?????hjk", seqs[0].getSequenceAsString());
+    assertEquals("12?????890", seqs[3].getSequenceAsString());
+  }
+
+  /**
+   * Unit test for JAL-1594 bug: click and drag sequence right to insert gaps -
+   * undo did not remove them all.
+   */
+  @Test
+  public void testUndo_multipleInsertGaps()
+  {
+    testee.appendEdit(Action.INSERT_GAP, seqs, 4, 1, al, true);
+    testee.appendEdit(Action.INSERT_GAP, seqs, 5, 1, al, true);
+    testee.appendEdit(Action.INSERT_GAP, seqs, 6, 1, al, true);
+
+    // undo edit commands
+    testee.undoCommand(new AlignmentI[]
+    { al });
+    assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
+    assertEquals("1234567890", seqs[3].getSequenceAsString());
+
+  }
+
+  /**
+   * Test cut followed by undo command
+   */
+  @Test
+  public void testUndo_cut()
+  {
+    testee.appendEdit(Action.CUT, seqs, 4, 3, al, true);
+    // check something changed
+    assertEquals("abcdhjk", seqs[0].getSequenceAsString());
+    testee.undoCommand(new AlignmentI[]
+    { al });
+    assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
+    assertEquals("fghjklmnopq", seqs[1].getSequenceAsString());
+    assertEquals("qrstuvwxyz", seqs[2].getSequenceAsString());
+    assertEquals("1234567890", seqs[3].getSequenceAsString());
+  }
+
+  /**
+   * Test the replace command (used to manually edit a sequence)
+   */
+  @Test
+  public void testReplace()
+  {
+    // seem to need a dataset sequence on the edited sequence here
+    seqs[1].setDatasetSequence(seqs[1]);
+    new EditCommand("", Action.REPLACE, "ZXY", new SequenceI[]
+    { seqs[1] }, 4, 8, al);
+    assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
+    assertEquals("qrstuvwxyz", seqs[2].getSequenceAsString());
+    assertEquals("1234567890", seqs[3].getSequenceAsString());
+    seqs[1] = new Sequence("seq1", "fghjZXYnopq");
+
+  }
+}