{*******************************************************************} { } { Developer Express Cross platform Visual Component Library } { ExpressSpreadSheet main unit } { } { 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 cxSSheet; {$I cxVer.inc} interface uses Classes, SysUtils, Math, Windows, Messages, Variants, Forms, StdCtrls, Menus, Controls, Dialogs, Graphics, ExtCtrls, dxCore, cxClasses, cxControls, cxGraphics, {$IFNDEF cxLib10} cxLookAndFeels, {$ENDIF} cxExcelConst, cxExcelAccess, cxSSHeaders, cxSSData, cxSSTypes, cxSSStyles, cxSSFormulas, cxSSViewInfo, cxSSPainters, cxSSEditors, cxSSUtils, cxSSPainterWrapper, cxSSIntf, cxSSRes, cxSSHistory, Clipbrd; type TcxCustomSpreadSheetBook = class; TcxSSBookSheet = class; ESpreadSheetError = class(EdxException); TcxSSListenerClass = class of TcxSSListener; TcxSSBookSheetClass = class of TcxSSBookSheet; TcxSSFormatDialogClass = class of TcxSSFormatDialog; TcxScrollBars = (sbsNone, sbsHorizontal, sbsVertical, sbsBoth); { TcxSSListener } TcxSSListener = class private FLockCount: Integer; FOwner: TcxCustomSpreadSheetBook; protected function BeginUpdate: Integer; function EndUpdate: Integer; function IsLocked: Boolean; procedure OnActiveCellChanging(Sender: TcxSSBookSheet; const ActiveCell: TPoint; var CanSelect: Boolean); virtual; procedure OnActiveSheetChanging(Sender: TcxCustomSpreadSheetBook; const ActiveSheet: Integer; var CanSelect: Boolean); virtual; procedure OnChangeCellData(Sender: TcxSSBookSheet; const ACol, ARow: Integer); virtual; procedure OnChangeDefaultStyle(const AOldValue, ANewValue: TcxSSCellStyleRec); virtual; procedure OnChangeLockColRow(Sender: TcxSSBookSheet; AKind: TcxSSHeaderType; AIndex: Integer; AOldValue, ANewValue: Boolean); virtual; procedure OnChangeSelection(Sender: TcxSSBookSheet; const AOldValue, ANewValue: TRect); virtual; procedure OnChangeSheetCaption(Sender: TcxSSBookSheet; var ACaption: string); virtual; procedure OnChangeSizeColRow(Sender: TcxSSBookSheet; AKind: TcxSSHeaderType; AIndex: Integer; var ANewSize: TcxSSSize); virtual; procedure OnChangeVisibleColRow(Sender: TcxSSBookSheet; AKind: TcxSSHeadertype; AIndex: Integer; AOldValue, ANewValue: Boolean); virtual; procedure OnClearCells(Sender: TcxSSBookSheet; const ACellRec: TRect; var AUseDefaultStyle, CanClear: Boolean); virtual; procedure OnEditing(Sender: TcxSSBookSheet; const ACol, ARow: Integer; var CanEdit: Boolean); virtual; procedure OnDeleteCells(Sender: TcxSSBookSheet; ACellRect: TRect; AModifyType: TcxSSModifyType); virtual; procedure OnHistoryChanged(Sender: TObject); virtual; procedure OnInsertCells(Sender: TcxSSBookSheet; ACellRect: TRect; AModifyType: TcxSSModifyType); virtual; procedure OnMergeCells(Sender: TcxSSBookSheet; ACellRect: TRect; AIsMerge: Boolean; var CanMerge: Boolean); virtual; procedure OnProgress(Sender: TObject; APercent: Byte); virtual; procedure OnResizeDataLength(Sender: TcxSSBookSheet; AType: TcxSSHeaderType); virtual; procedure OnSheetPopupMenu(Sender: TcxSSBookSheet; const AHitPoint: TPoint); virtual; procedure OnTopLeftChanging(Sender: TcxSSBookSheet; var ATopLeft: TPoint); virtual; procedure OnCaptionPopupMenu(Sender: TcxSSBookSheet; const AHitPoint: TPoint); virtual; procedure UpdateAfterChanged(Sender: TcxSSBookSheet; ACellRect: TRect); virtual; property LockRef: Integer read FLockCount; public constructor Create(AOwner: TcxCustomSpreadSheetBook); virtual; property Owner: TcxCustomSpreadSheetBook read FOwner; end; { TcxWorkBookControl } TcxWorkBookSubControl = class(TInterfacedObject) private FBounds: TRect; FOwner: TcxCustomSpreadSheetBook; FVisible: Boolean; function GetBoundsRect: TRect; function GetCanvas: TcxCanvasWrapper; function GetClientRect: TRect; function GetControlCanvas: TCanvas; function GetCursor: TCursor; function GetHeight: Integer; function GetLeft: Integer; function GetTop: Integer; function GetWidth: Integer; procedure SetBoundsRect(ARect: TRect); procedure SetCursor(const Value: TCursor); procedure SetHeight(const Value: Integer); procedure SetLeft(const Value: Integer); procedure SetTop(const Value: Integer); procedure SetVisible(const Value: Boolean); procedure SetWidth(const Value: Integer); protected function ClientToScreen(const X, Y: Integer): TPoint; procedure DblClick; virtual; procedure FocusChanged; virtual; procedure KeyDown(var Key: Word; Shift: TShiftState); virtual; procedure KeyPress(var Key: Char); virtual; procedure KeyUp(var Key: Word; Shift: TShiftState); virtual; procedure MouseMove(Shift: TShiftState; X, Y: Integer); virtual; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual; procedure Paint; virtual; procedure Resize; virtual; procedure SetBounds(const ALeft, ATop, AWidth, AHeight: Integer); procedure VisibleChanging; virtual; property Canvas: TcxCanvasWrapper read GetCanvas; property ControlCanvas: TCanvas read GetControlCanvas; property BoundsRect: TRect read GetBoundsRect write SetBoundsRect; property ClientRect: TRect read GetClientRect; property Height: Integer read GetHeight write SetHeight; property Left: Integer read GetLeft write SetLeft; property Owner: TcxCustomSpreadSheetBook read FOwner; property Top: Integer read GetTop write SetTop; property Visible: Boolean read FVisible write SetVisible; property Width: Integer read GetWidth write SetWidth; property Cursor: TCursor read GetCursor write SetCursor; public constructor Create(AOwner: TcxCustomSpreadSheetBook); virtual; procedure Invalidate; virtual; procedure InvalidateRect(ARect: TRect); end; TcxSSBookPageCaptionsClass = class of TcxSSBookPageCaptions; { TcxSSBookPageCaptions } TcxSSBookPageCaptions = class(TcxWorkBookSubControl) private FCaptionEditor: TcxSSInplaceTextEdit; FCaptionPainter: TcxPageCaptionPainter; FIsEditorActivate: Boolean; FMouseDownPos: TPoint; FSkipActivePageChanging: Boolean; FViewInfo: TcxSSBookCaptionViewInfo; function GetFirstVisibleCaption: Integer; procedure SetFirstVisibleCaption(const Value: Integer); protected procedure ActivateEditor; procedure DblClick; override; procedure DoEditCaption; virtual; function GetCaptionTextExtent(APage: Integer): TRect; function HitTest(X, Y: Integer; var AIndex: Integer): TcxSSCaptionHitTest; procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure OnEditCaptionText(Sender: TObject); virtual; procedure OnEndEditCaption(Sender: TObject); virtual; procedure Paint; override; procedure ReCalcViewInfo; virtual; procedure Resize; override; procedure UpdateCaptionInfo(APage: Byte; AState: TcxSSCaptionStates); virtual; procedure VisibleChanging; override; property ViewInfo: TcxSSBookCaptionViewInfo read FViewInfo; property PageCaptionPainter: TcxPageCaptionPainter read FCaptionPainter write FCaptionPainter; public property FirstVisibleCaption: Integer read GetFirstVisibleCaption write SetFirstVisibleCaption; constructor Create(AOwner: TcxCustomSpreadSheetBook); override; destructor Destroy; override; procedure MakeTabVisible(AIndex: Integer); end; { TcxSSCellObject } TcxSSCellObject = class(TInterfacedObject, IcxSpreadSheetCell) private FCol: Integer; FComplexAction: TcxComplexAction; FCreatedStyle: TcxSSCellStyle; FOwner: TcxSSDataStorage; FAction: TcxCustomAction; FRow: Integer; function GetCellStyle: IcxSpreadSheetCellStyle; function GetCellTextValue: string; function GetCellValue: Variant; function GetDataType: TcxSSDataType; function GetDateTime: TDateTime; function GetDisplayText: string; function GetDisplayTextAlignment: TcxDisplayTextAlignment; function GetIsLoading: Boolean; function GetMergedRect: TRect; function GetOwnerSheet: TcxSSBookSheet; function GetStyle: TcxSSCellStyle; function GetStyleExist: Boolean; function GetText: string; procedure SetDateTime(const Value: TDateTime); procedure SetStyle(const Value: TcxSSCellStyle); procedure SetText(const Value: string); procedure SetTextEx(const Value: string; IsFormula: Boolean = False; Analyze: Boolean = True); protected procedure CheckCellWordBreak; property Action: TcxCustomAction read FAction; property ComplexAction: TcxComplexAction read FComplexAction; property IsLoading: Boolean read GetIsLoading; property Owner: TcxSSDataStorage read FOwner; property OwnerSheet: TcxSSBookSheet read GetOwnerSheet; property MergedRect: TRect read GetMergedRect; public constructor Create(AOwner: TcxSSDataStorage; ACol, ARow: Integer); virtual; destructor Destroy; override; procedure Assign(Source: TcxSSCellObject); virtual; procedure SetCellText(const AText: string; const NeedParse: Boolean = False); property Col: Integer read FCol; property DateTime: TDateTime read GetDateTime write SetDateTime; property DataType: TcxSSDataType read GetDataType; property DisplayText: string read GetDisplayText; property DisplayTextAlignment: TcxDisplayTextAlignment read GetDisplayTextAlignment; property Text: string read GetText write SetText; property Row: Integer read FRow; property CellValue: Variant read GetCellValue; property Style: TcxSSCellStyle read GetStyle write SetStyle; property StyleExist: Boolean read GetStyleExist; end; TcxSSSheetState = (ssResize, ssColHeader, ssRowHeader, ssEditorActivate, ssSelection); TcxSSSheetStates = set of TcxSSSheetState; { TcxSSBookSheet } TcxSSBookSheet = class(TcxWorkBookSubControl, IcxBookSheet) private FChangedSizeValue: TcxSSSize; FCurrentPos: TPoint; FDataStorage: TcxSSDataStorage; FDownCellPos: TPoint; FEditingPos: TPoint; FIsEditMode: Boolean; FMouseDownPos: TPoint; FProtected: Boolean; FReadOnly: Boolean; FResizeHeaderType: TcxSSHeaderType; FSheetViewInfo: TcxSSheetViewInfo; FSheetState: TcxSSSheetStates; FShowGrid: Boolean; FShowHeaders: Boolean; FShowFormulas: Boolean; FSizeIndex: Integer; FStartSelection: TPoint; function GetActiveCell: TPoint; function GetCell(const ACol, ARow: Integer): IcxSpreadSheetCell; function GetCellEditor: TcxSSInplaceTextEdit; function GetColHeader: TcxSSHeader; function GetColumnCount: Integer; function GetCorners: TRect; function GetContentColCount: Integer; function GetContentRowCount: Integer; function GetCurrentCol: Integer; function GetCurrentRow: Integer; function GetHistory: TcxSpreadSheetHistory; function GetIsLoaded: Boolean; function GetListener: TcxSSListener; function GetPageIndex: Integer; function GetSheetCaption: string; function GetRowCount: Integer; function GetRowHeader: TcxSSHeader; function GetSelectionRect: TRect; function GetTopLeft: TPoint; procedure SetActiveCell(const Value: TPoint); procedure SetColRowSize(const AKind: TcxSSHeaderType; const AColumn, ASize: Integer; ALocked: Boolean; AVisible: Boolean = True); procedure SetCorners(const Value: TRect); procedure SetDefaultSize(const AKind: TcxSSHeaderType; ASize: Integer); procedure SetMergedCells(const ARect: TRect; IsMerge: Boolean); procedure SetPageDimension(const AHorzCount, AVertCount: Integer); procedure SetProtection(Value: Boolean); procedure SetSheetCaption(Value: string); procedure SetShowGrid(const Value: Boolean); procedure SetShowHeaders(const Value: Boolean); procedure SetShowFormulas(const Value: Boolean); procedure SetSelectionRect(Value: TRect); procedure SetTopLeft(const Value: TPoint); procedure SetViewInformation(const ASelectionRect: TRect; AViewFormulas, AViewGrid, AViewHeaders, AScrollBars: Boolean); protected procedure CellsChanged(const ARect: TRect); virtual; procedure DblClick; override; function DoEditorActivate: Boolean; virtual; function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; virtual; procedure FocusChanged; override; procedure InitScrollBars; virtual; procedure KeyDown(var Key: Word; Shift: TShiftState); override; procedure KeyPress(var Key: Char); override; procedure KeyUp(var Key: Word; Shift: TShiftState); override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure OnEndEditCell(Sender: TObject); virtual; procedure Paint; override; procedure Scroll(AScrollBarKind: TScrollBarKind; AScrollCode: TScrollCode; var AScrollPos: Integer; IsViewInfoUpdate: Boolean = True); virtual; function ViewInfoValid: Boolean; property CurrentPos: TPoint read FCurrentPos; property CellEditor: TcxSSInplaceTextEdit read GetCellEditor; property DataStorage: TcxSSDataStorage read FDataStorage; property IsEditMode: Boolean read FIsEditMode write FIsEditMode; property IsLoaded: Boolean read GetIsLoaded; property History: TcxSpreadSheetHistory read GetHistory; property Listener: TcxSSListener read GetListener; property TopLeft: TPoint read GetTopLeft write SetTopLeft; property ViewInfo: TcxSSheetViewInfo read FSheetViewInfo; public constructor Create(AOwner: TcxCustomSpreadSheetBook); override; destructor Destroy; override; procedure ApplyAutoHeight(ARow: Integer); virtual; procedure Assign(Source: TcxSSBookSheet); virtual; procedure ClearAll; virtual; procedure ClearCells(const ARect: TRect; SetDefaultStyle: Boolean = False); procedure Copy(const ARect: TRect; IsCut: Boolean); procedure DeleteCells(const ACells: TRect; ACellsModify: TcxSSCellsModify); procedure FormatCells(const ACells: TRect); function GetCellObject(ACol, ARow: Integer): TcxSSCellObject; virtual; procedure InsertCells(const ACells: TRect; ACellsModify: TcxSSCellsModify); procedure Invalidate; override; procedure Paste(const APlace: TPoint); procedure SelectCell(const ACol, ARow: Integer; OpenEditor: Boolean = False); procedure SetMergedState(const ARect: TRect; IsMerge: Boolean); procedure SetVisibleState(const ARect: TRect; ACols, ARows, AShow: Boolean); procedure Sort(const ARect: TRect; const ASortTypes: array of TcxSortType); property ActiveCell: TPoint read GetActiveCell write SetActiveCell; property Caption: string read GetSheetCaption write SetSheetCaption; property Col: Integer read GetCurrentCol; property Cols: TcxSSHeader read GetColHeader; property ColumnCount: Integer read GetColumnCount; property Corners: TRect read GetCorners write SetCorners; property ContentColCount: Integer read GetContentColCount; property ContentRowCount: Integer read GetContentRowCount; property PageIndex: Integer read GetPageIndex; property Protected: Boolean read FProtected write FProtected; property ReadOnly: Boolean read FReadOnly write FReadOnly; property Row: Integer read GetCurrentRow; property Rows: TcxSSHeader read GetRowHeader; property RowCount: Integer read GetRowCount; property SelectionRect: TRect read GetSelectionRect write SetSelectionRect; property ShowGrid: Boolean read FShowGrid write SetShowGrid; property ShowHeaders: Boolean read FShowHeaders write SetShowHeaders; property ShowFormulas: Boolean read FShowFormulas write SetShowFormulas; end; TcxSSActiveCellChangingEvent = procedure(Sender: TcxSSBookSheet; const ActiveCell: TPoint; var CanSelect: Boolean) of object; TcxSSActiveSheetChangingEvent = procedure(Sender: TcxCustomSpreadSheetBook; const ActiveSheet: Integer; var CanSelect: Boolean) of object; TcxSSCellChangeEvent = procedure(Sender: TcxSSBookSheet; const ACol, ARow: Integer) of object; TcxSSClearCellsEvent = procedure(Sender: TcxSSBookSheet; const ACellRect: TRect; var UseDefaultStyle, CanClear: Boolean) of object; TcxSSCustomPaintEvent = procedure (Sender: TObject; var PainterClass: TcxSheetPainterClass) of object; TcxSSDeleteSheetEvent = procedure(const ASheet: Integer; var CanDelete: Boolean) of object; TcxSSExchangeSheetsEvent = procedure(const ASheet1, ASheet2: Integer; var CanExchange: Boolean) of object; TcxSSSetSelectionEvent = procedure (Sender: TObject; ASheet: TcxSSBookSheet) of object; TcxSSSetPositionEvent = procedure (Sender: TObject; ASheet: TcxSSBookSheet) of object; TcxSSChangeVisible = procedure (Sender: TObject; ASheet: TcxSSBookSheet; AChangedIndex: Integer; APrevValue, ANewValue: Boolean) of object; TcxSSPopupMenuEvent = procedure (Sender: TObject; X, Y: Integer) of object; TcxSSResizeEvent = procedure(Sender: TcxSSBookSheet; AIndex: Integer; var ANewSize: TcxSSSize) of object; TcxSSFormatCellsEvent = procedure(Sender: TObject; var ACells: TRect; var CanFormat: Boolean; out FormatDialogClass: TcxSSFormatDialogClass) of object; TcxSSTopLeftChangingEvent = procedure(Sender: TcxSSBookSheet; var ATopLeft: TPoint) of object; TcxSSMergeCellsEvent = procedure(Sender: TcxSSBookSheet; ACellRect: TRect; AIsMerge: Boolean; var CanMerge: Boolean) of object; TcxSSChangeCaptionEvent = procedure(Sender: TcxSSBookSheet; var ACaption: string) of object; TcxSSEditingEvent = procedure(Sender: TcxSSBookSheet; const ACol, ARow: Integer; var CanEdit: Boolean) of object; {$IFNDEF DELPHI5} TcxSSContextPopupEvent = procedure(Sender: TObject; MousePos: TPoint; var Handled: Boolean) of object; {$ENDIF} { TcxCustomSpreadSheetBook } TcxCustomSpreadSheetBook = class(TcxControl, IUnknown, IcxSpreadSheetBook) private FTimer: TTimer; FActivePage: Integer; FBufferedPaint: Boolean; FCanvas: TcxCanvasWrapper; FCaptionBar: TcxSSBookPageCaptions; FCaptureControl: TcxWorkBookSubControl; FCellEditor: TcxSSInplaceTextEdit; FColHeaderHeight: Integer; FContextPopupHandled: Boolean; FDefaultColWidth: TcxSSSize; FDefaultRowHeight: TcxSSSize; FFormulasCache: TcxSSFormulasCache; FFloatPrecision: Byte; FGridColor: TColor; FHeaderColor: TColor; FHeaderFont: TFont; FHistory: TcxSpreadSheetHistory; FHideSelection: Boolean; FIsLoaded: Boolean; FListener: TcxSSListener; FProtected: Boolean; FMouseDownPos: TPoint; FMousePos: TPoint; FModified: Boolean; FPainter: TcxSheetPainter; FPaintBitmap: TBitmap; FPainterType: TcxSSPainterType; FPages: TList; FPageVisible: array of Boolean; FPalette: TcxExcelPalette; FReadOnly: Boolean; FRowHeaderWidth: Integer; FRowsAutoHeight: Boolean; FScrollBars: TcxScrollBars; FSelectionColor: TColor; FShift: TShiftState; FShowCaptionBar: Boolean; FShowFormulas: Boolean; FShowGrid: Boolean; FStyleCache: TcxSSStyleCache; FWindowColor: TColor; FOnActiveCellChanging: TcxSSActiveCellChangingEvent; FOnActiveSheetChanging: TcxSSActiveSheetChangingEvent; FOnAfterCalculation: TNotifyEvent; FOnCaptionPopupMenu: TcxSSPopupMenuEvent; FOnCellChange: TcxSSCellChangeEvent; FOnClearCells: TcxSSClearCellsEvent; FOnChangeColVisible: TcxSSChangeVisible; FOnChangeCaption: TcxSSChangeCaptionEvent; FOnChangeRowVisible: TcxSSChangeVisible; {$IFNDEF DELPHI5} FOnContextPopup: TcxSSContextPopupEvent; {$ENDIF} FOnCustomPaint: TcxSSCustomPaintEvent; FOnEditing: TcxSSEditingEvent; FOnEndEdit: TNotifyEvent; FOnFormatCells: TcxSSFormatCellsEvent; FOnHistoryChanged: TNotifyEvent; FOnMergeCells: TcxSSMergeCellsEvent; FOnProgress: TcxProgressEvent; FOnResizeCol: TcxSSResizeEvent; FOnResizeRow: TcxSSResizeEvent; FOnSetSelection: TcxSSSetSelectionEvent; FOnSheetPopupMenu: TcxSSPopupMenuEvent; FOnTopLeftChanging: TcxSSTopLeftChangingEvent; FExcelProtectionStyle: Boolean; function AddSheet(const AName: string; AVisible: Boolean): IcxBookSheet; function GetActiveCell: TPoint; function GetActiveSheet: TcxSSBookSheet; function GetAutoReCalc: Boolean; function GetCell(APage: Word; ACol, ARow: Integer): IcxSpreadSheetCell; function GetDefinedNames: TcxSSNamesDef; function GetDefaultStyle: TcxSSDefaultStyle; function GetPage(APage: Integer): TcxSSBookSheet; function GetPageCount: Word; function GetPageSelection(APage: Word): TRect; function GetPageVisible(APage: Word): Boolean; function GetRCRefStyle: Boolean; function GetSelection: TRect; function GetSheet(APage: Word): IcxBookSheet; function GetShowHeaders: Boolean; procedure SetActiveCell(const AValue: TPoint); procedure SetActivePage(AValue: Integer); procedure SetAutoRecalc(const AValue: Boolean); procedure SetBufferedPaint(const AValue: Boolean); procedure SetColHeaderHeight(const AValue: Integer); procedure SetCustomPainter(const AValue: TcxSSCustomPaintEvent); procedure SetDefaultColWidth(const AValue: TcxSSSize); procedure SetDefaultStyle(const AStyle: PcxSSCellStyleRec); procedure SetDefaultStyleProperty(AValue: TcxSSDefaultStyle); procedure SetDefaultRowHeight(const AValue: TcxSSSize); procedure SetDefaultColor(const AValue: TColor); procedure SetFloatPrecision(const AValue: Byte); procedure SetGridColor(const AValue: TColor); procedure SetHeaderFont(AValue: TFont); procedure SetHeaderColor(const AValue: TColor); procedure SetPainterType(const AValue: TcxSSPainterType); procedure SetPageCount(const AValue: Word); procedure SetPageSelection(APage: Word; const AValue: TRect); procedure SetPageVisible(APage: Word; const AValue: Boolean); procedure SetPalette(const APalette: PcxExcelPalette); procedure SetProtection(Value: Boolean); procedure SetRCRefStyle(const AValue: Boolean); procedure SetReadOnly(const AValue: Boolean); procedure SetRowHeaderWidth(const AValue: Integer); procedure SetSelectionColor(const AValue: TColor); procedure SetScrollBars(const AValue: TcxScrollBars); procedure SetShowCaptionBar(const AValue: Boolean); procedure SetShowFormulas(const AValue: Boolean); procedure SetShowHeaders(const AValue: Boolean); procedure SetShowGrid(const AValue: Boolean); procedure SetSelection(const AValue: TRect); procedure CM_CHANGELOCALE(var Message: TMessage); message CM_WININICHANGE; {$IFNDEF DELPHI5} procedure WMRButtonUp(var Message: TWMRButtonUp); message WM_RBUTTONUP; {$ENDIF} protected IsDataLoading: Boolean; procedure AddPage(ASheet: TcxSSBookSheet); virtual; procedure AddSheetPage(const APageName: string = ''); virtual; procedure AdjustControls; virtual; procedure DblClick; override; procedure DoRecalc; function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; override; {$IFDEF DELPHI5} procedure DoContextPopup( MousePos: TPoint; var Handled: Boolean); override; {$ENDIF} procedure FocusChanged; override; function GetBookPageCaptionsClass: TcxSSBookPageCaptionsClass; function GetCaptionPainterClass: TcxPageCaptionPainterClass; virtual; function GetDataStorageClass: TcxSSDataStorageClass; virtual; function GetFormulasCacheClass: TcxFormulasCacheClass; virtual; function GetHeaderClass: TcxSSHeaderClass; virtual; function GetHistoryClass: TcxSSHistoryClass; virtual; function GetHScrollBarBounds: TRect; override; function GetInplaceEditClass: TcxSSInplaceEditClass; virtual; function GetListenerClass: TcxSSListenerClass; virtual; function GetPainterClass: TcxSheetPainterClass; virtual; function GetPalettePtr: PcxExcelPalette; function GetStyleCacheClass: TcxSSStyleCacheClass; virtual; function GetSheetClass: TcxSSBookSheetClass; virtual; function GetVScrollBarBounds: TRect; override; function GetViewInfoClass: TcxSSheetViewInfoClass; virtual; procedure InitScrollBarsParameters; override; procedure InternalUpdate; virtual; procedure KeyDown(var Key: Word; Shift: TShiftState); override; procedure KeyPress(var Key: Char); override; procedure KeyUp(var Key: Word; Shift: TShiftState); override; procedure Loaded; override; procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure OnChangeHeaderStyle(Sender: TObject); virtual; procedure OnMouseTimerHandle(Sender: TObject); virtual; procedure Paint; override; procedure Resize; override; procedure Scroll(AScrollBarKind: TScrollBarKind; AScrollCode: TScrollCode; var AScrollPos: Integer); override; function SpreadSheetClipboardDataToData(ASheet: TcxSSBookSheet; const AColPos, ARowPos: Integer; out AChangedRect: TRect): Boolean; virtual; function SpreadSheetDataToClipboardData(ASheet: TcxSSBookSheet; const ACells: TRect): AnsiString; virtual; procedure SetModified; procedure VisibleChanging; override; function ViewInfoValid: Boolean; property ActiveCell: TPoint read GetActiveCell write SetActiveCell; property ActivePage: Integer read FActivePage write SetActivePage; property ActiveSheet: TcxSSBookSheet read GetActiveSheet; property AutoRecalc: Boolean read GetAutoRecalc write SetAutoRecalc default True; property CaptureControl: TcxWorkBookSubControl read FCaptureControl; property ColHeaderHeight: Integer read FColHeaderHeight write SetColHeaderHeight default 20; property CaptionBar: TcxSSBookPageCaptions read FCaptionBar; property Canvas: TcxCanvasWrapper read FCanvas; property DefaultColWidth: TcxSSSize read FDefaultColWidth write SetDefaultColWidth default 85; property DefaultRowHeight: TcxSSSize read FDefaultRowHeight write SetDefaultRowHeight default 20; property DefaultStyle: TcxSSDefaultStyle read GetDefaultStyle write SetDefaultStyleProperty; property DefinedNames: TcxSSNamesDef read GetDefinedNames; property FormulasCache: TcxSSFormulasCache read FFormulasCache; property GridColor: TColor read FGridColor write SetGridColor default clBtnFace; property HeaderColor: TColor read FHeaderColor write SetHeaderColor default clBtnFace; property HeaderFont: TFont read FHeaderFont write SetHeaderFont; property History: TcxSpreadSheetHistory read FHistory; property IsLoaded: Boolean read FIsLoaded; property Listener: TcxSSListener read FListener; property PageCount: Word read GetPageCount write SetPageCount default 1; property PageSelection[APage: Word]: TRect read GetPageSelection write SetPageSelection; property Pages[APage: Integer]: TcxSSBookSheet read GetPage; default; property PageVisible[APage: Word]: Boolean read GetPageVisible write SetPageVisible; property PaintBitmap: TBitmap read FPaintBitmap; property Painter: TcxSheetPainter read FPainter; property PainterType: TcxSSPainterType read FPainterType write SetPainterType default ptOffice97Style; property Palette: PcxExcelPalette read GetPalettePtr; property Precision: Byte read FFloatPrecision write SetFloatPrecision default 2; property RowHeaderWidth: Integer read FRowHeaderWidth write SetRowHeaderWidth default 85; property SelectionColor: TColor read FSelectionColor write SetSelectionColor default clHighLight; property StyleCache: TcxSSStyleCache read FStyleCache; property ShowCaptionBar: Boolean read FShowCaptionBar write SetShowCaptionBar default True; property ShowFormulas: Boolean read FShowFormulas write SetShowFormulas default False; property ShowGrid: Boolean read FShowGrid write SetShowGrid default True; property ShowHeaders: Boolean read GetShowHeaders write SetShowHeaders default True; property SelectionRect: TRect read GetSelection write SetSelection; property OnActiveCellChanging: TcxSSActiveCellChangingEvent read FOnActiveCellChanging write FOnActiveCellChanging; property OnActiveSheetChanging: TcxSSActiveSheetChangingEvent read FOnActiveSheetChanging write FOnActiveSheetChanging; property OnAfterCalculation: TNotifyEvent read FOnAfterCalculation write FOnAfterCalculation; property OnChangeColVisible: TcxSSChangeVisible read FOnChangeColVisible write FOnChangeColVisible; property OnChangeSheetCaption: TcxSSChangeCaptionEvent read FonChangeCaption write FonChangeCaption; property OnChangeRowVisible: TcxSSChangeVisible read FOnChangeRowVisible write FOnChangeRowVisible; property OnCellChange: TcxSSCellChangeEvent read FOnCellChange write FOnCellChange; property OnClearCells: TcxSSClearCellsEvent read FOnClearCells write FOnClearCells; {$IFNDEF DELPHI5} property OnContextPopup: TcxSSContextPopupEvent read FOnContextPopup write FOnContextPopup; {$ENDIF} property OnCustomPaint: TcxSSCustomPaintEvent read FOnCustomPaint write SetCustomPainter; property OnEditing: TcxSSEditingEvent read FOnEditing write FOnEditing; property OnEndEdit: TNotifyEvent read FOnEndEdit write FOnEndEdit; property OnFormatCells: TcxSSFormatCellsEvent read FOnFormatCells write FOnFormatCells; property OnHistoryChanged: TNotifyEvent read FOnHistoryChanged write FOnHistoryChanged; property OnMergeCells: TcxSSMergeCellsEvent read FOnMergeCells write FOnMergeCells; property OnProgress: TcxProgressEvent read FOnProgress write FOnProgress; property OnResizeCol: TcxSSResizeEvent read FOnResizeCol write FOnResizeCol; property OnResizeRow: TcxSSResizeEvent read FOnResizeRow write FOnResizeRow; property OnSetSelection: TcxSSSetSelectionEvent read FOnSetSelection write FOnSetSelection; property OnSheetPopupMenu: TcxSSPopupMenuEvent read FOnSheetPopupMenu write FOnSheetPopupMenu; property OnCaptionPopupMenu: TcxSSPopupMenuEvent read FOnCaptionPopupMenu write FOnCaptionPopupMenu; property OnTopLeftChanging: TcxSSTopLeftChangingEvent read FOnTopLeftChanging write FOnTopLeftChanging; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Assign(Source: TPersistent); override; function BeginUpdate: Integer; function CellsNameByRef(ASheet: Integer; const CellsRef: TRect; IsText: Boolean = True): string; procedure ClearAll; procedure DeactivateEditor; function DeleteName(const AName: string): Boolean; virtual; function DefineName(const AName: string; APage: Word; const ARect: TRect): Integer; virtual; function DefineNameEx(const AName: string; APage: Word; const ARect: TRect; Validate: Boolean = True): Integer; virtual; function EndUpdate: Integer; function HasRectName(ASheet: Integer; const ARect: TRect): Integer; function HitTest(const APoint: TPoint; out HitTestInfo: TcxSSHitTestInfo): Boolean; virtual; procedure LoadFromFile(const AFileName: string); virtual; procedure LoadFromStream(Stream: TStream); virtual; procedure Recalc; virtual; procedure SaveToFile(const AFileName: string); virtual; procedure SaveToStream(AStream: TStream); virtual; procedure UpdateControl; virtual; property DocumentModified: Boolean read FModified; published property BufferedPaint: Boolean read FBufferedPaint write SetBufferedPaint default False; property ExcelProtectionStyle: Boolean read FExcelProtectionStyle write FExcelProtectionStyle default True; property HideSelection: Boolean read FHideSelection write FHideSelection default False; property R1C1ReferenceStyle: Boolean read GetRCRefStyle write SetRCRefStyle default False; property RowsAutoHeight: Boolean read FRowsAutoHeight write FRowsAutoHeight default True; property ScrollBars: TcxScrollBars read FScrollBars write SetScrollBars default sbsBoth; property BackgroundColor: TColor read FWindowColor write SetDefaultColor default clWindow; property ReadOnly: Boolean read FReadOnly write SetReadOnly default False; property Protected: Boolean read FProtected write FProtected default False; property Visible; end; { TcxSSFormatDialog } TcxSSFormatDialog = class(TForm) public {$IFDEF DELPHI9} constructor Create(AOwner: TComponent); override; {$ENDIF} function Execute(const ACells: TRect; ASheet: TcxSSBookSheet): Boolean; virtual; published property Position default poDesigned; end; { TcxSpreadSheetBook } TcxSpreadSheetBook = class(TcxCustomSpreadSheetBook) private FOnDeleteSheet: TcxSSDeleteSheetEvent; FOnExchangeSheets: TcxSSExchangeSheetsEvent; public constructor Create(AOwner: TComponent); override; procedure AddSheetPage(const APageName: string = ''); override; procedure EditActiveSheetCaption; procedure ExchangeSheets(const ASheet1, ASheet2: Integer); virtual; procedure DeleteSheet(const ASheet: Integer); virtual; property ActiveCell; property ActivePage; property ActiveSheet; property DefinedNames; property History; property Palette; property Pages; property PageVisible; property SelectionRect; published property Align; property Anchors; property AutoRecalc; property ColHeaderHeight; property DefaultStyle; property DefaultColWidth; property DefaultRowHeight; property GridColor; property HeaderFont; property HeaderColor; property PainterType; property Precision; property PageCount; property PopupMenu; property RowHeaderWidth; property SelectionColor; property ShowCaptionBar; property ShowFormulas; property ShowGrid; property ShowHeaders; property OnDeleteSheet: TcxSSDeleteSheetEvent read FOnDeleteSheet write FOnDeleteSheet; property OnExchangeSheets: TcxSSExchangeSheetsEvent read FOnExchangeSheets write FOnExchangeSheets; property OnActiveCellChanging; property OnActiveSheetChanging; property OnAfterCalculation; property OnCellChange; property OnChangeColVisible; property OnChangeSheetCaption; property OnChangeRowVisible; property OnClearCells; property OnCustomPaint; property OnEditing; property OnEndEdit; property OnFormatCells; property OnHistoryChanged; property OnMergeCells; property OnProgress; property OnResizeCol; property OnResizeRow; property OnSetSelection; property OnSheetPopupMenu; property OnCaptionPopupMenu; property OnTopLeftChanging; property OnEnter; property OnExit; property OnClick; property OnContextPopup; property OnDblClick; property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnResize; property OnKeyDown; property OnKeyPress; property OnKeyUp; end; { TcxSpreadSheet } TcxSpreadSheet = class(TcxCustomSpreadSheetBook) private function GetSheet: TcxSSBookSheet; public constructor Create(AOwner: TComponent); override; property Sheet: TcxSSBookSheet read GetSheet; property ActiveCell; property History; property DefinedNames; property Palette; property SelectionRect; published property Align; property Anchors; property AutoRecalc; property ColHeaderHeight; property DefaultStyle; property DefaultColWidth; property DefaultRowHeight; property GridColor; property HeaderFont; property HeaderColor; property PainterType; property Precision; property RowHeaderWidth; property SelectionColor; property ShowFormulas; property ShowGrid; property ShowHeaders; property OnActiveCellChanging; property OnAfterCalculation; property OnCellChange; property OnChangeColVisible; property OnChangeRowVisible; property OnClearCells; property OnCustomPaint; property OnEditing; property OnEndEdit; property OnFormatCells; property OnHistoryChanged; property OnMergeCells; property OnProgress; property OnResizeCol; property OnResizeRow; property OnSetSelection; property OnSheetPopupMenu; property OnTopLeftChanging; property OnEnter; property OnExit; property OnClick; property OnContextPopup; property OnDblClick; property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnResize; property OnKeyDown; property OnKeyPress; property OnKeyUp; end; { TcxSSClipboard } TcxSSClipboard = class private function GetESSData: AnsiString; function GetUnicodeData: WideString; procedure SetUnicodeData(const Value: WideString); procedure SetESSData(const Value: AnsiString); protected function BufferSize(AFormat: Word): Integer; procedure GetBuffer(AFormat: Word; var ABuffer); procedure SetBuffer(AFormat: Word; const ABuffer; ASize: Integer; ClearClipboard: Boolean); public property DataAsUnicode: WideString read GetUnicodeData write SetUnicodeData; property DataAsEssFormat: AnsiString read GetESSData write SetEssData; end; function CanModify(ABook, ASheet: TObject; ACol, ARow: Integer): Boolean; overload; function CanModify(ABook, ASheet: TObject; const ARect: TRect): Boolean; overload; function CellReadOnly(ABook, ASheet: TObject; ACol, ARow: Integer): Boolean; implementation uses cxSSDesigner, cxLibraryConsts; {$R *.res} type TcxHeaderAccess = class(TcxSSHeader); TcxHistoryAccess = class(TcxSpreadSheetHistory); TcxDataStorageAccess = class(TcxSSDataStorage); TcxFormulasAccess = class(TcxSSFormulasCache); TcxStyleAccess = class(TcxSSCellStyle); TCustomControlAccess = class(TCustomControl); TWinControlAccess = class(TWinControl); var cxSSClipboard: TcxSSClipboard; CF_ESSDATA: Integer; const SCF_ESSCLIPBOARDFORMAT = 'ExpressSpreadSheet 1.0'; CellTerminator = #9; RowTerminator = #13#10; cxHScrollHeight: Integer = 16; cxVScrollWidth: Integer = 16; ScrollersVisible: array[TcxScrollBars, TScrollBarKind] of Boolean = ((False, False), (True, False), (False, True), (True, True)); function OrdinalToFormatStr(const AString: string; AFormat: TxlsDataFormat; ADig: Byte): string; var AFValue: Double; ABValue: Boolean; AColor: Word; begin Result := AString; if AFormat <> $31 then begin if cxTryStrToFloat(AString, AFValue) then Result := TcxSSUtils.FormatText(AFValue, AFormat, ADig, AColor) else if cxTryStrToBool(AString, ABValue) then Result := TcxSSUtils.FormatText(Byte(ABValue), AFormat, ADig, AColor) end; end; function CellReadOnly(ABook, ASheet: TObject; ACol, ARow: Integer): Boolean; var Wb: TcxCustomSpreadSheetBook; Sh: TcxSSBookSheet; AHasCell: Boolean; AState: TcxSSCellStates; begin Wb := TcxCustomSpreadSheetBook(ABook); Sh := TcxSSBookSheet(ASheet); Result := not Wb.IsDataLoading; if not Result then Exit; AState := Sh.DataStorage.Cells[ACol, ARow].StylePtr^.CellState; AHasCell := Sh.DataStorage.HasCell(ACol, ARow); if Wb.ExcelProtectionStyle then begin Result := Wb.Protected or Sh.Protected; if Result then begin if AHasCell then Result := cLocked in AState else Result := Sh.Cols.LockProtect[ACol]; end; end else Result := Wb.ReadOnly or Sh.ReadOnly or (cReadOnly in AState); end; function CanModify(ABook, ASheet: TObject; ACol, ARow: Integer): Boolean; begin Result := not CellReadOnly(ABook, ASheet, ACol, ARow); end; function CanModify(ABook, ASheet: TObject; const ARect: TRect): Boolean; var I, J: Integer; begin Result := True; for I := ARect.Left to ARect.Right do for J := ARect.Top to ARect.Bottom do begin Result := Result and CanModify(ABook, ASheet, I, J); if not Result then Exit; end; end; { TcxSpreadSheetBook } constructor TcxSpreadSheetBook.Create(AOwner: TComponent); begin inherited Create(AOwner); AddSheetPage; end; procedure TcxSpreadSheetBook.AddSheetPage(const APageName: string = ''); begin inherited; end; procedure TcxSpreadSheetBook.EditActiveSheetCaption; begin FCaptionBar.DoEditCaption; end; procedure TcxSpreadSheetBook.ExchangeSheets(const ASheet1, ASheet2: Integer); var ACanExchange: Boolean; begin if (ASheet1 > PageCount) or (ASheet2 > PageCount) then Exit; if Assigned(FOnExchangeSheets) then begin ACanExchange := True; FOnExchangeSheets(ASheet1, ASheet2, ACanExchange); if not ACanExchange then Exit; end; FPages.Exchange(ASheet1, ASheet2); if ASheet1 = FActivePage then FActivePage := ASheet2 else if ASheet2 = FActivePage then FActivePage := ASheet1; FormulasCache.UpdateOnExchangeSheets(ASheet1, ASheet2); FCaptionBar.ReCalcViewInfo; FCaptionBar.Invalidate; Recalc; end; procedure TcxSpreadSheetBook.DeleteSheet(const ASheet: Integer); var ACanDelete: Boolean; AIndex, I: Integer; begin if (ASheet >= PageCount) or (ASheet < 0) or (PageCount = 1) then Exit; if Assigned(FOnDeleteSheet) then begin ACanDelete := True; FOnDeleteSheet(ASheet, ACanDelete); if not ACanDelete then Exit; end; AIndex := -1; for I := PageCount - 1 downto 0 do begin if ((AIndex < 0) or (AIndex > ASheet)) and (I <> ASheet) and PageVisible[I] then AIndex := I; end; if AIndex = -1 then raise ESpreadSheetError.Create(cxGetResourceString(@scxSpreadSheetDeleteLastSheet)); SetActivePage(AIndex); if FActivePage > ASheet then Dec(FActivePage); TcxSSBookSheet(FPages[ASheet])._Release; FPages.Delete(ASheet); if ASheet < PageCount then System.Move(FPageVisible[ASheet + 1], FPageVisible[ASheet], (PageCount - ASheet) * SizeOf(Boolean)); SetLength(FPageVisible, Length(FPageVisible) - 1); FormulasCache.UpdateOnDeleteSheet(ASheet); if FCaptionBar.FirstVisibleCaption >= PageCount then FCaptionBar.FirstVisibleCaption := PageCount - 1; FCaptionBar.ReCalcViewInfo; UpdateControl; end; { TcxSpreadSheet } constructor TcxSpreadSheet.Create(AOwner: TComponent); begin inherited Create(AOwner); ShowCaptionBar := False; AddSheetPage; end; function TcxSpreadSheet.GetSheet: TcxSSBookSheet; begin Result := ActiveSheet; end; { TcxSSFormatDialog } {$IFDEF DELPHI9} constructor TcxSSFormatDialog.Create(AOwner: TComponent); begin inherited Create(AOwner); Position := poDesigned; end; {$ENDIF} function TcxSSFormatDialog.Execute(const ACells: TRect; ASheet: TcxSSBookSheet): Boolean; begin Result := False; end; { TcxWorkBookSubControl } constructor TcxWorkBookSubControl.Create(AOwner: TcxCustomSpreadSheetBook); begin FOwner := AOwner; FVisible := True; end; procedure TcxWorkBookSubControl.Invalidate; begin Owner.InvalidateRect(BoundsRect, False); end; procedure TcxWorkBookSubControl.InvalidateRect(ARect: TRect); begin if not Visible or Owner.Listener.IsLocked or not Owner.HandleAllocated then Exit; OffsetRect(ARect, Left, Top); if IntersectRect(ARect, BoundsRect, ARect) then; Owner.InvalidateRect(ARect, False); end; function TcxWorkBookSubControl.ClientToScreen(const X, Y: Integer): TPoint; begin Result := Point(X + FBounds.Left, Y + FBounds.Top); Result := Owner.ClientToScreen(Result) end; procedure TcxWorkBookSubControl.DblClick; begin end; procedure TcxWorkBookSubControl.FocusChanged; begin end; procedure TcxWorkBookSubControl.KeyDown(var Key: Word; Shift: TShiftState); begin end; procedure TcxWorkBookSubControl.KeyPress(var Key: Char); begin end; procedure TcxWorkBookSubControl.KeyUp(var Key: Word; Shift: TShiftState); begin end; procedure TcxWorkBookSubControl.MouseMove(Shift: TShiftState; X, Y: Integer); begin end; procedure TcxWorkBookSubControl.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin end; procedure TcxWorkBookSubControl.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin end; procedure TcxWorkBookSubControl.Paint; begin if Visible then Canvas.ExcludeClipRect(BoundsRect); end; procedure TcxWorkBookSubControl.Resize; begin Invalidate; end; procedure TcxWorkBookSubControl.SetBounds(const ALeft, ATop, AWidth, AHeight: Integer); begin if EqualRect(FBounds, Rect(ALeft, ATop, AWidth, AHeight)) then Exit; FBounds := Rect(ALeft, ATop, AWidth, AHeight); Resize; end; procedure TcxWorkBookSubControl.VisibleChanging; begin end; function TcxWorkBookSubControl.GetBoundsRect: TRect; begin Result := Rect(FBounds.Left, FBounds.Top, FBounds.Left + FBounds.Right, FBounds.Top + FBounds.Bottom); end; function TcxWorkBookSubControl.GetCanvas: TcxCanvasWrapper; begin Result := Owner.Canvas; end; function TcxWorkBookSubControl.GetClientRect: TRect; begin Result := Rect(0, 0, FBounds.Right, FBounds.Bottom); end; function TcxWorkBookSubControl.GetControlCanvas: TCanvas; begin Result := TCustomControlAccess(Owner).Canvas; end; function TcxWorkBookSubControl.GetCursor: TCursor; begin Result := Owner.Cursor; end; function TcxWorkBookSubControl.GetHeight: Integer; begin Result := FBounds.Bottom; end; function TcxWorkBookSubControl.GetLeft: Integer; begin Result := FBounds.Left; end; function TcxWorkBookSubControl.GetTop: Integer; begin Result := FBounds.Top; end; function TcxWorkBookSubControl.GetWidth: Integer; begin Result := FBounds.Right; end; procedure TcxWorkBookSubControl.SetBoundsRect(ARect: TRect); begin ARect.Bottom := ARect.Bottom - ARect.Top; ARect.Right := ARect.Right - ARect.Left; if not EqualRect(ARect, FBounds) then begin FBounds := ARect; Resize; end; end; procedure TcxWorkBookSubControl.SetCursor(const Value: TCursor); begin Owner.Cursor := Value; end; procedure TcxWorkBookSubControl.SetHeight(const Value: Integer); begin if FBounds.Bottom = Value then Exit; FBounds.Bottom := Value; Resize; end; procedure TcxWorkBookSubControl.SetLeft(const Value: Integer); begin FBounds.Left := Value; Invalidate; end; procedure TcxWorkBookSubControl.SetTop(const Value: Integer); begin FBounds.Top := Value; Invalidate; end; procedure TcxWorkBookSubControl.SetVisible(const Value: Boolean); begin if Value <> FVisible then begin if Value then Invalidate; FVisible := Value; VisibleChanging; end; end; procedure TcxWorkBookSubControl.SetWidth(const Value: Integer); begin FBounds.Right := Value; Resize; end; { TcxSSCellObject } constructor TcxSSCellObject.Create(AOwner: TcxSSDataStorage; ACol, ARow: Integer); begin FOwner := AOwner; FCol := ACol; FRow := ARow; FComplexAction := nil; with TcxHistoryAccess((FOwner.ParentBook as TcxCustomSpreadSheetBook).History) do AddComplexAction(TcxComplexAction, cxGetResourceString(@scxChangeCellsData), FComplexAction) end; destructor TcxSSCellObject.Destroy; begin if FComplexAction <> nil then TcxHistoryAccess((FOwner.ParentBook as TcxCustomSpreadSheetBook).History).StopComplexAction; if Assigned(FCreatedStyle) then FCreatedStyle.Free; inherited; end; procedure TcxSSCellObject.Assign(Source: TcxSSCellObject); begin if Source <> nil then begin Style.ReadOnly := False; Text := Source.Text; Style.Assign(Source.Style); end; end; procedure TcxSSCellObject.SetCellText(const AText: string; const NeedParse: Boolean = False); var ARec: TcxSSCellRec; begin if NeedParse then Text := AText else begin ARec := FOwner[FCol, FRow]; if ARec.DataType = dtFunction then (FOwner.ParentBook as TcxCustomSpreadSheetBook).FormulasCache.DestroyFunction(ARec.FuncRecPtr); ARec.DataType := dtText; ARec.Text := AText; FOwner[FCol, FRow] := ARec; CheckCellWordBreak; end; end; procedure TcxSSCellObject.CheckCellWordBreak; begin OwnerSheet.ApplyAutoHeight(FRow); end; function TcxSSCellObject.GetCellStyle: IcxSpreadSheetCellStyle; begin Supports(TObject(Style), IcxSpreadSheetCellStyle, Result); end; function TcxSSCellObject.GetCellTextValue: string; var ACell: TcxSSCellRec; AColor: Word; begin ACell := Owner[FCol, FRow]; if (ACell.DataType = dtFunction) then begin Result := TcxCustomSpreadSheetBook(Owner.ParentBook).FormulasCache.FuncRecToDisplayText(ACell.FuncRecPtr, AColor); end else if ACell.DataType = dtDateTime then Result := FloatToStr(ACell.DateTime) else Result := ACell.Text; end; function TcxSSCellObject.GetCellValue: Variant; function TextToValue(const AText: string): Variant; var AFloat: Double; ABool: Boolean; begin if cxTryStrToFloat(AText, AFloat) then Result := AFloat else if cxTryStrToBool(AText, ABool) then Result := ABool else Result := AText; end; var ACell: TcxSSCellRec; begin ACell := FOwner[FCol, FRow]; case ACell.DataType of dtText: Result := TextToValue(ACell.Text); dtFunction: Result := TcxCustomSpreadSheetBook(Owner.ParentBook).FormulasCache.GetFuncValue(ACell.FuncRecPtr); dtDateTime: Result := ACell.DateTime; dtControl: Result := Integer(ACell.Control); end; end; function TcxSSCellObject.GetDataType: TcxSSDataType; begin Result := FOwner.CellDataType[FCol, FRow]; end; function TcxSSCellObject.GetDateTime: TDateTime; begin Result := FOwner.CellDateTime[FCol, FRow]; end; function TcxSSCellObject.GetDisplayText: string; begin Result := OrdinalToFormatStr(GetCellTextValue, Owner[FCol, FRow].StylePtr^.FormatIndex, TcxCustomSpreadSheetBook(Owner.ParentBook).Precision); end; function TcxSSCellObject.GetDisplayTextAlignment: TcxDisplayTextAlignment; var C: Word; S: string; ACell: TcxSSCellRec; AHorzAlign: TcxHorzTextAlign; begin ACell := Owner[FCol, FRow]; if ACell.DataType = dtFunction then S := OwnerSheet.Owner.FormulasCache.FuncRecToDisplayText(ACell.FuncRecPtr, C, False) else S := ACell.Text; with ACell.StylePtr^ do begin AHorzAlign := HorzAlign; if AHorzAlign = haGeneral then begin if FormatIndex <> 31 then begin if cxTryStrToFloat(S) then Result := dtaRight else if cxTryStrToBool(S) then Result := dtaCenter else Result := dtaLeft; end else Result := dtaLeft; end else Result := TcxDisplayTextAlignment(Byte(AHorzAlign) - 1); end; end; function TcxSSCellObject.GetIsLoading: Boolean; begin Result := OwnerSheet.Owner.FormulasCache.IsLoading; end; function TcxSSCellObject.GetMergedRect: TRect; begin TcxSSDataStorage(FOwner).CheckInMergeRange(Point(FCol, FRow), Result); end; function TcxSSCellObject.GetOwnerSheet: TcxSSBookSheet; begin Result := TcxSSBookSheet(Owner.Owner); end; function TcxSSCellObject.GetText: string; begin Result := FOwner.CellText[FCol, FRow]; end; function TcxSSCellObject.GetStyle: TcxSSCellStyle; begin if not Assigned(FCreatedStyle) then FCreatedStyle := TcxSSCellStyle.Create( TcxCustomSpreadSheetBook(Owner.ParentBook).StyleCache, Owner, FCol, FRow); Result := FCreatedStyle; end; function TcxSSCellObject.GetStyleExist: Boolean; begin Result := (FCreatedStyle <> nil) or (FOwner[FCol, FRow].StylePtr <> TcxCustomSpreadSheetBook(Owner.ParentBook).StyleCache.StyleList[0]); end; procedure TcxSSCellObject.SetStyle(const Value: TcxSSCellStyle); begin if Assigned(FCreatedStyle) and (FCreatedStyle <> Value) then FCreatedStyle.Assign(Value) else GetStyle.Assign(Value); end; procedure TcxSSCellObject.SetDateTime(const Value: TDateTime); begin FOwner.CellDateTime[FCol, FRow] := Value; if Style.Format = 0 then begin if Trunc(Value) = 0 then Style.Format := $15 else begin if Frac(Value) = 0 then Style.Format := $0E else Style.Format := $16; end; end; end; procedure TcxSSCellObject.SetText(const Value: string); begin if CellReadOnly(OwnerSheet.Owner, OwnerSheet, Col, Row) then Exit; SetTextEx(Value); end; procedure TcxSSCellObject.SetTextEx(const Value: string; IsFormula: Boolean = False; Analyze: Boolean = True); var DT: TDateTime; C: Currency; begin if CellReadOnly(OwnerSheet.Owner, OwnerSheet, Col, Row) then Exit; if ((Style.Format = 0) or FormatIsDateTime(TcxStyleAccess(Style).StyleInfo.FormatIndex)) and cxTryStrToDateTime(Value, DT) and not cxTryStrToFloat(Value) then SetDateTime(DT) else if ((Style.Format = 0) or FormatIsCurrency(TcxStyleAccess(Style).StyleInfo.FormatIndex)) and cxTryStrToCurr(Value, C) and not cxTryStrToFloat(Value) then begin FOwner.CellText[FCol, FRow] := FloatToStr(C); if Style.Format = 0 then Style.Format := $8; end else TcxDataStorageAccess(FOwner).SetCellTextEx(FCol, FRow, Value, IsFormula, Analyze); CheckCellWordBreak; TcxCustomSpreadSheetBook(Owner.ParentBook).UpdateControl; end; { TcxSSClipboard } function TcxSSClipboard.GetESSData: AnsiString; begin SetLength(Result, BufferSize(CF_ESSDATA)); if Length(Result) > 0 then GetBuffer(CF_ESSDATA, Result[1]); end; function TcxSSClipboard.GetUnicodeData: WideString; begin if BufferSize(CF_UNICODETEXT) <> 0 then begin SetLength(Result, BufferSize(CF_UNICODETEXT) shr 1 - 1); GetBuffer(CF_UNICODETEXT, Result[1]); end else Result := ClipBoard.AsText; if (Result <> '') then begin case Result[Length(Result)] of #13, #10:; else Result := Result + #13#10; end; end; end; procedure TcxSSClipboard.SetESSData(const Value: AnsiString); begin if Value <> '' then begin SetBuffer(CF_ESSDATA, Value[1], Length(Value) + 1, True); end; end; procedure TcxSSClipboard.SetUnicodeData(const Value: WideString); begin if Value <> '' then begin SetBuffer(CF_UNICODETEXT, Value[1], (Length(Value) + 1) shl 1, False); end; end; function TcxSSClipboard.BufferSize(AFormat: Word): Integer; var AData: THandle; ADataPtr: Pointer; begin Result := 0; if not OpenClipboard(Application.Handle) then Exit; try AData := GetClipboardData(AFormat); if AData = 0 then Exit; ADataPtr := GlobalLock(AData); if ADataPtr = nil then Exit; try Result := GlobalSize(AData); finally GlobalUnlock(AData); end; finally CloseClipboard; end; end; procedure TcxSSClipboard.GetBuffer(AFormat: Word; var ABuffer); var Data: THandle; DataPtr: Pointer; begin if not OpenClipboard(Application.Handle) then Exit; try Data := GetClipboardData(AFormat); if Data = 0 then Exit; DataPtr := GlobalLock(Data); if DataPtr = nil then Exit; try Move(DataPtr^, ABuffer, GlobalSize(Data)); finally GlobalUnlock(Data); end; finally CloseClipboard; end; end; procedure TcxSSClipboard.SetBuffer(AFormat: Word; const ABuffer; ASize: Integer; ClearClipboard: Boolean); var Data: THandle; DataPtr: Pointer; begin if not OpenClipboard(Application.Handle) then Exit; try if ClearClipBoard then EmptyClipboard; if ASize > 0 then begin Data := GlobalAlloc(GMEM_MOVEABLE + GMEM_DDESHARE, ASize); try DataPtr := GlobalLock(Data); try Move(ABuffer, DataPtr^, ASize); SetClipboardData(AFormat, Data); finally GlobalUnlock(Data); end; except GlobalFree(Data); raise; end; end; finally CloseClipBoard; end; end; { procedure SaveBiffToFile; var Data: Integer; DataPtr: Pointer; AFormat, I: Integer; Name: array[0..255] of Char; F: File; begin OpenClipboard(0); try for I := 0 to CountClipboardFormats - 1 do begin AFormat := EnumClipBoardFormats(I); GetClipBoardFormatName(AFormat, Name, Sizeof(Name)); if Name = 'Biff8' then begin Data := GetClipboardData(AFormat); if Data = 0 then Exit; DataPtr := GlobalLock(Data); if DataPtr = nil then Exit; try AssignFile(F, 'C:\BinaryClipboard.xls'); Rewrite(F, 1); BlockWrite(F, DataPtr^, GlobalSize(Data)); CloseFile(F); finally GlobalUnlock(Data); end; end; end; finally CloseClipboard; end; end;} { TcxCustomSpreadSheetBook } constructor TcxCustomSpreadSheetBook.Create(AOwner: TComponent); begin inherited Create(AOwner); FFloatPrecision := 2; FListener := GetListenerClass.Create(Self); FRowsAutoHeight := True; FHistory := GetHistoryClass.Create; FExcelProtectionStyle := True; TcxHistoryAccess(FHistory).HistoryOwner := Self; TcxHistoryAccess(FHistory).OnChange := FListener.OnHistoryChanged; TcxHistoryAccess(FHistory).BeginUpdate; FPaintBitmap := nil; FBufferedPaint := False; FPalette := cxExcelStdColors; FHeaderFont := TFont.Create; FCanvas := TcxCanvasWrapper.Create(@FPalette); FHeaderFont.OnChange := OnChangeHeaderStyle; FCaptionBar := GetBookPageCaptionsClass.Create(Self); FPages := TList.Create; FCaptionBar.Visible := True; FShowCaptionBar := True; FShowGrid := True; FDefaultColWidth := 85; FDefaultRowHeight := 20; FColHeaderHeight := 20; FRowHeaderWidth := 85; FPainterType := ptOffice97Style; FPainter := GetPainterClass.Create; FStyleCache := GetStyleCacheClass.Create(Self); FFormulasCache := GetFormulasCacheClass.Create(Self); FReadOnly := False; Keys := [kAll, kArrows, kChars, kTab]; HScrollBar.Visible := True; VScrollBar.Visible := True; SetDefaultColor(clWindow); SetGridColor(clBtnFace); SetHeaderColor(clBtnFace); ScrollBars := sbsBoth; SetSelectionColor(clHighLight); SetBounds(Left, Top, 350, 200); TcxHistoryAccess(FHistory).EndUpdate; {$IFNDEF cxLib10} LookAndFeel.Kind := lfFlat; {$ENDIF} FTimer := TTimer.Create(Self); FTimer.Interval := 10; FTimer.Enabled := False; FTimer.OnTimer := OnMouseTimerHandle; end; destructor TcxCustomSpreadSheetBook.Destroy; var I: Integer; begin FTimer.Enabled := False; FTimer.Free; FListener.BeginUpdate; if Assigned(FPaintBitmap) then FPaintBitmap.Free; for I := 0 to PageCount - 1 do Pages[I]._Release; FCellEditor.Free; FHistory.Free; FCaptionBar.Free; FCanvas.Free; FPainter.Free; FHeaderFont.Free; FPages.Free; FStyleCache.Free; FFormulasCache.Free; FListener.Free; inherited Destroy; end; procedure TcxCustomSpreadSheetBook.Assign(Source: TPersistent); var I: Integer; ASourceBook: TcxCustomSpreadSheetBook; begin if (Source is TcxCustomSpreadSheetBook) and (Source <> Self) then begin ASourceBook := TcxCustomSpreadSheetBook(Source); Listener.BeginUpdate; try ClearAll; DefaultStyle.Assign(ASourceBook.DefaultStyle); FPalette := ASourceBook.FPalette; for I := 0 to ASourceBook.PageCount - 1 do begin AddSheetPage; Pages[I].Assign(ASourceBook[I]); end; finally Listener.EndUpdate; CaptionBar.FirstVisibleCaption := ASourceBook.CaptionBar.FirstVisibleCaption; FActivePage := -1; ActivePage := ASourceBook.ActivePage; CaptionBar.RecalcViewInfo; FReadOnly := ASourceBook.FReadOnly; Invalidate; end; end; end; function TcxCustomSpreadSheetBook.BeginUpdate: Integer; begin Result := FListener.BeginUpdate; if FFormulasCache <> nil then FFormulasCache.Lock := True; end; function TcxCustomSpreadSheetBook.CellsNameByRef(ASheet: Integer; const CellsRef: TRect; IsText: Boolean = True): string; function CellRefToText(const APoint: TPoint): string; begin if R1C1ReferenceStyle then Result := 'R' + IntToStr(APoint.Y + 1) + 'C' + IntToStr(APoint.X + 1) + '' else Result := TcxSSUtils.ColumnNameByIndex(APoint.X, R1C1ReferenceStyle) + IntToStr(APoint.Y + 1); end; var I: Integer; const Separators: array[Boolean] of string = (':', ' x '); begin if IsText then begin for I := 0 to Length(DefinedNames) - 1 do begin with DefinedNames[I].Definition do begin if (Page = ASheet) and EqualRect(TRect(Area), CellsRef) and not DefinedNames[I].IsDeleted then begin Result := DefinedNames[I].Name; Exit; end; end; end; end; Result := CellRefToText(CellsRef.TopLeft); if Int64(CellsRef.TopLeft) <> Int64(CellsRef.BottomRight) then Result := Result + Separators[IsText] + CellRefToText(CellsRef.BottomRight) end; procedure TcxCustomSpreadSheetBook.ClearAll; var I: Integer; begin for I := 0 to PageCount - 1 do Pages[I]._Release; FormulasCache.Clear; FStyleCache.Clear; FPages.Clear; FActivePage := 0; FHistory.Clear; if HandleAllocated and not Listener.IsLocked then Invalidate; end; procedure TcxCustomSpreadSheetBook.DeactivateEditor; begin if Assigned(FCellEditor) and FCellEditor.Visible then begin FCellEditor.Visible := False; SetFocus; end; end; function TcxCustomSpreadSheetBook.DeleteName(const AName: string): Boolean; begin Result := FFormulasCache.DeleteName(AName); end; function TcxCustomSpreadSheetBook.DefineName(const AName: string; APage: Word; const ARect: TRect): Integer; begin Result := FFormulasCache.DefineName(AName, APage, TRange(ARect)); end; function TcxCustomSpreadSheetBook.DefineNameEx(const AName: string; APage: Word; const ARect: TRect; Validate: Boolean = True): Integer; begin Result := FFormulasCache.DefineName(AName, APage, TRange(ARect), Validate); end; function TcxCustomSpreadSheetBook.EndUpdate: Integer; begin FFormulasCache.Lock := False; Result := FListener.EndUpdate; if Assigned(FCaptionBar) then begin FCaptionBar.ReCalcViewInfo; FCaptionBar.Invalidate; end; if Result <= 0 then UpdateControl; end; function TcxCustomSpreadSheetBook.HasRectName(ASheet: Integer; const ARect: TRect): Integer; var I: Integer; ANames: TcxSSNamesDef; begin ANames := DefinedNames; Result := -1; for I := 0 to Length(ANames) - 1 do with ANames[I].Definition do if (Page = ASheet) and EqualRect(TRect(Area), ARect) and not ANames[I].IsDeleted then begin Result := I; Break; end; end; function TcxCustomSpreadSheetBook.HitTest(const APoint: TPoint; out HitTestInfo: TcxSSHitTestInfo): Boolean; var I: Integer; ACol, ARow: Integer; AStates: TcxSSHitTestStates; begin FillChar(HitTestInfo, SizeOf(HitTestInfo), 0); Result := False; if FCaptionBar.Visible and PtInRect(FCaptionBar.BoundsRect, APoint) then begin case FCaptionBar.HitTest(APoint.X, APoint.Y - FCaptionBar.Top, I) of htCaption: begin HitTestInfo.HitType := htSheetCaption; HitTestInfo.Page := I; Result := True; end; htButton: begin HitTestInfo.HitType := htCaptionButton; HitTestInfo.Button := TcxSSNavigatorBtn(I); Result := True; end; end; end else if (PageCount > 0) and PtInRect(ActiveSheet.BoundsRect, APoint) then begin Result := True; AStates := ActiveSheet.ViewInfo.HitTest(APoint.X, APoint.Y, ACol, ARow); if htCell in AStates then begin HitTestInfo.HitType := htSheetCell; HitTestInfo.CellCol := ACol; HitTestInfo.CellRow := ARow; end else if htRowHeader in AStates then begin HitTestInfo.HitType := htSheetRow; HitTestInfo.Row := ARow; end else if htColHeader in AStates then begin HitTestInfo.HitType := htSheetColumn; HitTestInfo.Col := ACol; end else if htUpperLeft in AStates then begin HitTestInfo.HitType := htSheetColumn; HitTestInfo.CellCol := -1; HitTestInfo.CellRow := -1; end; end; end; procedure TcxCustomSpreadSheetBook.LoadFromFile(const AFileName: string); var AFileStream: TFileStream; begin if FileExists(AFileName) then begin AFileStream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone); try LoadFromStream(AFileStream); finally AFileStream.Free; end; end else raise ESpreadSheetError.CreateFmt(cxGetResourceString(@scxSpreadSheetInvalidFileName), [AFileName]); end; procedure TcxCustomSpreadSheetBook.LoadFromStream(Stream: TStream); var AReader: TcxExcelFileReader; ACursor: TCursor; I, J: Integer; ALockRef: Integer; begin ALockRef := TcxFormulasAccess(FFormulasCache).FLockRef; AReader := TcxExcelFileReader.Create(Self); ReadOnly := False; History.Clear; History.BeginUpdate; BeginUpdate; ACursor := Screen.Cursor; Screen.Cursor := crHourGlass; R1C1ReferenceStyle := False; IsDataLoading := True; if FCaptionBar.Visible then FCaptionBar.FirstVisibleCaption := 0; try FIsLoaded := True; if AReader.AssignStream(Stream) then begin try ClearAll; FFormulasCache.IsLoading := True; FFormulasCache.Lock := True; FPalette := cxExcelStdColors; AReader.OnProgress := Listener.OnProgress; AReader.OpenStream; FModified := False; except try ClearAll; if PageCount <> 0 then Pages[0].Caption := cxGetResourceString(@scxSheetName) + IntToStr(1) else AddSheetPage; finally raise EdxException.Create(cxGetResourceString(@scxSpreadSheetInvalidStreamFormat)); end; end end else raise ESpreadSheetError.Create(cxGetResourceString(@scxSpreadSheetInvalidStreamFormat)); if AReader.HasUnknownFunction then raise ESpreadSheetError.Create(cxGetResourceString(@scxXLSFileHasUnknownFunction)); finally IsDataLoading := False; if RowsAutoHeight then begin for I := 0 to PageCount - 1 do for J := 0 to Pages[I].RowCount - 1 do Pages[I].ApplyAutoHeight(J); end; FActivePage := -1; ActivePage := 0; FIsLoaded := False; FFormulasCache.IsLoading := False; Screen.Cursor := ACursor; EndUpdate; AReader.Free; AdjustControls; UpdateControl; History.EndUpdate; History.Clear; TcxFormulasAccess(FFormulasCache).FLockRef := ALockRef; end; end; procedure TcxCustomSpreadSheetBook.Recalc; begin if Listener.IsLocked then Exit; FFormulasCache.Updating := True; try if PageCount > 0 then FFormulasCache.Recalc; finally FFormulasCache.Updating := False; if (FFormulasCache.FuncCount > 0)then try if Assigned(OnAfterCalculation) then begin Listener.BeginUpdate; OnAfterCalculation(Self); Listener.EndUpdate; end; finally InternalUpdate; end; end; end; procedure TcxCustomSpreadSheetBook.SaveToFile(const AFileName: string); var AStream: TFileStream; begin AStream := TFileStream.Create(AFileName, fmOpenWrite or fmCreate or fmShareDenyNone); try SaveToStream(AStream); finally AStream.Free; end; end; procedure TcxCustomSpreadSheetBook.SaveToStream(AStream: TStream); var I, J: Integer; ACursor: TCursor; APage: Integer; AWriter: TcxExcelFileWriter; procedure SetColsRowsInformation; var J: Integer; AHeader: TcxHeaderAccess; begin AHeader := TcxHeaderAccess(Pages[APage].Cols); AWriter.SetDefaultColWidth(APage, AHeader.DefaultSize); for J := 0 to AHeader.Count - 1 do if J < 255 then with AHeader.Data^[J] do if (hsHidden in States) or (not (hsDefault in States)) or not (hsLockProtect in States) then AWriter.SetColStyle(APage, J, Size, (hsLockProtect in States) <> DefaultStyle.Locked, hsHidden in States); AHeader := TcxHeaderAccess(Pages[APage].Rows); AWriter.SetDefaultRowHeight(APage, AHeader.DefaultSize); for J := 0 to AHeader.Count - 1 do begin if J < $FFFF then with AHeader.Data^[J] do if (hsHidden in States) or (not (hsDefault in States)) then AWriter.SetRowStyle(APage, J, Size, hsHidden in States); end; end; procedure SetCellValue(ACol, ARow: Word; ACell: PcxSSCellRec; AllowFormula: Boolean = False); var AStackItem: TcxStackItem; begin if (ACell <> nil) and (AllowFormula = (ACell^.DataType = dtFunction)) then begin AWriter.SelectStyle(ACell.StylePtr); case ACell^.DataType of dtText: AWriter.SetCellValue(APage, ACol, ARow, ACell^.Text, ACell^.StylePtr^.FormatIndex = $31); dtDateTime: AWriter.SetCellValue(APage, ACol, ARow, ACell^.DateTime); dtFunction: try AStackItem := FFormulasCache.SpreadSheetTokensToExcelTokens(ACell^.FuncRecPtr); if AStackItem.Size > 0 then AWriter.SetCellFunction(APage, ACol, ARow, ACell^.FuncRecPtr^.CalcResult, AStackItem.Size, AStackItem.Tokens); finally FreeMem(AStackItem.Tokens); FillChar(AStackItem, SizeOf(TcxStackItem), 0); AStackItem.Tokens := nil; end; end; end; end; begin AWriter := TcxExcelFileWriter.Create(Self); ACursor := Screen.Cursor; Screen.Cursor := crHourGlass; Listener.OnProgress(Self, 0); TcxHistoryAccess(History).Clear; TcxHistoryAccess(History).BeginUpdate; try AWriter.PageCount := PageCount; AWriter.SetPalette(@FPalette); AWriter.SetProtection(-1, Protected); for I := 0 to Length(DefinedNames) - 1 do AWriter.DefineName(@DefinedNames[I]); AWriter.SetDefaultStyle(TcxStyleAccess(StyleCache.DefaultStyle).StylePtr); for APage := 0 to PageCount - 1 do begin Listener.OnProgress(Self, MulDiv(APage, 100, PageCount)); AWriter.AddSheet(Pages[APage].Caption, Pages[APage].ShowGrid, True); AWriter.SetProtection(APage, Pages[APage].Protected); with TcxDataStorageAccess(Pages[APage].DataStorage) do begin SetColsRowsInformation; for I := 0 to MaxColumn - 1 do for J := 0 to Columns[I].CellsCount - 1 do if (I <= 255) and (J <= $FFFF) then SetCellValue(I, J, Columns[I].Cells^[J]); for I := 0 to MaxColumn - 1 do for J := 0 to Columns[I].CellsCount - 1 do if (I <= 255) and (J <= $FFFF) then SetCellValue(I, J, Columns[I].Cells^[J], True); AWriter.SetMergedCells(APage, MergedCells.Rects); end; end; AWriter.SaveToStream(AStream); finally Screen.Cursor := ACursor; TcxHistoryAccess(History).EndUpdate; AWriter.Free; Listener.OnProgress(Self, 100); end; FModified := False; end; procedure TcxCustomSpreadSheetBook.UpdateControl; begin if not Listener.IsLocked then begin DoRecalc; InternalUpdate; end; end; procedure TcxCustomSpreadSheetBook.AddPage(ASheet: TcxSSBookSheet); var APageId: Integer; begin APageId := FPages.Add(ASheet); if APageId = 0 then begin FActivePage := 0; ASheet.Visible := True; end else ASheet.Visible := False; SetLength(FPageVisible, APageId + 1); PageVisible[APageId] := True; if HandleAllocated then begin FCaptionBar.ReCalcViewInfo; FCaptionBar.Invalidate; end; if (APageID = 0) or (APageID = ActivePage) then AdjustControls; end; procedure TcxCustomSpreadSheetBook.AddSheetPage(const APageName: string = ''); var ASheetPage: TcxSSBookSheet; begin BeginUpdate; try ASheetPage := GetSheetClass.Create(Self); ASheetPage._AddRef; if APageName = '' then ASheetPage.DataStorage.SheetCaption := cxGetResourceString(@scxSheetName) + IntToStr(PageCount + 1) else ASheetPage.DataStorage.SheetCaption := APageName; AddPage(ASheetPage); finally EndUpdate; end; end; procedure TcxCustomSpreadSheetBook.AdjustControls; var AVScrollWidth: Integer; AHScrollHeight: Integer; AHeight: Integer; AWidth: Integer; begin if FCaptionBar = nil then Exit; if FCaptionBar.Visible then FCaptionBar.RecalcViewInfo; if ScrollersVisible[FScrollBars, sbVertical] then AVScrollWidth := VScrollBar.Width else AVScrollWidth := 0; if FCaptionBar.Visible or ScrollersVisible[FScrollBars, sbHorizontal] then AHScrollHeight := FCaptionBar.Height else AHScrollHeight := 0; if HandleAllocated then begin AHeight := ClientHeight; AWidth := ClientWidth; end else begin AHeight := Height; AWidth := Width; end; if FCaptionBar.Visible then FCaptionBar.SetBounds(0, AHeight - AHScrollHeight, Width, AHScrollHeight); if PageCount > 0 then ActiveSheet.SetBounds(0, 0, AWidth - AVScrollWidth, AHeight - AHScrollHeight); UpdateControl; FCaptionBar.ReCalcViewInfo; FCaptionBar.Invalidate; end; procedure TcxCustomSpreadSheetBook.DblClick; begin inherited; if PageCount > 0 then begin with FMouseDownPos do begin if FCaptionBar.Visible and PtInRect(FCaptionBar.BoundsRect, Point(X, Y)) then FCaptionBar.DblClick else ActiveSheet.DblClick; end; end; end; procedure TcxCustomSpreadSheetBook.DoRecalc; begin if AutoRecalc then Recalc; end; function TcxCustomSpreadSheetBook.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; begin Result := inherited DoMouseWheel(Shift, WheelDelta, MousePos); if (PageCount > 0) and ((FCaptureControl = nil) or ((FCaptureControl <> nil) and (FCaptureControl = ActiveSheet))) then Result := ActiveSheet.DoMousewheel(Shift, WheelDelta, MousePos); end; {$IFDEF DELPHI5} procedure TcxCustomSpreadSheetBook.DoContextPopup( MousePos: TPoint; var Handled: Boolean); begin if not FContextPopupHandled then begin inherited; FContextPopupHandled := False; end; end; {$ENDIF} procedure TcxCustomSpreadSheetBook.FocusChanged; begin FCaptionBar.FocusChanged; if PageCount > 0 then ActiveSheet.FocusChanged; end; function TcxCustomSpreadSheetBook.GetBookPageCaptionsClass: TcxSSBookPageCaptionsClass; begin Result := TcxSSBookPageCaptions; end; function TcxCustomSpreadSheetBook.GetCaptionPainterClass: TcxPageCaptionPainterClass; begin Result := TcxPageCaptionPainter end; function TcxCustomSpreadSheetBook.GetDataStorageClass: TcxSSDataStorageClass; begin Result := TcxSSDataStorage; end; function TcxCustomSpreadSheetBook.GetFormulasCacheClass: TcxFormulasCacheClass; begin Result := TcxSSFormulasCache; end; function TcxCustomSpreadSheetBook.GetHeaderClass: TcxSSHeaderClass; begin Result := TcxSSHeader; end; function TcxCustomSpreadSheetBook.GetHistoryClass: TcxSSHistoryClass; begin Result := TcxSpreadSheetHistory; end; function TcxCustomSpreadSheetBook.GetHScrollBarBounds: TRect; var AClientSize: TSize; HScrollHeight: Integer; begin if FCaptionBar.Visible then HScrollHeight := FCaptionBar.Height else HScrollHeight := cxHScrollHeight; AClientSize := TSize(ClientRect.BottomRight); if ScrollersVisible[FScrollBars, sbHorizontal] then with AClientSize do begin if ScrollersVisible[FScrollBars, sbVertical] then Result := Rect(0, CY - HScrollHeight, CX - cxVScrollWidth, CY) else Result := Rect(0, CY - HScrollHeight, CX, CY); if FCaptionBar.Visible then Result.Left := CX shr 1 end; end; function TcxCustomSpreadSheetBook.GetInplaceEditClass: TcxSSInplaceEditClass; begin Result := TcxSSInplaceTextEdit; end; function TcxCustomSpreadSheetBook.GetListenerClass: TcxSSListenerClass; begin Result := TcxSSListener; end; function TcxCustomSpreadSheetBook.GetPainterClass: TcxSheetPainterClass; const APainters: array[TcxSSPainterType] of TcxSheetPainterClass = (TcxSheetPainter, TcxXPPainter, TcxSheetPainter); begin Result := APainters[FPainterType]; if (FPainterType = ptCustom) and not IsDesigning then if Assigned(FOnCustomPaint) then FOnCustomPaint(Self, Result); end; function TcxCustomSpreadSheetBook.GetPalettePtr: PcxExcelPalette; begin Result := @FPalette; end; function TcxCustomSpreadSheetBook.GetStyleCacheClass: TcxSSStyleCacheClass; begin Result := TcxSSStyleCache; end; function TcxCustomSpreadSheetBook.GetSheetClass: TcxSSBookSheetClass; begin Result := TcxSSBookSheet; end; function TcxCustomSpreadSheetBook.GetVScrollBarBounds: TRect; var AClientSize: TSize; begin AClientSize := TSize(ClientRect.BottomRight); if ScrollersVisible[FScrollBars, sbVertical] then with AClientSize do begin if ScrollersVisible[FScrollBars, sbHorizontal] or FCaptionBar.Visible then Result := Rect(CX - cxVScrollWidth, 0, CX, CY - HScrollbar.Height) else Result := Rect(CX - cxVScrollWidth, 0, CX, CY) end; end; function TcxCustomSpreadSheetBook.GetViewInfoClass: TcxSSheetViewInfoClass; begin Result := TcxSSheetViewInfo; end; procedure TcxCustomSpreadSheetBook.Paint; var ARect: TRect; procedure PaintControls; var AClipRgn, ARgn : TcxRegionHandle; begin if FCaptionBar.Visible then begin AClipRgn := CreateRectRgnIndirect(ClientRect); ARgn := CreateRectRgnIndirect(FCaptionBar.BoundsRect); GetClipRgn(Canvas.Handle, AClipRgn); CombineRgn(ARgn, AClipRgn, ARgn, RGN_AND); Canvas.ExcludeClipRect(FCaptionBar.BoundsRect); end else begin AClipRgn := EmptyHandle; ARgn := EmptyHandle; end; if ActiveSheet.Visible then ActiveSheet.Paint; if FCaptionBar.Visible then begin SelectClipRgn(Canvas.Handle, ARgn); DeleteObject(AClipRgn); DeleteObject(ARgn); if FCaptionBar.Visible and ScrollersVisible[FScrollBars, sbHorizontal] then ARect := Rect(HScrollBar.Left, HScrollBar.Top, Width + 1, Height + 1); FCaptionBar.Paint; end; end; begin inherited Paint; Painter.HideSelection := HideSelection and not Focused; Canvas.BeginPaint(inherited Canvas.Canvas); if PageCount > 0 then begin if BufferedPaint then begin Canvas.BeginPaint(FPaintBitmap.Canvas); SelectClipRgn(FPaintBitmap.Canvas.Handle, 0); if (FCaptionBar <> nil) and (FCaptionBar.Visible) then FCaptionBar.Paint; if ActiveSheet.ViewInfo.InfoChanged then ActiveSheet.Paint; BitBlt(inherited Canvas.Handle, 0, 0, Width, Height, FPaintBitmap.Canvas.Handle, 0, 0, srcCopy); end else PaintControls; end else begin ARect := Rect(0, 0, ClientWidth - 1, ClientHeight -1); Canvas.FillRect(ARect, fsSolid, clBtnFace, cxSSDefaultColorValue); Canvas.FrameRect(ARect, clBtnHighLight, clBtnShadow); end; end; procedure TcxCustomSpreadSheetBook.InitScrollBarsParameters; begin if PageCount > 0 then ActiveSheet.InitScrollBars; end; procedure TcxCustomSpreadSheetBook.InternalUpdate; begin if PageCount > 0 then ActiveSheet.ViewInfo.UpdateViewInfo; if HandleAllocated then UpdateScrollBars else if PageCount > 0 then ActiveSheet.InitScrollBars; if not Listener.IsLocked then Invalidate; end; procedure TcxCustomSpreadSheetBook.KeyDown(var Key: Word; Shift: TShiftState); function InKeys(const AKeys: WideString): Boolean; var I: Integer; begin Result := False; if Length(AKeys) <> 0 then for I := 1 to Length(AKeys) do if Result then Break else Result := WideChar(Key) = AKeys[I]; end; begin inherited KeyDown(Key, Shift); if PageCount > 0 then begin if (ssCtrl in Shift) and InKeys('CXVZY') then with ActiveSheet do begin case WideChar(Key) of 'C': Copy(SelectionRect, False); 'X': Copy(SelectionRect, True); 'V': Paste(SelectionRect.TopLeft); 'Z': History.Undo(1); 'Y': History.Redo(1); end; end else begin case Key of VK_F9: try FFormulasCache.Lock := False; Recalc; finally FFormulasCache.Lock := True; UpdateControl; end; else if (FCaptureControl = nil) and ViewInfoValid then ActiveSheet.KeyDown(Key, Shift); end; end; end; end; procedure TcxCustomSpreadSheetBook.KeyPress(var Key: Char); begin if PageCount > 0 then begin if (FCaptureControl = nil) and ViewInfoValid then ActiveSheet.KeyPress(Key); end; inherited; end; procedure TcxCustomSpreadSheetBook.KeyUp(var Key: Word; Shift: TShiftState); begin if PageCount > 0 then begin if (FCaptureControl = nil) and ViewInfoValid then ActiveSheet.KeyUp(Key, Shift); end; inherited; end; procedure TcxCustomSpreadSheetBook.Loaded; begin inherited; AdjustControls; if Assigned(FCaptionBar) then FCaptionBar.RecalcViewInfo; UpdateControl; end; procedure TcxCustomSpreadSheetBook.MouseMove(Shift: TShiftState; X, Y: Integer); var R: TRect; begin FMousePos := Point(X, Y); if PageCount > 0 then begin if (FCaptureControl = FCaptionBar) or ((FCaptureControl = nil) and PtInRect(FCaptionBar.BoundsRect, Point(X, Y))) then FCaptionBar.MouseMove(Shift, X, Y - FCaptionBar.Top) else if ViewInfoValid then begin ActiveSheet.MouseMove(Shift, X, Y); FShift := Shift; R.BottomRight := ActiveSheet.ClientRect.BottomRight; R.TopLeft := Point(RowHeaderWidth, ColHeaderHeight); FTimer.Enabled := not PtInRect(R, FMousePos); end; end; inherited; end; procedure TcxCustomSpreadSheetBook.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var HitTestInfo: TcxSSHitTestInfo; begin inherited; FContextPopupHandled := False; HitTest(Point(X, Y), HitTestInfo); if PageCount > 0 then begin Windows.SetFocus( Handle ); FMouseDownPos := Point(X, Y); if FCaptionBar.Visible and PtInRect(FCaptionBar.BoundsRect, Point(X, Y)) then begin FCaptionBar.MouseDown(Button, Shift, X, Y - FCaptionBar.Top); if Button <> mbRight then FCaptureControl := FCaptionBar; end else begin if Button <> mbRight then FCaptureControl := ActiveSheet; if ViewInfoValid then begin ActiveSheet.MouseDown(Button, Shift, X, Y); end; end; end; end; procedure TcxCustomSpreadSheetBook.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin FTimer.Enabled := False; {$IFNDEF DELPHI5} if FContextPopupHandled then begin FContextPopupHandled := False; Exit; end; {$ENDIF} inherited; if PageCount > 0 then begin if (FCaptionBar.Visible and PtInRect(FCaptionBar.BoundsRect, Point(X, Y))) or ((FCaptionBar <> nil) and (FCaptureControl = FCaptionBar)) then FCaptionBar.MouseUp(Button, Shift, X, Y - FCaptionBar.Top) else if ViewInfoValid then ActiveSheet.MouseUp(Button, Shift, X, Y); FCaptureControl := nil; end; end; procedure TcxCustomSpreadSheetBook.OnChangeHeaderStyle(Sender: TObject); begin if ViewInfoValid then ActiveSheet.ViewInfo.UpdateViewInfo; end; procedure TcxCustomSpreadSheetBook.OnMouseTimerHandle(Sender: TObject); begin with FMousePos do MouseMove(FShift, X, Y); end; procedure TcxCustomSpreadSheetBook.Resize; begin inherited Resize; AdjustControls; if Assigned(FPaintBitmap) then begin FPaintBitmap.Height := Height; FPaintBitmap.Width := Width; end; if (FCaptionBar <> nil) and (FCaptionBar.FCaptionEditor <> nil) or (PageCount > 0) and (ActiveSheet.CellEditor <> nil) and CanFocus then SetFocus; UpdateScrollBars; end; function TcxCustomSpreadSheetBook.AddSheet(const AName: string; AVisible: Boolean): IcxBookSheet; begin AddSheetPage(AName); Supports(TObject(Pages[PageCount - 1]), IcxBookSheet, Result); end; function TcxCustomSpreadSheetBook.GetActiveCell: TPoint; begin Result := ActiveSheet.ActiveCell; end; function TcxCustomSpreadSheetBook.GetActiveSheet: TcxSSBookSheet; begin Result := Pages[FActivePage]; end; function TcxCustomSpreadSheetBook.GetAutoReCalc: Boolean; begin Result := not FFormulasCache.Lock end; function TcxCustomSpreadSheetBook.GetCell(APage: Word; ACol, ARow: Integer): IcxSpreadSheetCell; begin Result := Pages[APage].GetCell(ACol, ARow) end; function TcxCustomSpreadSheetBook.GetDefinedNames: TcxSSNamesDef; begin Result := FFormulasCache.Names; end; function TcxCustomSpreadSheetBook.GetDefaultStyle: TcxSSDefaultStyle; begin Result := FStyleCache.DefaultStyle; end; function TcxCustomSpreadSheetBook.GetPage(APage: Integer): TcxSSBookSheet; begin try Result := TcxSSBookSheet(FPages[APage]); except raise ESpreadSheetError.Create(cxGetResourceString(@scxSpreadSheetInvalidSheetNumber)); end; end; function TcxCustomSpreadSheetBook.GetPageCount: Word; begin if not Assigned(FPages) then Result := 0 else Result := FPages.Count; end; function TcxCustomSpreadSheetBook.GetPageSelection(APage: Word): TRect; begin Result := Pages[APage].SelectionRect; end; function TcxCustomSpreadSheetBook.GetPageVisible(APage: Word): Boolean; begin if APage >= Length(FPageVisible) then Result := False else Result := FPageVisible[APage] end; function TcxCustomSpreadSheetBook.GetRCRefStyle: Boolean; begin Result := FFormulasCache.RCRefStyle; end; function TcxCustomSpreadSheetBook.GetSelection: TRect; begin Result := ActiveSheet.SelectionRect; end; function TcxCustomSpreadSheetBook.GetSheet(APage: Word): IcxBookSheet; begin Supports(TObject(Pages[APage]), IcxBookSheet, Result); end; function TcxCustomSpreadSheetBook.GetShowHeaders: Boolean; begin Result := ActiveSheet.ShowHeaders; end; procedure TcxCustomSpreadSheetBook.SetPalette( const APalette: PcxExcelPalette); begin FPalette := APalette^; end; procedure TcxCustomSpreadSheetBook.SetProtection(Value: Boolean); begin FProtected := Value; end; procedure TcxCustomSpreadSheetBook.SetActiveCell(const AValue: TPoint); begin ActiveSheet.ActiveCell := AValue; end; procedure TcxCustomSpreadSheetBook.SetActivePage(AValue: Integer); var ACanSelect: Boolean; const AState: array[Boolean] of TcxSSCaptionStates = ([], [csCurrent]); begin if (FActivePage = AValue) or (AValue < 0) or (AValue >= PageCount) then Exit; while not FPageVisible[AValue] and (AValue < (PageCount - 1)) do Inc(AValue); while not FPageVisible[AValue] and (AValue > 0) do Dec(AValue); ACanSelect := True; Listener.OnActiveSheetChanging(Self, AValue, ACanSelect); if ACanSelect then begin if (FCellEditor <> nil) and FCellEditor.Focused then SetFocus; if AValue >= Length(FCaptionBar.ViewInfo.Bricks) then FCaptionBar.RecalcViewInfo; if FActivePage >= 0 then FCaptionBar.UpdateCaptionInfo(FActivePage, []); Pages[AValue].SetBounds(ClientBounds.Top, ClientBounds.Left, ClientBounds.Right, ClientBounds.Bottom); Pages[AValue].Visible := True; if FActivePage >= 0 then Pages[FActivePage].Visible := False; FCaptionBar.UpdateCaptionInfo(AValue, [csCurrent]); FActivePage := AValue; ActiveSheet.SelectionRect := ActiveSheet.DataStorage.CheckSelectionRect(ActiveSheet.SelectionRect); if ViewInfoValid then ActiveSheet.ViewInfo.UpdateViewInfo; FCaptionBar.MakeTabVisible(FActivePage); ActiveSheet.Invalidate; end; end; procedure TcxCustomSpreadSheetBook.SetAutoRecalc(const AValue: Boolean); begin if Assigned(FFormulasCache) then begin if (AValue and not FFormulasCache.Lock) or (not AValue and FFormulasCache.Lock) then Exit; FFormulasCache.Lock := not AValue; if AValue then ReCalc; end; end; procedure TcxCustomSpreadSheetBook.SetBufferedPaint(const AValue: Boolean); begin if FBufferedPaint <> AValue then begin FBufferedPaint := AValue; if AValue then begin if FPaintBitmap = nil then FPaintBitmap := TBitmap.Create; FPaintBitmap.Width := Width; FPaintBitmap.Height := Height; end; end; end; procedure TcxCustomSpreadSheetBook.SetCustomPainter(const AValue: TcxSSCustomPaintEvent); begin FOnCustomPaint := AValue; if Assigned(FPainter) then FPainter.Free; FPainter := GetPainterClass.Create; if PageCount > 0 then ActiveSheet.Invalidate; end; procedure TcxCustomSpreadSheetBook.SetColHeaderHeight(const AValue: Integer); begin if (AValue <= 0) or (AValue = FColHeaderHeight) then Exit; FColHeaderHeight := AValue; if ViewInfoValid then ActiveSheet.ViewInfo.UpdateViewInfo; end; procedure TcxCustomSpreadSheetBook.SetDefaultColWidth(const AValue: TcxSSSize); var I: Integer; begin if AValue = FDefaultColWidth then Exit; FDefaultColWidth := AValue; for I := 0 to PageCount - 1 do Pages[I].DataStorage.Headers[htCol].DefaultSize := AValue; if ViewInfoValid then ActiveSheet.ViewInfo.UpdateViewInfo; end; procedure TcxCustomSpreadSheetBook.SetDefaultStyle(const AStyle: PcxSSCellStyleRec); var AFontPtr: PcxSSFontRec; begin AFontPtr := FStyleCache.Styles[0]^.FontPtr; DeleteObject(AFontPtr^.FontHandle); AStyle^.FontPtr^.FontHandle := CreateFontHandle(AStyle^.FontPtr); AFontPtr^ := AStyle^.FontPtr^; FStyleCache.Styles[0]^ := AStyle^; TcxStyleAccess(FStyleCache.DefaultStyle).StyleInfo := FStyleCache.Styles[0]^; FStyleCache.Styles[0]^.FontPtr := AFontPtr; FStyleCache.Styles[0]^.RefCount := 1; TcxStyleAccess(DefaultStyle).StyleInfo := FStyleCache.Styles[0]^; end; procedure TcxCustomSpreadSheetBook.SetDefaultStyleProperty(AValue: TcxSSDefaultStyle); begin FStyleCache.DefaultStyle.Assign(AValue); end; procedure TcxCustomSpreadSheetBook.SetDefaultRowHeight(const AValue: TcxSSSize); var I: Integer; begin if AValue = FDefaultRowHeight then Exit; FDefaultRowHeight := AValue; for I := 0 to PageCount - 1 do Pages[I].DataStorage.Headers[htRow].DefaultSize := AValue; if ViewInfoValid then ActiveSheet.ViewInfo.UpdateViewInfo; end; procedure TcxCustomSpreadSheetBook.SetDefaultColor(const AValue: TColor); begin if FWindowColor = AValue then Exit; FWindowColor := AValue; Canvas.WindowColor := Canvas.GetNativeColor(FWindowColor); if not Listener.IsLocked then Invalidate; end; procedure TcxCustomSpreadSheetBook.SetFloatPrecision(const AValue: Byte); begin if FFloatPrecision <> AValue then begin FFloatPrecision := AValue; UpdateControl; end; end; procedure TcxCustomSpreadSheetBook.SetGridColor(const AValue: TColor); begin if AValue <> FGridColor then begin FGridColor := AValue; Canvas.BorderColor := Canvas.GetNativeColor(FGridColor); if not Listener.IsLocked then Invalidate; end; end; procedure TcxCustomSpreadSheetBook.SetHeaderFont(AValue: TFont); begin if not Assigned(AValue) then Exit; FHeaderFont.Assign(AValue); AdjustControls; end; procedure TcxCustomSpreadSheetBook.SetHeaderColor(const AValue: TColor); begin if AValue <> FHeaderColor then begin FHeaderColor := AValue; if ViewInfoValid then PInteger(@ActiveSheet.ViewInfo.InfoData.HeaderColor)^ := Canvas.GetNativeColor(FHeaderColor); if not Listener.IsLocked then Invalidate; end; end; procedure TcxCustomSpreadSheetBook.SetPainterType(const AValue: TcxSSPainterType); begin if AValue = FPainterType then Exit; FPainterType := AValue; if Assigned(FPainter) then FPainter.Free; FPainter := GetPainterClass.Create; if ViewInfoValid then ActiveSheet.ViewInfo.InfoChanged := True; if not Listener.IsLocked then Invalidate; end; procedure TcxCustomSpreadSheetBook.SetPageCount(const AValue: Word); var I, ACount: Integer; begin if PageCount <> AValue then try BeginUpdate; ACount := PageCount; if ACount > AValue then begin for I := AValue to ACount - 1 do begin Pages[AValue]._Release; FPages.Delete(AValue); end; ActivePage := 0; end else if ACount < AValue then begin ACount := PageCount; for I := ACount to AValue - 1 do AddSheetPage; end; finally EndUpdate; FCaptionBar.Invalidate; end; end; procedure TcxCustomSpreadSheetBook.SetPageSelection(APage: Word; const AValue: TRect); begin Pages[APage].SelectionRect := AValue; end; procedure TcxCustomSpreadSheetBook.SetPageVisible(APage: Word; const AValue: Boolean); begin FPageVisible[APage] := AValue; end; procedure TcxCustomSpreadSheetBook.SetRCRefStyle(const AValue: Boolean); begin if AValue <> FFormulasCache.RCRefStyle then begin FFormulasCache.RCRefStyle := AValue; UpdateControl; end; end; procedure TcxCustomSpreadSheetBook.SetReadOnly(const AValue: Boolean); begin if AValue <> FReadOnly then begin DefaultStyle.ReadOnly := AValue; FReadOnly := AValue; end; end; procedure TcxCustomSpreadSheetBook.Scroll(AScrollBarKind: TScrollBarKind; AScrollCode: TScrollCode; var AScrollPos: Integer); begin inherited Scroll(AScrollBarKind, AScrollCode, AScrollPos); if ViewInfoValid then begin ActiveSheet.Scroll(AScrollBarKind, AScrollCode, AScrollPos); ActiveSheet.InitScrollBars; end; end; function TcxCustomSpreadSheetBook.SpreadSheetClipboardDataToData( ASheet: TcxSSBookSheet; const AColPos, ARowPos: Integer; out AChangedRect: TRect): Boolean; var DC, DR: Integer; procedure SetCellData(ACol, ARow: Integer; const AData: AnsiString); var ADataSize: Integer; ACell: TcxSSCellRec; AFont: TcxSSFontRec; ASide: TcxSSEdgeBorder; IsFuncValid: Boolean; procedure GetBuf(var Buf; ASize: Integer); begin Move(AData[ADataSize], Buf, ASize); Inc(ADataSize, ASize); end; function GetByte: Byte; begin GetBuf(Result, SizeOf(Result)); end; function GetWord: Word; begin GetBuf(Result, SizeOf(Result)); end; function GetString: string; var ASize: Integer; begin GetBuf(ASize, SizeOf(ASize)); SetLength(Result, ASize div SizeOf(Char)); if ASize > 0 then GetBuf(Result[1], ASize); end; begin if AData <> '' then begin IsFuncValid := True; ADataSize := 1; with ASheet.GetCellObject(ACol, ARow) do try if not CanModify(ASheet.Owner, ASheet, ACol, ARow) then Exit; with TcxStyleAccess(Style).StyleInfo do begin CellState := []; GetBuf(FormatIndex, SizeOf(FormatIndex)); GetBuf(HorzAlign, SizeOf(HorzAlign)); GetBuf(VertAlign, SizeOf(VertAlign)); GetBuf(WordBreak, SizeOf(WordBreak)); GetBuf(ShrinkToFit, SizeOf(ShrinkToFit)); GetBuf(BrushStyle, SizeOf(BrushStyle)); GetBuf(BrushFgColor, SizeOf(BrushFgColor)); GetBuf(BrushBkColor, SizeOf(BrushBkColor)); AFont.Name := GetString; AFont.FontColor := GetWord; Byte(AFont.Style) := GetByte; Byte(AFont.Charset) := GetByte; AFont.Size := SmallInt(GetByte); with Style.Font do AssignInfo(AFont.Name, AFont.Size, AFont.Style, AFont.Charset, AFont.FontColor); TcxStyleAccess(Style).DoOnChange(Style, siAll); for ASide := eLeft to eBottom do begin Borders[ASide].Style := TcxSSEdgeLineStyle(GetByte); Borders[ASide].Color := GetWord; TcxStyleAccess(Style).DoOnChange(Style.Borders[ASide], siBorder); end; GetBuf(CellState, SizeOf(TcxSSCellStates)); TcxStyleAccess(Style).DoOnChange(Style, siAll); end; finally Free; end; ACell := ASheet.DataStorage[ACol, ARow]; with ACell do try if (DataType = dtFunction) and (FuncRecPtr <> nil) then begin FormulasCache.DestroyFunction(FuncRecPtr); FuncRecPtr := nil; { FreeMem(FuncRecPtr^.CalcResult.Tokens); FreeMem(FuncRecPtr^.FuncTree.Tokens); FillChar(FuncRecPtr^.FuncTree, SizeOf(TcxStackItem), 0); FillChar(FuncRecPtr^.CalcResult, SizeOf(TcxStackItem), 0);} end; GetBuf(DataType, SizeOf(DataType)); if DataType = dtDateTime then GetBuf(DateTime, SizeOf(DateTime)) else if DataType = dtFunction then begin if FuncRecPtr = nil then begin New(FuncRecPtr); FillChar(FuncRecPtr^, SizeOf(TcxSSFuncRec), 0); FuncRecPtr^.Col := ACol; FuncRecPtr^.Row := ARow; FuncRecPtr^.Page := FPages.IndexOf(ASheet); end; with FuncRecPtr^ do begin States := fsSource; GetBuf(FuncRecPtr^.FuncTree.Size, SizeOf(FuncRecPtr^.FuncTree.Size)); GetMem(FuncRecPtr^.FuncTree.Tokens, FuncRecPtr^.FuncTree.Size); GetBuf(FuncRecPtr^.FuncTree.Tokens^, FuncRecPtr^.FuncTree.Size); end; FFormulasCache.Add(FuncRecPtr); IsFuncValid := FFormulasCache.ValidateRef(FuncRecPtr); FFormulasCache.UpdateExternalLinks(FuncRecPtr, DR, DC); Text := FFormulasCache.FuncHandler.TokensToString(FuncRecPtr); end; if DataType <> dtFunction then Text := GetString; finally TcxDataStorageAccess(ASheet.DataStorage).SetCellRec(ACol, ARow, ACell); if not IsFuncValid then TcxDataStorageAccess(ASheet.DataStorage).SetCellTextEx(ACol, ARow, scxRefError); end; end; end; var S, S1: AnsiString; R: TRect; ALen, APos: Integer; DX, DY, I, J: Integer; MergedCells: TcxSSRectsArray; begin S := cxSSClipboard.DataAsEssFormat; Result := Length(S) > 0; if Result then try APos := 1; Move(S[1], R, SizeOf(R)); Inc(APos, SizeOf(R)); DX := R.Right - R.Left; DY := R.Bottom - R.Top; with TcxDataStorageAccess(ASheet.DataStorage).MergedCells do Result := IntersectMerge(Rect(AColPos, ARowPos, AColPos + DX + 1, ARowPos + DY + 1)); if Result then raise ESpreadSheetError.Create(cxGetResourceString(@scxChangePartOfMergeCells)) else Result := True; ALen := PInteger(@S[APos])^; Inc(APos, SizeOf(Integer)); if ALen > 0 then begin SetLength(MergedCells, ALen); Move(S[APos], MergedCells[0], ALen * SizeOf(TRect)); for I := 0 to ALen - 1 do OffsetRect(MergedCells[I], AColPos - R.Left, ARowPos - R.Top); Inc(APos, ALen shl 4); end; DC := AColPos - R.Left; DR := ARowPos - R.Top; for I := AColPos to AColPos + DX do begin for J := ARowPos to ARowPos + DY do begin Move(S[APos], ALen, SizeOf(ALen)); Inc(APos, SizeOf(ALen)); if (ALen + APos) < Length(S) then begin if ALen > 0 then begin SetLength(S1, ALen); Move(S[APos], S1[1], ALen); SetCellData(I, J, S1); end; Inc(APos, ALen); end else Break; end; end; AChangedRect := Rect(AColPos, ARowPos, AColPos + DX, ARowPos + DY); with TcxDataStorageAccess(ASheet.DataStorage).MergedCells do AddMerges(MergedCells); finally with TcxDataStorageAccess(ASheet.DataStorage) do begin if CheckInMergeRange(Point(AColPos, ARowPos), R) then SelectionRect := R; end; end; end; function TcxCustomSpreadSheetBook.SpreadSheetDataToClipboardData( ASheet: TcxSSBookSheet; const ACells: TRect): AnsiString; function GetCellData(ACol, ARow: Integer): AnsiString; var ADataSize: Integer; ACapacity: Integer; APtr: PByteArray; const Null: Integer = 0; procedure ReallocBuf(NeedSize: Integer); begin while (ADataSize + NeedSize) >= ACapacity do Inc(ACapacity, 2048); ReallocMem(APtr, ACapacity); end; procedure WriteBuf(const Buf; ASize: Integer; WriteSize: Boolean = False); begin if WriteSize then begin ReallocBuf(SizeOf(Integer)); Move(ASize, APtr^[ADataSize], SizeOf(Integer)); Inc(ADataSize, SizeOf(Integer)); end; ReallocBuf(ASize); if ASize <> 0 then begin Move(Buf, APtr^[ADataSize], ASize); Inc(ADataSize, ASize); end; end; begin with ASheet.DataStorage[ACol, ARow] do begin ADataSize := 0; ACapacity := 0; APtr := nil; try with StylePtr^ do begin WriteBuf(FormatIndex, SizeOf(FormatIndex)); WriteBuf(HorzAlign, SizeOf(HorzAlign)); WriteBuf(VertAlign, SizeOf(VertAlign)); WriteBuf(WordBreak, SizeOf(WordBreak)); WriteBuf(ShrinkToFit, SizeOf(ShrinkToFit)); WriteBuf(BrushStyle, SizeOf(BrushStyle)); WriteBuf(BrushFgColor, SizeOf(BrushFgColor)); WriteBuf(BrushBkColor, SizeOf(BrushBkColor)); with FontPtr^ do begin WriteBuf(Name[1], Length(Name) * SizeOf(Char), True); WriteBuf(FontColor, SizeOf(FontColor)); WriteBuf(Style, SizeOf(Style)); WriteBuf(Charset, SizeOf(Charset)); WriteBuf(Size, SizeOf(Size)); end; WriteBuf(Borders, SizeOf(Borders)); WriteBuf(CellState, SizeOf(TcxSSCellStates)); end; WriteBuf(DataType, SizeOf(DataType)); if DataType = dtDateTime then WriteBuf(DateTime, SizeOf(DateTime)) else if (DataType = dtFunction) and (FuncRecPtr <> nil) and (FuncRecPtr^.FuncTree.Size <> 0) then begin WriteBuf(FuncRecPtr^.FuncTree.Size, SizeOf(FuncRecPtr^.FuncTree.Size)); WriteBuf(FuncRecPtr^.FuncTree.Tokens^, FuncRecPtr^.FuncTree.Size); end; if Length(Text) > 0 then WriteBuf(Text[1], Length(Text) * SizeOf(Char), True) else WriteBuf(Null, SizeOf(Integer)); finally SetLength(Result, ADataSize + SizeOf(Integer)); Move(ADataSize, Result[1], SizeOf(Integer)); Move(APtr^, Result[5], ADataSize); FreeMem(APtr); end; end; end; var I, J: Integer; MergedCells: TcxSSRectsArray; begin with TcxDataStorageAccess(ASheet.DataStorage).MergedCells do MergedCells := IntersectMergedCells(Rect(ACells.Left, ACells.Top, ACells.Right + 1, ACells.Bottom + 1)); SetLength(Result, SizeOf(Integer) + (Length(MergedCells) + 1) * SizeOf(TRect)); Move(ACells, Result[1], SizeOf(ACells)); PInteger(@Result[1 + SizeOf(ACells)])^ := Length(MergedCells); if Length(MergedCells) > 0 then Move(MergedCells[0], Result[5 + SizeOf(ACells)], Length(MergedCells) * SizeOf(TRect)); TcxHistoryAccess(History).BeginUpdate; try for I := ACells.Left to ACells.Right do for J := ACells.Top to ACells.Bottom do Result := Result + GetCellData(I, J); finally TcxHistoryAccess(History).EndUpdate; end; end; procedure TcxCustomSpreadSheetBook.VisibleChanging; begin inherited; UpdateControl; AdjustControls; end; procedure TcxCustomSpreadSheetBook.SetModified; begin FModified := True; end; function TcxCustomSpreadSheetBook.ViewInfoValid: Boolean; begin Result := (PageCount > 0) and ActiveSheet.ViewInfoValid; end; procedure TcxCustomSpreadSheetBook.SetRowHeaderWidth(const AValue: Integer); begin if (AValue = FRowHeaderWidth) or (AValue <= 0) then Exit; FRowHeaderWidth := AValue; if ViewInfoValid then ActiveSheet.ViewInfo.UpdateViewInfo; end; procedure TcxCustomSpreadSheetBook.SetSelectionColor(const AValue: TColor); begin if FSelectionColor = AValue then Exit; FSelectionColor := AValue; Canvas.SelectionColor := Canvas.GetNativeColor(FSelectionColor); if not Listener.IsLocked then Invalidate; end; procedure TcxCustomSpreadSheetBook.SetScrollBars(const AValue: TcxScrollBars); const AVisibleState: array[TcxScrollBars, 0..1] of Boolean = ((False, False), (True, False), (False, True), (True, True)); begin if AValue <> FScrollBars then begin FScrollBars := AValue; AdjustControls; if not Listener.IsLocked then InvalidateRect(Rect(0, Height - Max(FCaptionBar.Height, HScrollBar.Height), Width, Height), False); end; end; procedure TcxCustomSpreadSheetBook.SetShowCaptionBar(const AValue: Boolean); begin if FShowCaptionBar = AValue then Exit; FShowCaptionBar := AValue; FCaptionBar.Visible := AValue; if AValue then FCaptionBar.RecalcViewInfo; AdjustControls; end; procedure TcxCustomSpreadSheetBook.SetShowFormulas(const AValue: Boolean); var I: Integer; begin if FShowFormulas = AValue then Exit; FShowFormulas := AValue; for I := 0 to PageCount - 1 do Pages[I].ShowFormulas := AValue; end; procedure TcxCustomSpreadSheetBook.SetShowHeaders(const AValue: Boolean); var I: Integer; begin for I := 0 to PageCount - 1 do Pages[I].FShowHeaders := AValue; if ViewInfoValid then ActiveSheet.ViewInfo.UpdateViewInfo; end; procedure TcxCustomSpreadSheetBook.SetSelection(const AValue: TRect); begin ActiveSheet.SelectionRect := AValue; end; procedure TcxCustomSpreadSheetBook.SetShowGrid(const AValue: Boolean); var I: Integer; begin FShowGrid := AValue; for I := 0 to PageCount - 1 do Pages[I].ShowGrid := AValue; end; procedure TcxCustomSpreadSheetBook.CM_CHANGELOCALE(var Message: TMessage); begin inherited; if IsWinNT then CurrencyString := GetLocaleStrW(GetThreadLocale, LOCALE_SCURRENCY); GetFormatSettings; SetControlCodes; UpdateControl; end; {$IFNDEF DELPHI5} procedure TcxCustomSpreadSheetBook.WMRButtonUp(var Message: TWMRButtonUp); begin with Message do begin if Assigned(OnContextPopup) and not FContextPopupHandled then OnContextPopup(Self, ScreenToClient(Point(XPos, YPos)), FContextPopupHandled); if FContextPopupHandled then Result := 1 else inherited; end; end; {$ENDIF} { TcxSSBookPageCaptions } constructor TcxSSBookPageCaptions.Create(AOwner: TcxCustomSpreadSheetBook); begin inherited Create(AOwner); FCaptionPainter := Owner.GetCaptionPainterClass.Create; FViewInfo.FirstVisibleCaption := 0; end; destructor TcxSSBookPageCaptions.Destroy; begin FCaptionPainter.Free; inherited Destroy; end; procedure TcxSSBookPageCaptions.MakeTabVisible(AIndex: Integer); function IsVisible: Integer; var W: Integer; R: TRect; begin if (AIndex < 0) or (AIndex >= Length(FViewInfo.Bricks)) then begin Result := 0; Exit; end; R := FViewInfo.Bricks[AIndex].BoundsRect; Result := FirstVisibleCaption - AIndex; if Result > 0 then Result := -1 else if Result < 0 then Result := 1; if Result > 0 then begin if Owner.HScrollBar.Visible then W := Owner.Width shr 1 else W := Owner.Width; if R.Right < W then Result := 0; end; end; begin while IsVisible <> 0 do FirstVisibleCaption := FirstVisibleCaption + IsVisible; end; procedure TcxSSBookPageCaptions.ActivateEditor; var ARect: TRect; begin if FCaptionEditor = nil then begin FCaptionEditor := Owner.GetInplaceEditClass.Create(Owner, False) as TcxSSInplaceTextEdit; FCaptionEditor.Parent := Owner; FCaptionEditor.WantTab := True; FCaptionEditor.OnEndEdit := OnEndEditCaption; FCaptionEditor.OnChange := OnEditCaptionText; end; FCaptionEditor.Font.Assign(Owner.HeaderFont); ARect := FViewInfo.Bricks[Owner.ActivePage].BoundsRect; OffsetRect(ARect, 13, 0); FCaptionEditor.SetBounds(ARect.Left + 2, ARect.Top + 2, ARect.Right - ARect.Left - 2, ARect.Bottom - ARect.Top - 2); with Owner.ActiveSheet do FCaptionEditor.InitEditor(Caption, Caption); end; procedure TcxSSBookPageCaptions.DblClick; var AIndex: Integer; begin if HitTest(FMouseDownPos.X, FMouseDownPos.Y, AIndex) <> htCaption then Exit; if Owner.ActivePage < 0 then Exit; with Owner.ActiveSheet.SelectionRect do if CanModify(Owner, Owner.ActiveSheet, Left, Top) then begin ActivateEditor; FIsEditorActivate := True; end; end; procedure TcxSSBookPageCaptions.DoEditCaption; function SheetRectIsVisible(const ARect: TRect): Boolean; var W: Integer; begin if Owner.HScrollBar.Visible then W := Owner.Width shr 1 else W := Owner.Width; Result := ARect.Right < W; end; begin if Owner.ActivePage < FirstVisibleCaption then FirstVisibleCaption := Owner.ActivePage; while (FirstVisibleCaption < Owner.ActivePage) and not SheetRectIsVisible(FViewInfo.Bricks[Owner.ActivePage].BoundsRect) do begin FirstVisibleCaption := FirstVisibleCaption + 1; end; ActivateEditor; FCaptionEditor.SetFocus; end; function TcxSSBookPageCaptions.GetCaptionTextExtent(APage: Integer): TRect; var I: Byte; begin Canvas.SelectFont(Owner.HeaderFont); with FViewInfo do begin Result := Rect(0, Bounds.Top, 0, Bounds.Bottom - 1); for I := FirstVisibleCaption to APage do if csHidden in Bricks[I].State then Continue else begin Result.Left := Result.Right; if Owner.HandleAllocated then Result.Right := Result.Left + Canvas.TextWidth(Bricks[I].DisplayText) + 30; if Result.Left > 0 then OffsetRect(Result, -10, 0); end; end; end; function TcxSSBookPageCaptions.HitTest(X, Y: Integer; var AIndex: Integer): TcxSSCaptionHitTest; function CheckHitInCaption(ACaptionRect: TRect; AX, AY: Integer): Boolean; var DX: Integer; begin OffsetRect(ACaptionRect, -Left, -Top); AX := AX - Left; AY := AY - Top; DX := Round(AY * 10 / Height); Result := (AY > ACaptionRect.Top) and (AY < ACaptionRect.Bottom) and ((AX >= (ACaptionRect.Left + DX)) and (AX <= (ACaptionRect.Right - DX))) end; var I: Integer; AHitPoint: TPoint; begin Result := htNone; AIndex := 0; AHitPoint := Point(X + Left, Y + Top); with FViewInfo do begin for I := 0 to 3 do if PtInRect(BtnBricks[TcxSSNavigatorBtn(I)], AHitPoint) then begin AIndex := I; Result := htButton; Exit; end; AIndex := -1; for I := FViewInfo.FirstVisibleCaption to Length(Bricks) - 1 do if not (csHidden in Bricks[I].State) then begin if CheckHitInCaption(Bricks[I].BoundsRect, AHitPoint.X, AHitPoint.Y) then begin if (AIndex < 0) or (csCurrent in Bricks[I].State) then AIndex := I; end; end; if AIndex >=0 then Result := htCaption; end; end; procedure TcxSSBookPageCaptions.MouseMove(Shift: TShiftState; X, Y: Integer); var AHitRes: Integer; AHitType: TcxSSCaptionHitTest; AIsDown: Boolean; begin Cursor := crDefault; AHitType := HitTest(X, Y, AHitRes); with FViewInfo do begin if BtnDown <> -1 then begin AIsDown := (AHitType = htButton) and (AHitRes = BtnDown); if AIsDown <> IsButtonDown then begin IsButtonDown := AIsDown; if not Owner.Listener.IsLocked then Owner.InvalidateRect(BtnBricks[TcxSSNavigatorBtn(BtnDown)], False); end; end; end; end; procedure TcxSSBookPageCaptions.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var AHitRes: Integer; AHitType: TcxSSCaptionHitTest; begin if FIsEditorActivate then Exit; if Button = mbRight then Owner.Listener.OnCaptionPopupMenu(Owner.ActiveSheet, ClientToScreen(X, Y)) else with FViewInfo do begin FMouseDownPos := Point(X, Y); AHitType := HitTest(X, Y, AHitRes); with Owner do begin if AHitType = htButton then begin IsButtonDown := True; BtnDown := AHitRes; if not Listener.IsLocked then InvalidateRect(BtnBricks[TcxSSNavigatorBtn(AHitRes)], False); end else if AHitType = htCaption then begin FSkipActivePageChanging := True; ActivePage := AHitRes; end; end; end; end; procedure TcxSSBookPageCaptions.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var AHitRes: Integer; AHitType: TcxSSCaptionHitTest; ACaption: Integer; begin inherited; if FIsEditorActivate then begin FIsEditorActivate := False; FCaptionEditor.Font.Assign(Owner.HeaderFont); FCaptionEditor.SetFocus; Exit; end; FMouseDownPos := Point(X, Y); AHitType := HitTest(X, Y, AHitRes); if AHitType = htButton then begin ACaption := FViewInfo.FirstVisibleCaption; if FViewInfo.BtnDown = AHitRes then begin case AHitRes of 0: ACaption := 0; 1: if ACaption > 0 then Dec(ACaption); 2: if ACaption < (Owner.PageCount - 1) then Inc(ACaption); 3: ACaption := Owner.PageCount - 1; end; end; if not Self.Owner.Listener.IsLocked then Self.Owner.InvalidateRect(FViewInfo.BtnBricks[TcxSSNavigatorBtn(FViewInfo.BtnDown)], False); FirstVisibleCaption := ACaption; end else if (AHitType = htCaption) and not FSkipActivePageChanging then Owner.ActivePage := AHitRes; FSkipActivePageChanging := False; FViewInfo.IsButtonDown := False; FViewInfo.BtnDown := -1; end; procedure TcxSSBookPageCaptions.OnEditCaptionText(Sender: TObject); var I: Integer; begin with ViewInfo do begin Bricks[Owner.ActivePage].DisplayText := (Sender as TcxSSInplaceTextEdit).Text; for I := Owner.ActivePage to Owner.PageCount - 1 do begin Bricks[I].BoundsRect := GetCaptionTextExtent(I); OffsetRect(Bricks[I].BoundsRect, BtnBricks[nbEnd].Right, 0); end; end; Invalidate; end; procedure TcxSSBookPageCaptions.OnEndEditCaption(Sender: TObject); var ARect: TRect; begin if FCaptionEditor.Focused then Owner.SetFocus; FCaptionEditor.Visible := False; try Owner.ActiveSheet.Caption := FCaptionEditor.Text; finally RecalcViewInfo; ARect.TopLeft := ViewInfo.Bricks[Owner.ActivePage].BoundsRect.TopLeft; ARect.BottomRight := ViewInfo.Bounds.BottomRight; if not Owner.Listener.IsLocked then Owner.InvalidateRect(ARect, False); end; end; procedure TcxSSBookPageCaptions.Paint; begin FViewInfo.FillColor := Canvas.GetNativeColor(Owner.HeaderColor); FViewInfo.Font := Owner.HeaderFont; FCaptionPainter.Paint(Canvas, FViewInfo); inherited; end; procedure TcxSSBookPageCaptions.ReCalcViewInfo; var I: Integer; ALeft: Integer; const AVisibleState: array[Boolean] of TcxSSCaptionStates = ([csHidden], []); AActiveState: array[Boolean] of TcxSSCaptionStates = ([], [csCurrent]); begin if not Owner.HandleAllocated or Owner.Listener.IsLocked then Exit; Canvas.BeginPaint(ControlCanvas); with FViewInfo do begin IsButtonDown := False; BtnDown := -1; Font := Owner.HeaderFont; Bounds := Rect(Left, Top, Left + Width, Top + Height); SetLength(Bricks, Owner.PageCount); Enabled := [nbStart, nbPrev, nbNext, nbEnd]; for I := 0 to 3 do BtnBricks[TcxSSNavigatorBtn(I)] := Rect(Bounds.Left + I * Height, Bounds.Top, Bounds.Left + (I + 1) * Height, Bounds.Bottom - 1); with FViewInfo do begin ALeft := BtnBricks[nbEnd].Right; for I := FViewInfo.FirstVisibleCaption to Owner.PageCount - 1 do begin Bricks[I].DisplayText := Owner.Pages[I].Caption; Bricks[I].State := AVisibleState[Owner.PageVisible[I]] + AActiveState[Owner.ActivePage = I]; Bricks[I].BoundsRect := GetCaptionTextExtent(I); OffsetRect(Bricks[I].BoundsRect, ALeft, 0); end; end; end; Canvas.Canvas.Font.Assign(Owner.HeaderFont); Height := Canvas.TextHeight('I') + 5; end; procedure TcxSSBookPageCaptions.Resize; begin inherited Resize; if not EqualRect(ClientRect, FViewInfo.Bounds) then RecalcViewInfo; end; procedure TcxSSBookPageCaptions.UpdateCaptionInfo(APage: Byte; AState: TcxSSCaptionStates); begin if APage < Length(FViewInfo.Bricks) then begin with FViewInfo.Bricks[APage] do begin State := AState; InvalidateRect(ClientRect); end; end; end; procedure TcxSSBookPageCaptions.VisibleChanging; begin if Owner.CaptionBar.Visible then Owner.HScrollBar.Left := Owner.CaptionBar.Width else Owner.HScrollBar.Left := 0 end; function TcxSSBookPageCaptions.GetFirstVisibleCaption: Integer; begin Result := FViewInfo.FirstVisibleCaption; end; procedure TcxSSBookPageCaptions.SetFirstVisibleCaption(const Value: Integer); begin if FirstVisibleCaption <> Value then begin FViewInfo.FirstVisibleCaption := Value; RecalcViewInfo; InvalidateRect(ClientRect); end; end; { TcxSSBookSheet } constructor TcxSSBookSheet.Create(AOwner: TcxCustomSpreadSheetBook); begin inherited Create(AOwner); FDataStorage := Owner.GetDataStorageClass.Create(Self); FSheetViewInfo := Owner.GetViewInfoClass.Create(Self); FShowFormulas := Owner.ShowFormulas; FShowGrid := Owner.ShowGrid; FShowHeaders := True; FSheetState := []; FCurrentPos := Point(0, 0); FVisible := False; end; destructor TcxSSBookSheet.Destroy; begin try FDataStorage.Free; FSheetViewInfo.Free; finally inherited Destroy; end; end; procedure TcxSSBookSheet.Assign(Source: TcxSSBookSheet); begin if Source <> nil then begin Owner.BeginUpdate; try FReadOnly := Source.FReadOnly; FShowGrid := Source.ShowGrid; FShowHeaders := Source.FShowHeaders; FShowFormulas := Source.FShowFormulas; DataStorage.Assign(Source.DataStorage); Cols.Assign(Source.Cols); Rows.Assign(Source.Rows); finally Owner.EndUpdate; end; end; end; procedure TcxSSBookSheet.ClearAll; begin Owner.DeactivateEditor; Owner.History.StartComplexAction(cxGetResourceString(@scxClearAllAction)); try DataStorage.ClearCells(Rect(-1, -1, -1, -1), True); finally if ViewInfoValid then ViewInfo.UpdateViewInfo; end; Owner.History.StopComplexAction; end; procedure TcxSSBookSheet.ClearCells(const ARect: TRect; SetDefaultStyle: Boolean = False); var I: Integer; StartAction: Boolean; begin if not CanModify(Owner, Self, ARect) then Exit; Owner.DeactivateEditor; StartAction := Owner.History.StartComplexAction(cxGetResourceString(@scxClearCells)); try DataStorage.ClearCells(ARect, SetDefaultStyle); for I := ARect.Top to ARect.Bottom do ApplyAutoHeight(I); finally if StartAction then Owner.History.StopComplexAction; ViewInfo.UpdateViewInfo; CellsChanged(ARect); end; end; procedure TcxSSBookSheet.DeleteCells(const ACells: TRect; ACellsModify: TcxSSCellsModify); begin if Owner.ExcelProtectionStyle and not CanModify(Owner, Self, ACells) then Exit; with Owner do begin BeginUpdate; try if ACellsModify in [msAllRow, msAllCol] then FormulasCache.UpdateRef(FPages.IndexOf(Self), ACells, True, ACellsModify = msAllCol); DataStorage.DeleteCells(ACells, ACellsModify); finally EndUpdate; end; end; end; procedure TcxSSBookSheet.Copy(const ARect: TRect; IsCut: Boolean); var I, J: Integer; AText: string; Action: TcxComplexAction; begin for J := ARect.Top to ARect.Bottom do begin for I := ARect.Left to ARect.Right do begin AText := AText + DataStorage[I, J].Text; if I < ARect.Right then AText := AText + CellTerminator; end; if J < ARect.Bottom then AText := AText + RowTerminator; end; cxSSClipboard.DataAsEssFormat := Owner.SpreadSheetDataToClipboardData(Self, ARect) + #13#10; cxSSClipboard.DataAsUnicode := AText + #13#10; if IsCut and CanModify(Owner, Self, ARect) then begin TcxHistoryAccess(Owner.History).AddComplexAction(TcxComplexAction, cxGetResourceString(@scxCutCommand), Action); try DataStorage.ClearCells(ARect); finally if Action <> nil then TcxHistoryAccess(Owner.History).StopComplexAction; end; end; end; procedure TcxSSBookSheet.FormatCells(const ACells: TRect); var ADesignerClass: TcxSSFormatDialogClass; ACanFormat: Boolean; AForm: TForm; ARect: TRect; begin ADesignerClass := TcxSSStyleDesigner; ACanFormat := True; if Assigned(Owner.FOnFormatCells) then Owner.OnFormatCells(Owner, PRect(@ACells)^, ACanFormat, ADesignerClass); if ACanFormat then begin History.StartComplexAction(cxGetResourceString(@scxChangeCellsStyle)); try AForm := ADesignerClass.Create(nil); ARect := Owner.BoundsRect; ARect.TopLeft := Owner.ClientToScreen(ARect.TopLeft); ARect.BottomRight := Owner.ClientToScreen(ARect.BottomRight); AForm.Top := (ARect.Top + ARect.Bottom - AForm.Height) shr 1; AForm.Left := (ARect.Left + ARect.Right - AForm.Width) shr 1; try (AForm as TcxSSFormatDialog).Execute(ACells, Self); finally AForm.Free; end; finally History.StopComplexAction; end; end; end; procedure TcxSSBookSheet.InsertCells(const ACells: TRect; ACellsModify: TcxSSCellsModify); begin if Owner.ExcelProtectionStyle and not CanModify(Owner, Self, ACells) then Exit; with Owner do begin BeginUpdate; try if ACellsModify in [msAllRow, msAllCol] then FormulasCache.UpdateRef(FPages.IndexOf(Self), ACells, False, ACellsModify = msAllCol); DataStorage.InsertCells(ACells, ACellsModify); finally EndUpdate; end; end; end; procedure TcxSSBookSheet.Invalidate; begin if not Owner.CaptionBar.Visible then Owner.Invalidate else inherited Invalidate; end; procedure TcxSSBookSheet.Paste(const APlace: TPoint); var S: string; AText: string; APos, I: Integer; ACol, ARow: Integer; Action: TcxComplexAction; ACanEdit: Boolean; AChangedCells: TRect; AreCellsChanged: Boolean; begin ACol := APlace.X; ARow := APlace.Y; if not CanModify(Owner, Self, ACol, ARow) then Exit; ACanEdit := True; Owner.Listener.OnEditing(Self, ACol, ARow, ACanEdit); if not ACanEdit then Exit; APos := 1; TcxHistoryAccess(Owner.History).AddComplexAction(TcxComplexAction, cxGetResourceString(@scxPasteCommand), Action); Owner.BeginUpdate; AreCellsChanged := True; try try if not Owner.SpreadSheetClipboardDataToData(Self, APlace.X, APlace.Y, AChangedCells) then begin AChangedCells := Rect(ACol, ARow, ACol - 1, ARow - 1); S := cxSSClipBoard.DataAsUnicode; if (Length(S) > 0) and (S[Length(S)] = #0) then SetLength(S, Length(S) - 1); AText := ''; AChangedCells.TopLeft := APlace; while APos < Length(S) do begin I := APos; while (I < Length(S)) and not dxCharInSet(S[I], [#9, #13, #10]) do Inc(I); if I <> APos then AText := System.Copy(S, APos, I - APos) else begin if S[I] = #9 then begin Inc(ACol); end else if S[I] = #13 then begin if (I < Length(S)) and (S[I + 1] = #10) then Inc(I); Inc(ARow); ACol := APlace.X; end; Inc(I); if I > Length(S) then Dec(ARow); AText := ''; end; if I <= Length(S) then begin if CanModify(Owner, Self, ACol, ARow) then with GetCellObject(ACol, ARow) do try Text := AText; finally Free; end; end; AChangedCells.Bottom := ARow; APos := I; AChangedCells.Right := Max(AChangedCells.Right, ACol); end; end; except on ESpreadSheetError do begin AreCellsChanged := False; raise; end else raise; end; finally if Assigned(Owner.FOnEndEdit) then Owner.FOnEndEdit(Self); if AreCellsChanged then CellsChanged(AChangedCells); Owner.EndUpdate; Owner.UpdateControl; if Action <> nil then TcxHistoryAccess(Owner.History).StopComplexAction; end; end; function TcxSSBookSheet.GetCellObject(ACol, ARow: Integer): TcxSSCellObject; begin Result := TcxSSCellObject(DataStorage.CreateAccessCellObject(ACol, ARow)); end; procedure TcxSSBookSheet.SelectCell(const ACol, ARow: Integer; OpenEditor: Boolean = False); begin if (CellEditor <> nil) and CellEditor.Visible then Exit; DataStorage.Selection := Rect(ACol, ARow, ACol, ARow); if OpenEditor then begin Owner.SetFocus; if DoEditorActivate then begin CellEditor.SetFocus; CellEditor.SetCursorPosition(Point(0, 0)); end; end; Invalidate; end; procedure TcxSSBookSheet.SetMergedState(const ARect: TRect; IsMerge: Boolean); begin if not CanModify(Owner, Self, ARect) then Exit; Owner.BeginUpdate; try DataStorage.MergeUnMerge(ARect, IsMerge); if IsMerge then begin with GetCellObject(ARect.Left, ARect.Top) do try if Text <> '' then CheckCellWordBreak; finally Free; end; end; finally Owner.EndUpdate; { if not Listener.IsLocked then ViewInfo.UpdateViewInfo;} end; end; procedure TcxSSBookSheet.SetVisibleState(const ARect: TRect; ACols, ARows, AShow: Boolean); var I: Integer; R: TRect; begin if (Owner.FCellEditor <> nil) and Owner.FCellEditor.Focused then Owner.SetFocus; Owner.BeginUpdate; try if ACols then for I := ARect.Left to ARect.Right do begin DataStorage.Headers[htCol].Visible[I] := AShow; if AShow and (DataStorage.Headers[htCol].Size[I] = 0) then DataStorage.Headers[htCol].Size[I] := DataStorage.Headers[htCol].DefaultSize; end; if ARows then for I := ARect.Top to ARect.Bottom do begin DataStorage.Headers[htRow].Visible[I] := AShow; if AShow and (DataStorage.Headers[htRow].Size[I] = 0) then DataStorage.Headers[htRow].Size[I] := DataStorage.Headers[htRow].DefaultSize; end; finally if not AShow and EqualRect(ARect, SelectionRect) then begin R := ARect; if ACols then with TcxHeaderAccess(Cols) do OffsetRect(R, GetNextItem(ARect.Left, True) - ARect.Left, 0); if ARows then with TcxHeaderAccess(Rows) do OffsetRect(R, 0, GetNextItem(ARect.Top, True) - ARect.Top); SelectionRect := R; end; Owner.EndUpdate; Owner.UpdateControl; end; end; procedure TcxSSBookSheet.Sort(const ARect: TRect; const ASortTypes: array of TcxSortType); var Action: TcxComplexAction; begin TcxHistoryAccess(Owner.History).AddComplexAction(TcxComplexAction, cxGetResourceString(@scxSortCellsAction), Action); try Owner.BeginUpdate; try DataStorage.Sort(ARect, ASortTypes); finally Owner.EndUpdate; end; finally if Action <> nil then TcxHistoryAccess(Owner.History).StopComplexAction; end; end; function TcxSSBookSheet.DoEditorActivate: Boolean; var ATopLeft: TPoint; ARect: TRect; I, J: Integer; begin if CellReadOnly(Owner, Self, DataStorage.Col, DataStorage.Row) then Exit; Result := True; Listener.OnEditing(Self, DataStorage.Col, DataStorage.Row, Result); if not Result then Exit; if CellEditor = nil then begin Owner.FCellEditor := Owner.GetInplaceEditClass.Create(Owner, True) as TcxSSInplaceTextEdit; CellEditor.Parent := Owner; CellEditor.OnEndEdit := OnEndEditCell; end; if DataStorage.Col < ViewInfo.LeftCol then ViewInfo.LeftCol := DataStorage.Col; if DataStorage.Row < ViewInfo.TopRow then ViewInfo.TopRow := DataStorage.Row; ATopLeft := TPoint(ViewInfo.TopLeft); FEditingPos := Point(DataStorage.Col, DataStorage.Row); ARect := DataStorage.CellRect(ATopLeft.X, ATopLeft.Y, DataStorage.Col, DataStorage.Row, True); with GetCellObject(DataStorage.Col, DataStorage.Row) do try Style.Font.AssignTo(CellEditor.Font); if Style.Brush.BackgroundColor <= 55 then CellEditor.Color := Self.Owner.Palette^[Style.Brush.BackgroundColor] else CellEditor.Color := Self.Owner.BackgroundColor; finally Free; end; with ViewInfo.InfoData do for I := 0 to Length(Bricks) - 1 do if Bricks[I, 0].Col >= DataStorage.Col then begin for J := 0 to Length(Bricks[0]) do if Bricks[0, J].Row >= DataStorage.Row then with Bricks[I, J] do begin if not IsMerge then begin ViewInfo.ClearBrickText(I, J); CellEditor.AutoWidth := True; CellEditor.MinimalWidth := Max(RectWidth(DisplayRect), RectWidth(TextRect)) - 5; CellEditor.MinimalHeight := Max(RectHeight(DisplayRect), RectHeight(TextRect)) - 5; ARect := Rect(TextRect.Left + 3, DisplayRect.Top, TextRect.Right, DisplayRect.Bottom + 2); InflateRect(ARect, 0, -2); end else begin CellEditor.AutoWidth := True; ARect := UnionBricks[UnionIndex].DisplayRect; OffsetRect(ARect, 1, 1); InflateRect(ARect, -3, -2); CellEditor.MinimalWidth := RectWidth(ARect); CellEditor.MinimalHeight := RectHeight(ARect); end; Dec(ARect.Bottom, 1); Break; end; if ARect.Right < ViewInfo.RowHeaderWidth then ARect.Right := ViewInfo.RowHeaderWidth; if ARect.Top < ViewInfo.ColHeaderHeight then ARect.Top := ViewInfo.ColHeaderHeight; Break; end; CellEditor.SetBounds(ARect.Left - 2, ARect.Top, RectWidth(ARect), RectHeight(ARect)); CellEditor.InitEditor(DataStorage.CellText[Col, Row], DataStorage.CellText[Col, Row]); FSheetState := [ssEditorActivate]; CellEditor.OnEndEdit := OnEndEditCell; ViewInfo.UpdateOnChangeSelection; end; function TcxSSBookSheet.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; begin Owner.DeactivateEditor; Result := True; end; procedure TcxSSBookSheet.ApplyAutoHeight(ARow: Integer); function GetCellHeight(ACol: Integer): Integer; var I: Integer; R, R1: TRect; ACell: TcxSSCellRec; ASettings: TcxTextParameters; S: string; begin ACell := DataStorage.Cells[ACol, ARow]; Result := 0; if ACell.DataType <> dtText then Exit; R := ClientRect; R.Right := R.Left; if DataStorage.CheckInMergeRange(Point(ACol, ARow), R1) then Exit; with R1 do for I := Left to Right do Inc(R.Right, Cols[I]); InflateRect(R, -2, -2); if (R.Right <= R.Left) or (ACell.Text = '') then Exit; if Owner.FormulasCache.IsLoading or ACell.StylePtr^.WordBreak then begin Canvas.SelectFont(ACell.StylePtr^.FontPtr^.FontHandle); Result := Canvas.TextHeight('Wg') + 2; if not ACell.StylePtr^.WordBreak then Exit; with ACell.StylePtr^ do begin S := OrdinalToFormatStr(ACell.Text, FormatIndex, TcxCustomSpreadSheetBook(Owner).Precision); Canvas.CalculateTextExtents(S, R, HorzAlign, VertAlign, WordBreak, ASettings); end; if (Length(ASettings.TextBricks) = 1) and (Rows.DefaultSize > Result) then Result := Rows.DefaultSize else Result := Result * Length(ASettings.TextBricks); end; end; var I: Integer; ASize: Integer; begin if Owner.IsDataLoading or not Owner.RowsAutoHeight {or not Rows.IsDefault[ARow]} then Exit; ASize := 0; for I := 0 to DataStorage.GetContentColCount do ASize := Max(ASize, GetCellHeight(I)); if ASize <> 0 then TcxHeaderAccess(Rows).SetScaledSize(ARow, ASize); end; procedure TcxSSBookSheet.CellsChanged(const ARect: TRect); var I, J: Integer; begin for I := ARect.Left to ARect.Right do for J := ARect.Top to ARect.Bottom do if Assigned(Owner.OnCellChange) then Owner.OnCellChange(Self, I, J); end; procedure TcxSSBookSheet.DblClick; const InactiveStates: TcxSSHitTestStates = [htRowHeader, htResize, htUpperLeft, htColHeader]; var AHitState: TcxSSHitTestStates; ACol, ARow: Integer; begin AHitState := ViewInfo.HitTest(FMouseDownPos.X, FMouseDownPos.Y, ACol, ARow); if InactiveStates * AHitState <> [] then Exit; DoEditorActivate; end; procedure TcxSSBookSheet.FocusChanged; begin inherited; if not (ssEditorActivate in FSheetState) then FSheetState := []; if Owner.HideSelection then ViewInfo.UpdateOnCancelMode; end; procedure TcxSSBookSheet.InitScrollBars; procedure SetInfo(Kind: TScrollBarKind; MaxLine, Up, Down: Integer); var AMax: Integer; begin AMax := Max(MaxLine, Down); if (AMax > MaxLine) and (Up > 0) then Dec(AMax); with Owner do SetScrollBarInfo(Kind, 0, AMax, 1, Down - Up, Up, ScrollersVisible[ScrollBars, Kind], True); end; begin SetInfo(sbVertical, DataStorage.MaxRow, Corners.Top, Corners.Bottom); SetInfo(sbHorizontal, DataStorage.MaxColumn, Corners.Left, Corners.Right); Owner.VScrollbar.ApplyData; Owner.HScrollbar.ApplyData; end; procedure TcxSSBookSheet.KeyDown(var Key: Word; Shift: TShiftState); procedure ChangeCursorPos(AKey: Integer; AShift: TShiftState); var APos: TRect; AOldPos: TPoint; ARect: TRect; begin with DataStorage do begin if ssSelection in FSheetState then begin APos.TopLeft := FCurrentPos; APos.BottomRight := FCurrentPos; end else APos := Selection; AOldPos := FCurrentPos; case AKey of VK_LEFT: FCurrentPos.X := TcxHeaderAccess(Headers[htCol]).GetNextItem(APos.Left, False); VK_UP: FCurrentPos.Y := TcxHeaderAccess(Headers[htRow]).GetNextItem(APos.Top, False); VK_RIGHT: FCurrentPos.X := TcxHeaderAccess(Headers[htCol]).GetNextItem(APos.Right, True); VK_DOWN: FCurrentPos.Y := TcxHeaderAccess(Headers[htRow]).GetNextItem(APos.Bottom, True); end; if (ssSelection in FSheetState) then begin ARect := Selection; case AKey of VK_LEFT: if AOldPos.X = ARect.Right then begin ARect.Left := AOldPos.X; ARect := CheckSelectionRect(ARect); if ARect.Left <> AOldPos.X then FCurrentPos.X := ARect.Left - 1 end; VK_UP: if AOldPos.Y = ARect.Bottom then begin ARect.Top := AOldPos.Y; ARect := CheckSelectionRect(ARect); if ARect.Top <> AOldPos.Y then FCurrentPos.Y := ARect.Top - 1 end; VK_RIGHT: begin if AOldPos.X = ARect.Left then ARect.Right := AOldPos.X else ARect.Left := AOldPos.X; ARect := CheckSelectionRect(ARect); if ARect.Right <> AOldPos.X then FCurrentPos.X := ARect.Right + 1 end; VK_DOWN: begin if AOldPos.Y = ARect.Top then ARect.Bottom := AOldPos.Y else ARect.Top := AOldPos.Y; ARect := CheckSelectionRect(ARect); if ARect.Bottom <> AOldPos.Y then FCurrentPos.Y := ARect.Bottom + 1 end; end; end; end; end; function GetCorners: TRect; begin Result.TopLeft := TPoint(ViewInfo.TopLeft); Result.BottomRight := TPoint(ViewInfo.BottomRight); end; procedure ValidateCorners(var ACorners: TRect; var APos: TPoint); begin if APos.X < ACorners.Left then ViewInfo.LeftCol := APos.X else if FCurrentPos.X > ACorners.Right then ViewInfo.RightCol := APos.X; if APos.Y < ACorners.Top then ViewInfo.TopRow := APos.Y else if APos.Y > ACorners.Bottom then ViewInfo.BottomRow := APos.Y end; function IsUnusedKey: Boolean; begin Result := (ssAlt in Shift) and (DataStorage.SelectionState = ssMultiSelect) or (Key = VK_APPS); end; var ACorners: TRect; AScrollsPos: TPoint; begin inherited KeyDown(Key, Shift); if IsUnusedKey then Exit; if (Key = VK_F2) and (not ((ssShift in Shift) or (ssCtrl in Shift) or CellReadOnly(Owner, Self, FEditingPos.X, FEditingPos.Y))) then begin if DoEditorActivate then begin CellEditor.SetFocus; CellEditor.SetCursorPosition(Point(0, 0)); end; Exit; end; if Key = VK_TAB then begin FSheetState := []; if ssShift in Shift then Key := VK_LEFT else Key := VK_RIGHT; Shift := []; end; if not (ssShift in Shift) then FCurrentPos := DataStorage.Selection.TopLeft; if Key = VK_CONTROL then Exit; ACorners := GetCorners; with DataStorage do begin if SelectionState = ssCurrentSelect then FCurrentPos := Point(Col, Row); if (Key = VK_SHIFT) or (not (ssSelection in FSheetState) and (ssShift in Shift)) then begin FStartSelection := Selection.TopLeft; FCurrentPos := Selection.BottomRight; FSheetState := [ssSelection]; end; if Key = VK_SHIFT then Exit; ValidateCorners(ACorners, FCurrentPos); case Key of VK_LEFT..VK_DOWN : ChangeCursorPos(Key, Shift); VK_PRIOR: begin ViewInfo.BottomRow := ACorners.Top; FCurrentPos.Y := ViewInfo.TopRow; ACorners := GetCorners; end; VK_NEXT: begin FCurrentPos.Y := Row - ACorners.Top; ViewInfo.TopRow := ACorners.Bottom; FCurrentPos.Y := ViewInfo.TopRow; ACorners := GetCorners; end; VK_END: if ssCtrl in Shift then FCurrentPos := Point(MaxColumn, MaxRow); VK_HOME: begin if ssCtrl in Shift then FCurrentPos := Point(0, 0) else FCurrentPos.X := 0; while not Cols.Visible[FCurrentPos.X] do Inc(FCurrentPos.X); while not Rows.Visible[FCurrentPos.Y] do Inc(FCurrentPos.Y); end; VK_DELETE: begin if Shift = [ssShift] then Copy(SelectionRect, True) else Self.ClearCells(DataStorage.Selection, ssCtrl in Shift); end; VK_RETURN: FCurrentPos.Y := FCurrentPos.Y + 1; VK_INSERT: begin if Shift = [ssShift] then Paste(SelectionRect.TopLeft) else if Shift = [ssCtrl] then Copy(SelectionRect, False); end; end; ValidateCorners(ACorners, FCurrentPos); if not (ssSelection in FSheetState) and (Key <> VK_Shift) then with FCurrentPos do Selection := Rect(X, Y, X, Y) else Selection := Rect(FCurrentPos.X, FCurrentPos.Y, FStartSelection.X, FStartSelection.Y); end; AScrollsPos := TPoint(ViewInfo.TopLeft); if (Key = VK_PRIOR) or (Key = VK_NEXT) or (Key = VK_END) or (Key = VK_HOME) or ((Key >= VK_LEFT) or (Key <=VK_DOWN)) then begin Scroll(sbHorizontal, scPosition, AScrollsPos.X, False); Scroll(sbVertical, scPosition, AScrollsPos.Y, False); end; end; procedure TcxSSBookSheet.KeyPress(var Key: Char); begin inherited KeyPress(Key); if (Byte(Key) >= $21) and not CellReadOnly(Owner, Self, DataStorage.Col, DataStorage.Row) then begin if DoEditorActivate then begin CellEditor.Text := Key; CellEditor.SetFocus; CellEditor.SetCursorPosition(Point(1, 0)); end else Exit; end; end; procedure TcxSSBookSheet.KeyUp(var Key: Word; Shift: TShiftState); begin if Key = VK_SHIFT then FSheetState := []; inherited; end; procedure TcxSSBookSheet.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ACol, ARow: Integer; AHitState: TcxSSHitTestStates; const AResizeCursor: array[Boolean] of TCursor = (crVSplit, crHSplit); AState: array[Boolean] of TcxSSSheetState = (ssRowHeader, ssColHeader); begin inherited MouseDown(Button, Shift, X, Y); if ssEditorActivate in FSheetState then begin CellEditor.SetFocus; CellEditor.SetCursorPosition(CellEditor.GetEditPos(X - CellEditor.Left, Y - CellEditor.Top)); FSheetState := []; Exit; end; FMouseDownPos := Point(X, Y); AHitState := ViewInfo.HitTest(X, Y, ACol, ARow); if htResize in AHitState then begin if ACol < 0 then begin FResizeHeaderType := htRow; FSizeIndex := ARow end else begin FResizeHeaderType := htCol; FSizeIndex := ACol; end; FSheetState := [ssResize] + [AState[htColHeader in AHitState]]; FChangedSizeValue := DataStorage.Headers[FResizeHeaderType][FSizeIndex]; end else begin if mbRight = Button then if (ACol < 0) or (ARow < 0) or DataStorage.IsMultiSelection then Listener.OnSheetPopupMenu(Self, ClientToScreen(X, Y)) else begin DataStorage.Selection := Rect(ACol, ARow, ACol, ARow); FDownCellPos := Point(ACol, ARow); Listener.OnSheetPopupMenu(Self, ClientToScreen(X, Y)) end; if (htCell in AHitState) and not (Button = mbRight) then begin if Button = mbLeft then FSheetState := [ssSelection]; DataStorage.Selection := Rect(ACol, ARow, ACol, ARow); FDownCellPos := Point(ACol, ARow); end; end; end; procedure TcxSSBookSheet.MouseMove(Shift: TShiftState; X, Y: Integer); procedure CheckNeedScrollContent; var ANeedViewInfoUpdate: Boolean; procedure DoScroll(AKind: TScrollBarKind; ACode: TScrollCode; APos: Integer); begin if APos > 0 then begin Scroll(AKind, ACode, APos, False); ANeedViewInfoUpdate := True; end; end; begin if Y < Owner.ColHeaderHeight then DoScroll(sbVertical, scLineUp, ViewInfo.TopRow) else if Y > Height then DoScroll(sbVertical, scLineDown, ViewInfo.BottomRow); if X < Owner.RowHeaderWidth then DoScroll(sbHorizontal, scLineUp, ViewInfo.LeftCol) else if X > Width then DoScroll(sbHorizontal, scLineDown, ViewInfo.RightCol); if ANeedViewInfoUpdate then ViewInfo.TopLeft := Point(Owner.HScrollBar.Data.Position, Owner.VScrollBar.Data.Position); end; var ACol, ARow: Integer; AHitState: TcxSSHitTestStates; ASize: Integer; AR, ACr: TRect; const AResizeCursor: array[Boolean] of TCursor = (crVSplit, crHSplit); begin inherited MouseMove(Shift, X, Y); if ((ssLeft in Shift) or (ssRight in Shift)) and not ((ssResize in FSheetState) or (ssSelection in FSheetState)) then Exit; // if need scrolling if (ssLeft in Shift) and not (ssResize in FSheetState) then CheckNeedScrollContent; //.......... if (ssSelection in FSheetState) and not ((ssLeft in Shift) or (ssRight in Shift)) then Exit; AHitState := ViewInfo.HitTest(X, Y, ACol, ARow); if (ssResize in FSheetState) and (ssLeft in Shift) then begin if FResizeHeaderType = htCol then ASize := X - FMouseDownPos.X else ASize := Y - FMouseDownPos.Y; ASize := ASize + FChangedSizeValue + 1; if ASize < 0 then ASize := 0; DataStorage.Headers[FResizeHeaderType].Size[FSizeIndex] := ASize; end else begin if (htResize in AHitState) and not (ssSelection in FSheetState) then begin Cursor := AResizeCursor[htColHeader in AHitState]; if htColHeader in AHitState then FSizeIndex := ACol else FSizeIndex := ARow; end else begin Cursor := crSSSelect; if ssSelection in FSheetState then begin with ViewInfo.InfoData do begin if ACol < 0 then ACol := 0; if ARow < 0 then ARow := 0; end; DataStorage.Selection := Rect(ACol, ARow, FDownCellPos.X, FDownCellPos.Y); AR := DataStorage.Selection; ACr.TopLeft := ViewInfo.TopLeft; ACr.BottomRight := ViewInfo.BottomRight; { if (ARow > FDownCellPos.Y) then begin if (AR.Bottom - 1) >= ACr.Bottom then ViewInfo.BottomRow := AR.Bottom; end else if (ARow <= FDownCellPos.Y) then begin end; } end; end; end; end; procedure TcxSSBookSheet.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin inherited; if not (ssEditorActivate in FSheetState) then begin FSheetState := []; Exit; end else FSheetState := []; end; procedure TcxSSBookSheet.OnEndEditCell(Sender: TObject); begin if Owner.HandleAllocated then begin try FSheetState := []; CellEditor.Visible := False; with GetCellObject(FEditingPos.X, FEditingPos.Y) do try FIsEditMode := True; Text := CellEditor.DisplayText; finally FIsEditMode := False; Free; end; finally ViewInfo.UpdateViewInfo; if Assigned(Owner.FOnEndEdit) then Owner.FOnEndEdit(Self); end; end; end; procedure TcxSSBookSheet.Paint; begin ViewInfo.InfoChanged := False; Owner.Painter.Paint(Canvas, ViewInfo.InfoData); end; procedure TcxSSBookSheet.Scroll(AScrollBarKind: TScrollBarKind; AScrollCode: TScrollCode; var AScrollPos: Integer; IsViewInfoUpdate: Boolean = True); var AMax: Integer; AUpPos: Integer; ADown: Integer; APageSize: Integer; AScroller: TcxControlScrollBar; begin if AScrollCode = scEndScroll then Exit; if AScrollBarKind = sbHorizontal then begin AScroller := Owner.HScrollBar; AMax := Max(DataStorage.MaxColumn, ViewInfo.RightCol); AUpPos := ViewInfo.LeftCol + TcxHeaderAccess(DataStorage.Headers[htCol]).GetCountItems(ViewInfo.LeftCol, Width - ViewInfo.RowHeaderWidth, False) + 1; ADown:= FSheetViewInfo.RightCol; APageSize := ViewInfo.RightCol - ViewInfo.LeftCol; if FSheetViewInfo.RightCol = FSheetViewInfo.LeftCol then begin if AScrollCode = scPageUp then Dec(AUpPos) else Inc(ADown); Inc(APageSize); end; end else begin AScroller := Owner.VScrollBar; AMax := Max(DataStorage.MaxRow, ViewInfo.BottomRow); AUpPos := ViewInfo.TopRow + TcxHeaderAccess(DataStorage.Headers[htRow]).GetCountItems(ViewInfo.TopRow, Height - ViewInfo.ColHeaderHeight, False) + 1; ADown:= FSheetViewInfo.BottomRow; APageSize := ViewInfo.BottomRow - ViewInfo.TopRow; if FSheetViewInfo.TopRow = FSheetViewInfo.BottomRow then begin Inc(ADown); Inc(APageSize); end; end; if AUpPos < 0 then AUpPos := 0; with AScroller.Data do begin Position := AScroller.Position; Max := AScroller.Max; PageSize := APageSize; case AScrollCode of scLineUp : Position := TcxHeaderAccess(DataStorage.Headers[TcxSSHeaderType(AScrollBarKind)]).GetNextItem(Position, False); scLineDown: Position := TcxHeaderAccess(DataStorage.Headers[TcxSSHeaderType(AScrollBarKind)]).GetNextItem(Position, True); scPageDown: Position := ADown; scPageUp: Position := AUpPos; scPosition: Position := AScrollPos; end; if Position < 0 then Position := 0; if (Position + PageSize) > AMax then Max := Position + PageSize - 1; if Max < 15 then Max := 15; end; if IsViewInfoUpdate then case AScrollBarKind of sbHorizontal: begin FSheetViewInfo.LeftCol := AScroller.Data.Position; AScrollPos := FSheetViewInfo.LeftCol; end; sbVertical: begin FSheetViewInfo.TopRow := AScroller.Data.Position; AScrollPos := FSheetViewInfo.TopRow; end; end; // InitScrollBars; // AScroller.ApplyData; end; function TcxSSBookSheet.ViewInfoValid: Boolean; begin Result := Visible and (ViewInfo <> nil) and (Owner <> nil) and (Owner.ActiveSheet = Self); end; function TcxSSBookSheet.GetActiveCell: TPoint; begin Result := DataStorage.Selection.TopLeft; end; function TcxSSBookSheet.GetCellEditor: TcxSSInplaceTextEdit; begin Result := Owner.FCellEditor; end; function TcxSSBookSheet.GetColHeader: TcxSSHeader; begin Result := DataStorage.Headers[htCol]; end; function TcxSSBookSheet.GetColumnCount: Integer; begin Result := DataStorage.MaxColumn; end; function TcxSSBookSheet.GetCorners: TRect; begin if ViewInfo <> nil then begin with ViewInfo do begin Result.TopLeft := TopLeft; Result.BottomRight := BottomRight; end; end else Result := Rect(0, 0, 0, 0); end; function TcxSSBookSheet.GetContentColCount: Integer; begin Result := DataStorage.GetContentColCount; end; function TcxSSBookSheet.GetContentRowCount: Integer; begin Result := DataStorage.GetContentRowCount; end; function TcxSSBookSheet.GetCurrentCol: Integer; begin Result := DataStorage.Col; end; function TcxSSBookSheet.GetCurrentRow: Integer; begin Result := DataStorage.Row; end; function TcxSSBookSheet.GetCell(const ACol, ARow: Integer): IcxSpreadSheetCell; begin Supports(TObject(GetCellObject(ACol, ARow)), IcxSpreadSheetCell, Result); end; function TcxSSBookSheet.GetHistory: TcxSpreadSheetHistory; begin Result := Owner.History; end; function TcxSSBookSheet.GetIsLoaded: Boolean; begin Result := Owner.IsLoaded; end; function TcxSSBookSheet.GetListener: TcxSSListener; begin Result := (Owner as TcxCustomSpreadSheetBook).Listener; end; function TcxSSBookSheet.GetPageIndex: Integer; begin Result := Owner.FPages.IndexOf(Self); end; function TcxSSBookSheet.GetSheetCaption: string; begin Result := DataStorage.SheetCaption; end; function TcxSSBookSheet.GetRowCount: Integer; begin Result := DataStorage.MaxRow; end; function TcxSSBookSheet.GetRowHeader: TcxSSHeader; begin Result := DataStorage.Headers[htRow]; end; function TcxSSBookSheet.GetSelectionRect: TRect; begin Result := DataStorage.Selection; end; function TcxSSBookSheet.GetTopLeft: TPoint; begin Result := ViewInfo.TopLeft; end; procedure TcxSSBookSheet.SetActiveCell(const Value: TPoint); begin DataStorage.Selection := Rect(Value.X, Value.Y, Value.X, Value.Y); end; procedure TcxSSBookSheet.SetColRowSize(const AKind: TcxSSHeaderType; const AColumn, ASize: Integer; ALocked: Boolean; AVisible: Boolean = True); begin with DataStorage.Headers[AKind] do begin Size[AColumn] := ASize; LockProtect[AColumn] := ALocked; Visible[AColumn] := AVisible; end; end; procedure TcxSSBookSheet.SetCorners(const Value: TRect); begin ViewInfo.TopLeft := Value.TopLeft; end; procedure TcxSSBookSheet.SetDefaultSize(const AKind: TcxSSHeaderType; ASize: Integer); begin DataStorage.Headers[AKind].DefaultSize := ASize; end; procedure TcxSSBookSheet.SetMergedCells(const ARect: TRect; IsMerge: Boolean); begin SetMergedState(ARect, IsMerge); end; procedure TcxSSBookSheet.SetPageDimension(const AHorzCount, AVertCount: Integer); begin DataStorage.Dimension := TSize(Point(AHorzCount + 1, AVertCount + 1)); DataStorage.SetCapacity(TSize(Point(AHorzCount, AVertCount))); end; procedure TcxSSBookSheet.SetProtection(Value: Boolean); begin FProtected := Value; end; procedure TcxSSBookSheet.SetSheetCaption(Value: string); var I: Integer; begin Owner.Listener.OnChangeSheetCaption(Self, Value); if DataStorage.SheetCaption <> Value then begin for I := 0 to Owner.PageCount - 1 do if (Owner.Pages[I] <> Self) and (AnsiCompareText(Owner.Pages[I].DataStorage.SheetCaption, Value) = 0) then raise ESpreadSheetError.Create(cxGetResourceString(@scxSpreadSheetInvalidSheetCaption)); DataStorage.SheetCaption := Value; Owner.CaptionBar.ReCalcViewInfo; Owner.UpdateControl; end; end; procedure TcxSSBookSheet.SetShowGrid(const Value: Boolean); begin if Value = FShowGrid then Exit; FShowGrid := Value; ViewInfo.UpdateViewInfo; end; procedure TcxSSBookSheet.SetShowHeaders(const Value: Boolean); begin if FShowHeaders = Value then Exit; FShowHeaders := Value; Owner.UpdateControl; end; procedure TcxSSBookSheet.SetShowFormulas(const Value: Boolean); begin if Value = FShowFormulas then Exit; FShowFormulas := Value; Owner.UpdateControl; end; procedure TcxSSBookSheet.SetSelectionRect(Value: TRect); function GetActualSize(AItems: TcxSSHeader; AStart, AFinish: Integer): Integer; var I: Integer; begin Result := 0; for I := AStart to AFinish do begin Inc(Result, AItems.Size[I]); if Result <> 0 then Break; end; end; var ColsWidth, RowsHeight: Integer; begin repeat ColsWidth := GetActualSize(Cols, Value.Left, Value.Right); if ColsWidth = 0 then begin OffsetRect(Value, 1, 0); ColsWidth := GetActualSize(Cols, Value.Left, Value.Right); end; RowsHeight := GetActualSize(Rows, Value.Top, Value.Bottom); if RowsHeight = 0 then begin OffsetRect(Value, 0, 1); RowsHeight := GetActualSize(Rows, Value.Top, Value.Bottom); end; until (ColsWidth <> 0) and (RowsHeight <> 0); DataStorage.Selection := Value; end; procedure TcxSSBookSheet.SetTopLeft(const Value: TPoint); begin ViewInfo.TopLeft := Value; end; procedure TcxSSBookSheet.SetViewInformation(const ASelectionRect: TRect; AViewFormulas, AViewGrid, AViewHeaders, AScrollBars: Boolean); begin FShowHeaders := AViewHeaders; FShowGrid := AViewGrid; FShowFormulas := AViewFormulas; DataStorage.Selection := ASelectionRect; Owner.UpdateControl; end; { TcxSSListener } constructor TcxSSListener.Create(AOwner: TcxCustomSpreadSheetBook); begin FOwner := AOwner; FLockCount := 0; end; function TcxSSListener.BeginUpdate: Integer; begin Inc(FLockCount); Result := FLockCount; end; function TcxSSListener.EndUpdate: Integer; begin if FLockCount > 0 then Dec(FLockCount); Result := FLockCount; end; function TcxSSListener.IsLocked: Boolean; begin Result := FLockCount > 0; end; procedure TcxSSListener.OnActiveCellChanging(Sender: TcxSSBookSheet; const ActiveCell: TPoint; var CanSelect: Boolean); begin if IsLocked then Exit; if Assigned(Owner.OnActiveCellChanging) then Owner.OnActiveCellChanging(Sender, ActiveCell, CanSelect) end; procedure TcxSSListener.OnActiveSheetChanging(Sender: TcxCustomSpreadSheetBook; const ActiveSheet: Integer; var CanSelect: Boolean); begin if IsLocked then Exit; if Assigned(Owner.OnActiveSheetChanging) then Owner.OnActiveSheetChanging(Sender, ActiveSheet, CanSelect); end; procedure TcxSSListener.OnChangeCellData(Sender: TcxSSBookSheet; const ACol, ARow: Integer); begin if IsLocked then Exit; if Sender.ViewInfoValid then Sender.ViewInfo.UpdateCellInfo(ACol, ARow); if Assigned(Owner.OnCellChange) then Owner.OnCellChange(Sender, ACol, ARow); end; procedure TcxSSListener.OnChangeDefaultStyle(const AOldValue, ANewValue: TcxSSCellStyleRec); begin if IsLocked then Exit; if Owner.ViewInfoValid then Owner.ActiveSheet.ViewInfo.UpdateViewInfo; end; procedure TcxSSListener.OnChangeLockColRow(Sender: TcxSSBookSheet; AKind: TcxSSHeadertype; AIndex: Integer; AOldValue, ANewValue: Boolean); begin if IsLocked then Exit; end; procedure TcxSSListener.OnChangeSelection(Sender: TcxSSBookSheet; const AOldValue, ANewValue: TRect); begin if IsLocked then Exit; if Sender.ViewInfoValid then Sender.ViewInfo.UpdateOnChangeSelection; if Assigned(Owner.OnSetSelection) then Owner.OnSetSelection(Owner, Sender); end; procedure TcxSSListener.OnChangeSheetCaption(Sender: TcxSSBookSheet; var ACaption: string); begin Owner.SetModified; if IsLocked then Exit; if Assigned(Owner.OnChangeSheetCaption) then Owner.OnChangeSheetCaption(Sender, ACaption); end; procedure TcxSSListener.OnChangeSizeColRow(Sender: TcxSSBookSheet; AKind: TcxSSHeaderType; AIndex: Integer; var ANewSize: TcxSSSize); begin with Owner do begin if (AKind = htCol) and Assigned(OnResizeCol) then OnResizeCol(Sender, AIndex, ANewSize) else if (AKind = htRow) and Assigned(OnResizeRow) then OnResizeRow(Sender, AIndex, ANewSize); end; end; procedure TcxSSListener.OnChangeVisibleColRow(Sender: TcxSSBookSheet; AKind: TcxSSHeaderType; AIndex: Integer; AOldValue, ANewValue: Boolean); var I: Integer; begin with Sender, SelectionRect do begin if (AKind = htRow) and ((AIndex >= Top) or (AIndex <= Bottom)) and not ANewValue then begin I := AIndex + 1; while not Sender.Rows.Visible[I] do Inc(I); SelectionRect := Rect(Left, I, Right, I); end; end; if AKind = htCol then begin if Assigned(Owner.OnChangeColVisible) then Owner.OnChangeColVisible(Owner, Sender, AIndex, AOldValue, ANewValue) end else begin if Assigned(Owner.OnChangeRowVisible) then Owner.OnChangeRowVisible(Owner, Sender, AIndex, AOldValue, ANewValue); end; if IsLocked then Exit; if Sender.ViewInfoValid then Sender.ViewInfo.UpdateViewInfo; end; procedure TcxSSListener.OnClearCells(Sender: TcxSSBookSheet; const ACellRec: TRect; var AUseDefaultStyle, CanClear: Boolean); begin if Assigned(Owner.OnClearCells) then Owner.OnClearCells(Sender, ACellRec, AUseDefaultStyle, CanClear); end; procedure TcxSSListener.OnEditing(Sender: TcxSSBookSheet; const ACol, ARow: Integer; var CanEdit: Boolean); begin if IsLocked then Exit; if Assigned(FOwner.OnEditing) then FOwner.OnEditing(Sender, ACol, ARow, CanEdit); end; procedure TcxSSListener.OnDeleteCells(Sender: TcxSSBookSheet; ACellRect: TRect; AModifyType: TcxSSModifyType); begin if IsLocked then Exit; end; procedure TcxSSListener.OnHistoryChanged(Sender: TObject); begin if IsLocked then Exit; if Assigned(Owner.OnHistoryChanged) then Owner.OnHistoryChanged(Owner); end; procedure TcxSSListener.OnInsertCells(Sender: TcxSSBookSheet; ACellRect: TRect; AModifyType: TcxSSModifyType); begin if IsLocked then Exit; end; procedure TcxSSListener.OnMergeCells(Sender: TcxSSBookSheet; ACellRect: TRect; AIsMerge: Boolean; var CanMerge: Boolean); begin if IsLocked then Exit; if Assigned(Owner.OnMergeCells) then Owner.OnMergeCells(Sender, ACellRect, AIsMerge, CanMerge); end; procedure TcxSSListener.OnSheetPopupMenu(Sender: TcxSSBookSheet; const AHitPoint: TPoint); begin try if Assigned(Owner.OnContextPopup) then Owner.OnContextPopup(Owner, AHitPoint, Owner.FContextPopupHandled); if Owner.FContextPopupHandled or Assigned(Owner.PopupMenu) then Exit; if Assigned(Owner.OnSheetPopupMenu) then Owner.OnSheetPopupMenu(Sender, AHitPoint.X, AHitPoint.Y); finally Owner.FContextPopupHandled := False; end; end; procedure TcxSSListener.OnCaptionPopupMenu(Sender: TcxSSBookSheet; const AHitPoint: TPoint); begin try if Assigned(Owner.OnContextPopup) then Owner.OnContextPopup(Owner, AHitPoint, Owner.FContextPopupHandled); if Owner.FContextPopupHandled or Assigned(Owner.PopupMenu) then Exit; if Assigned(Owner.OnCaptionPopupMenu) then Owner.OnCaptionPopupMenu(Sender, AHitPoint.X, AHitPoint.Y); finally Owner.FContextPopupHandled := False; end; end; procedure TcxSSListener.OnTopLeftChanging(Sender: TcxSSBookSheet; var ATopLeft: TPoint); begin if Assigned(Owner.OnTopLeftChanging) then Owner.OnTopLeftChanging(Sender, ATopLeft); end; procedure TcxSSListener.OnProgress(Sender: TObject; APercent: Byte); begin if Assigned(Owner.OnProgress) then Owner.OnProgress(Owner, APercent); end; procedure TcxSSListener.OnResizeDataLength(Sender: TcxSSBookSheet; AType: TcxSSHeaderType); begin if IsLocked then Exit; end; procedure TcxSSListener.UpdateAfterChanged(Sender: TcxSSBookSheet; ACellRect: TRect); begin if IsLocked then Exit; Owner.DoRecalc; if Sender.ViewInfoValid then Sender.ViewInfo.UpdateCellsInfo(ACellRect); end; initialization CF_ESSDATA := RegisterClipboardFormat(SCF_ESSCLIPBOARDFORMAT); if IsWinNT then CurrencyString := GetLocaleStrW(GetThreadLocale, LOCALE_SCURRENCY); cxSSClipboard := TcxSSClipboard.Create; if Screen.Cursors[crSSSelect] = Screen.Cursors[crDefault] then Screen.Cursors[crSSSelect] := LoadCursor(HInstance, 'CR_SELECT'); if IsWinNT then CurrencyString := GetLocaleStrW(GetThreadLocale, LOCALE_SCURRENCY); cxHScrollHeight := GetSystemMetrics(SM_CYHSCROLL); cxVScrollWidth := GetSystemMetrics(SM_CXVSCROLL); finalization cxSSClipboard.Free; end.