{*******************************************************************} { } { Developer Express Cross platform Visual Component Library } { ExpressSpreadSheet } { } { Copyright (c) 2001-2009 Developer Express Inc. } { ALL RIGHTS RESERVED } { } { The entire contents of this file is protected by U.S. and } { International Copyright Laws. Unauthorized reproduction, } { reverse-engineering, and distribution of all or any portion of } { the code contained in this file is strictly prohibited and may } { result in severe civil and criminal penalties and will be } { prosecuted to the maximum extent possible under the law. } { } { RESTRICTIONS } { } { THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES } { (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE } { SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS } { LICENSED TO DISTRIBUTE THE EXPRESSSPREADSHEET AND ALL } { ACCOMPANYING VCL AND CLX CONTROLS AS PART OF AN EXECUTABLE } { PROGRAM ONLY. } { } { THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED } { FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE } { COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE } { AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT } { AND PERMISSION FROM DEVELOPER EXPRESS INC. } { } { CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON } { ADDITIONAL RESTRICTIONS. } { } {*******************************************************************} unit cxSSHistory; {$I cxVer.inc} interface uses Classes, SysUtils, Windows, {$IFDEF DELPHI6} Types, {$ENDIF} Forms, Controls, cxSSData, cxSSTypes, Graphics, cxSSRes, cxControls, cxClasses; type TcxCustomAction = class; TcxActionList = class; TcxActionClass = class of TcxCustomAction; TcxSSHistoryClass = class of TcxSpreadSheetHistory; { TcxCustomHistory } TcxCustomHistory = class private FCurrentAction: TcxCustomAction; FFuncCount: Integer; FIsSafeException: Boolean; FMaxActionCount: Integer; FOwner: TObject; FRedoList: TcxActionList; FUndoList: TcxActionList; FUpdateRef: Integer; FOnChange: TNotifyEvent; function AddNewAction(ActionClass: TcxActionClass; var Action): Boolean; function GetLocked: Boolean; function GetIsComplexAction: Boolean; procedure SetMaxActionCount(const Value: Integer); protected function AddAction(ActionClass: TcxActionClass; var Action): Boolean; function AddComplexAction(ActionClass: TcxActionClass; const ADescription: string; var Action): Boolean; procedure Change; virtual; procedure ChangeUpdateState(CanUpdate: Boolean); virtual; procedure SafeException; virtual; procedure UpdateFormulas; virtual; property HistoryOwner: TObject read FOwner write FOwner; property IsComplexAction: Boolean read GetIsComplexAction; property Locked: Boolean read GetLocked; property MaxActions: Integer read FMaxActionCount write SetMaxActionCount; property Owner: TObject read FOwner; property RedoActions: TcxActionList read FRedoList; property UndoActions: TcxActionList read FUndoList; property OnChange: TNotifyEvent read FOnChange write FOnChange; public procedure AfterConstruction; override; procedure BeforeDestruction; override; function BeginUpdate: Integer; procedure Clear; virtual; function EndUpdate: Integer; function StartComplexAction(const ADescription: string): Boolean; procedure StopComplexAction; procedure Redo(const ACount: Integer = -1); virtual; procedure Undo(const ACount: Integer = -1); virtual; end; { TcxCustomAction } TcxCustomAction = class private FChild: TcxCustomAction; FHistory: TcxCustomHistory; FNext: TcxCustomAction; FOwner: TcxCustomHistory; FParent: TcxCustomAction; FPrev: TcxCustomAction; function GetCount: Integer; function GetHistoryOwner: TObject; function GetItem(AIndex: Integer): TcxCustomAction; protected procedure Clear; virtual; function GetActionDescription: string; virtual; procedure DeleteFromChain; procedure DoUndo; virtual; procedure DoRedo; virtual; class function GetCountActions(Action: TcxCustomAction): Integer; class function GetFirstAction(Action: TcxCustomAction): TcxCustomAction; class function GetLastAction(Action: TcxCustomAction): TcxCustomAction; class function GetPosition(Action: TcxCustomAction): Integer; procedure InsertAfter(Action: TcxCustomAction); virtual; procedure InsertBefore(Action: TcxCustomAction); virtual; property Item[AIndex: Integer]: TcxCustomAction read GetItem; default; property Count: Integer read GetCount; property Parent: TcxCustomAction read FParent; property History: TcxCustomHistory read FHistory; property HistoryOwner: TObject read GetHistoryOwner; public destructor Destroy; override; property Description: string read GetActionDescription; end; { TcxSpreadSheetHistory } TcxSpreadSheetHistory = class(TcxCustomHistory) protected procedure ChangeUpdateState(CanUpdate: Boolean); override; procedure UpdateFormulas; override; public procedure Clear; override; property MaxActions; property RedoActions; property UndoActions; end; { TcxActionList } TcxActionList = class(TcxCustomAction) public property Item; property Count; end; { TcxStoreCellRec } TcxStoreCellRec = {$IFNDEF DELPHI12} packed {$ENDIF} record Data: string; DataType: TcxSSDataType; FontName: string; FontColor: Word; FontStyle: TFontStyles; FontCharset: TFontCharset; FontSize: ShortInt; FormatIndex: Byte; HorzAlign: TcxHorzTextAlign; VertAlign: TcxVertTextAlign; WordBreak: Boolean; ShrinkToFit: Boolean; CellState: TcxSSCellStates; BrushStyle: TcxSSFillStyle; BrushFgColor: Word; BrushBkColor: Word; Borders: TcxSSBordersStyle; end; TcxCellsData = array of array of TcxStoreCellRec; { TcxSpreadSheetActions } TcxSpreadSheetActions = class(TcxCustomAction) private FData: TcxCellsData; FRect: TRect; FSheet: TObject; procedure GetCellData(const ACol, ARow: Integer; var AStoredData: TcxStoreCellRec); function GetDataStorage: TcxSSDataStorage; procedure SetCellData(const ACol, ARow: Integer; var AStoredData: TcxStoreCellRec); protected procedure DoRedo; override; procedure DoUndo; override; procedure RestoreCellsData; virtual; procedure SetData(ASheet: TObject; const ACellRect: TRect; const SaveCells: Boolean = True); procedure StoreCellsData(var AData: TcxCellsData); virtual; property CellsRect: TRect read FRect; property Data: TcxCellsData read FData; property DataStorage: TcxSSDataStorage read GetDataStorage; property Sheet: TObject read FSheet; end; { TcxComplexAction } TcxComplexAction = class(TcxCustomAction) private FDescription: string; protected procedure CheckEmpty; function GetActionDescription: string; override; public property Item; property Count; end; { TcxSpreadSheetInsertDeleteActions } TcxSpreadSheetInsertDeleteActions = class(TcxSpreadSheetActions) private FRects: TcxSSRectsArray; FModifyType: TcxSSCellsModify; public procedure BeforeAction(ASheet: TObject; const ACellRect: TRect; AModifyType: TcxSSCellsModify); virtual; property ModifyType: TcxSSCellsModify read FModifyType; end; { TcxInsertCellsAction } TcxInsertCellsAction = class(TcxSpreadSheetInsertDeleteActions) protected procedure DoRedo; override; procedure DoUndo; override; function GetActionDescription: string; override; end; { TcxDeleteCellsAction } TcxDeleteCellsAction = class(TcxSpreadSheetInsertDeleteActions) protected procedure DoRedo; override; procedure DoUndo; override; function GetActionDescription: string; override; public procedure BeforeAction(ASheet: TObject; const ACellRect: TRect; AModifyType: TcxSSCellsModify); override; end; {TcxSpreadSheetChangeCells} TcxSpreadSheetChangeCellsAction = class(TcxSpreadSheetActions) public procedure BeforeAction(ASheet: TObject; const ACellRect: TRect); end; { TcxChangeDataAction } TcxChangeDataAction = class(TcxSpreadSheetChangeCellsAction) protected function GetActionDescription: string; override; end; { TcxChangeStyleAction } TcxChangeStyleAction = class(TcxSpreadSheetChangeCellsAction) protected function GetActionDescription: string; override; end; { TcxMergeSplitActions } TcxMergeSplitActions = class(TcxSpreadSheetActions) private FRects: TcxSSRectsArray; protected procedure DoRedo; override; procedure DoUndo; override; public procedure BeforeAction(ASheet: TObject; const ACellRect: TRect); virtual; end; { TcxMergeCellsAction } TcxMergeCellsAction = class(TcxMergeSplitActions) protected function GetActionDescription: string; override; end; { TcxSplitCellsAction } TcxSplitCellsAction = class(TcxMergeSplitActions) protected function GetActionDescription: string; override; end; const MaximumActionsCount: Integer = 15; implementation uses cxSSheet, cxSSFormulas, cxSSStyles ; type TcxSheetAccess = class(TcxSSBookSheet); TcxBookAccess = class(TcxCustomSpreadSheetBook); TcxDataStorageAccess = class(TcxSSDataStorage); TcxMergedCellsAccess = class(TcxSSMergedCellsStorage); TcxFormulasCacheAccess = class(TcxSSFormulasCache); procedure TcxCustomHistory.AfterConstruction; begin FUndoList := TcxActionList.Create; FRedoList := TcxActionList.Create; FCurrentAction := FUndoList; FUpdateRef := 0; FMaxActionCount := MaximumActionsCount; inherited AfterConstruction; end; procedure TcxCustomHistory.BeforeDestruction; begin try Clear; FUndoList.Free; FRedoList.Free; finally inherited BeforeDestruction; end; end; procedure ClearHistoryList(Action: TcxCustomAction); function GetLatest(AChild: TcxCustomAction): TcxCustomAction; begin Result := AChild; if Result = nil then Exit; repeat while (Result <> nil) and (Result.FNext <> nil) do Result := Result.FNext; if Result.FChild <> nil then begin Result := Result.FChild; Continue; end; until Result.FChild = nil; end; var ASavedAction, AItem: TcxCustomAction; begin ASavedAction := Action; try AItem := GetLatest(Action); while AItem.FParent <> nil do begin Action := AItem.Parent; AItem.Clear; AItem := Action; end; Action.Clear; finally ASavedAction.Clear; end; end; procedure TcxCustomHistory.Clear; begin try ClearHistoryList(FUndoList); finally FCurrentAction := FUndoList; ClearHistoryList(FRedoList); end; Change; end; procedure TcxCustomHistory.Redo(const ACount: Integer = -1); var I: Integer; AList: TcxCustomAction; Action: TcxCustomAction; ACursor: TCursor; begin FFuncCount := 0; TcxBookAccess(Owner).BeginUpdate; ACursor := Screen.Cursor; try BeginUpdate; Screen.Cursor := crHourGlass; ChangeUpdateState(False); I := 0; AList := FRedoList.FChild; while (I <> ACount) and (AList <> nil) do try AList.DoRedo; Action := AList; AList := AList.FNext; FUndoList.InsertBefore(Action); Inc(I); except SafeException; raise; end; finally Screen.Cursor := ACursor; UpdateFormulas; ChangeUpdateState(True); EndUpdate; TcxBookAccess(Owner).EndUpdate; Change; end; end; function TcxCustomHistory.StartComplexAction(const ADescription: string): Boolean; var Action: TcxComplexAction; begin Result := AddComplexAction(TcxComplexAction, ADescription, Action); end; procedure TcxCustomHistory.StopComplexAction; var AAction: TcxComplexAction; begin if (FCurrentAction <> nil) and (FCurrentAction is TcxComplexAction) then begin AAction := FCurrentAction as TcxComplexAction; FCurrentAction := FCurrentAction.FParent; AAction.CheckEmpty; if AAction.Count = 0 then AAction.Free else Change; end; end; procedure TcxCustomHistory.Undo(const ACount: Integer = -1); var I: Integer; AList: TcxCustomAction; Action: TcxCustomAction; begin FFuncCount := 0; TcxBookAccess(Owner).BeginUpdate; try BeginUpdate; I := 0; AList := FUndoList.FChild; while (I <> ACount) and (AList <> nil) do try AList.DoUndo; Action := AList; AList := AList.FNext; FRedoList.InsertBefore(Action); Inc(I); except SafeException; raise; end; finally UpdateFormulas; ChangeUpdateState(True); FCurrentAction := FUndoList; EndUpdate; Change; end; end; function TcxCustomHistory.AddAction(ActionClass: TcxActionClass; var Action): Boolean; begin TcxCustomAction(Action) := nil; try if not Locked and AddNewAction(ActionClass, Action) then begin TcxCustomAction(Action).FParent := FCurrentAction; Change; end; finally Result := TcxCustomAction(Action) <> nil; end; end; function TcxCustomHistory.AddComplexAction(ActionClass: TcxActionClass; const ADescription: string; var Action): Boolean; begin TcxCustomAction(Action) := nil; try if not Locked and AddNewAction(ActionClass, Action) then with TcxComplexAction(Action) do begin FDescription := ADescription; FParent := FCurrentAction; FCurrentAction := TcxComplexAction(Action); end; finally Result := TcxComplexAction(Action) <> nil; end; end; function TcxCustomHistory.BeginUpdate: Integer; begin Inc(FUpdateRef); Result := FUpdateRef; end; procedure TcxCustomHistory.Change; begin if Assigned(FOnChange) then FOnChange(Self); end; procedure TcxCustomHistory.ChangeUpdateState(CanUpdate: Boolean); begin end; function TcxCustomHistory.EndUpdate: Integer; begin Dec(FUpdateRef); Result := FUpdateRef; end; procedure TcxCustomHistory.SafeException; begin if not FIsSafeException then try FIsSafeException := True; Clear; finally FIsSafeException := False; FUndoList.FChild := nil; FRedoList.FChild := nil; end; end; procedure TcxCustomHistory.UpdateFormulas; begin end; function TcxCustomHistory.AddNewAction(ActionClass: TcxActionClass; var Action): Boolean; var NewAction: TcxCustomAction; begin NewAction := nil; try try if not Locked then begin if (FCurrentAction = FUndoList) and (FUndoList.Count = FMaxActionCount) and (FUndoList.GetLastAction(FUndoList.FChild) <> nil) then begin with FUndoList.GetLastAction(FUndoList.FChild) do try DeleteFromChain; finally Free; end; end; NewAction := ActionClass.Create; if not (NewAction is TcxComplexAction) then FRedoList.Clear; NewAction.FOwner := Self; if FCurrentAction.FChild <> nil then begin NewAction.FNext := FCurrentAction.FChild; if FCurrentAction.FChild <> nil then FCurrentAction.FChild.FPrev := NewAction; end; FCurrentAction.FChild := NewAction; end; except SafeException; raise; end; finally Result := NewAction <> nil; TcxCustomAction(Action) := NewAction end; end; function TcxCustomHistory.GetLocked: Boolean; begin Result := FUpdateRef > 0; end; function TcxCustomHistory.GetIsComplexAction: Boolean; begin Result := FCurrentAction is TcxComplexAction; end; procedure TcxCustomHistory.SetMaxActionCount(const Value: Integer); begin if Value <> FMaxActionCount then begin FMaxActionCount := Value; Clear; end; end; { TcxCustomAction } destructor TcxCustomAction.Destroy; begin Clear; inherited Destroy; end; procedure TcxCustomAction.Clear; begin if FChild <> nil then try while FChild.FNext <> nil do begin FChild := FChild.FNext; FChild.FPrev.Free; end; finally FreeAndNil(FChild); end; end; function TcxCustomAction.GetActionDescription: string; begin Result := ClassName; end; procedure TcxCustomAction.DeleteFromChain; begin if FPrev = nil then begin if (FParent <> nil) and (FParent.FChild = Self) then FParent.FChild := FNext end else FPrev.FNext := FNext; if FNext <> nil then FNext.FPrev := FPrev; FParent := nil; FNext := nil; FPrev := nil; end; class function TcxCustomAction.GetCountActions( Action: TcxCustomAction): Integer; begin Result := 0; Action := Action.FChild; while Action <> nil do begin Action := Action.FNext; Inc(Result); end; end; procedure TcxCustomAction.DoRedo; var I: Integer; begin for I := Count - 1 downto 0 do Item[I].DoRedo; end; procedure TcxCustomAction.DoUndo; var I: Integer; begin for I := 0 to Count - 1 do Item[I].DoUndo; end; class function TcxCustomAction.GetFirstAction( Action: TcxCustomAction): TcxCustomAction; begin Result := Action; while (Result <> nil) and (Result.FPrev <> nil) do Result := Result.FPrev; end; class function TcxCustomAction.GetLastAction( Action: TcxCustomAction): TcxCustomAction; begin Result := Action; while (Result <> nil) and (Result.FNext <> nil) do Result := Result.FNext; end; class function TcxCustomAction.GetPosition( Action: TcxCustomAction): Integer; begin if Action <> nil then begin Result := 0; while Action.FPrev <> nil do begin Action := Action.FPrev; Inc(Result); end; end else Result := -1; end; procedure TcxCustomAction.InsertAfter(Action: TcxCustomAction); begin Action.DeleteFromChain; Action.FParent := Self; if FChild <> nil then begin Action.FPrev := GetLastAction(FChild); Action.FPrev.FNext := Action; end else FChild := Action.FPrev; end; procedure TcxCustomAction.InsertBefore(Action: TcxCustomAction); begin Action.DeleteFromChain; Action.FParent := Self; if FChild <> nil then begin Action.FNext := FChild; FChild.FPrev := Action; end; FChild := Action; end; function TcxCustomAction.GetCount: Integer; begin Result := GetCountActions(Self); end; function TcxCustomAction.GetHistoryOwner: TObject; begin if FOwner <> nil then Result := FOwner.Owner else Result := nil; end; function TcxCustomAction.GetItem(AIndex: Integer): TcxCustomAction; begin if AIndex >= 0 then begin Result := FChild; while (Result <> nil) and (AIndex > 0) do begin Result := Result.FNext; Dec(AIndex); end; end else Result := nil; end; { TcxSpreadSheetHistory } procedure TcxSpreadSheetHistory.Clear; begin inherited Clear; end; procedure TcxSpreadSheetHistory.ChangeUpdateState(CanUpdate: Boolean); begin inherited ChangeUpdateState(CanUpdate); if CanUpdate then TcxBookAccess(Owner).EndUpdate else TcxBookAccess(Owner).BeginUpdate; end; procedure TcxSpreadSheetHistory.UpdateFormulas; var I, ALockRef: Integer; begin ALockRef := TcxFormulasCacheAccess(TcxBookAccess(Owner).FormulasCache).FLockRef; try TcxFormulasCacheAccess(TcxBookAccess(Owner).FormulasCache).FLockRef := 0; // forward and backward recalcultion for I := 0 to TcxBookAccess(Owner).PageCount * 2 - 1 do TcxFormulasCacheAccess(TcxBookAccess(Owner).FormulasCache).DoRecalc; finally TcxFormulasCacheAccess(TcxBookAccess(Owner).FormulasCache).FLockRef := ALockRef; end; end; { TcxSpreadSheetActions } procedure TcxSpreadSheetActions.DoRedo; begin RestoreCellsData; end; procedure TcxSpreadSheetActions.DoUndo; begin RestoreCellsData; end; procedure TcxSpreadSheetActions.RestoreCellsData; var I, J: Integer; AStoredCell: TcxStoreCellRec; begin for I := FRect.Left to FRect.Right do for J := FRect.Top to FRect.Bottom do begin GetCellData(I, J, AStoredCell); SetCellData(I, J, FData[I - FRect.Left, J - FRect.Top]); FData[I - FRect.Left, J - FRect.Top] := AStoredCell; end; end; procedure TcxSpreadSheetActions.SetData(ASheet: TObject; const ACellRect: TRect; const SaveCells: Boolean = True); begin try FSheet := ASheet; FRect := ACellRect; if SaveCells then StoreCellsData(FData); except if FOwner <> nil then FOwner.SafeException; raise; end; end; procedure TcxSpreadSheetActions.StoreCellsData; var I, J: Integer; begin with FRect do SetLength(FData, (Right - Left + 1), (Bottom - Top + 1)); for I := FRect.Left to FRect.Right do for J := FRect.Top to FRect.Bottom do GetCellData(I, J, FData[I - FRect.Left, J - FRect.Top]); end; procedure TcxSpreadSheetActions.GetCellData(const ACol, ARow: Integer; var AStoredData: TcxStoreCellRec); var ACell: TcxSSCellRec; begin ACell := DataStorage[ACol, ARow]; with AStoredData do begin Data := ACell.Text; DataType := ACell.DataType; FontName := ACell.StylePtr.FontPtr.Name; FontColor := ACell.StylePtr.FontPtr.FontColor; FontStyle := ACell.StylePtr.FontPtr.Style; FontCharset := ACell.StylePtr.FontPtr.Charset; FontSize := ACell.StylePtr.FontPtr.Size; FormatIndex := ACell.StylePtr.FormatIndex; HorzAlign := ACell.StylePtr.HorzAlign; VertAlign := ACell.StylePtr.VertAlign; WordBreak := ACell.StylePtr.WordBreak; ShrinkToFit := ACell.StylePtr.ShrinkToFit; CellState := ACell.StylePtr.CellState; BrushStyle := ACell.StylePtr.BrushStyle; BrushFgColor := ACell.StylePtr.BrushFgColor; BrushBkColor := ACell.StylePtr.BrushBkColor; Borders := ACell.StylePtr.Borders; end; end; function TcxSpreadSheetActions.GetDataStorage: TcxSSDataStorage; begin if (Sheet <> nil) and (Sheet is TcxSSBookSheet) then Result := TcxSheetAccess(Sheet).DataStorage else Result := nil; end; type TcxStyleAccess = class(TcxSSCellStyle); procedure TcxSpreadSheetActions.SetCellData(const ACol, ARow: Integer; var AStoredData: TcxStoreCellRec); var ACell: TcxSSCellObject; ASide: TcxSSEdgeBorder; begin ACell := TcxSheetAccess(Sheet).GetCellObject(ACol, ARow); try with AStoredData do begin ACell.Text := Data; if DataType = dtFunction then Inc(FOwner.FFuncCount); ACell.Style.Brush.AssignInfo(BrushStyle, BrushBkColor, BrushFgColor); TcxStyleAccess(ACell.Style).SetState(CellState); TcxStyleAccess(ACell.Style).StyleInfo.FormatIndex := FormatIndex; TcxStyleAccess(ACell.Style).StyleInfo.HorzAlign := HorzAlign; TcxStyleAccess(ACell.Style).StyleInfo.VertAlign := VertAlign; TcxStyleAccess(ACell.Style).StyleInfo.WordBreak := WordBreak; ACell.Style.Font.AssignInfo(FontName, FontSize, FontStyle, FontCharset, FontColor); for ASide := eLeft to eBottom do with Borders[ASide] do ACell.Style.Borders[ASide].AssignInfo(Style, Color); end; finally ACell.Free; TcxSheetAccess(Sheet).CellsChanged(Rect(ACol, ARow, ACol, ARow)); end; end; { TcxComplexAction } function TcxComplexAction.GetActionDescription: string; begin Result := FDescription; end; procedure TcxComplexAction.CheckEmpty; var AList: TcxCustomAction; AC: TcxComplexAction; begin AList := FChild; while AList <> nil do begin if AList is TcxComplexAction then begin AC := AList as TcxComplexAction; AList := AList.FNext; AC.CheckEmpty; end else Break; end; if Count = 0 then DeleteFromChain; end; { TcxSpreadSheetInsertDeleteActions } procedure TcxSpreadSheetInsertDeleteActions.BeforeAction(ASheet: TObject; const ACellRect: TRect; AModifyType: TcxSSCellsModify); begin FModifyType := AModifyType; SetData(ASheet, ACellRect, False); FRects := TcxMergedCellsAccess(TcxDataStorageAccess(DataStorage).MergedCells).GetRects; end; { TcxInsertCellsAction } procedure TcxInsertCellsAction.DoRedo; begin TcxSheetAccess(Sheet).InsertCells(FRect, FModifyType); end; procedure TcxInsertCellsAction.DoUndo; begin TcxSheetAccess(Sheet).DeleteCells(FRect, FModifyType); end; function TcxInsertCellsAction.GetActionDescription: string; begin Result := cxGetResourceString(@scxChangeInsertCells); end; { TcxDeleteCellsAction } procedure TcxDeleteCellsAction.BeforeAction(ASheet: TObject; const ACellRect: TRect; AModifyType: TcxSSCellsModify); begin inherited; StoreCellsData(FData); end; procedure TcxDeleteCellsAction.DoRedo; begin inherited; TcxSheetAccess(Sheet).DeleteCells(FRect, FModifyType); end; procedure TcxDeleteCellsAction.DoUndo; begin try TcxSheetAccess(Sheet).InsertCells(FRect, FModifyType); finally TcxMergedCellsAccess(TcxDataStorageAccess(DataStorage).MergedCells).SetRects(FRects); inherited DoUndo; end; end; function TcxDeleteCellsAction.GetActionDescription: string; begin Result := cxGetResourceString(@scxChangeDeleteCells); end; { TcxSpreadSheetChangeCellsAction } procedure TcxSpreadSheetChangeCellsAction.BeforeAction(ASheet: TObject; const ACellRect: TRect); begin SetData(ASheet, ACellRect); end; { TcxChangeDataAction } function TcxChangeDataAction.GetActionDescription: string; begin Result := cxGetResourceString(@scxChangeCellsData); end; { TcxChangeStyleAction } function TcxChangeStyleAction.GetActionDescription: string; begin Result := cxGetResourceString(@scxChangeCellsStyle); end; { TcxMergeCellsAction } procedure TcxMergeSplitActions.BeforeAction(ASheet: TObject; const ACellRect: TRect); begin SetData(ASheet, ACellRect); FRects := TcxMergedCellsAccess(TcxDataStorageAccess(DataStorage).MergedCells).GetRects; end; procedure TcxMergeSplitActions.DoRedo; begin try inherited DoRedo; finally FRects := TcxMergedCellsAccess(TcxDataStorageAccess(DataStorage).MergedCells).SetRects(FRects); end; end; procedure TcxMergeSplitActions.DoUndo; begin try inherited DoUndo; finally FRects := TcxMergedCellsAccess(TcxDataStorageAccess(DataStorage).MergedCells).SetRects(FRects); end; end; { TcxMergeCellsAction } function TcxMergeCellsAction.GetActionDescription: string; begin Result := cxGetResourceString(@scxPopupMenuMergeCells); end; { TcxSplitCellsAction } function TcxSplitCellsAction.GetActionDescription: string; begin Result := cxGetResourceString(@scxPopupMenuSplitCells); end; end.