lazarus-ccr/components/fpspreadsheet/source/visual/fpsactions.pas
wp_xxyyzz 74d1082ccb fpspreadsheet: Less hints and warnings
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7638 8e941d3f-bd1b-0410-a28a-d453659cc2b4
2020-08-28 11:26:13 +00:00

2319 lines
63 KiB
ObjectPascal

{ fpActions }
{@@ ----------------------------------------------------------------------------
A collection of standard actions to simplify creation of menu and toolbar
for spreadsheet applications.
AUTHORS: Werner Pamler
LICENSE: See the file COPYING.modifiedLGPL.txt, included in the Lazarus
distribution, for details about the license.
-------------------------------------------------------------------------------}
unit fpsActions;
{$mode objfpc}{$H+}
interface
uses
SysUtils, Classes, Controls, Graphics, ActnList, StdActns, Dialogs,
fpstypes, fpspreadsheet, fpspreadsheetctrls;
type
TsSpreadsheetAction = class(TCustomAction)
private
FWorkbookSource: TsWorkbookSource;
function GetActiveCell: PCell;
function GetSelection: TsCellRangeArray;
function GetWorkbook: TsWorkbook;
function GetWorksheet: TsWorksheet;
protected
procedure ApplyFormatToCell(ACell: PCell); virtual;
procedure ApplyFormatToRange(ARange: TsCellrange); virtual;
procedure ApplyFormatToSelection; virtual;
procedure ExtractFromCell(ACell: PCell); virtual;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
property ActiveCell: PCell read GetActiveCell;
property Selection: TsCellRangeArray read GetSelection;
property Worksheet: TsWorksheet read GetWorksheet;
public
function HandlesTarget(Target: TObject): Boolean; override;
procedure UpdateTarget(Target: TObject); override;
property Workbook: TsWorkbook read GetWorkbook;
published
property WorkbookSource: TsWorkbookSource read FWorkbookSource write FWorkbookSource;
end;
{ --- Actions related to worksheets --- }
TsWorksheetAction = class(TsSpreadsheetAction)
private
public
function HandlesTarget(Target: TObject): Boolean; override;
procedure UpdateTarget(Target: TObject); override;
property Worksheet;
published
property Caption;
property Enabled;
property HelpContext;
property HelpKeyword;
property HelpType;
property Hint;
property ImageIndex;
property OnExecute;
property OnHint;
property OnUpdate;
property SecondaryShortCuts;
property ShortCut;
property Visible;
end;
TsWorksheetNameEvent = procedure (Sender: TObject; AWorksheet: TsWorksheet;
var ASheetName: String) of object;
{ Action for adding a worksheet }
TsWorksheetAddAction = class(TsWorksheetAction)
private
FNameMask: String;
FOnGetWorksheetName: TsWorksheetNameEvent;
procedure SetNameMask(const AValue: String);
protected
function GetUniqueSheetName: String;
public
constructor Create(AOwner: TComponent); override;
procedure ExecuteTarget(Target: TObject); override;
published
property NameMask: String read FNameMask write SetNameMask;
property OnGetWorksheetName: TsWorksheetNameEvent
read FOnGetWorksheetName write FOnGetWorksheetName;
end;
{ Action for deleting selected worksheet }
TsWorksheetDeleteAction = class(TsWorksheetAction)
public
constructor Create(AOwner: TComponent); override;
procedure ExecuteTarget(Target: TObject); override;
end;
{ Action for renaming selected worksheet }
TsWorksheetRenameAction = class(TsWorksheetAction)
private
FOnGetWorksheetName: TsWorksheetNameEvent;
public
constructor Create(AOwner: TComponent); override;
procedure ExecuteTarget(Target: TObject); override;
published
property OnGetWorksheetName: TsWorksheetNameEvent
read FOnGetWorksheetName write FOnGetWorksheetName;
end;
{ Action foz zooming the selected worksheet }
TsWorksheetZoomAction = class(TsWorksheetAction)
private
FZoom: Integer;
procedure SetZoom(AValue: Integer);
public
constructor Create(AOwner: TComponent); override;
procedure ExecuteTarget(Target: TObject); override;
procedure UpdateTarget({%H-}Target: TObject); override;
published
property Zoom: Integer read FZoom write SetZoom default 100;
end;
{ --- Actions related to cell and cell selection formatting--- }
TsCopyItem = (ciFormat, ciValue, ciFormula, ciAll);
TsCopyMode = (cmBrush, cmCopy, cmCut, cmPaste);
TsCopyAction = class(TsSpreadsheetAction)
private
FCopyItem: TsCopyItem;
FCopyMode: TsCopyMode;
public
procedure ExecuteTarget(Target: TObject); override;
function HandlesTarget(Target: TObject): Boolean; override;
procedure UpdateTarget(Target: TObject); override;
published
property Caption;
property CopyItem: TsCopyItem read FCopyItem write FCopyItem default ciFormat;
property CopyMode: TsCopyMode read FCopyMode write FCopyMode default cmBrush;
property Enabled;
property HelpContext;
property HelpKeyword;
property HelpType;
property Hint;
property ImageIndex;
property OnExecute;
property OnHint;
property OnUpdate;
property SecondaryShortCuts;
property ShortCut;
property Visible;
end;
TsCellAction = class(TsSpreadsheetAction)
public
function HandlesTarget(Target: TObject): Boolean; override;
property ActiveCell;
property Selection;
property Worksheet;
end;
TsAutoFormatAction = class(TsCellAction)
protected
procedure UpdateTargetFromActiveCell;
public
procedure ExecuteTarget(Target: TObject); override;
procedure UpdateTarget(Target: TObject); override;
published
property Caption;
property Enabled;
property HelpContext;
property HelpKeyword;
property HelpType;
property Hint;
property ImageIndex;
property OnExecute;
property OnHint;
property OnUpdate;
property SecondaryShortCuts;
property ShortCut;
property Visible;
end;
{ TsClearFormatAction }
TsClearFormatAction = class(TsAutoFormatAction)
protected
procedure ApplyFormatToCell(ACell: PCell); override;
public
constructor Create(AOwner: TComponent); override;
end;
{ TsFontStyleAction }
TsFontStyleAction = class(TsAutoFormatAction)
private
FFontStyle: TsFontStyle;
procedure SetFontStyle(AValue: TsFontStyle);
protected
procedure ApplyFormatToCell(ACell: PCell); override;
procedure ExtractFromCell(ACell: PCell); override;
public
constructor Create(AOwner: TComponent); override;
published
property FontStyle: TsFontStyle read FFontStyle write SetFontStyle;
end;
{ TsHorAlignmentAction }
TsHorAlignmentAction = class(TsAutoFormatAction)
private
FHorAlign: TsHorAlignment;
procedure SetHorAlign(AValue: TsHorAlignment);
protected
procedure ApplyFormatToCell(ACell: PCell); override;
procedure ExtractFromCell(ACell: PCell); override;
public
constructor Create(AOwner: TComponent); override;
published
property HorAlignment: TsHorAlignment
read FHorAlign write SetHorAlign default haDefault;
end;
{ TsVertAlignmentAction }
TsVertAlignmentAction = class(TsAutoFormatAction)
private
FVertAlign: TsVertAlignment;
procedure SetVertAlign(AValue:TsVertAlignment);
protected
procedure ApplyFormatToCell(ACell: PCell); override;
procedure ExtractFromCell(ACell: PCell); override;
public
constructor Create(AOwner: TComponent); override;
published
property VertAlignment: TsVertAlignment
read FVertAlign write SetVertAlign default vaDefault;
end;
{ TsTextRotationAction }
TsTextRotationAction = class(TsAutoFormatAction)
private
FTextRotation: TsTextRotation;
procedure SetTextRotation(AValue: TsTextRotation);
protected
procedure ApplyFormatToCell(ACell: PCell); override;
procedure ExtractFromCell(ACell: PCell); override;
public
constructor Create(AOwner: TComponent); override;
published
property TextRotation: TsTextRotation
read FTextRotation write SetTextRotation default trHorizontal;
end;
{ TsWordwrapAction }
TsWordwrapAction = class(TsAutoFormatAction)
private
function GetWordwrap: Boolean;
procedure SetWordwrap(AValue: Boolean);
protected
procedure ApplyFormatToCell(ACell: PCell); override;
procedure ExtractFromCell(ACell: PCell); override;
public
constructor Create(AOwner: TComponent); override;
published
property Wordwrap: boolean
read GetWordwrap write SetWordwrap default false;
end;
{ TsNumberFormatAction }
TsNumFormatStrEvent = procedure (Sender: TObject; AWorkbook: TsWorkbook;
var ANumFormatStr: String) of object;
TsNumberFormatAction = class(TsAutoFormatAction)
private
FNumberFormat: TsNumberFormat;
FNumberFormatStr: string;
FCustomNumberFormatStr: String;
FOnGetNumFormatStr: TsNumFormatStrEvent;
procedure SetNumberFormat(AValue: TsNumberFormat);
procedure SetNumberFormatStr(AValue: String);
protected
procedure ApplyFormatToCell(ACell: PCell); override;
procedure ExtractFromCell(ACell: PCell); override;
procedure UpdateCaptionAndHint;
public
constructor Create(AOwner: TComponent); override;
procedure ExecuteTarget(Target: TObject); override;
published
property NumberFormat: TsNumberFormat
read FNumberFormat write SetNumberFormat default nfGeneral;
property NumberFormatString: string
read FNumberFormatStr write SetNumberFormatStr;
property OnGetNumberFormatString: TsNumFormatStrEvent
read FOnGetNumFormatStr write FOnGetNumFormatStr;
end;
{ TsDecimalsAction }
TsDecimalsAction = class(TsAutoFormatAction)
private
FDecimals: Integer;
FDelta: Integer;
procedure SetDelta(AValue: Integer);
protected
procedure ApplyFormatToCell(ACell: PCell); override;
procedure ExtractFromCell(ACell: PCell); override;
public
constructor Create(AOwner: TComponent); override;
published
property Delta: Integer
read FDelta write SetDelta default +1;
property Hint stored false;
end;
{ TsCellProtectionAction }
TsCellProtectionAction = class(TsAutoFormatAction)
private
FProtection: TsCellProtection;
protected
procedure ApplyFormatToCell(ACell: PCell); override;
procedure ExtractFromCell(ACell: PCell); override;
public
constructor Create(AOwner: TComponent); override;
procedure UpdateTarget(Target: TObject); override;
published
property AutoCheck default true;
property Protection: TsCellProtection read FProtection write FProtection default cpLockCell;
end;
{ TsCellBorderAction }
TsActionBorders = class;
TsActionBorder = class(TPersistent)
private
FOwner: TsActionBorders;
FLineStyle: TsLineStyle;
FColor: TColor;
FVisible: Boolean;
procedure SetLineStyle(AVAlue: TsLineStyle);
protected
procedure Changed;
public
constructor Create(AOwner: TsActionBorders);
function GetStyle: TsCellBorderStyle;
procedure SetStyle(const AValue: TsCellBorderStyle);
procedure SetVisible(const AValue: Boolean);
published
property LineStyle: TsLineStyle read FLineStyle write SetLineStyle;
property Color: TColor read FColor write FColor;
property Visible: Boolean read FVisible write SetVisible;
end;
TsActionBorders = class(TPersistent)
private
FAction: TsCellAction;
FBorders: Array[0..ord(High(TsCellBorder))+2] of TsActionBorder;
function GetBorder(AIndex: Integer): TsActionBorder;
procedure SetBorder(AIndex: integer; AValue: TsActionBorder);
protected
procedure Update;
public
constructor Create(Action: TsCellAction);
destructor Destroy; override;
procedure ExtractFromCell(AWorkbook: TsWorkbook; ACell: PCell);
published
property East: TsActionBorder index ord(cbEast)
read GetBorder write SetBorder;
property North: TsActionBorder index ord(cbNorth)
read GetBorder write SetBorder;
property South: TsActionBorder index ord(cbSouth)
read GetBorder write SetBorder;
property West: TsActionBorder index ord(cbWest)
read GetBorder write SetBorder;
property DiagonalUp: TsActionBorder index ord(cbDiagUp)
read GetBorder write SetBorder;
property DiagonalDown: TsActionBorder index ord(cbDiagDown)
read GetBorder write SetBorder;
property InnerHor: TsActionBorder index ord(High(TsCellBorder))+1
read GetBorder write SetBorder;
property InnerVert: TsActionBorder index ord(High(TsCellBorder))+2
read GetBorder write SetBorder;
end;
TsCellBorderAction = class(TsCellAction)
private
FBorders: TsActionBorders;
protected
procedure ApplyFormatToRange(ARange: TsCellRange); override;
procedure ExtractFromCell(ACell: PCell); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure ExecuteTarget(Target: TObject); override;
published
property Borders: TsActionBorders read FBorders write FBorders;
property Caption;
property Enabled;
property HelpContext;
property HelpKeyword;
property HelpType;
property Hint;
property ImageIndex;
property OnExecute;
property OnHint;
property OnUpdate;
property SecondaryShortCuts;
property ShortCut;
property Visible;
end;
TsNoCellBordersAction = class(TsCellAction)
protected
procedure ApplyFormatToCell(ACell: PCell); override;
public
constructor Create(AOwner: TComponent); override;
procedure ExecuteTarget(Target: TObject); override;
published
property Caption;
property Enabled;
property HelpContext;
property HelpKeyword;
property HelpType;
property Hint;
property ImageIndex;
property OnExecute;
property OnHint;
property OnUpdate;
property SecondaryShortCuts;
property ShortCut;
property Visible;
end;
{ Cell comment actions }
TsCellCommentMode = (ccmNew, ccmEdit, ccmDelete);
TsCellCommentAction = class(TsCellAction)
private
FMode: TsCellCommentMode;
procedure SetMode(AValue: TsCellCommentMode);
protected
function EditComment(ACaption: String; var AText: String): Boolean; virtual;
public
constructor Create(AOwner: TComponent); override;
procedure ExecuteTarget(Target: TObject); override;
procedure UpdateTarget(Target: TObject); override;
published
property Mode: TsCellCommentMode read FMode write SetMode default ccmNew;
property Caption;
property Enabled;
property HelpContext;
property HelpKeyword;
property HelpType;
property Hint;
property ImageIndex;
property OnExecute;
property OnHint;
property OnUpdate;
property SecondaryShortCuts;
property ShortCut;
property Visible;
end;
{ Cell hyperlink actions }
TsCellHyperlinkMode = (chmNew, chmEdit, chmDelete);
TsCellHyperlinkEvent = procedure (Sender: TObject; ACaption: String;
var AHyperlink: TsHyperlink) of object;
TsCellHyperlinkAction = class(TsCellAction)
private
FMode: TsCellHyperlinkMode;
FOnHyperlink: TsCellHyperlinkEvent;
procedure SetMode(AValue: TsCellHyperlinkMode);
protected
function EditHyperlink(ACaption: String; var AHyperlink: TsHyperlink): Boolean; virtual;
public
constructor Create(AOwner: TComponent); override;
procedure ExecuteTarget(Target: TObject); override;
procedure UpdateTarget(Target: TObject); override;
published
property Mode: TsCellHyperlinkMode read FMode write SetMode;
property OnHyperlink: TsCellHyperlinkEvent read FOnHyperlink write FOnHyperlink;
property Caption;
property Enabled;
property HelpContext;
property HelpKeyword;
property HelpType;
property Hint;
property ImageIndex;
property OnExecute;
property OnHint;
property OnUpdate;
property SecondaryShortCuts;
property ShortCut;
property Visible;
end;
{ TsMergeAction }
TsMergeAction = class(TsAutoFormatAction)
private
function GetMerged: Boolean;
procedure SetMerged(AValue: Boolean);
protected
procedure ApplyFormatToRange(ARange: TsCellRange); override;
procedure ExtractFromCell(ACell: PCell); override;
public
constructor Create(AOwner: TComponent); override;
published
property Merged: Boolean read GetMerged write SetMerged default false;
end;
{ --- Actions like those derived from TCommonDialogAction --- }
TsCommonDialogSpreadsheetAction = class(TsSpreadsheetAction)
private
FBeforeExecute: TNotifyEvent;
FExecuteResult: Boolean;
FOnAccept: TNotifyEvent;
FOnCancel: TNotifyEvent;
protected
FDialog: TCommonDialog;
procedure DoAccept; virtual;
procedure DoBeforeExecute; virtual;
procedure DoCancel; virtual;
function GetDialogClass: TCommonDialogClass; virtual;
procedure CreateDialog; virtual;
public
constructor Create(AOwner: TComponent); override;
procedure ExecuteTarget(Target: TObject); override;
property ExecuteResult: Boolean read FExecuteResult;
property BeforeExecute: TNotifyEvent read FBeforeExecute write FBeforeExecute;
property OnAccept: TNotifyEvent read FOnAccept write FOnAccept;
property OnCancel: TNotifyEvent read FOnCancel write FOnCancel;
end;
{ TsCommondDialogCellAction }
TsCommonDialogCellAction = class(TsCommondialogSpreadsheetAction)
protected
procedure DoAccept; override;
procedure DoBeforeExecute; override;
public
property ActiveCell;
property Selection;
property Workbook;
property Worksheet;
published
property Caption;
property Enabled;
property HelpContext;
property HelpKeyword;
property HelpType;
property Hint;
property ImageIndex;
property ShortCut;
property SecondaryShortCuts;
property Visible;
property BeforeExecute;
property OnAccept;
property OnCancel;
property OnHint;
end;
{ TsFontDialogAction }
TsFontDialogAction = class(TsCommonDialogCellAction)
private
function GetDialog: TFontDialog;
protected
procedure ApplyFormatToCell(ACell: PCell); override;
procedure ExtractFromCell(ACell: PCell); override;
function GetDialogClass: TCommonDialogClass; override;
public
constructor Create(AOwner: TComponent); override;
published
property Dialog: TFontDialog read GetDialog;
end;
{ TsBackgroundColorDialogAction }
TsBackgroundColorDialogAction = class(TsCommonDialogCellAction)
private
FBackgroundColor: TsColor;
function GetDialog: TColorDialog;
protected
procedure ApplyFormatToCell(ACell: PCell); override;
procedure DoAccept; override;
procedure DoBeforeExecute; override;
procedure ExtractFromCell(ACell: PCell); override;
function GetDialogClass: TCommonDialogClass; override;
public
constructor Create(AOwner: TComponent); override;
published
property Dialog: TColorDialog read GetDialog;
end;
implementation
uses
StdCtrls, ExtCtrls, Buttons, Forms,
fpsStrings, fpsUtils, fpsNumFormat, fpsVisualUtils, fpSpreadsheetGrid;
{ TsSpreadsheetAction }
{ Copies the format item for which the action is responsible to the
specified cell. Must be overridden by descendants. }
procedure TsSpreadsheetAction.ApplyFormatToCell(ACell: PCell);
begin
Unused(ACell);
end;
procedure TsSpreadsheetAction.ApplyFormatToRange(ARange: TsCellRange);
var
r, c, r1, c1, r2, c2: Cardinal;
cell, base: PCell;
begin
r := ARange.Row1;
while r <= ARange.Row2 do
begin
c := ARange.Col1;
while c <= ARange.Col2 do
begin
cell := Worksheet.GetCell(r, c); // use "GetCell" here to format empty cells as well
if Worksheet.IsMerged(cell) then begin
Worksheet.FindMergedRange(cell, r1, c1, r2, c2);
base := Worksheet.FindCell(r1, c1);
ApplyFormatToCell(base);
c := c2+1;
end else
begin
ApplyFormatToCell(cell);
inc(c);
end;
end;
inc(r);
end;
{
for r := ARange.Row1 to ARange.Row2 do
for c := ARange.Col1 to ARange.Col2 do
begin
cell := Worksheet.GetCell(r, c); // Use "GetCell" here to format empty cells as well
if Worksheet.IsMerged(cell) then
ApplyFormatToCell(cell); // no check for nil required because of "GetCell"
end;
}
end;
procedure TsSpreadsheetAction.ApplyFormatToSelection;
var
sel: TsCellRangeArray;
range: Integer;
begin
sel := GetSelection;
for range := 0 to High(sel) do
ApplyFormatToRange(sel[range]);
end;
{ Extracts the format item for which the action is responsible from the
specified cell. Must be overridden by descendants. }
procedure TsSpreadsheetAction.ExtractFromCell(ACell: PCell);
begin
Unused(ACell);
end;
function TsSpreadsheetAction.GetActiveCell: PCell;
begin
if Worksheet <> nil then
Result := Worksheet.FindCell(Worksheet.ActiveCellRow, Worksheet.ActiveCellCol)
else
Result := nil;
end;
function TsSpreadsheetAction.GetSelection: TsCellRangeArray;
begin
Result := Worksheet.GetSelection;
end;
function TsSpreadsheetAction.GetWorkbook: TsWorkbook;
begin
if FWorkbookSource <> nil then
Result := FWorkbookSource.Workbook
else
Result := nil;
end;
function TsSpreadsheetAction.GetWorksheet: TsWorksheet;
begin
if FWorkbookSource <> nil then
Result := FWorkbookSource.Worksheet
else
Result := nil;
end;
function TsSpreadsheetAction.HandlesTarget(Target: TObject): Boolean;
begin
Result := (Target <> nil) and (Target = FWorkbookSource);
end;
procedure TsSpreadsheetAction.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (AComponent = FWorkbookSource) then
FWorkbookSource := nil;
end;
procedure TsSpreadsheetAction.UpdateTarget(Target: TObject);
begin
Enabled := HandlesTarget(Target);
end;
{ TsWorksheetAction }
function TsWorksheetAction.HandlesTarget(Target: TObject): Boolean;
begin
Result := inherited HandlesTarget(Target) and (Worksheet <> nil);
end;
procedure TsWorksheetAction.UpdateTarget(Target: TObject);
begin
Unused(Target);
Enabled := inherited Enabled and (Worksheet <> nil);
end;
{ TsWorksheetAddAction }
constructor TsWorksheetAddAction.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Caption := rsAddCaption;
Hint := rsAddWorksheetHint;
FNameMask := 'Sheet%d';
end;
{ Helper procedure which creates a default worksheetname by counting a number
up until - if inserted in the NameMask - it provides a unique worksheet name. }
function TsWorksheetAddAction.GetUniqueSheetName: String;
var
i: Integer;
begin
Result := '';
if Workbook = nil then
exit;
i := 0;
repeat
inc(i);
Result := Format(FNameMask, [i]);
until Workbook.GetWorksheetByName(Result) = nil
end;
procedure TsWorksheetAddAction.ExecuteTarget(Target: TObject);
var
sheetName: String;
begin
if HandlesTarget(Target) then
begin
// Get default name of the new worksheet
sheetName := GetUniqueSheetName;
// If available use own procedure to specify new worksheet name
if Assigned(FOnGetWorksheetName) then
FOnGetWorksheetName(self, Worksheet, sheetName);
// Check validity of worksheet name
if not Workbook.ValidWorksheetName(sheetName) then
begin
MessageDlg(Format('"5s" is not a valid worksheet name.', [sheetName]), mtError, [mbOK], 0);
exit;
end;
// Add new worksheet using the worksheet name.
Workbook.AddWorksheet(sheetName);
end;
end;
procedure TsWorksheetAddAction.SetNameMask(const AValue: String);
begin
if AValue = FNameMask then
exit;
if pos('%d', AValue) = 0 then
raise Exception.Create('Worksheet name mask must contain a %d place-holder.');
FNameMask := AValue;
end;
{ TsWorksheetDeleteAction }
constructor TsWorksheetDeleteAction.Create(AOwner: TComponent);
begin
inherited;
Caption := rsDeleteCaption;
Hint := rsDeleteWorksheetHint;
end;
procedure TsWorksheetDeleteAction.ExecuteTarget(Target: TObject);
begin
if HandlesTarget(Target) then
begin
// Make sure that the last worksheet is not deleted - there must always be
// at least 1 worksheet.
if Workbook.GetWorksheetCount = 1 then
begin
MessageDlg('The workbook must contain at least 1 worksheet', mtError, [mbOK], 0);
exit;
end;
// Confirmation dialog
if MessageDlg(
Format('Do you really want to delete worksheet "%s"?', [Worksheet.Name]),
mtConfirmation, [mbYes, mbNo], 0) <> mrYes
then
exit;
// Remove the worksheet; the workbookSource takes care of selecting the
// next worksheet after deletion.
Workbook.RemoveWorksheet(Worksheet);
end;
end;
{ TsWorksheetRenameAction }
constructor TsWorksheetRenameAction.Create(AOwner: TComponent);
begin
inherited;
Caption := rsRenameCaption;
Hint := rsRenameWorksheetHint;
end;
procedure TsWorksheetRenameAction.ExecuteTarget(Target: TObject);
var
s: String;
begin
if HandlesTarget(Target) then
begin
s := Worksheet.Name;
// If requested, override input box by own input
if Assigned(FOnGetWorksheetName) then
FOnGetWorksheetName(self, Worksheet, s)
else
s := InputBox('Rename worksheet', 'New worksheet name', s);
// No change
if s = Worksheet.Name then
exit;
// Check validity of new worksheet name
if Workbook.ValidWorksheetName(s) then
Worksheet.Name := s
else
MessageDlg(Format('"%s" is not a valid worksheet name.', [s]), mtError, [mbOK], 0);
end;
end;
{ TsWorksheetZoomAction }
constructor TsWorksheetZoomAction.Create(AOwner: TComponent);
begin
inherited;
Caption := rsZoomCaption;
Hint := rsZoomWorksheetHint;
FZoom := 100;
end;
procedure TsWorksheetZoomAction.ExecuteTarget(Target: TObject);
begin
if HandlesTarget(Target) then
Worksheet.Zoomfactor := FZoom / 100;
end;
procedure TsWorksheetZoomAction.SetZoom(AValue: Integer);
begin
if AValue = FZoom then
exit;
if FZoom = 0 then
raise Exception.Create('Zoomfactor cannot be 0.');
FZoom := AValue;
end;
procedure TsWorksheetZoomAction.UpdateTarget(Target: TObject);
begin
Checked := (Worksheet <> nil) and (round(Worksheet.ZoomFactor*100) = FZoom);
end;
{ TsCopyAction }
procedure TsCopyAction.ExecuteTarget(Target: TObject);
const
OPERATIONS: array[TsCopyItem] of TsCopyOperation = (
coCopyFormat, coCopyValue, coCopyFormula, coCopyCell
);
begin
if (Target is TsCustomWorksheetGrid) or (Target is TsWorkbookSource) then
// if Target is TsCustomWorksheetGrid then
case FCopyMode of
cmBrush:
begin
Checked := true;
WorkbookSource.SetPendingOperation(OPERATIONS[FCopyItem], Worksheet.GetSelection);
end;
cmCopy:
begin
Checked := false;
WorkbookSource.CopyCellsToClipboard;
end;
cmCut:
begin
Checked := false;
WorkbookSource.CutCellsToClipboard;
end;
cmPaste:
begin
Checked := false;
WorkbookSource.PasteCellsFromClipboard(OPERATIONS[FCopyItem]);
end;
end
else
if Target is TCustomEdit then
case FCopyMode of
cmBrush : ;
cmCopy : (Target as TCustomEdit).CopyToClipboard;
cmCut : (Target as TCustomEdit).CutToClipboard;
cmPaste : (Target as TCustomEdit).PasteFromClipboard;
end;
end;
function TsCopyAction.HandlesTarget(Target: TObject): Boolean;
begin
case FCopyMode of
cmBrush: Result := inherited HandlesTarget(Target);
cmCopy,
cmCut,
cmPaste: Result := (Target <> nil) and
( (Target is TsCustomWorksheetGrid) or (Target is TCustomEdit) );
end;
end;
procedure TsCopyAction.UpdateTarget(Target: TObject);
begin
Unused(Target);
case FCopyMode of
cmBrush:
if WorkbookSource.PendingOperation = coNone then Checked := false;
cmCopy, cmCut:
Enabled := (Worksheet <> nil) and (Worksheet.GetSelectionCount > 0);
cmPaste:
Enabled := SpreadsheetFormatInClipboard;
end;
end;
{ TsCellAction }
function TsCellAction.HandlesTarget(Target: TObject): Boolean;
begin
Result := inherited HandlesTarget(Target) and (Worksheet <> nil) and (Length(GetSelection) > 0);
end;
{ TsAutoFormatAction - action for cell formatting which is automatically
updated according to the current selection }
procedure TsAutoFormatAction.ExecuteTarget(Target: TObject);
begin
Unused(Target);
ApplyFormatToSelection;
end;
procedure TsAutoFormatAction.UpdateTarget(Target: TObject);
begin
Unused(Target);
Enabled := inherited Enabled and (Worksheet <> nil) and (Length(GetSelection) > 0);
if Enabled then
UpdateTargetFromActiveCell;
end;
procedure TsAutoFormatAction.UpdateTargetFromActiveCell;
var
cell: PCell;
begin
cell := ActiveCell;
if Worksheet.IsMerged(cell) then
cell := Worksheet.FindMergeBase(cell);
ExtractFromCell(cell);
end;
{ TsClearFormatAction }
constructor TsClearFormatAction.Create(AOwner: TComponent);
begin
inherited;
Caption := rsClearFormat;
Hint := rsClearFormat;
end;
procedure TsClearFormatAction.ApplyFormatToCell(ACell: PCell);
begin
if ACell <> nil then
begin
ACell^.FormatIndex := 0; // Default format
Worksheet.ChangedCell(ACell^.Row, ACell^.Col);
end;
end;
{ TsFontStyleAction }
constructor TsFontStyleAction.Create(AOwner: TComponent);
begin
inherited;
Caption := rsCellFontCaption;
Hint := rsCellFontHint;
AutoCheck := true;
end;
procedure TsFontStyleAction.ApplyFormatToCell(ACell: PCell);
var
fnt: TsFont;
fs: TsFontStyles;
begin
fnt := Worksheet.ReadCellFont(ACell);
fs := fnt.Style;
if Checked then
Include(fs, FFontStyle)
else
Exclude(fs, FFontStyle);
Worksheet.WriteFontStyle(ACell, fs);
end;
procedure TsFontStyleAction.ExtractFromCell(ACell: PCell);
var
fnt: TsFont;
fmt: PsCellFormat;
begin
if (ACell = nil) then
begin
Checked := false;
exit;
end;
fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex);
if (uffFont in fmt^.UsedFormattingFields) then
begin
fnt := Workbook.GetFont(fmt^.FontIndex);
Checked := (FFontStyle in fnt.Style);
end else
Checked := false;
end;
procedure TsFontStyleAction.SetFontStyle(AValue: TsFontStyle);
begin
if AValue = FFontStyle then
exit;
FFontStyle := AValue;
case AValue of
fssBold : Caption := rsFontStyle_Bold;
fssItalic : Caption := rsFontStyle_Italic;
fssUnderline : Caption := rsFontStyle_Underlined;
fssStrikeOut : Caption := rsFontStyle_StrikeThrough;
end;
Hint := Caption;
end;
{ TsHorAlignmentAction }
constructor TsHorAlignmentAction.Create(AOwner: TComponent);
begin
inherited;
Caption := rsHorAlignment_Default;
Hint := rsHorAlignment_Default;
GroupIndex := 1411122312; // Date/time when this was written
AutoCheck := true;
end;
procedure TsHorAlignmentAction.ApplyFormatToCell(ACell: PCell);
begin
if Checked then
Worksheet.WriteHorAlignment(ACell, FHorAlign)
else
Worksheet.WriteHorAlignment(ACell, haDefault);
end;
procedure TsHorAlignmentAction.ExtractFromCell(ACell: PCell);
begin
Checked := (ACell <> nil) and (Worksheet.ReadHorAlignment(ACell) = FHorAlign);
end;
procedure TsHorAlignmentAction.SetHorAlign(AValue: TsHorAlignment);
begin
if AValue = FHorAlign then exit;
FHorAlign := AValue;
case FHorAlign of
haDefault: Caption := rsHorAlignment_Default;
haLeft : Caption := rsHorAlignment_Left;
haCenter : Caption := rsHorAlignment_Center;
haRight : Caption := rsHorAlignment_Right;
end;
Hint := Caption;
end;
{ TsVertAlignmentAction }
constructor TsVertAlignmentAction.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Caption := rsVertAlignment_Default;
Hint := rsVertAlignment_Default;
GroupIndex := 1411122322; // Date/time when this was written
AutoCheck := true;
end;
procedure TsVertAlignmentAction.ApplyFormatToCell(ACell: PCell);
begin
if Checked then
Worksheet.WriteVertAlignment(ACell, FVertAlign)
else
Worksheet.WriteVertAlignment(ACell, vaDefault);
end;
procedure TsVertAlignmentAction.ExtractFromCell(ACell: PCell);
begin
Checked := (ACell <> nil) and (Worksheet.ReadVertAlignment(ACell) = FVertAlign);
end;
procedure TsVertAlignmentAction.SetVertAlign(AValue: TsVertAlignment);
begin
if AValue = FVertAlign then exit;
FVertAlign := AValue;
case FVertAlign of
vaDefault: Caption := rsVertAlignment_Default;
vaTop : Caption := rsVertAlignment_Top;
vaCenter : Caption := rsVertAlignment_Center;
vaBottom : Caption := rsVertAlignment_Bottom;
end;
Hint := Caption;
end;
{ TsTextRotationAction }
constructor TsTextRotationAction.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Caption := rsTextRotation_Hor;
Hint := rsTextRotation_Hor;
GroupIndex := 1411141108; // Date/time when this was written
AutoCheck := true;
end;
procedure TsTextRotationAction.ApplyFormatToCell(ACell: PCell);
begin
if Checked then
Worksheet.WriteTextRotation(ACell, FTextRotation)
else
Worksheet.WriteTextRotation(ACell, trHorizontal);
end;
procedure TsTextRotationAction.ExtractFromCell(ACell: PCell);
begin
Checked := (ACell <> nil) and (Worksheet.ReadTextRotation(ACell) = FTextRotation);
end;
procedure TsTextRotationAction.SetTextRotation(AValue: TsTextRotation);
begin
if AValue <> FTextRotation then exit;
FTextRotation := AValue;
case FTextRotation of
trHorizontal : Caption := rsTextRotation_Hor;
rt90DegreeClockwiseRotation : Caption := rsTextRotation_Vert_CW;
rt90DegreeCounterClockwiseRotation : Caption := rsTextRotation_Vert_CCW;
rtStacked : Caption := rsTextRotation_Vert_Stacked;
end;
Hint := Caption;
end;
{ TsWordwrapAction }
constructor TsWordwrapAction.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
AutoCheck := true;
Caption := rsWordWrap;
Hint := rsWordWrap;
end;
procedure TsWordwrapAction.ApplyFormatToCell(ACell: PCell);
begin
Worksheet.WriteWordwrap(ACell, Checked);
end;
procedure TsWordwrapAction.ExtractFromCell(ACell: PCell);
begin
Checked := (ACell <> nil) and Worksheet.ReadWordwrap(ACell);
end;
function TsWordwrapAction.GetWordwrap: Boolean;
begin
Result := Checked;
end;
procedure TsWordwrapAction.SetWordwrap(AValue: Boolean);
begin
Checked := AValue;
end;
{ TsNumberFormatAction }
constructor TsNumberFormatAction.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Caption := rsNumberFormatCaption_General;
Hint := rsNumberFormatHint_General;
GroupIndex := 1411141258; // Date/time when this code was written
//AutoCheck := true;
end;
procedure TsNumberFormatAction.ApplyFormatToCell(ACell: PCell);
var
nf: TsNumberFormat;
nfstr: String;
begin
if Checked then
begin
nf := FNumberFormat;
if FNumberFormat = nfCustom then
nfstr := FCustomNumberFormatStr
else
nfstr := FNumberFormatStr;
end else
begin
nf := nfGeneral;
nfstr := '';
end;
if IsDateTimeFormat(nf) then
Worksheet.WriteDateTimeFormat(ACell, nf, nfstr)
else
Worksheet.WriteNumberFormat(ACell, nf, nfstr);
end;
procedure TsNumberFormatAction.ExecuteTarget(Target: TObject);
var
nf: TsNumberFormat;
nfstr: String;
begin
if (FNumberFormat = nfCustom) and Assigned(FOnGetNumFormatStr) then
begin
Worksheet.ReadNumFormat(ActiveCell, nf, nfstr);
FOnGetNumFormatStr(self, Workbook, nfstr);
FCustomNumberFormatStr := nfstr;
Checked := true;
end else
Checked := not Checked;
inherited;
end;
procedure TsNumberFormatAction.ExtractFromCell(ACell: PCell);
var
nf: TsNumberFormat;
nfs: String;
begin
Worksheet.ReadNumFormat(ACell, nf, nfs);
Checked := (ACell <> nil) and (nf = FNumberFormat) and
((FNumberFormatStr = '') or (nfs = FNumberFormatStr));
end;
procedure TsNumberFormatAction.SetNumberFormat(AValue: TsNumberFormat);
begin
FNumberFormat := AValue;
UpdateCaptionAndHint;
end;
procedure TsNumberFormatAction.SetNumberFormatStr(AValue: String);
begin
FNumberFormatStr := AValue;
UpdateCaptionAndHint;
end;
procedure TsNumberFormatAction.UpdateCaptionAndHint;
procedure CaptionAndHint(ACaption, AHint: String);
begin
if Caption = '' then begin
if FNumberFormatStr <> '' then
Caption := Format('%s (%s)', [ACaption, FNumberFormatStr])
else
Caption := ACaption;
end;
if Hint = '' then
Hint := AHint;
end;
begin
case FNumberFormat of
nfGeneral:
CaptionAndHint(rsNumberFormatCaption_General, rsNumberFormatHint_General);
nfFixed:
CaptionAndHint(rsNumberFormatCaption_Fixed, rsNumberFormatHint_Fixed);
nfFixedTh:
CaptionAndHint(rsNumberFormatCaption_FixedTh, rsNumberFormatHint_FixedTh);
nfExp:
CaptionAndHint(rsNumberFormatCaption_Exp, rsNumberFormatHint_Exp);
nfPercentage:
CaptionAndHint(rsNumberFormatCaption_Percentage, rsNumberFormatHint_Percentage);
nfFraction:
CaptionAndHint(rsNumberFormatCaption_Fraction, rsNumberFormatHint_Fraction);
nfCurrency:
CaptionAndHint(rsNumberFormatCaption_Currency, rsNumberFormatHint_Currency);
nfCurrencyRed:
CaptionAndHint(rsNumberFormatCaption_CurrencyRed, rsNumberFormatHint_CurrencyRed);
nfShortDateTime:
CaptionAndHint(rsNumberFormatCaption_ShortDateTime, rsNumberFormatHint_ShortDateTime);
nfShortDate:
CaptionAndHint(rsNumberFormatCaption_ShortDate, rsNumberFormatHint_ShortDate);
nfLongDate:
CaptionAndHint(rsNumberFormatCaption_LongDate, rsNumberFormatHint_LongDate);
nfShortTime:
CaptionAndHint(rsNumberFormatCaption_ShortTime, rsNumberFormatHint_ShortTime);
nfLongTime:
CaptionAndHint(rsNumberFormatCaption_LongTime, rsNumberFormatHint_LongTime);
nfShortTimeAM:
CaptionAndHint(rsNumberFormatCaption_ShortTimeAM, rsNumberFormatHint_ShortTimeAM);
nfLongTimeAM:
CaptionAndHint(rsNumberFormatCaption_LongTimeAM, rsNumberFormatHint_LongTimeAM);
nfDayMonth:
CaptionAndHint(rsNumberFormatCaption_DayMonth, rsNumberFormatHint_DayMonth);
nfMonthYear:
CaptionAndHint(rsNumberFormatCaption_MonthYear, rsNumberFormatHint_MonthYear);
nfTimeInterval:
CaptionAndHint(rsNumberFormatCaption_TimeInterval, rsNumberFormatHint_TimeInterval);
nfText:
CaptionAndHint(rsNumberFormatCaption_Text, rsNumberFormatHint_Text);
nfCustom:
CaptionAndHint(rsNumberFormatCaption_Custom, rsNumberFormatHint_Custom);
end;
Hint := Caption;
end;
{ TsDecimalsAction }
constructor TsDecimalsAction.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FDelta := +1;
Caption := rsMoreDecimals;
Hint := rsLessDecimals;
end;
procedure TsDecimalsAction.ApplyFormatToCell(ACell: PCell);
var
decs: Integer;
nf: TsNumberFormat;
nfs: String;
begin
Worksheet.ReadNumFormat(ACell, nf, nfs);
if IsDateTimeFormat(nf) then
exit;
if (ACell^.ContentType in [cctEmpty, cctNumber]) and (nf <> nfGeneral) then
decs := Worksheet.GetDisplayedDecimals(ACell)
else
decs := FDecimals;
inc(decs, FDelta);
if decs < 0 then decs := 0;
Worksheet.WriteDecimals(ACell, decs);
end;
procedure TsDecimalsAction.ExtractFromCell(ACell: PCell);
var
csym: String;
decs: Byte;
nf: TsNumberFormat;
nfs: String;
begin
if ACell = nil then begin
FDecimals := 2;
exit;
end;
Worksheet.ReadNumFormat(ACell, nf, nfs);
if (ACell^.ContentType in [cctEmpty, cctNumber]) and (nf <> nfGeneral) then
decs := Worksheet.GetDisplayedDecimals(ACell)
else
Worksheet.GetNumberFormatAttributes(ACell, decs, csym);
FDecimals := decs;
end;
procedure TsDecimalsAction.SetDelta(AValue: Integer);
begin
if AValue = FDelta then exit;
FDelta := AValue;
if FDelta > 0 then Caption := rsMoreDecimals else Caption := rsLessDecimals;
Hint := Caption;
end;
{ TsCellProtectionAction }
constructor TsCellProtectionAction.Create(AOwner: TComponent);
begin
inherited;
AutoCheck := true;
end;
procedure TsCellProtectionAction.ApplyFormatToCell(ACell: PCell);
var
p: TsCellProtections;
begin
if (Worksheet.IsProtected and (spCells in Worksheet.Protection)) then
exit;
p := Worksheet.ReadCellProtection(ACell);
if Checked then
Include(p, FProtection)
else
Exclude(p, FProtection);
Worksheet.WriteCellProtection(ACell, p);
end;
procedure TsCellProtectionAction.ExtractFromCell(ACell: PCell);
var
p: TsCellProtections;
begin
if ACell = nil then begin
Checked := FProtection = cpLockCell;
exit;
end;
p := Worksheet.ReadCellProtection(ACell);
Checked := FProtection in p;
Enabled := not (Worksheet.IsProtected and (spCells in Worksheet.Protection));
end;
procedure TsCellProtectionAction.UpdateTarget(Target: TObject);
begin
Unused(Target);
UpdateTargetFromActiveCell;
end;
{ TsCellBorderAction }
constructor TsActionBorder.Create(AOwner: TsActionBorders);
begin
inherited Create;
FOwner := AOwner;
end;
procedure TsActionBorder.Changed;
begin
FOwner.Update;
end;
function TsActionBorder.GetStyle: TsCellBorderStyle;
begin
Result.LineStyle := FLineStyle;
Result.Color := FColor and $00FFFFFF;
end;
procedure TsActionBorder.SetLineStyle(AValue: TsLineStyle);
begin
if FLineStyle = AValue then
exit;
FLineStyle := AValue;
Changed;
end;
procedure TsActionBorder.SetStyle(const AValue: TsCellBorderStyle);
var
rgb: TColor;
begin
rgb := ColorToRGB(AValue.Color);
if (FLineStyle = AValue.LineStyle) and (FColor = rgb) then
exit;
FLineStyle := AValue.LineStyle;
FColor := rgb;
Changed;
end;
procedure TsActionBorder.SetVisible(const AValue: Boolean);
begin
if FVisible = AValue then exit;
FVisible := AValue;
Changed;
end;
{ --- }
constructor TsActionBorders.Create(Action: TsCellAction);
var
cb: Integer;
begin
inherited Create;
FAction := Action;
for cb := 0 to High(FBorders) do
FBorders[cb] := TsActionBorder.Create(self);
end;
destructor TsActionBorders.Destroy;
var
cb: Integer;
begin
for cb := High(FBorders) downto 0 do FBorders[cb].Free;
inherited Destroy;
end;
procedure TsActionBorders.ExtractFromCell(AWorkbook: TsWorkbook; ACell: PCell);
var
cb: Integer;
fmt: PsCellFormat;
sheet: TsWorksheet;
begin
if (ACell <> nil) then begin
sheet := TsWorksheet(ACell^.Worksheet);
if sheet.IsMerged(ACell) then
ACell := sheet.FindMergeBase(ACell);
fmt := AWorkbook.GetPointerToCellFormat(ACell^.FormatIndex);
end;
if (ACell = nil) or not (uffBorder in fmt^.UsedFormattingFields) then
for cb := 0 to High(FBorders)-2 do // inner styles not needed here
begin
FBorders[cb].SetStyle(DEFAULT_BORDERSTYLES[TsCellBorder(cb)]);
FBorders[cb].Visible := false;
end
else
for cb := 0 to High(FBorders)-2 do // inner styles not needed here
begin
FBorders[cb].SetStyle(fmt^.BorderStyles[TsCellBorder(cb)]);
FBorders[cb].Visible := TsCellBorder(cb) in fmt^.Border;
end;
end;
function TsActionBorders.GetBorder(AIndex: Integer): TsActionBorder;
begin
Result := FBorders[AIndex];
end;
procedure TsActionBorders.SetBorder(AIndex: Integer; AValue: TsActionBorder);
begin
FBorders[AIndex] := AValue;
Update;
end;
procedure TsActionBorders.Update;
type
TVisibleSet = set of byte;
{ LS = get LineStyle as String }
function _LS(ALineStyle: TsLineStyle): String;
begin
case ALineStyle of
lsThin: Result := rsThin;
lsMedium: Result := rsMedium;
lsDashed: Result := rsDashed;
lsDotted: Result := rsDotted;
lsThick: Result := rsThick;
lsDouble: Result := rsDouble;
lsHair: Result := rsHair;
lsMediumDash: Result := rsMediumDash;
lsDashDot: Result := rsDashDot;
lsMediumDashDot: Result := rsMediumDashDot;
lsDashDotDot: Result := rsDashDotDot;
lsMediumDashDotDot: Result := rsMediumDashDotDot;
lsSlantDashDot: Result := rsSlantDashDot;
else raise Exception.Create('[TsActionBorders] Linetype not supported.');
end;
end;
{ CH = set Caption and Hint }
procedure _CH(ACaption, AHint: String; AParam: String = '');
begin
if AParam = '' then begin
FAction.Caption := ACaption;
FAction.Hint := AHint;
end else begin
FAction.Caption := Format(ACaption, [AParam]);
FAction.Hint := Format(AHint, [AParam]);
end;
end;
function Check(const Visible: TVisibleSet): Boolean;
{ 0 = North, 1 = West, 2 = East, 3 = South, 4 = DiagUp, 5 = DiagDown, 6 = InnerHor, 7 = InnerVert }
var
i: Byte;
iVisible, borderVisible: Boolean;
begin
Result := false;
for i := 0 to 7 do begin
iVisible := i in Visible;
borderVisible := FBorders[i].Visible;
if iVisible and not borderVisible then exit;
if not iVisible and borderVisible then exit;
end;
Result := true;
end;
begin
if Check([0]) then begin // 0 = North = Top
if FBorders[0].LineStyle = lsThin then
_CH(rsBorderTop_Menu, rsBorderTop_Hint)
else
_CH(rsBorderTopFmt_Menu, rsBorderTopFmt_Hint, _LS(FBorders[0].LineStyle));
end else
if Check([1]) then begin // 1 = West = Left
if FBorders[1].LineStyle = lsThin then
_CH(rsBorderLeft_Menu, rsBorderLeft_Hint)
else
_CH(rsBorderLeftFmt_Menu, rsBorderLeftFmt_Hint, _LS(FBorders[1].LineStyle))
end else
if Check([2]) then begin // 2 = East = Right
if FBorders[2].LineStyle = lsThin then
_CH(rsBorderRight_Menu, rsBorderRight_Hint)
else
_CH(rsBorderRightFmt_Menu, rsBorderRightFmt_Hint, _LS(FBorders[2].LineStyle))
end else
if Check([3]) then begin // 3 = South
if FBorders[3].LineStyle = lsThin then
_CH(rsBorderBottom_Menu, rsBorderBottom_Hint)
else
_CH(rsBorderBottomFmt_Menu, rsBorderBottomFmt_Hint, _LS(FBorders[3].LineStyle))
end else
if Check([4]) then begin // 4 = diagonal up
if FBorders[4].LineStyle = lsThin then
_CH(rsBorderDiagUp, rsBorderdiagUp)
else
_CH(rsBorderDiagUpFmt, rsBorderDiagUpFmt, _LS(FBorders[4].LineStyle))
end else
if Check([5]) then begin // 5 = diagonal down
if FBorders[5].LineStyle = lsThin then
_CH(rsBorderDiagDown, rsBorderDiagDown)
else
_CH(rsBorderDiagDownFmt, rsBorderDiagDownFmt, _LS(FBorders[5].LineStyle))
end else
if Check([6]) then begin // 6 = Inner hor
if FBorders[6].LineStyle = lsThin then
_CH(rsBorderInnerHor_Menu, rsBorderInnerHor_Hint)
else
_CH(rsBorderInnerHorFmt_Menu, rsBorderInnerHorFmt_Hint, _LS(FBorders[6].LineStyle))
end else
if Check([7]) then begin // 7 = InnerVert
if FBorders[7].LineStyle = lsThin then
_CH(rsBorderInnerVert_Menu, rsBorderInnerVert_Hint)
else
_CH(rsBorderInnerVertFmt_Menu, rsBorderInnerVertFmt_Hint, _LS(FBorders[7].LineStyle))
end else
if Check([0, 4]) then // top & bottom
begin
if (FBorders[0].LineStyle = lsThin) and (FBorders[4].LineStyle <> lsThin) then
// top line always thin, bottom line chan vary
_CH(rsBorderBottomFmt_Menu, rsBorderBottomFmt_Hint, _LS(FBorders[4].LineStyle))
else
_CH(rsBorderBottom_Menu, rsBorderBottom_Hint)
end else
if check([0, 3, 6]) then begin // all horizontal lines
if (FBorders[0].LineStyle = FBorders[3].LineStyle) and
(FBorders[3].LineStyle = FBorders[6].LineStyle)
then
_CH(rsBorderAllHorFmt_Menu, rsBorderAllHorFmt_Hint, _LS(FBorders[3].LineStyle))
else
_CH(rsBorderAllHor_Menu, rsBorderAllHor_Hint);
end else
if Check([1, 2, 7]) then begin // all vertical lines
if (FBorders[1].LineStyle = FBorders[2].LineStyle) and
(FBorders[2].LineStyle = FBorders[7].LineStyle)
then
_CH(rsBorderAllVertFmt_Menu, rsBorderAllVertFmt_Hint, _LS(FBorders[2].LineStyle))
else
_CH(rsBorderAllVert_Menu, rsBorderAllVert_Hint)
end else
if Check([6, 7]) then begin // all inner lines
if (FBorders[6].LineStyle = FBorders[7].LineStyle) then
_CH(rsBorderAllInnerFmt_Menu, rsBorderAllInnerFmt_Hint, _LS(FBorders[6].LineStyle))
else
_CH(rsBorderAllInner_Menu, rsBorderAllInner_Hint)
end else
if Check([0, 1, 2, 3]) then begin // all outer lines, no inner
if (FBorders[0].LineStyle = FBorders[1].LineStyle) and
(FBorders[1].LineStyle = FBorders[2].LineStyle) and
(FBorders[2].LineStyle = FBorders[3].LineStyle)
then
_CH(rsBorderAllOuterFmt_Menu, rsBorderAllOuterFmt_Hint, _LS(FBorders[0].LineStyle))
else
_CH(rsBorderAllOuter_Menu, rsBorderAllOuter_Hint);
end else
if Check([0, 1, 2, 3, 6, 7]) then begin // inner and outer lines, inner thin, outer may change
if (FBorders[0].LineStyle = FBorders[1].LineStyle) and
(FBorders[1].LineStyle = FBorders[2].LineStyle) and
(FBorders[2].LineStyle = FBorders[3].LineStyle) and
(FBorders[6].LineStyle = FBorders[7].LineStyle) and
(FBorders[6].LineStyle = lsThin)
then
_CH(rsBorderAllFmt_Menu, rsBorderAllFmt_Hint, _LS(FBorders[0].LineStyle))
else
_CH(rsBorderAll_Menu, rsBorderAll_Hint)
end else
_CH(rsCellBorder, rsCellBorder);
end;
{ --- }
constructor TsCellBorderAction.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FBorders := TsActionBorders.Create(Self);
Caption := rsCellBorder;
Hint := rsCellBorder;
end;
destructor TsCellBorderAction.Destroy;
begin
FBorders.Free;
inherited;
end;
procedure TsCellBorderAction.ApplyFormatToRange(ARange: TsCellRange);
procedure ShowBorder(ABorder: TsCellBorder; ACell: PCell;
ABorderStyle: TsCellBorderStyle; AEnable: boolean);
var
fmt: TsCellFormat;
begin
fmt := Workbook.GetCellFormat(ACell^.FormatIndex);
if AEnable then
begin
Include(fmt.UsedFormattingFields, uffBorder);
Include(fmt.Border, ABorder);
fmt.BorderStyles[ABorder] := ABorderStyle;
ACell^.FormatIndex := Workbook.AddCellFormat(fmt);
end else
Exclude(fmt.UsedFormattingFields, uffBorder);
Worksheet.ChangedCell(ACell^.Row, ACell^.Col);
end;
procedure ShowBorders(ABorder: TsCellBorder; AStart, AEnd, AColRow: LongInt;
AColRowIsCol: Boolean; ABorderStyle: TsCellBorderStyle; AEnable: Boolean);
var
i: Integer;
r1, c1, r2, c2: Cardinal;
cell: PCell;
begin
i := AStart;
while i <= AEnd do
begin
if AColRowIsCol then
// Scan along specified column, i.e. i is row index
begin
cell := Worksheet.GetCell(i, AColRow);
if Worksheet.IsMerged(cell) then
begin
Worksheet.FindMergedRange(cell, r1, c1, r2, c2);
if (LongInt(r1) >= AStart) and (LongInt(r2) <= AEnd) then
begin
cell := Worksheet.GetCell(r1, c1);
ShowBorder(ABorder, cell, ABorderStyle, AEnable);
while (i <= longint(r2)) do begin
cell := GetWorksheet.GetCell(i, AColRow);
inc(i);
end;
Continue;
end;
end;
end
else
// Scan along specified row, i.e. i is column index
begin
cell := Worksheet.GetCell(AColRow, i);
if Worksheet.IsMerged(cell) then
begin
Worksheet.FindMergedRange(cell, r1, c1, r2, c2);
if (longInt(c1) >= AStart) and (LongInt(c2) <= AEnd) then
begin
cell := Worksheet.GetCell(r1, c1);
ShowBorder(ABorder, cell, ABorderStyle, AEnable);
while (i <= longInt(c2)) do begin
cell := GetWorksheet.GetCell(AColRow, i);
inc(i);
end;
Continue;
end;
end;
end;
ShowBorder(ABorder, cell, ABorderStyle, AEnable);
inc(i);
end;
end;
var
r, c: LongInt;
begin
// Top edge of range
ShowBorders(cbNorth, ARange.Col1, ARange.Col2, ARange.Row1, false,
Borders.North.GetStyle, Borders.North.Visible);
// Bottom edge of range
ShowBorders(cbSouth, ARange.Col1, ARange.Col2, ARange.Row2, false,
Borders.South.GetStyle, Borders.South.Visible);
// Left edge of range
ShowBorders(cbWest, ARange.Row1, ARange.Row2, ARange.Col1, true,
Borders.West.GetStyle, Borders.West.Visible);
// Right edge of range
ShowBorders(cbEast, ARange.Row1, ARange.Row2, ARange.Col2, true,
Borders.East.GetStyle, Borders.East.Visible);
// Inner horizontal edges
for r := ARange.Row1 to ARange.Row2-1 do
ShowBorders(cbSouth, ARange.Col1, ARange.Col2, r, false,
Borders.InnerHor.GetStyle, Borders.InnerHor.Visible);
for r := ARange.Row1+1 to ARange.Row2 do
ShowBorders(cbNorth, ARange.Col1, ARange.Col2, r, false,
Borders.InnerHor.GetStyle, Borders.InnerHor.Visible);
// Inner vertical edges
for c := ARange.Col1 to ARange.Col2-1 do
ShowBorders(cbEast, ARange.Row1, ARange.Row2, c, true,
Borders.InnerVert.GetStyle, Borders.InnerVert.Visible);
for c := ARange.Col1+1 to ARange.Col2 do
ShowBorders(cbWest, ARange.Row1, ARange.Row2, c, true,
Borders.InnerVert.GetStyle, Borders.InnerVert.Visible);
// Diagonal up and down lines
for c := ARange.Col1 to ARange.Col2 do
begin
ShowBorders(cbDiagUp, ARange.Row1, ARange.Row2, c, true,
Borders.DiagonalUp.GetStyle, Borders.DiagonalUp.Visible);
ShowBorders(cbDiagDown, ARange.Row1, ARange.Row2, c, true,
Borders.DiagonalDown.GetStyle, Borders.DiagonalDown.Visible);
end;
end;
procedure TsCellBorderAction.ExecuteTarget(Target: TObject);
begin
Unused(Target);
ApplyFormatToSelection;
end;
procedure TsCellBorderAction.ExtractFromCell(ACell: PCell);
var
EmptyCell: TCell;
begin
if (ACell = nil) or not (uffBorder in Worksheet.ReadUsedFormatting(ACell)) then
begin
EmptyCell.Row := 0; // silence the compiler...
InitCell(EmptyCell);
FBorders.ExtractFromCell(Workbook, @EmptyCell);
end else
FBorders.ExtractFromCell(Workbook, ACell);
end;
{ TsNoCellBordersAction }
constructor TsNoCellBordersAction.Create(AOwner: TComponent);
begin
inherited;
Caption := rsNoCellBorders;
Hint := rsNoCellBorders;
end;
procedure TsNoCellBordersAction.ApplyFormatToCell(ACell: PCell);
begin
Worksheet.WriteBorders(ACell, []);
end;
procedure TsNoCellBordersAction.ExecuteTarget(Target: TObject);
begin
Unused(Target);
ApplyFormatToSelection;
end;
{ TsCellCommentAction }
constructor TsCellCommentAction.Create(AOwner: TComponent);
begin
inherited;
Caption := rsCommentCaption_New;
Hint := rsCommentHint_New;
end;
function TsCellCommentAction.EditComment(ACaption: String;
var AText: String): Boolean;
var
F: TForm;
memo: TMemo;
panel: TPanel;
btn: TBitBtn;
begin
F := TForm.Create(nil);
try
F.Caption := ACaption;
F.Width := 400;
F.Height := 300;
F.Position := poMainFormCenter;
memo := TMemo.Create(F);
memo.Parent := F;
memo.Align := alClient;
memo.BorderSpacing.Around := 4;
memo.Lines.Text := AText;
panel := TPanel.Create(F);
panel.Parent := F;
panel.Align := alBottom;
panel.Height := 44;
panel.BevelOuter := bvNone;
panel.Caption := '';
btn := TBitBtn.Create(F);
btn.Parent := panel;
btn.Kind := bkOK;
btn.Left := panel.ClientWidth - 2*btn.Width - 2*8;
btn.Top := 6;
btn.Anchors := [akTop, akRight];
btn := TBitBtn.Create(F);
btn.Parent := panel;
btn.Kind := bkCancel;
btn.Left := panel.ClientWidth - btn.Width - 8;
btn.Top := 6;
btn.Anchors := [akTop, akRight];
if F.ShowModal = mrOK then
begin
Result := true;
AText := memo.Lines.Text;
end else
Result := false;
finally
F.Free;
end;
end;
procedure TsCellCommentAction.ExecuteTarget(Target: TObject);
var
txt: String;
cellStr: String;
begin
Unused(Target);
if Worksheet = nil then
exit;
cellstr := GetCellString(Worksheet.ActiveCellRow, Worksheet.ActiveCellCol);
case FMode of
ccmNew:
begin
txt := '';
if EditComment(Format('New comment for cell %s',[cellStr]), txt) then
Worksheet.WriteComment(Worksheet.ActiveCellRow, Worksheet.ActiveCellCol, txt);
end;
ccmEdit:
begin
txt := Worksheet.ReadComment(ActiveCell);
if EditComment(Format('Edit comment for cell %s', [cellStr]), txt) then
Worksheet.WriteComment(Worksheet.ActiveCellRow, Worksheet.ActiveCellCol, txt);
end;
ccmDelete:
Worksheet.WriteComment(ActiveCell, '');
end;
end;
procedure TsCellCommentAction.SetMode(AValue: TsCellCommentMode);
procedure CaptionAndHint(ACaption, AHint: String);
begin
Caption := ACaption;
Hint := AHint;
end;
begin
if AValue = FMode then exit;
FMode := AValue;
case FMode of
ccmNew : CaptionAndHint(rsCommentCaption_New, rsCommentHint_New);
ccmEdit : CaptionAndHint(rsCommentCaption_Edit, rsCommentHint_Edit);
ccmDelete: CaptionAndHint(rsCommentCaption_Delete, rsCommentHint_Delete);
end;
end;
procedure TsCellCommentAction.UpdateTarget(Target: TObject);
begin
Unused(Target);
case FMode of
ccmNew:
Enabled := (Worksheet <> nil) and (Length(GetSelection) > 0) and not Worksheet.HasComment(ActiveCell);
ccmEdit, ccmDelete:
Enabled := (Worksheet <> nil) and (Worksheet.ReadComment(ActiveCell) <> '');
end;
end;
{ TsCellHyperlinkAction }
constructor TsCellHyperlinkAction.Create(AOwner: TComponent);
begin
inherited;
Caption := rsHyperlinkCaption_New;
Hint := rsHyperlinkHint_New;
end;
function TsCellHyperlinkAction.EditHyperlink(ACaption: String;
var AHyperlink: TsHyperlink): Boolean;
begin
if Assigned(FOnHyperlink) then
FOnHyperlink(Self, ACaption, AHyperlink)
else
AHyperlink.Target := InputBox(ACaption, 'Target', AHyperlink.Target);
Result := AHyperlink.Target <> '';
end;
procedure TsCellHyperlinkAction.ExecuteTarget(Target: TObject);
var
txt: String;
cellStr: String;
hyperlink: TsHyperlink;
begin
Unused(Target);
if Worksheet = nil then
exit;
cellstr := GetCellString(Worksheet.ActiveCellRow, Worksheet.ActiveCellCol);
case FMode of
chmNew:
begin
txt := Format('New hyperlink for cell %s', [cellStr]);
hyperlink.Target := '';
hyperlink.Tooltip := '';
if EditHyperlink(txt, hyperlink) then
Worksheet.WriteHyperlink(
Worksheet.ActiveCellRow, Worksheet.ActiveCellCol,
hyperlink.Target, hyperlink.ToolTip
);
end;
chmEdit:
begin
hyperlink := Worksheet.ReadHyperlink(ActiveCell);
txt := Format('Edit hyperlink for cell %s', [cellStr]);
if EditHyperlink(txt, hyperlink) then
begin
Worksheet.WriteHyperlink(
Worksheet.ActiveCellRow, Worksheet.ActiveCellCol,
hyperlink.Target, hyperlink.ToolTip
);
end;
end;
chmDelete:
Worksheet.WriteHyperlink(ActiveCell, '');
end;
end;
procedure TsCellHyperlinkAction.SetMode(AValue: TsCellHyperlinkMode);
procedure CaptionAndHint(ACaption, AHint: String);
begin
Caption := ACaption;
Hint := AHint;
end;
begin
if AValue = FMode then exit;
FMode := AValue;
case FMode of
chmNew : CaptionAndHint(rsHyperlinkCaption_New, rsHyperlinkHint_New);
chmEdit : CaptionAndHint(rsHyperlinkCaption_Edit, rsHyperlinkHint_Edit);
chmDelete: CaptionAndHint(rsHyperlinkCaption_Delete, rsHyperlinkHint_Delete);
end;
end;
procedure TsCellHyperlinkAction.UpdateTarget(Target: TObject);
begin
Unused(Target);
case FMode of
chmNew:
Enabled := (Worksheet <> nil) and (Length(GetSelection) > 0) and not Worksheet.HasHyperlink(ActiveCell);
chmEdit, chmDelete:
Enabled := (Worksheet <> nil) and Worksheet.HasHyperlink(ActiveCell);
end;
end;
{ TsMergeAction }
constructor TsMergeAction.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
AutoCheck := true;
Caption := rsMergeUnmerge;
Hint := rsMergeUnmerge;
end;
procedure TsMergeAction.ApplyFormatToRange(ARange: TsCellRange);
begin
if Merged then
Worksheet.MergeCells(ARange.Row1, ARange.Col1, ARange.Row2, ARange.Col2)
else
Worksheet.UnmergeCells(ARange.Row1, ARange.Col1);
end;
procedure TsMergeAction.ExtractFromCell(ACell: PCell);
begin
Checked := (ACell <> nil) and Worksheet.IsMerged(ACell);
end;
function TsMergeAction.GetMerged: Boolean;
begin
Result := Checked;
end;
procedure TsMergeAction.SetMerged(AValue: Boolean);
begin
Checked := AValue;
end;
{ TsCommonDialogSpreadsheetAction }
constructor TsCommonDialogSpreadsheetAction.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
CreateDialog;
DisableIfNoHandler := False;
Enabled := True;
end;
procedure TsCommonDialogSpreadsheetAction.CreateDialog;
var
DlgClass: TCommonDialogClass;
begin
DlgClass := GetDialogClass;
if Assigned(DlgClass) then
begin
FDialog := DlgClass.Create(Self);
FDialog.Name := DlgClass.ClassName;
FDialog.SetSubComponent(True);
end;
end;
procedure TsCommonDialogSpreadsheetAction.DoAccept;
begin
if Assigned(FOnAccept) then
FOnAccept(Self);
end;
procedure TsCommonDialogSpreadsheetAction.DoBeforeExecute;
var
cell: PCell;
begin
if Assigned(FBeforeExecute) then
FBeforeExecute(Self);
cell := Worksheet.FindCell(Worksheet.ActiveCellRow, Worksheet.ActiveCellCol);
ExtractFromCell(cell);
end;
procedure TsCommonDialogSpreadsheetAction.DoCancel;
begin
if Assigned(FOnCancel) then
FOnCancel(Self);
end;
function TsCommonDialogSpreadsheetAction.GetDialogClass: TCommonDialogClass;
begin
result := nil;
end;
procedure TsCommonDialogSpreadsheetAction.ExecuteTarget(Target: TObject);
begin
Unused(Target);
DoBeforeExecute;
FExecuteResult := FDialog.Execute;
if FExecuteResult then
DoAccept
else
DoCancel;
end;
{ TsCommonDialogCellAction }
procedure TsCommonDialogCellAction.DoAccept;
begin
ApplyFormatToSelection;
inherited;
end;
procedure TsCommonDialogCellAction.DoBeforeExecute;
begin
inherited;
ExtractFromCell(ActiveCell);
end;
{ TsFontDialogAction }
constructor TsFontDialogAction.Create(AOwner: TComponent);
begin
inherited;
Caption := rsCellFontCaption;
Hint := rsCellFontHint;
end;
procedure TsFontDialogAction.ApplyFormatToCell(ACell: PCell);
var
sfnt: TsFont;
begin
sfnt := TsFont.Create;
Convert_Font_to_sFont(GetDialog.Font, sfnt);
Worksheet.WriteFont(ACell, Workbook.AddFont(sfnt));
end;
procedure TsFontDialogAction.ExtractFromCell(ACell: PCell);
var
sfnt: TsFont;
fnt: TFont;
fmt: PsCellFormat;
begin
fnt := TFont.Create;
try
if (ACell = nil) then
sfnt := Workbook.GetDefaultFont
else begin
fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex);
{
if (uffBold in fmt^.UsedFormattingFields) then
sfnt := Workbook.GetFont(BOLD_FONTINDEX)
else}
if (uffFont in fmt^.UsedFormattingFields) then
sfnt := Workbook.GetFont(fmt^.FontIndex)
else
sfnt := Workbook.GetDefaultFont;
end;
Convert_sFont_to_Font(sfnt, fnt);
GetDialog.Font.Assign(fnt);
finally
fnt.Free;
end;
end;
function TsFontDialogAction.GetDialog: TFontDialog;
begin
Result := TFontDialog(FDialog);
end;
function TsFontDialogAction.GetDialogClass: TCommonDialogClass;
begin
Result := TFontDialog;
end;
{ TsBackgroundColorDialogAction }
constructor TsBackgroundColorDialogAction.Create(AOwner: TComponent);
begin
inherited;
Caption := rsBackgroundColorCaption;
Hint := rsBackgroundColorHint;
end;
procedure TsBackgroundColorDialogAction.ApplyFormatToCell(ACell: PCell);
begin
Worksheet.WritebackgroundColor(ACell, FBackgroundColor);
end;
procedure TsBackgroundColorDialogAction.DoAccept;
begin
FBackgroundColor := ColorToRgb(Dialog.Color);
inherited;
end;
procedure TsBackgroundColorDialogAction.DoBeforeExecute;
begin
inherited;
Dialog.Color := FBackgroundColor and $00FFFFFF;
end;
procedure TsBackgroundColorDialogAction.ExtractFromCell(ACell: PCell);
var
fmt: PsCellFormat;
begin
FBackgroundColor := scNotDefined;
if (ACell <> nil) then begin
fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex);
if (uffBackground in fmt^.UsedFormattingFields) then
begin
if fmt^.Background.Style = fsSolidFill then
FBackgroundColor := fmt^.Background.FgColor
else
FBackgroundColor := fmt^.Background.BgColor;
end;
end;
end;
function TsBackgroundColorDialogAction.GetDialog: TColorDialog;
begin
Result := TColorDialog(FDialog);
end;
function TsBackgroundColorDialogAction.GetDialogClass: TCommonDialogClass;
begin
Result := TColorDialog;
end;
end.