public void Undo() { if (undoList.Count > 0 && undoPosition < undoList.Count) { undoPosition++; UndoRecord undoRecord = undoList[undoList.Count - undoPosition]; if (undoCallback != null) { undoCallback(undoRecord); } } }
public void Redo() { if (undoPosition > 0) { UndoRecord undoRecord = undoList[undoList.Count - undoPosition]; undoPosition--; if (undoCallback != null) { undoCallback(undoRecord); } } }
/// <summary> /// Commits the pending <see cref="IUndoState"/> record created by /// <see cref="BeginTransaction"/> to the undo stack, and clears the redo stack. /// </summary> private void Commit() { if (_pendingRecord == null) { throw new InvalidOperationException(Resources.UndoManager_Commit_Commit_called_with_no_pending_undo_record); } _redoStack.Clear(); _undoStack.Push(_pendingRecord); _pendingRecord = null; if (StacksChanged != null) { StacksChanged(this, new EventArgs()); } }
public void AddUndoRecord(UndoRecord record) { if (undoPosition > 0) { undoList.RemoveRange(undoList.Count - undoPosition, undoPosition); undoPosition = 0; } undoList.Add(record); while (undoList.Count > 0 && ((memoryLimit > 0 && UsedMemory() > memoryLimit) || (undoStepLimit > 0 && undoList.Count > undoStepLimit))) { undoList.RemoveAt(0); } }
/// <summary> /// Creates a pending undo transaction, which may be committed after the /// undoable work is completed successfully, or rolledback in case of failure. /// The <see cref="IUndoTransaction"/> implements <see cref="IDisposable"/> /// and is intended for use inside a using clause, which rollback the transaction /// automatically, if it is not commited within the scope. /// </summary> /// <param name="description">Description of the action to be performed</param> /// <param name="undoState">An undo state snapshot from the UI thread, in case the transation is begun on another thread</param> /// <returns>Transaction instance</returns> public IUndoTransaction BeginTransaction(string description, IUndoState undoState = null) { if (InUndoRedo) { throw new InvalidOperationException(Resources.UndoManager_BeginTransaction_Undo_transaction_may_not_be_started_in_undo_redo); } // Inner transactions are ignored, since only the initial record is // desired in the undo stack. if (_pendingRecord != null) { return(new NoOpTransaction()); } _pendingRecord = new UndoRecord(description, undoState ?? _client.GetUndoState()); return(new UndoTransaction(this)); }
public UndoHandler(EditViewModel vm) { _editViewModel = vm; //set up the buffer record _startBracket = new UndoRecord { Description = "#start#", Level = 0, UndoAction = null, RedoAction = null }; _endBracket = new UndoRecord { Description = "#end#", Level = 0, UndoAction = null, RedoAction = null }; Initialize(); }
/// <summary> /// Creates a pending undo transaction, which may be committed after the /// undoable work is completed successfully, or rolledback in case of failure. /// The <see cref="IUndoTransaction"/> implements <see cref="IDisposable"/> /// and is intended for use inside a using clause, which rollback the transaction /// automatically, if it is not commited within the scope. /// </summary> /// <param name="description">Description of the action to be performed</param> /// <param name="undoState">An undo state snapshot from the UI thread, in case the transation is begun on another thread</param> /// <returns>Transaction instance</returns> public IUndoTransaction BeginTransaction(string description, IUndoState undoState = null) { if (InUndoRedo) throw new InvalidOperationException(Resources.UndoManager_BeginTransaction_Undo_transaction_may_not_be_started_in_undo_redo); // Inner transactions are ignored, since only the initial record is // desired in the undo stack. if (_pendingRecord != null) return new NoOpTransaction(); _pendingRecord = new UndoRecord(description, undoState ?? _client.GetUndoState()); return new UndoTransaction(this); }
/// <summary> /// Fais en sorte que l'action <c>aor</c> soit exécutée sur tous les "ranges" sélectionnés. /// </summary> /// <param name="act">L'action à effectuer sur un texte. Par exemple <c>MarkSyls</c> ou <c>MarkNoir</c></param> /// <param name="undoTxt">Le texte qui est inscrit dans le <c>UndoRecord</c> et que l'utilisateur voit s'il va /// sur la lsite des actions qu'il peut annuler.</param> private static void ActOnSelectedText(ActOnMSWText act, string undoTxt, Config conf) { logger.ConditionalDebug("ActOnSelectedText"); try { ProgressNotifier.thePN.Start(); if (ColorizationMSW.thisAddIn.Application.Documents.Count > 0) { UndoRecord objUndo = ColorizationMSW.thisAddIn.Application.UndoRecord; objUndo.StartCustomRecord(undoTxt); ColorizationMSW.thisAddIn.Application.ScreenUpdating = false; Selection sel = ColorizationMSW.thisAddIn.Application.ActiveWindow.Selection; switch (sel.Type) { case WdSelectionType.wdSelectionInlineShape: case WdSelectionType.wdNoSelection: case WdSelectionType.wdSelectionIP: // IP: Insertion Point // rien à faire ... break; case WdSelectionType.wdSelectionFrame: foreach (Frame f in sel.Frames) { act(new MSWText(f.Range), conf); } break; case WdSelectionType.wdSelectionShape: foreach (Shape sh in sel.ShapeRange) { ActOnShape(sh, act, conf); } break; case WdSelectionType.wdSelectionColumn: case WdSelectionType.wdSelectionRow: case WdSelectionType.wdSelectionBlock: case WdSelectionType.wdSelectionNormal: act(new MSWText(sel.Range), conf); foreach (Shape sh in sel.Range.ShapeRange) { ActOnShape(sh, act, conf); } break; default: throw new ArgumentException(String.Format("Type de sélection non traitée: {0}", sel.Type.ToString())); break; } ColorizationMSW.thisAddIn.Application.ScreenUpdating = true; objUndo.EndCustomRecord(); } ProgressNotifier.thePN.Completed(); } catch (Exception e) { StringBuilder sb = new StringBuilder(); sb.Append("Ouups. Une vilaine erreur s'est produite. Désolé. N'hésitez pas à nous "); sb.AppendLine("envoyer une description de votre problème à [email protected]."); sb.AppendLine(e.Message); sb.AppendLine(e.StackTrace); logger.Error(sb.ToString()); MessageBox.Show(sb.ToString(), ConfigBase.ColorizationName, MessageBoxButtons.OK, MessageBoxIcon.Error); Debug.Assert(false); } logger.ConditionalDebug("EXIT ActOnSelectedText"); }
public void CloseGroup() { if (groupStart == null) { Debug.Assert(false); throw new InvalidOperationException(); } if (groupStart == records) { // delete empty undo group to eliminate no-op entries on user's undo stack records = records.Next; return; } if (clearRedo) { textEdit.redo = null; } SelectionUndoRecord selection = new SelectionUndoRecord(textEdit); selection.Next = records; records = selection; GroupEndUndoRecord end = new GroupEndUndoRecord(groupStart); end.Next = records; records = end; groupStart = null; }
/// <summary> /// Discards the pending <see cref="IUndoState"/> record created by /// <see cref="BeginTransaction"/>. /// </summary> private void Rollback() { _pendingRecord = null; }
public void Undo() { if (records != null) { if (records is GroupEndUndoRecord) { do { UndoRecord one = records; records = records.Next; one.Undo(textEdit); } while (!(records is GroupStartUndoRecord)); records = records.Next; // also remove group start } else { UndoRecord one = records; records = records.Next; one.Undo(textEdit); } } }
public void SaveSelection() { SelectionUndoRecord selection = new SelectionUndoRecord(textEdit); selection.Next = records; records = selection; }
public IDisposable OpenGroup() { // defer this until close group - avoids clearing redo if group was empty //if (clearRedo) //{ // textEdit.redo = null; //} if (groupStart == null) { groupStart = new GroupStartUndoRecord(); groupStart.Next = records; records = groupStart; return new UndoGroupCloser(this); } else { return null; } }
void ITextEditorChangeTracking.ReplacingRange( int startLine, int startChar, ITextStorage deleted, int replacedEndLine, int replacedEndCharPlusOne) { if (clearRedo) { textEdit.redo = null; } //SelectionUndoRecord selection = new SelectionUndoRecord(textEdit); //selection.next = records; //records = selection; ReplaceRangeUndoRecord newRange = new ReplaceRangeUndoRecord( startLine, startChar, deleted, replacedEndLine, replacedEndCharPlusOne); UndoRecord last = records; while ((last != null) && !(last is ReplaceRangeUndoRecord)) { last = last.Next; } if ((newRange.StartLine == newRange.EndLine) && (newRange.StartChar == newRange.EndCharPlusOne) && (newRange.StartLine == newRange.ReplacedEndLine) && (newRange.StartChar + 1 == newRange.ReplacedEndCharPlusOne)) { // if current is a keypress (single char insertion) try to coalesce with previous record ReplaceRangeUndoRecord lastRange = last != null ? (ReplaceRangeUndoRecord)last : null; if ((lastRange != null) && lastRange.Deleted.Empty && (lastRange.StartLine == lastRange.EndLine) && (lastRange.StartLine == newRange.StartLine) && (lastRange.ReplacedEndCharPlusOne == newRange.StartChar)) { lastRange.ReplacedEndCharPlusOne++; return; } } else if ((newRange.StartLine == newRange.EndLine) && (newRange.StartChar == newRange.EndCharPlusOne - 1) && (newRange.StartLine == newRange.ReplacedEndLine) && (newRange.StartChar == newRange.ReplacedEndCharPlusOne)) { // if current is a backspace/del (single char removal) try to coalesce with previous record ReplaceRangeUndoRecord lastRange = last != null ? (ReplaceRangeUndoRecord)last : null; if ((lastRange != null) && (lastRange.StartLine == lastRange.EndLine) && (lastRange.StartLine == newRange.StartLine) && (lastRange.StartChar == newRange.EndCharPlusOne)) { lastRange.StartChar--; lastRange.ReplacedEndCharPlusOne--; lastRange.Deleted.InsertSection(0, 0, newRange.Deleted); return; } else if ((lastRange != null) && (lastRange.StartLine == lastRange.EndLine) && (lastRange.StartChar == lastRange.ReplacedEndCharPlusOne) && (lastRange.StartLine == newRange.StartLine) && (lastRange.StartChar == newRange.StartChar)) { lastRange.Deleted.InsertSection(0, lastRange.Deleted[0].Length, newRange.Deleted); return; } } newRange.Next = records; records = newRange; }
/// <summary> /// Commits the pending <see cref="IUndoState"/> record created by /// <see cref="BeginTransaction"/> to the undo stack, and clears the redo stack. /// </summary> private void Commit() { if (_pendingRecord == null) throw new InvalidOperationException(Resources.UndoManager_Commit_Commit_called_with_no_pending_undo_record); _redoStack.Clear(); _undoStack.Push(_pendingRecord); _pendingRecord = null; if (StacksChanged != null) StacksChanged(this, new EventArgs()); }
/// <summary> /// Restores the <see cref="IUndoState"/> at a specified depth in one of the stacks. /// This method depends on the fact that this undo stack is really a document /// history and not a record of actions. A record of actions would need to replay /// each in order. Here we just pop the specified number of records, and restore /// the one left at the top. /// /// When the index is zero, however, it behaves much like any other undo manager. /// </summary> /// <param name="index">Index of record on the stack to restore</param> /// <param name="from">Stack to pop from</param> /// <param name="to">Stack to push resulting <see cref="IUndoState"/> to</param> private void Restore(int index, Stack <UndoRecord> from, Stack <UndoRecord> to) { if (_pendingRecord != null) { throw new InvalidOperationException(Resources.UndoManager_Restore_Attempting_undo_redo_inside_undo_transaction); } if (index >= from.Count) { throw new IndexOutOfRangeException(string.Format(Resources.UndoManager_Restore_Attempt_to_index__0__beyond_length__1__, index, from.Count)); } try { InUndoRedo = true; // Because the undo manager stores a history of states, rather // than one of actions, all preceding states may simply be popped // off the stack, and only the desired state restored. // The undo state returned from the call to IUndoState.Restore // must be the first record pushed onto the redo stack, since it // contains the information needed to return the application to // the state prior to this undo. // After that the rest of the popped undo history gets pushed // onto the redo stack so that an undo of 10 changes, and then // a redo will restore the state to that of 9 changes ago, and // 9 more redos will restore the state before the undo. Or vice- // versa, if the from stack is the redo stack. // Save any records skipped by this operation. var list = new List <UndoRecord>(); for (int i = 0; i < index; i++) { list.Add(from.Pop()); } // Descriptions need to be correctly assigned, with the record // returned from the actual restore operation containing the // description from the top of the undo stack. string description = (list.Count == 0 ? null : list[0].Description); // Restore the desired state, and push the original state. UndoRecord top = from.Pop(); to.Push(top.Restore(description)); // If undo/redo was multi-record, restore the rest of the history. // All descriptions need to shift, and the last record needs the // description of the just popped record. for (int i = 0; i < list.Count; i++) { description = (i < list.Count - 1 ? list[i + 1].Description : top.Description); to.Push(new UndoRecord(description, list[i].UndoState)); } } finally { InUndoRedo = false; } if (StacksChanged != null) { StacksChanged(this, new EventArgs()); } }
/// <summary> /// Discards the pending <see cref="IUndoState"/> record created by /// <see cref="BeginTransaction"/>. /// </summary> private void Rollback() { _pendingRecord = null; }
public void Clear() { records = null; }