/// <summary> /// Stop the current transaction, either rolling it back or committing it. /// </summary> /// <param name="commit">true to terminate the transaction normally; /// false to abort it and rollback the existing edits</param> /// <param name="tname">the internal locale-neutral name for the transaction</param> /// <returns>true for a committed top-level transaction</returns> /// <remarks> /// <para> /// If this call stops a top-level transaction, a value of false for /// <paramref name="commit"/> just undoes and discards the information in the /// <see cref="CurrentEdit"/>. /// If <paramref name="commit"/> is true for a top-level transaction, /// we mark the <see cref="CurrentEdit"/> complete, /// call <see cref="CommitCompoundEdit"/>, /// and add the resulting <see cref="UndoManager.CompoundEdit"/> /// to the list of compound edits that this undo manager is recording. /// </para> /// <para> /// Committing a transaction when there have been some undos without /// corresponding redos will throw away the compound edits holding /// changes that happened after the current state, before adding this /// new compound edit to the undo manager's list of edits. /// </para> /// <para> /// This method raises a <see cref="IDiagramModel.Changed"/> event /// for each of this undo manager's <see cref="Models"/>, /// with a hint of <see cref="ModelChange.CommittedTransaction"/>, /// and with a <see cref="ModelChangedEventArgs.OldValue"/> /// that is the <see cref="UndoManager.CompoundEdit"/> /// that has been added to the list of <see cref="CompoundEdits"/>. /// Similarly, if the transaction is aborted, either because <paramref name="commit"/> /// is false or because there is no <see cref="CurrentEdit"/> to commit, /// all of the <see cref="Models"/> get a <see cref="ModelChange.RolledBackTransaction"/> /// Changed event. The values passed in the <see cref="ModelChangedEventArgs"/> /// may all be null, however. /// </para> /// </remarks> protected virtual bool EndTransaction(bool commit, String tname) { if (this.IsUndoingRedoing) { return(false); } bool toplevel = (this.TransactionLevel == 1); int start = 0; // decrement the transaction level, but not below zero if (this.TransactionLevel > 0) { this.TransactionLevel--; int numnames = this.NestedTransactionNames.Count; if (numnames > 0) { if (tname == null) { tname = this.NestedTransactionNames[0]; } this.NestedTransactionNames.RemoveAt(numnames - 1); } int numstarts = this.NestedTransactionStarts.Count; if (numstarts > 0) { start = this.NestedTransactionStarts[numstarts - 1]; this.NestedTransactionStarts.RemoveAt(numstarts - 1); } } if (tname == null) { tname = ""; } CompoundEdit current = this.CurrentEdit; //Diagram.Debug(this.TransactionLevel, (commit ? "commit: " : "rollback: ") + (tname != "" ? tname : "(unknown)") + " " + // (current != null ? current.Edits.Count.ToString() : "(no CEdit)") + " " + this.CompoundEdits.Count.ToString()); if (toplevel) { if (commit) { // finish the current edit CompoundEdit cedit = CommitCompoundEdit(current); if (cedit != null) { cedit.IsComplete = true; cedit.Name = tname; // throw away any compound edits following the current index for (int i = this.CompoundEdits.Count - 1; i > this.UndoEditIndex; i--) { this.CompoundEdits[i].Clear(); this.CompoundEdits.RemoveAt(i); } // if there is a limit, just throw away the oldest edit int max = this.MaximumEditCount; if (max == 0) { max = 1; } if (max > 0) { if (this.CompoundEdits.Count >= max) { this.CompoundEdits[0].Clear(); this.CompoundEdits.RemoveAt(0); this.UndoEditIndex--; } } // add to CompoundEdits list this.CompoundEdits.Add(cedit); this.UndoEditIndex++; } // notify all models foreach (IDiagramModel model in this.ModelsList) { RaiseChanged(model, ModelChange.CommittedTransaction, tname, cedit, null); } } else // !commit // rollback the current compound edit by undoing all of its edits { if (current != null) { try { current.IsComplete = true; this.IsUndoingRedoing = true; current.Undo(); } finally { this.IsUndoingRedoing = false; } } foreach (IDiagramModel model in this.ModelsList) { RaiseChanged(model, ModelChange.RolledBackTransaction, tname, current, null); } // now we can throw away all those undone edits if (current != null) { current.Clear(); } } this.CurrentEdit = null; return(true); } else // !toplevel // rollback the current edit by undoing all of its edits, but not of parent edits { if (!commit && current != null) { current.RollbackTo(start); } return(false); } }