UndoableStack.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. module wijmo.grid.sheet {
  2. 'use strict';
  3. /**
  4. * Defines the UndoableStack class.
  5. *
  6. * It deals with the undo\redo for the Flexsheet control.
  7. */
  8. export class UndoableStack {
  9. private MAX_STACK_SIZE = 500;
  10. private _owner: FlexSheet;
  11. private _stack = [];
  12. private _pointer = -1;
  13. private _pendingAction: _UndoableAction;
  14. private _resizingTriggered = false;
  15. /**
  16. * Initializes a new instance of a @see:UndoableStack class.
  17. *
  18. * @param owener The @see: FlexSheet control that the UndoableStack works for.
  19. */
  20. constructor(owner: FlexSheet) {
  21. this._owner = owner;
  22. // Handles the cell edit action for editing cell
  23. this._owner.prepareCellForEdit.addHandler(this._initCellEditAction, this);
  24. this._owner.cellEditEnded.addHandler(this._afterProcessCellEditAction, this);
  25. // Handles the cell edit action for copy\paste operation
  26. this._owner.pasting.addHandler(this._initCellEditAction, this);
  27. this._owner.pasted.addHandler(this._afterProcessCellEditAction, this);
  28. // Handles the resize column action
  29. this._owner.resizingColumn.addHandler((sender: FlexGrid, e: CellRangeEventArgs) => {
  30. if (!this._resizingTriggered) {
  31. this._pendingAction = new _ColumnResizeAction(this._owner, e.col);
  32. this._resizingTriggered = true;
  33. }
  34. }, this)
  35. this._owner.resizedColumn.addHandler((sender: FlexGrid, e: CellRangeEventArgs) => {
  36. if (this._pendingAction instanceof _ColumnResizeAction && this._pendingAction.saveNewState()) {
  37. this.addAction(this._pendingAction);
  38. }
  39. this._pendingAction = null;
  40. this._resizingTriggered = false;
  41. }, this);
  42. // Handles the resize row action
  43. this._owner.resizingRow.addHandler((sender: FlexGrid, e: CellRangeEventArgs) => {
  44. if (!this._resizingTriggered) {
  45. this._pendingAction = new _RowResizeAction(this._owner, e.row);
  46. this._resizingTriggered = true;
  47. }
  48. }, this)
  49. this._owner.resizedRow.addHandler((sender: FlexGrid, e: CellRangeEventArgs) => {
  50. if (this._pendingAction instanceof _RowResizeAction && this._pendingAction.saveNewState()) {
  51. this.addAction(this._pendingAction);
  52. }
  53. this._pendingAction = null;
  54. this._resizingTriggered = false;
  55. }, this);
  56. }
  57. /**
  58. * Check whether undo can be done.
  59. */
  60. get canUndo(): boolean {
  61. return this._pointer > -1 && this._pointer < this._stack.length;
  62. }
  63. /**
  64. * Check whether redo can be done.
  65. */
  66. get canRedo(): boolean {
  67. return this._pointer + 1 > -1 && this._pointer + 1 < this._stack.length;
  68. }
  69. /**
  70. * Occurs when the undoable stack changed.
  71. */
  72. undoableStackChanged = new wijmo.Event();
  73. /**
  74. * Raises the undoableStackChanged event.
  75. */
  76. onUndoableStackChanged() {
  77. this.undoableStackChanged.raise(this);
  78. }
  79. /**
  80. * Executes an undo command.
  81. */
  82. undo() {
  83. var action: _UndoableAction;
  84. if (this.canUndo) {
  85. action = this._stack[this._pointer];
  86. this._beforeUndoRedo(action);
  87. action.undo();
  88. this._pointer--;
  89. this.onUndoableStackChanged();
  90. }
  91. }
  92. /**
  93. * Executes an redo command.
  94. */
  95. redo() {
  96. var action: _UndoableAction;
  97. if (this.canRedo) {
  98. this._pointer++;
  99. action = this._stack[this._pointer];
  100. this._beforeUndoRedo(action);
  101. action.redo();
  102. this.onUndoableStackChanged();
  103. }
  104. }
  105. /**
  106. * Add the undoable action into the undo stack.
  107. */
  108. addAction(action: _UndoableAction) {
  109. // trim stack
  110. if (this._stack.length > 0 && this._stack.length > this._pointer + 1) {
  111. this._stack.splice(this._pointer + 1, this._stack.length - this._pointer - 1);
  112. }
  113. if (this._stack.length >= this.MAX_STACK_SIZE) {
  114. this._stack.splice(0, this._stack.length - this.MAX_STACK_SIZE + 1);
  115. }
  116. // update pointer and add action to stack
  117. this._pointer = this._stack.length;
  118. this._stack.push(action);
  119. this.onUndoableStackChanged();
  120. }
  121. /**
  122. * Clear the undo stack.
  123. */
  124. clear() {
  125. this._stack.length = 0;
  126. }
  127. // initialize the cell edit action.
  128. private _initCellEditAction() {
  129. this._pendingAction = new _EditAction(this._owner);
  130. }
  131. // after processing the cell edit action.
  132. private _afterProcessCellEditAction() {
  133. if (this._pendingAction instanceof _EditAction && this._pendingAction.saveNewState()) {
  134. this.addAction(this._pendingAction);
  135. }
  136. this._pendingAction = null;
  137. }
  138. // Called before an action is undone or redone.
  139. private _beforeUndoRedo(action: _UndoableAction) {
  140. this._owner.selectedSheetIndex = action.sheetIndex;
  141. }
  142. }
  143. }