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
This commit is contained in:
wp_xxyyzz
2015-01-06 17:42:54 +00:00
parent b450c32ad3
commit 157a1133fb
9 changed files with 140 additions and 87 deletions

View File

@ -28,13 +28,10 @@
<FormatVersion Value="1"/>
</local>
</RunParams>
<RequiredPackages Count="2">
<RequiredPackages Count="1">
<Item1>
<PackageName Value="TAChartLazarusPkg"/>
</Item1>
<Item2>
<PackageName Value="LCL"/>
</Item2>
</Item1>
</RequiredPackages>
<Units Count="2">
<Unit0>

View File

@ -7,7 +7,7 @@ uses
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, tachartlazaruspkg, main;
Forms, main;
{$R *.res}

View File

@ -51,13 +51,10 @@
<FormatVersion Value="1"/>
</local>
</RunParams>
<RequiredPackages Count="2">
<RequiredPackages Count="1">
<Item1>
<PackageName Value="TAChartLazarusPkg"/>
</Item1>
<Item2>
<PackageName Value="LCL"/>
</Item2>
</Item1>
</RequiredPackages>
<Units Count="2">
<Unit0>

View File

@ -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}

View File

@ -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

View File

@ -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,39 +922,20 @@ 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

View File

@ -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;

View File

@ -28,6 +28,7 @@ It provides graphical components like a grid and chart."/>
</Item1>
<Item2>
<Filename Value="fpspreadsheetgrid.pas"/>
<HasRegisterProc Value="True"/>
<UnitName Value="fpspreadsheetgrid"/>
</Item2>
<Item3>

View File

@ -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;