+ /**
+ * 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. If simply
+ * expanding the range of the last command added, then modify it instead of
+ * adding a new command.
+ *
+ * @param e
+ */
+ public void addEdit(Edit e)
+ {
+ if (!expandEdit(edits, e))
+ {
+ edits.add(e);
+ }
+ }
+
+ /**
+ * Returns true if the new edit is incorporated by updating (expanding the
+ * range of) the last edit on the list, else false. We can 'expand' the last
+ * edit if the new one is the same action, on the same sequences, and acts on
+ * a contiguous range. This is the case where a mouse drag generates a series
+ * of contiguous gap insertions or deletions.
+ *
+ * @param edits
+ * @param e
+ * @return
+ */
+ protected static boolean expandEdit(List<Edit> edits, Edit e)
+ {
+ if (edits == null || edits.isEmpty())
+ {
+ return false;
+ }
+ Edit lastEdit = edits.get(edits.size() - 1);
+ Action action = e.command;
+ if (lastEdit.command != action)
+ {
+ return false;
+ }
+
+ /*
+ * Both commands must act on the same sequences - compare the underlying
+ * dataset sequences, rather than the aligned sequences, which change as
+ * they are edited.
+ */
+ if (lastEdit.seqs.length != e.seqs.length)
+ {
+ return false;
+ }
+ for (int i = 0; i < e.seqs.length; i++)
+ {
+ if (lastEdit.seqs[i].getDatasetSequence() != e.seqs[i]
+ .getDatasetSequence())
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Check a contiguous edit; either
+ * <ul>
+ * <li>a new Insert <n> positions to the right of the last <insert n>,
+ * or</li>
+ * <li>a new Delete <n> gaps which is <n> positions to the left of the last
+ * delete.</li>
+ * </ul>
+ */
+ boolean contiguous = (action == Action.INSERT_GAP
+ && e.position == lastEdit.position + lastEdit.number)
+ || (action == Action.DELETE_GAP
+ && e.position + e.number == lastEdit.position);
+ if (contiguous)
+ {
+ /*
+ * We are just expanding the range of the last edit. For delete gap, also
+ * moving the start position left.
+ */
+ lastEdit.number += e.number;
+ lastEdit.seqs = e.seqs;
+ if (action == Action.DELETE_GAP)
+ {
+ lastEdit.position--;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 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;
+ }
+