From 157a1133fb1130ab622bde2dfcffd6a811f52017 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Tue, 6 Jan 2015 17:42:54 +0000 Subject: [PATCH] fpspreadsheet: Use interfaces in the notification mechanism of the visual controls - this avoids requiring the TAChart package even in case of non-chart-aware spreadsheet programs. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3872 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../fpsctrls_no_install/demo_ctrls.lpi | 7 +- .../fpsctrls_no_install/demo_ctrls.lpr | 2 +- .../examples/fpsgrid_no_install/fpsgrid.lpi | 7 +- .../examples/fpsgrid_no_install/fpsgrid.lpr | 2 +- .../fpspreadsheet/fpspreadsheetchart.pas | 18 ++- .../fpspreadsheet/fpspreadsheetctrls.pas | 150 ++++++++++-------- .../fpspreadsheet/fpspreadsheetgrid.pas | 39 +++-- .../laz_fpspreadsheet_visual.lpk | 1 + .../laz_fpspreadsheet_visual.pas | 1 + 9 files changed, 140 insertions(+), 87 deletions(-) diff --git a/components/fpspreadsheet/examples/fpsctrls_no_install/demo_ctrls.lpi b/components/fpspreadsheet/examples/fpsctrls_no_install/demo_ctrls.lpi index d1b1dc218..dda4a8d9a 100644 --- a/components/fpspreadsheet/examples/fpsctrls_no_install/demo_ctrls.lpi +++ b/components/fpspreadsheet/examples/fpsctrls_no_install/demo_ctrls.lpi @@ -28,13 +28,10 @@ - + - - - - + diff --git a/components/fpspreadsheet/examples/fpsctrls_no_install/demo_ctrls.lpr b/components/fpspreadsheet/examples/fpsctrls_no_install/demo_ctrls.lpr index 91629d122..1d3ae70d5 100644 --- a/components/fpspreadsheet/examples/fpsctrls_no_install/demo_ctrls.lpr +++ b/components/fpspreadsheet/examples/fpsctrls_no_install/demo_ctrls.lpr @@ -7,7 +7,7 @@ uses cthreads, {$ENDIF}{$ENDIF} Interfaces, // this includes the LCL widgetset - Forms, tachartlazaruspkg, main; + Forms, main; {$R *.res} diff --git a/components/fpspreadsheet/examples/fpsgrid_no_install/fpsgrid.lpi b/components/fpspreadsheet/examples/fpsgrid_no_install/fpsgrid.lpi index b81e9bb7e..3b346347c 100644 --- a/components/fpspreadsheet/examples/fpsgrid_no_install/fpsgrid.lpi +++ b/components/fpspreadsheet/examples/fpsgrid_no_install/fpsgrid.lpi @@ -51,13 +51,10 @@ - + - - - - + diff --git a/components/fpspreadsheet/examples/fpsgrid_no_install/fpsgrid.lpr b/components/fpspreadsheet/examples/fpsgrid_no_install/fpsgrid.lpr index 481d4c295..75994f791 100644 --- a/components/fpspreadsheet/examples/fpsgrid_no_install/fpsgrid.lpr +++ b/components/fpspreadsheet/examples/fpsgrid_no_install/fpsgrid.lpr @@ -7,7 +7,7 @@ uses cthreads, {$ENDIF}{$ENDIF} Interfaces, // this includes the LCL widgetset - Forms, tachartlazaruspkg, mainfrm + Forms, mainfrm { you can add units after this }; {$R *.res} diff --git a/components/fpspreadsheet/fpspreadsheetchart.pas b/components/fpspreadsheet/fpspreadsheetchart.pas index bd811d050..a47b15841 100644 --- a/components/fpspreadsheet/fpspreadsheetchart.pas +++ b/components/fpspreadsheet/fpspreadsheetchart.pas @@ -82,7 +82,7 @@ type TsXYRange = (rngX, rngY); - TsWorkbookChartSource = class(TCustomChartSource) + TsWorkbookChartSource = class(TCustomChartSource, IsSpreadsheetControl) private FWorkbookSource: TsWorkbookSource; FWorkbook: TsWorkbook; @@ -108,10 +108,13 @@ type procedure SetYCount(AValue: Cardinal); override; public destructor Destroy; override; - procedure ListenerNotification(AChangedItems: TsNotificationItems; AData: Pointer = nil); procedure Reset; property PointsNumber: Cardinal read FPointsNumber; property Workbook: TsWorkbook read GetWorkbook; + public + // Interface to TsWorkbookSource + procedure ListenerNotification(AChangedItems: TsNotificationItems; AData: Pointer = nil); + procedure RemoveWorkbookSource; published property WorkbookSource: TsWorkbookSource read FWorkbookSource write SetWorkbookSource; property XRange: String index rngX read GetRange write SetRange; @@ -119,9 +122,9 @@ type end; - procedure Register; + implementation uses @@ -586,6 +589,15 @@ begin end; end; +{@@ ---------------------------------------------------------------------------- + Removes the link of the ChartSource to the WorkbookSource. + Required before destruction. +-------------------------------------------------------------------------------} +procedure TsWorkbookChartSource.RemoveWorkbookSource; +begin + SetWorkbookSource(nil); +end; + {@@ ---------------------------------------------------------------------------- Resets internal buffers and notfies chart elements of the changes, in particular, enforces recalculation of axis limits diff --git a/components/fpspreadsheet/fpspreadsheetctrls.pas b/components/fpspreadsheet/fpspreadsheetctrls.pas index 29bf1e4cf..4755105a7 100644 --- a/components/fpspreadsheet/fpspreadsheetctrls.pas +++ b/components/fpspreadsheet/fpspreadsheetctrls.pas @@ -159,12 +159,23 @@ type end; +const + GUID_SpreadsheetControl = '{CBCAAE52-D29E-4D0C-A7F4-1016C873448A}'; + +type + { IsSpreadsheetControl } + IsSpreadsheetControl = interface [GUID_SpreadsheetControl] + procedure ListenerNotification(AChangedItems: TsNotificationItems; + AData: Pointer = nil); + procedure RemoveWorkbookSource; + end; + { TsWorkbookTabControl } {@@ TsWorkbookTabControl is a tab control which displays the sheets of the workbook currently loaded by the WorkbookSource in tabs. Selecting another tab is communicated to other spreadsheet controls via the WorkbookSource. } - TsWorkbookTabControl = class(TTabControl) + TsWorkbookTabControl = class(TTabControl, IsSpreadsheetControl) private FWorkbookSource: TsWorkbookSource; FLockCount: Integer; @@ -179,6 +190,7 @@ type destructor Destroy; override; procedure ListenerNotification(AChangedItems: TsNotificationItems; AData: Pointer = nil); + procedure RemoveWorkbookSource; {@@ The worksheet names of this workbook are currently displayed as tabs of the TabControl. } property Workbook: TsWorkbook read GetWorkbook; {@@ Identifies the worksheet which corresponds to the selected tab } @@ -193,7 +205,7 @@ type {@@ TsCellEdit allows to edit the content or formula of the active cell of a worksheet, simular to Excel's cell editor above the cell grid. } - TsCellEdit = class(TMemo) + TsCellEdit = class(TMemo, IsSpreadsheetControl) private FWorkbookSource: TsWorkbookSource; function GetSelectedCell: PCell; @@ -209,6 +221,7 @@ type procedure EditingDone; override; procedure ListenerNotification(AChangedItems: TsNotificationItems; AData: Pointer = nil); + procedure RemoveWorkbookSource; {@@ Pointer to the currently active cell in the workbook. This cell is displayed in the control and can be edited. } property SelectedCell: PCell read GetSelectedCell; @@ -227,7 +240,7 @@ type {@@ TsCellIndicator displays the address of the currently active cell of the worksheet and workbook. Editing the address allows to jump to the corresponding cell. } - TsCellIndicator = class(TEdit) + TsCellIndicator = class(TEdit, IsSpreadsheetControl) private FWorkbookSource: TsWorkbookSource; function GetWorkbook: TsWorkbook; @@ -241,6 +254,7 @@ type procedure EditingDone; override; procedure ListenerNotification(AChangedItems: TsNotificationItems; AData: Pointer = nil); + procedure RemoveWorkbookSource; {@@ Refers to the underlying worksheet to which the edited cell belongs. } property Workbook: TsWorkbook read GetWorkbook; {@@ Refers to the underlying worksheet to which the edited cell belongs. } @@ -262,7 +276,7 @@ type {@@ TsCellCombobox is a multi-purpose combobox for selection of formatting items of a cell } - TsCellCombobox = class(TCustomCombobox) + TsCellCombobox = class(TCustomCombobox, IsSpreadsheetControl) private FWorkbookSource: TsWorkbookSource; FFormatItem: TsCellFormatItem; @@ -290,6 +304,7 @@ type destructor Destroy; override; procedure ListenerNotification(AChangedItems: TsNotificationItems; AData: Pointer = nil); + procedure RemoveWorkbookSource; {@@ Refers to the underlying workbook } property Workbook: TsWorkbook read GetWorkbook; {@@ Refers to the underlying worksheet containing the displayed cell } @@ -383,7 +398,7 @@ type {@@ TsSpreadsheetInspector displays all properties of a workbook, worksheet, cell content and cell formatting in a way similar to the Object Inspector of Lazarus. } - TsSpreadsheetInspector = class(TValueListEditor) + TsSpreadsheetInspector = class(TValueListEditor, IsSpreadsheetControl) private FWorkbookSource: TsWorkbookSource; FMode: TsInspectorMode; @@ -403,6 +418,7 @@ type destructor Destroy; override; procedure ListenerNotification(AChangedItems: TsNotificationItems; AData: Pointer = nil); + procedure RemoveWorkbookSource; {@@ Refers to the underlying workbook which is displayed by the inspector. } property Workbook: TsWorkbook read GetWorkbook; {@@ Refers to the underlying worksheet which is displayed by the inspector. } @@ -427,7 +443,7 @@ implementation uses Types, Math, TypInfo, LCLType, Dialogs, Forms, - fpsStrings, fpsUtils, fpSpreadsheetGrid, fpSpreadsheetChart; + fpsStrings, fpsUtils; //, fpSpreadsheetGrid, fpSpreadsheetChart; {@@ ---------------------------------------------------------------------------- @@ -437,7 +453,7 @@ uses procedure Register; begin RegisterComponents('FPSpreadsheet', [ - TsWorkbookSource, TsWorkbookTabControl, TsWorksheetGrid, + TsWorkbookSource, TsWorkbookTabControl, //TsWorksheetGrid, TsCellEdit, TsCellIndicator, TsCellCombobox, TsSpreadsheetInspector ]); @@ -884,36 +900,18 @@ end; procedure TsWorkbookSource.NotifyListeners(AChangedItems: TsNotificationItems; AData: Pointer = nil); var - i: Integer; + j: Integer; + I: IsSpreadsheetControl; + C: TComponent; begin - for i:=0 to FListeners.Count-1 do - if TObject(FListeners[i]) is TsCellCombobox then - TsCellCombobox(FListeners[i]).ListenerNotification(AChangedItems, AData) + for j:=0 to FListeners.Count-1 do begin + C := TComponent(FListeners[j]); + if C.GetInterface(GUID_SpreadsheetControl, I) then + I.ListenerNotification(AChangedItems, AData) else - if TObject(FListeners[i]) is TsCellIndicator then - TsCellIndicator(FListeners[i]).ListenerNotification(AChangedItems, AData) - else - if TObject(FListeners[i]) is TsCellEdit then - TsCellEdit(FListeners[i]).ListenerNotification(AChangedItems, AData) - else - if TObject(FListeners[i]) is TsWorkbookTabControl then - TsWorkbookTabControl(FListeners[i]).ListenerNotification(AChangedItems, AData) - else - if TObject(FListeners[i]) is TsWorksheetGrid then - TsWorksheetGrid(FListeners[i]).ListenerNotification(AChangedItems, AData) - else - if TObject(FListeners[i]) is TsSpreadsheetInspector then - TsSpreadsheetInspector(FListeners[i]).ListenerNotification(AChangedItems, AData) - else - if TObject(FListeners[i]) is TsWorkbookChartSource then - TsWorkbookChartSource(FListeners[i]).ListenerNotification(AChangedItems, AData) - else - { - if TObject(FListeners[i]) is TsSpreadsheetAction then - TsSpreadsheetAction(FListeners[i]).ListenerNotifiation(AChangedItems, AData) - else } raise Exception.CreateFmt('Class %s is not prepared to be a spreadsheet listener.', - [TObject(FListeners[i]).ClassName]); + [C.ClassName]); + end; end; {@@ ---------------------------------------------------------------------------- @@ -924,40 +922,21 @@ end; -------------------------------------------------------------------------------} procedure TsWorkbookSource.RemoveListener(AListener: TComponent); var - i: Integer; + j: Integer; + I: IsSpreadsheetControl; + C: TComponent; begin - for i:= FListeners.Count-1 downto 0 do - if TComponent(FListeners[i]) = AListener then + for j:=FListeners.Count-1 downto 0 do begin + C := TComponent(FListeners[j]); + if C = AListener then begin - FListeners.Delete(i); - if (AListener is TsCellCombobox) then - TsCellCombobox(AListener).WorkbookSource := nil + FListeners.Delete(j); + if C.GetInterface(GUID_SpreadsheetControl, I) then + I.RemoveWorkbookSource else - if (AListener is TsCellIndicator) then - TsCellIndicator(AListener).WorkbookSource := nil - else - if (AListener is TsCellEdit) then - TsCellEdit(AListener).WorkbookSource := nil - else - if (AListener is TsWorkbookTabControl) then - TsWorkbookTabControl(AListener).WorkbookSource := nil - else - if (AListener is TsWorksheetGrid) then - TsWorksheetGrid(AListener).WorkbookSource := nil - else - if (AListener is TsSpreadsheetInspector) then - TsSpreadsheetInspector(AListener).WorkbookSource := nil - else - if (AListener is TsWorkbookChartSource) then - TsWorkbookChartSource(AListener).WorkbookSource := nil - else - { - if (AListener is TsSpreadsheetAction) then - TsSpreadsheetAction(AListener).WorksheetLink := nil - else } raise Exception.CreateFmt('Class %s not prepared for listening.',[AListener.ClassName]); - exit; end; + end; end; {@@ ---------------------------------------------------------------------------- @@ -1455,6 +1434,15 @@ begin SetWorkbookSource(nil); end; +{@@ ---------------------------------------------------------------------------- + Removes the link of the TabControl to the WorkbookSource. Required before + destruction. +-------------------------------------------------------------------------------} +procedure TsWorkbookTabControl.RemoveWorkbookSource; +begin + SetWorkbookSource(nil); +end; + {@@ ---------------------------------------------------------------------------- Setter method for the WorkbookSource -------------------------------------------------------------------------------} @@ -1593,6 +1581,15 @@ begin SetWorkbookSource(nil); end; +{@@ ---------------------------------------------------------------------------- + Removes the link of the CellEdit to the WorkbookSource. Required before + destruction. +-------------------------------------------------------------------------------} +procedure TsCellEdit.RemoveWorkbookSource; +begin + SetWorkbookSource(nil); +end; + {@@ ---------------------------------------------------------------------------- Setter method for the WorkbookSource -------------------------------------------------------------------------------} @@ -1751,6 +1748,15 @@ begin SetWorkbooksource(nil); end; +{@@ ---------------------------------------------------------------------------- + Removes the link of the CellIndicator to the WorkbookSource. Required before + destruction. +-------------------------------------------------------------------------------} +procedure TsCellIndicator.RemoveWorkbookSource; +begin + SetWorkbookSource(nil); +end; + {@@ ---------------------------------------------------------------------------- Setter method for the WorkbookSource -------------------------------------------------------------------------------} @@ -2120,6 +2126,15 @@ begin end; end; +{@@ ---------------------------------------------------------------------------- + Removes the link of the CellCombobox to the WorkbookSource. Required before + destruction. +-------------------------------------------------------------------------------} +procedure TsCellCombobox.RemoveWorkbookSource; +begin + SetWorkbookSource(nil); +end; + {@@ ---------------------------------------------------------------------------- A new item in the combobox is selected. Calls "ProcessValue" to changes the selected cells according to the Mode property by calling ApplyFormatToCell. @@ -2477,6 +2492,15 @@ begin SetWorkbookSource(nil); end; +{@@ ---------------------------------------------------------------------------- + Removes the link of the SpreadsheetInspector to the WorkbookSource. + Required before destruction. +-------------------------------------------------------------------------------} +procedure TsSpreadsheetInspector.RemoveWorkbookSource; +begin + SetWorkbookSource(nil); +end; + {@@ ---------------------------------------------------------------------------- Setter method for the Mode property. This property filters groups of properties for display (workbook-, worksheet-, cell value- or cell formatting-related diff --git a/components/fpspreadsheet/fpspreadsheetgrid.pas b/components/fpspreadsheet/fpspreadsheetgrid.pas index 216726eca..9d5809e31 100644 --- a/components/fpspreadsheet/fpspreadsheetgrid.pas +++ b/components/fpspreadsheet/fpspreadsheetgrid.pas @@ -1,7 +1,7 @@ { fpspreadsheetgrid } {@@ ---------------------------------------------------------------------------- - Grid component which can load and write data from / to FPSpreadsheet documents. + Grid component which can load and write data from/to FPSpreadsheet documents. Can either be used alone or in combination with a TsWorkbookSource component. The latter case requires less written code. @@ -34,7 +34,7 @@ type {@@ TsCustomWorksheetGrid is the ancestor of TsWorksheetGrid and is able to display spreadsheet data along with their formatting. } - TsCustomWorksheetGrid = class(TCustomDrawGrid) + TsCustomWorksheetGrid = class(TCustomDrawGrid, IsSpreadsheetControl) private { Private declarations } FWorkbookSource: TsWorkbookSource; @@ -225,9 +225,10 @@ type procedure Convert_Font_to_sFont(AFont: TFont; sFont: TsFont); function FindNearestPaletteIndex(AColor: TColor): TsColor; - { Interfacing with WorkbookLink } + { Interfacing with WorkbookSource} procedure ListenerNotification(AChangedItems: TsNotificationItems; AData: Pointer = nil); + procedure RemoveWorkbookSource; { public properties } {@@ Link to the workbook } @@ -555,6 +556,7 @@ type property OnContextPopup; end; +procedure Register; implementation @@ -3189,14 +3191,12 @@ begin end; {@@ ---------------------------------------------------------------------------- - Splits a merged cell block into single cells + Removes the link of the WorksheetGrid to the WorkbookSource. + Required before destruction. -------------------------------------------------------------------------------} -procedure TsCustomWorksheetGrid.UnmergeCells; +procedure TsCustomWorksheetGrid.RemoveWorkbookSource; begin - Worksheet.UnmergeCells( - GetWorksheetRow(Selection.Top), - GetWorksheetCol(Selection.Left) - ); + SetWorkbookSource(nil); end; {@@ ---------------------------------------------------------------------------- @@ -3462,6 +3462,17 @@ begin Delete(Result, Length(Result), 1); end; +{@@ ---------------------------------------------------------------------------- + Splits a merged cell block into single cells +-------------------------------------------------------------------------------} +procedure TsCustomWorksheetGrid.UnmergeCells; +begin + Worksheet.UnmergeCells( + GetWorksheetRow(Selection.Top), + GetWorksheetCol(Selection.Left) + ); +end; + {@@ ---------------------------------------------------------------------------- Updates column widths according to the data in the TCol records -------------------------------------------------------------------------------} @@ -4186,6 +4197,16 @@ begin end; +{@@ ---------------------------------------------------------------------------- + Registers the worksheet grid in the Lazarus component palette, + page "FPSpreadsheet". +-------------------------------------------------------------------------------} +procedure Register; +begin + RegisterComponents('FPSpreadsheet', [TsWorksheetGrid]); +end; + + initialization fpsutils.ScreenPixelsPerInch := Screen.PixelsPerInch; diff --git a/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk b/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk index 837ccd953..fae3683e8 100644 --- a/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk +++ b/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk @@ -28,6 +28,7 @@ It provides graphical components like a grid and chart."/> + diff --git a/components/fpspreadsheet/laz_fpspreadsheet_visual.pas b/components/fpspreadsheet/laz_fpspreadsheet_visual.pas index c2e9186ca..91d790a75 100644 --- a/components/fpspreadsheet/laz_fpspreadsheet_visual.pas +++ b/components/fpspreadsheet/laz_fpspreadsheet_visual.pas @@ -15,6 +15,7 @@ implementation procedure Register; begin RegisterUnit('fpspreadsheetctrls', @fpspreadsheetctrls.Register); + RegisterUnit('fpspreadsheetgrid', @fpspreadsheetgrid.Register); RegisterUnit('fpspreadsheetchart', @fpspreadsheetchart.Register); RegisterUnit('fpsActions', @fpsActions.Register); end;