Componentes.Terceros.jvcl/official/3.32/run/JvDSADialogs.pas

2497 lines
84 KiB
ObjectPascal

{-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.
The Original Code is: JvDSADialogs.PAS, released on 2002-08-23.
The Initial Developer of the Original Code is Marcel Bestebroer [marcelb att zeelandnet dott nl]
Portions created by Marcel Bestebroer are Copyright (C) 2002 Marcel Bestebroer.
All Rights Reserved.
Contributor(s):
Steve Magruder
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
located at http://jvcl.sourceforge.net
Known Issues:
-----------------------------------------------------------------------------}
// $Id: JvDSADialogs.pas 11051 2006-11-27 22:26:43Z outchy $
unit JvDSADialogs;
{$I jvcl.inc}
interface
uses
{$IFDEF UNITVERSIONING}
JclUnitVersioning,
{$ENDIF UNITVERSIONING}
{$IFDEF MSWINDOWS}
Windows,
{$ENDIF MSWINDOWS}
{$IFDEF VisualCLX}
QWindows, QClipbrd,
{$ENDIF VisualCLX}
SysUtils, Classes, Contnrs, Graphics, Controls, Forms, StdCtrls, Dialogs,
ExtCtrls, JvComponent,
JvComponentBase, JvDynControlEngine, JvTypes;
type
TDlgCenterKind = (dckScreen, dckMainForm, dckActiveForm);
TDSAMessageForm = class(TJvForm)
private
FTimeout: Integer;
FTimer: TTimer;
FCountdown: TLabel;
protected
procedure CustomKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure CustomMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure CustomShow(Sender: TObject);
procedure HelpButtonClick(Sender: TObject);
procedure TimerEvent(Sender: TObject);
procedure WriteToClipboard(const Text: string);
function GetFormText: string;
class function TimeoutUnit(Count: Integer; Seconds: Boolean = True): string;
procedure CancelAutoClose;
public
constructor CreateNew(AOwner: TComponent; Dummy: Integer = 0); override;
function IsDSAChecked: Boolean;
property Timeout: Integer read FTimeout write FTimeout;
end;
//----------------------------------------------------------------------------
// DSA storage and registration classes, types, constants and exceptions
//----------------------------------------------------------------------------
type
TDSACheckTextKind = type Integer;
const
ctkShow = 0;
ctkAsk = 1;
ctkWarn = 2;
type
TDSAStorage = class;
TDSARegItem = record
ID: Integer;
Name: string;
Description: string;
Storage: TDSAStorage;
ChkTextKind: TDSACheckTextKind;
end;
TDSACustomData = procedure(const Storage: TDSAStorage; const DSAInfo: TDSARegItem) of object;
TDSAStorage = class(TObject)
private
FStates: TStack;
protected
procedure BeginCustomRead(const DSAInfo: TDSARegItem); virtual;
procedure BeginCustomWrite(const DSAInfo: TDSARegItem); virtual;
procedure BeginRead(const DSAInfo: TDSARegItem); virtual;
procedure BeginWrite(const DSAInfo: TDSARegItem); virtual;
procedure EndCustomRead(const DSAInfo: TDSARegItem); virtual;
procedure EndCustomWrite(const DSAInfo: TDSARegItem); virtual;
procedure EndRead(const DSAInfo: TDSARegItem); virtual;
procedure EndWrite(const DSAInfo: TDSARegItem); virtual;
function IsKeyNameAllowed(const Key: string): Boolean;
function GetCheckMarkTextSuffix: string; virtual; abstract;
procedure SetCheckMarkTextSuffix(const Value: string); virtual; abstract;
public
constructor Create;
destructor Destroy; override;
function GetState(const DSAInfo: TDSARegItem; out LastResult: Integer;
const OnCustomData: TDSACustomData = nil): Boolean; virtual;
function ReadBool(const DSAInfo: TDSARegItem; const Key: string): Boolean; virtual; abstract;
function ReadBoolDef(const DSAInfo: TDSARegItem; const Key: string;
const Default: Boolean): Boolean; virtual; abstract;
function ReadFloat(const DSAInfo: TDSARegItem; const Key: string): Extended; virtual; abstract;
function ReadFloatDef(const DSAInfo: TDSARegItem; const Key: string;
const Default: Extended): Extended; virtual; abstract;
function ReadInt64(const DSAInfo: TDSARegItem; const Key: string): Int64; virtual; abstract;
function ReadInt64Def(const DSAInfo: TDSARegItem; const Key: string;
const Default: Int64): Int64; virtual; abstract;
function ReadInteger(const DSAInfo: TDSARegItem; const Key: string): Integer; virtual; abstract;
function ReadIntegerDef(const DSAInfo: TDSARegItem; const Key: string;
const Default: Integer): Integer; virtual; abstract;
function ReadString(const DSAInfo: TDSARegItem; const Key: string): string; virtual; abstract;
function ReadStringDef(const DSAInfo: TDSARegItem; const Key: string;
const Default: string): string; virtual; abstract;
procedure SetState(const DSAInfo: TDSARegItem; const DontShowAgain: Boolean;
const LastResult: Integer; const OnCustomData: TDSACustomData = nil); virtual;
procedure WriteBool(const DSAInfo: TDSARegItem; const Key: string; const Value: Boolean); virtual; abstract;
procedure WriteFloat(const DSAInfo: TDSARegItem; const Key: string; const Value: Extended); virtual; abstract;
procedure WriteInt64(const DSAInfo: TDSARegItem; const Key: string; const Value: Int64); virtual; abstract;
procedure WriteInteger(const DSAInfo: TDSARegItem; const Key: string; const Value: Integer); virtual; abstract;
procedure WriteString(const DSAInfo: TDSARegItem; const Key: string; const Value: string); virtual; abstract;
property CheckMarkTextSuffix: string read GetCheckMarkTextSuffix;
end;
{$IFDEF MSWINDOWS}
TDSARegStorage = class(TDSAStorage)
private
FRootKey: HKEY;
FKey: string;
protected
procedure CreateKey(const DSAInfo: TDSARegItem); virtual;
function GetCheckMarkTextSuffix: string; override;
procedure SetCheckMarkTextSuffix(const Value: string); override;
public
constructor Create(const ARootKey: HKEY; const AKey: string);
function ReadBool(const DSAInfo: TDSARegItem; const Key: string): Boolean; override;
function ReadBoolDef(const DSAInfo: TDSARegItem; const Key: string; const Default: Boolean): Boolean; override;
function ReadFloat(const DSAInfo: TDSARegItem; const Key: string): Extended; override;
function ReadFloatDef(const DSAInfo: TDSARegItem; const Key: string; const Default: Extended): Extended; override;
function ReadInt64(const DSAInfo: TDSARegItem; const Key: string): Int64; override;
function ReadInt64Def(const DSAInfo: TDSARegItem; const Key: string; const Default: Int64): Int64; override;
function ReadInteger(const DSAInfo: TDSARegItem; const Key: string): Integer; override;
function ReadIntegerDef(const DSAInfo: TDSARegItem; const Key: string; const Default: Integer): Integer; override;
function ReadString(const DSAInfo: TDSARegItem; const Key: string): string; override;
function ReadStringDef(const DSAInfo: TDSARegItem; const Key: string; const Default: string): string; override;
procedure WriteBool(const DSAInfo: TDSARegItem; const Key: string; const Value: Boolean); override;
procedure WriteFloat(const DSAInfo: TDSARegItem; const Key: string; const Value: Extended); override;
procedure WriteInt64(const DSAInfo: TDSARegItem; const Key: string; const Value: Int64); override;
procedure WriteInteger(const DSAInfo: TDSARegItem; const Key: string; const Value: Integer); override;
procedure WriteString(const DSAInfo: TDSARegItem; const Key: string; const Value: string); override;
property RootKey: HKEY read FRootKey write FRootKey;
property Key: string read FKey write FKey;
end;
{$ENDIF MSWINDOWS}
TDSAQueueStorage = class(TDSAStorage)
private
FList: TStringList;
FCheckMarkSuffix: string;
protected
procedure AddDSA(const DSAInfo: TDSARegItem);
procedure DeleteDSA(const Index: Integer);
function FindDSA(const DSAInfo: TDSARegItem): Integer;
function GetCheckMarkTextSuffix: string; override;
function GetDSAValue(const DSAInfo: TDSARegItem; const Key: string; const Kind: Integer): string;
function HasDSAKey(const DSAInfo: TDSARegItem; const Key: string): Boolean;
procedure SetCheckMarkTextSuffix(const Value: string); override;
procedure SetDSAValue(const DSAInfo: TDSARegItem; const Key: string; const Kind: Integer; const Value: string);
public
constructor Create;
destructor Destroy; override;
procedure Clear;
function ReadBool(const DSAInfo: TDSARegItem; const Key: string): Boolean; override;
function ReadBoolDef(const DSAInfo: TDSARegItem; const Key: string; const Default: Boolean): Boolean; override;
function ReadFloat(const DSAInfo: TDSARegItem; const Key: string): Extended; override;
function ReadFloatDef(const DSAInfo: TDSARegItem; const Key: string; const Default: Extended): Extended; override;
function ReadInt64(const DSAInfo: TDSARegItem; const Key: string): Int64; override;
function ReadInt64Def(const DSAInfo: TDSARegItem; const Key: string; const Default: Int64): Int64; override;
function ReadInteger(const DSAInfo: TDSARegItem; const Key: string): Integer; override;
function ReadIntegerDef(const DSAInfo: TDSARegItem; const Key: string; const Default: Integer): Integer; override;
function ReadString(const DSAInfo: TDSARegItem; const Key: string): string; override;
function ReadStringDef(const DSAInfo: TDSARegItem; const Key: string; const Default: string): string; override;
procedure WriteBool(const DSAInfo: TDSARegItem; const Key: string; const Value: Boolean); override;
procedure WriteFloat(const DSAInfo: TDSARegItem; const Key: string; const Value: Extended); override;
procedure WriteInt64(const DSAInfo: TDSARegItem; const Key: string; const Value: Int64); override;
procedure WriteInteger(const DSAInfo: TDSARegItem; const Key: string; const Value: Integer); override;
procedure WriteString(const DSAInfo: TDSARegItem; const Key: string; const Value: string); override;
property CheckMarkTextSuffix: string read GetCheckMarkTextSuffix write SetCheckMarkTextSuffix;
end;
const
ssCustomRead: Pointer = @TDSAStorage.BeginCustomRead;
ssCustomWrite: Pointer = @TDSAStorage.BeginCustomWrite;
ssRead: Pointer = @TDSAStorage.BeginRead;
ssWrite: Pointer = @TDSAStorage.BeginWrite;
//--------------------------------------------------------------------------------------------------
// MessageDlg replacements and extensions
//--------------------------------------------------------------------------------------------------
// Additional values for DefaultButton, CancelButton and HelpButton parameters
const
mbNone = TMsgDlgBtn(-1);
mbDefault = TMsgDlgBtn(-2);
procedure ShowMessage(const Msg: string; const Center: TDlgCenterKind = dckScreen; const Timeout: Integer = 0;
const ADynControlEngine: TJvDynControlEngine = nil);
procedure ShowMessageFmt(const Msg: string; const Params: array of const; const Center: TDlgCenterKind = dckScreen;
const Timeout: Integer = 0; const ADynControlEngine: TJvDynControlEngine = nil);
function MessageDlg(const Msg: string; const DlgType: TMsgDlgType; const Buttons: TMsgDlgButtons;
const HelpCtx: Longint; const Center: TDlgCenterKind = dckScreen; const Timeout: Integer = 0;
const DefaultButton: TMsgDlgBtn = mbDefault; const CancelButton: TMsgDlgBtn = mbDefault;
const HelpButton: TMsgDlgBtn = mbHelp;
const ADynControlEngine: TJvDynControlEngine = nil): TModalResult; overload;
function MessageDlg(const Caption, Msg: string; const DlgType: TMsgDlgType; const Buttons: TMsgDlgButtons;
const HelpCtx: Longint; const Center: TDlgCenterKind = dckScreen; const Timeout: Integer = 0;
const DefaultButton: TMsgDlgBtn = mbDefault; const CancelButton: TMsgDlgBtn = mbDefault;
const HelpButton: TMsgDlgBtn = mbHelp;
const ADynControlEngine: TJvDynControlEngine = nil): TModalResult; overload;
function MessageDlg(const Caption, Msg: string; const Picture: TGraphic; const Buttons: TMsgDlgButtons;
const HelpCtx: Longint; const Center: TDlgCenterKind = dckScreen; const Timeout: Integer = 0;
const DefaultButton: TMsgDlgBtn = mbDefault; const CancelButton: TMsgDlgBtn = mbDefault;
const HelpButton: TMsgDlgBtn = mbHelp;
const ADynControlEngine: TJvDynControlEngine = nil): TModalResult; overload;
function MessageDlgEx(const Msg: string; const DlgType: TMsgDlgType; const Buttons: array of string;
const Results: array of Integer; const HelpCtx: Longint; const Center: TDlgCenterKind = dckScreen;
const Timeout: Integer = 0; const DefaultButton: Integer = 0; const CancelButton: Integer = 1;
const HelpButton: Integer = -1;
const ADynControlEngine: TJvDynControlEngine = nil): TModalResult; overload;
function MessageDlgEx(const Caption, Msg: string; const DlgType: TMsgDlgType; const Buttons: array of string;
const Results: array of Integer; const HelpCtx: Longint; const Center: TDlgCenterKind = dckScreen;
const Timeout: Integer = 0; const DefaultButton: Integer = 0; const CancelButton: Integer = 1;
const HelpButton: Integer = -1;
const ADynControlEngine: TJvDynControlEngine = nil): TModalResult; overload;
function MessageDlgEx(const Caption, Msg: string; const Picture: TGraphic; const Buttons: array of string;
const Results: array of Integer; const HelpCtx: Longint; const Center: TDlgCenterKind = dckScreen;
const Timeout: Integer = 0; const DefaultButton: Integer = 0; const CancelButton: Integer = 1;
const HelpButton: Integer = -1;
const ADynControlEngine: TJvDynControlEngine = nil): TModalResult; overload;
//--------------------------------------------------------------------------------------------------
// "Don't Show Again" (DSA) dialogs
//--------------------------------------------------------------------------------------------------
procedure DSAShowMessage(const DlgID: Integer; const Msg: string; const Center: TDlgCenterKind = dckScreen;
const Timeout: Integer = 0; const ADynControlEngine: TJvDynControlEngine = nil);
procedure DSAShowMessageFmt(const DlgID: Integer; const Msg: string; const Params: array of const;
const Center: TDlgCenterKind = dckScreen; const Timeout: Integer = 0;
const ADynControlEngine: TJvDynControlEngine = nil);
function DSAMessageDlg(const DlgID: Integer; const Msg: string; const DlgType: TMsgDlgType;
const Buttons: TMsgDlgButtons; const HelpCtx: Longint; const Center: TDlgCenterKind = dckScreen;
const Timeout: Integer = 0; const DefaultButton: TMsgDlgBtn = mbDefault;
const CancelButton: TMsgDlgBtn = mbDefault; const HelpButton: TMsgDlgBtn = mbHelp;
const ADynControlEngine: TJvDynControlEngine = nil): TModalResult; overload;
function DSAMessageDlg(const DlgID: Integer; const Caption, Msg: string; const DlgType: TMsgDlgType;
const Buttons: TMsgDlgButtons; const HelpCtx: Longint; const Center: TDlgCenterKind = dckScreen;
const Timeout: Integer = 0; const DefaultButton: TMsgDlgBtn = mbDefault;
const CancelButton: TMsgDlgBtn = mbDefault; const HelpButton: TMsgDlgBtn = mbHelp;
const ADynControlEngine: TJvDynControlEngine = nil): TModalResult; overload;
function DSAMessageDlg(const DlgID: Integer; const Caption, Msg: string; const Picture: TGraphic;
const Buttons: TMsgDlgButtons; const HelpCtx: Longint; const Center: TDlgCenterKind = dckScreen;
const Timeout: Integer = 0; const DefaultButton: TMsgDlgBtn = mbDefault;
const CancelButton: TMsgDlgBtn = mbDefault; const HelpButton: TMsgDlgBtn = mbHelp;
const ADynControlEngine: TJvDynControlEngine = nil): TModalResult; overload;
function DSAMessageDlgEx(const DlgID: Integer; const Msg: string; const DlgType: TMsgDlgType;
const Buttons: array of string; const Results: array of Integer; const HelpCtx: Longint;
const Center: TDlgCenterKind = dckScreen; const Timeout: Integer = 0;
const DefaultButton: Integer = 0; const CancelButton: Integer = 1; const HelpButton: Integer = -1;
const ADynControlEngine: TJvDynControlEngine = nil): Integer; overload;
function DSAMessageDlgEx(const DlgID: Integer; const Caption, Msg: string; const DlgType: TMsgDlgType;
const Buttons: array of string; const Results: array of Integer; const HelpCtx: Longint;
const Center: TDlgCenterKind = dckScreen; const Timeout: Integer = 0; const DefaultButton: Integer = 0;
const CancelButton: Integer = 1; const HelpButton: Integer = -1;
const ADynControlEngine: TJvDynControlEngine = nil): TModalResult; overload;
function DSAMessageDlgEx(const DlgID: Integer; const Caption, Msg: string; const Picture: TGraphic;
const Buttons: array of string; const Results: array of Integer; const HelpCtx: Longint;
const Center: TDlgCenterKind = dckScreen; const Timeout: Integer = 0; const DefaultButton: Integer = 0;
const CancelButton: Integer = 1; const HelpButton: Integer = -1;
const ADynControlEngine: TJvDynControlEngine = nil): Integer; overload;
//----------------------------------------------------------------------------
// Generic DSA dialog
//----------------------------------------------------------------------------
function CreateDSAMessageForm(const ACaption, Msg: string; const APicture: TGraphic;
const Buttons: array of string; const Results: array of Integer; const HelpCtx: Integer;
const CheckCaption: string; const Center: TDlgCenterKind = dckScreen;
const ATimeout: Integer = 0; const DefaultButton: Integer = 0; const CancelButton: Integer = 1;
HelpButton: Integer = -1; const ADynControlEngine: TJvDynControlEngine = nil): TDSAMessageForm;
//----------------------------------------------------------------------------
// DSA registration
//----------------------------------------------------------------------------
procedure RegisterDSA(const DlgID: Integer; const Name, Description: string;
const Storage: TDSAStorage; const CheckTextKind: TDSACheckTextKind = ctkShow);
procedure UnregisterDSA(const DlgID: Integer);
function LocateDSAReg(const DlgID: Integer): TDSARegItem;
//----------------------------------------------------------------------------
// DSA state setting/retrieving
//----------------------------------------------------------------------------
function GetDSAState(const DlgID: Integer): Boolean; overload;
function GetDSAState(const DlgID: Integer; out ResCode: Integer;
const OnCustomData: TDSACustomData = nil): Boolean; overload;
procedure SetDSAState(const DlgID: Integer; const DontShowAgain: Boolean;
const LastResult: Integer = mrNone; const OnCustomData: TDSACustomData = nil);
//----------------------------------------------------------------------------
// Iterating the DSA registration
//----------------------------------------------------------------------------
function DSACount: Integer;
function DSAItem(const Index: Integer): TDSARegItem;
//----------------------------------------------------------------------------
// DSA check box text registration
//----------------------------------------------------------------------------
procedure RegisterDSACheckMarkText(const ID: TDSACheckTextKind; const Text: string);
procedure UnregisterDSACheckMarkText(const ID: TDSACheckTextKind);
function GetDSACheckMarkText(const ID: TDSACheckTextKind): string;
//----------------------------------------------------------------------------
// Standard DSA storage devices
//----------------------------------------------------------------------------
{$IFDEF MSWINDOWS}
function DSARegStore: TDSARegStorage;
{$ENDIF MSWINDOWS}
function DSAQueueStore: TDSAQueueStorage;
//----------------------------------------------------------------------------
// DSA time formatting function.
// Returns a string representing the number of seconds.
// Standard function returns this:
// "(Secs) sec" if Secs is lower than 60
// "(Secs div 60) min (Secs mod 60) sec" if Secs is greater or equal to 60
// The min and sec constants are taken from resource strings in JvResources.
//----------------------------------------------------------------------------
type
TJvDSATimeFormatter = function(Secs: Integer) : string;
procedure SetDSATimeFormatter(const ATimeFormatter: TJvDSATimeFormatter);
function StandardDSATimeFormatter(Secs: Integer) : string;
//----------------------------------------------------------------------------
// VCL component
//----------------------------------------------------------------------------
type
EJvDSADialog = class(EJVCLException);
TJvDSADataEvent = procedure(Sender: TObject; const DSAInfo: TDSARegItem; const Storage: TDSAStorage) of object;
TJvDSAAutoCloseEvent = procedure(Sender: TObject; var Handled: Boolean) of object;
TJvDSADialog = class(TJvComponent)
private
FCheckControl: TWinControl;
FDialogID: Integer;
FIgnoreDSAChkMrkTxt: Boolean;
FOnUpdateKeys: TJvDSADataEvent;
FOnApplyKeys: TJvDSADataEvent;
FOrgOwner: TComponent;
FOrgShowModalPtr: Pointer;
FTimeout: Integer;
FTimer: TTimer;
FTimerCount: Integer;
FOnCountdown: TNotifyEvent;
FOnAutoClose: TJvDSAAutoCloseEvent;
protected
procedure AutoClose;
procedure AfterShow; virtual;
procedure ApplySavedState; virtual;
procedure BeforeShow; virtual;
procedure DoApplyKeys(const Storage: TDSAStorage; const DSAInfo: TDSARegItem); virtual;
function DoAutoClose: Boolean;
procedure DoCountDown;
procedure DoUpdateKeys(const Storage: TDSAStorage; const DSAInfo: TDSARegItem); virtual;
function GetDSAStateInternal(out ModalResult: Integer): Boolean;
function GetOrgOwner: TComponent;
function GetOrgShowModalPtr: Pointer;
function GetStorage: TDSAStorage;
procedure FormPatch;
procedure FormUnPatch;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure SetCheckControl(Value: TWinControl); virtual;
procedure SetDialogID(Value: Integer); virtual;
procedure SetOrgOwner(Value: TComponent);
procedure SetOrgShowModalPtr(Value: Pointer);
procedure TimerEvent(Sender: TObject);
procedure UpdateDSAState; virtual;
property OrgOwner: TComponent read GetOrgOwner write SetOrgOwner;
property OrgShowModalPtr: Pointer read GetOrgShowModalPtr write SetOrgShowModalPtr;
property Storage: TDSAStorage read GetStorage;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function GetModalResult: Integer; virtual;
function IsDSAChecked: Boolean; virtual;
procedure Loaded; override;
procedure CancelCountdown; virtual;
function SecondsLeft: Integer;
published
property Timeout: Integer read FTimeout write FTimeout;
property CheckControl: TWinControl read FCheckControl write SetCheckControl;
property DialogID: Integer read FDialogID write SetDialogID;
property IgnoreDSAChkMrkTxt: Boolean read FIgnoreDSAChkMrkTxt write FIgnoreDSAChkMrkTxt;
property OnApplyKeys: TJvDSADataEvent read FOnApplyKeys write FOnApplyKeys;
property OnUpdateKeys: TJvDSADataEvent read FOnUpdateKeys write FOnUpdateKeys;
property OnCountdown: TNotifyEvent read FOnCountdown write FOnCountdown;
property OnAutoClose: TJvDSAAutoCloseEvent read FOnAutoClose write FOnAutoClose;
end;
{$IFDEF UNITVERSIONING}
const
UnitVersioning: TUnitVersionInfo = (
RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/tags/JVCL3_32/run/JvDSADialogs.pas $';
Revision: '$Revision: 11051 $';
Date: '$Date: 2006-11-27 23:26:43 +0100 (lun., 27 nov. 2006) $';
LogPath: 'JVCL\run'
);
{$ENDIF UNITVERSIONING}
implementation
uses
Consts, Math, TypInfo,
{$IFDEF MSWINDOWS}
JclRegistry,
{$ENDIF MSWINDOWS}
JclBase, JclSysUtils,
JvDynControlEngineIntf, JvConsts, JvResources;
const
cDSAStateValueName = 'DSA_State'; // do not localize
cDSAStateLastResultName = 'LastResult'; // do not localize
type
PBoolean = ^Boolean;
var
TimeFormatter: TJvDSATimeFormatter = StandardDSATimeFormatter;
procedure SetDSATimeFormatter(const ATimeFormatter: TJvDSATimeFormatter);
begin
TimeFormatter := ATimeFormatter
end;
function StandardDSATimeFormatter(Secs: Integer) : string;
var
Mins: Integer;
TimeStr: string;
begin
Mins := Secs div 60;
Secs := Secs mod 60;
if Mins <> 0 then
TimeStr := Format('%d %s %d %s', [Mins, TDSAMessageForm.TimeoutUnit(Mins, False),
Secs, TDSAMessageForm.TimeoutUnit(Secs)])
else
TimeStr := Format('%d %s', [Secs, TDSAMessageForm.TimeoutUnit(Secs)]);
Result := Format(RsCntdownText, [TimeStr]);
end;
//=== CheckMarkTexts =========================================================
var
GlobalCheckMarkTexts: TStringList = nil;
function CheckMarkTexts: TStrings;
begin
if GlobalCheckMarkTexts = nil then
GlobalCheckMarkTexts := TStringList.Create;
Result := GlobalCheckMarkTexts;
end;
function GetCheckMarkText(const ID: TDSACheckTextKind): string;
var
Idx: Integer;
begin
Idx := CheckMarkTexts.IndexOfObject(TObject(ID));
if Idx > -1 then
Result := CheckMarkTexts[Idx]
else
Result := '';
end;
//=== { TDSAMessageForm } ====================================================
constructor TDSAMessageForm.CreateNew(AOwner: TComponent; Dummy: Integer);
{$IFDEF VCL}
var
NonClientMetrics: TNonClientMetrics;
{$ENDIF VCL}
begin
inherited CreateNew(AOwner, Dummy);
{$IFDEF VCL}
NonClientMetrics.cbSize := SizeOf(NonClientMetrics);
if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NonClientMetrics, 0) then
Font.Handle := CreateFontIndirect(NonClientMetrics.lfMessageFont);
{$ENDIF VCL}
FTimer := TTimer.Create(Self);
FTimer.Enabled := False;
FTimer.Interval := 1000;
FTimer.OnTimer := TimerEvent;
end;
procedure TDSAMessageForm.CustomKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
CancelAutoClose;
if (Shift = [ssCtrl]) and (Key = Word('C')) then
begin
// (rom) deactivated annoying
// SysUtils.Beep;
WriteToClipboard(GetFormText);
end;
end;
procedure TDSAMessageForm.CustomMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
CancelAutoClose;
end;
procedure TDSAMessageForm.CustomShow(Sender: TObject);
var
I: Integer;
begin
if Timeout <> 0 then
FTimer.Enabled := True;
for I := 0 to ComponentCount - 1 do
begin
if (Components[I] is TButton) and (Components[I] as TButton).Default then
begin
(Components[I] as TButton).SetFocus;
Break;
end;
end;
FCountdown := TLabel(FindComponent('Countdown'));
end;
procedure TDSAMessageForm.HelpButtonClick(Sender: TObject);
begin
CancelAutoClose;
{$IFDEF VCL}
Application.HelpContext(HelpContext);
{$ENDIF VCL}
{$IFDEF VisualCLX}
Application.ContextHelp(HelpContext);
{$ENDIF VisualCLX}
end;
procedure TDSAMessageForm.TimerEvent(Sender: TObject);
var
I: Integer;
begin
if FTimer.Enabled then
begin
Dec(FTimeout);
if FTimeout = 0 then
begin
FTimer.Enabled := False;
for I := 0 to ComponentCount - 1 do
begin
if (Components[I] is TButton) and (Components[I] as TButton).Default then
begin
(Components[I] as TButton).Click;
Exit;
end;
end;
// No default button found; just close the form
Close;
end
else
if FCountdown <> nil then
FCountdown.Caption := TimeFormatter(Timeout);
end;
end;
{$IFDEF VCL}
procedure TDSAMessageForm.WriteToClipboard(const Text: string);
var
Data: THandle;
DataPtr: Pointer;
begin
if OpenClipboard(0) then
begin
try
Data := GlobalAlloc(GMEM_MOVEABLE + GMEM_DDESHARE, Length(Text) + 1);
try
DataPtr := GlobalLock(Data);
try
Move(PChar(Text)^, DataPtr^, Length(Text) + 1);
EmptyClipboard;
SetClipboardData(CF_TEXT, Data);
finally
GlobalUnlock(Data);
end;
except
GlobalFree(Data);
raise;
end;
finally
CloseClipboard;
end;
end
else
raise EJVCLException.CreateRes(@SCannotOpenClipboard);
end;
{$ENDIF VCL}
{$IFDEF VisualCLX}
procedure TDSAMessageForm.WriteToClipboard(const Text: string);
begin
Clipboard.AsText := Text;
end;
{$ENDIF VisualCLX}
function TDSAMessageForm.GetFormText: string;
var
DividerLine, ButtonCaptions: string;
I: Integer;
begin
DividerLine := StringOfChar('-', 27) + CrLf;
for I := 0 to ComponentCount - 1 do
if Components[I] is TButton then
ButtonCaptions := ButtonCaptions + TButton(Components[I]).Caption + StringOfChar(' ', 3);
ButtonCaptions := StringReplace(ButtonCaptions, '&', '', [rfReplaceAll]);
I := ComponentCount - 1;
while (I > -1) and not (Components[I] is TLabel) do
Dec(I);
Result := Format('%s%s%s%s%s%s%s%s%s%s', [DividerLine, Caption, CrLf, DividerLine,
TLabel(Components[I]).Caption, CrLf, DividerLine, ButtonCaptions, CrLf, DividerLine]);
end;
class function TDSAMessageForm.TimeoutUnit(Count: Integer; Seconds: Boolean): string;
begin
if Seconds then
if Count <> 1 then
Result := RsCntdownSecsText
else
Result := RsCntdownSecText
else
if Count <> 1 then
Result := RsCntdownMinsText
else
Result := RsCntdownMinText;
end;
procedure TDSAMessageForm.CancelAutoClose;
begin
FTimer.Enabled := False;
FreeAndNil(FCountdown);
end;
function TDSAMessageForm.IsDSAChecked: Boolean;
var
I: Integer;
begin
I := ComponentCount - 1;
while (I > -1) and not (Components[I] is TCustomCheckBox) do
Dec(I);
if (I > -1) then
Result := TCheckBox(Components[I]).Checked
else
Result := False;
end;
function GetAveCharSize(Canvas: TCanvas): TPoint;
var
I: Integer;
Buffer: array [0..51] of Char;
begin
for I := 0 to 25 do
Buffer[I] := Chr(I + Ord('A'));
for I := 0 to 25 do
Buffer[I + 26] := Chr(I + Ord('a'));
GetTextExtentPoint32(Canvas.Handle, Buffer, 52, TSize(Result));
Result.X := Result.X div 52;
end;
function CreateDSAMessageForm(const ACaption, Msg: string; const APicture: TGraphic;
const Buttons: array of string; const Results: array of Integer; const HelpCtx: Integer;
const CheckCaption: string; const Center: TDlgCenterKind = dckScreen;
const ATimeout: Integer = 0; const DefaultButton: Integer = 0;
const CancelButton: Integer = 1; HelpButton: Integer = -1;
const ADynControlEngine: TJvDynControlEngine = nil): TDSAMessageForm;
const
mcHorzMargin = 8;
mcVertMargin = 8;
mcHorzSpacing = 10;
mcVertSpacing = 10;
mcButtonWidth = 50;
mcButtonHeight = 14;
mcButtonSpacing = 4;
var
DialogUnits: TPoint;
HorzMargin, VertMargin, HorzSpacing, VertSpacing, ButtonWidth: Integer;
ButtonHeight, ButtonSpacing, ButtonCount, ButtonGroupWidth: Integer;
IconTextWidth, IconTextHeight, X, ALeft: Integer;
ChkTextWidth: Integer;
TimeoutTextWidth: Integer;
IconID: PChar;
TempRect, TextRect: TRect;
I: Integer;
CenterParent: TComponent;
CenterParLeft, CenterParTop, CenterParWidth, CenterParHeight: Integer;
DynControlEngine: TJvDynControlEngine;
CountDownlabel, MessageLabel: TControl;
Image: TWinControl;
DynControlImage: IJvDynControlImage;
DynControlLabel: IJvDynControlLabel;
DynControlAutoSize: IJvDynControlAutoSize;
Panel: TWinControl;
begin
if Assigned(ADynControlEngine) then
DynControlEngine := ADynControlEngine
else
DynControlEngine := DefaultDynControlEngine;
case Center of
dckScreen:
CenterParent := Screen;
dckMainForm:
CenterParent := Application.MainForm;
dckActiveForm:
CenterParent := Screen.ActiveCustomForm;
else
CenterParent := nil;
end;
if CenterParent = nil then
CenterParent := Screen;
if CenterParent is TScreen then
begin
CenterParLeft := 0;
CenterParTop := 0;
CenterParWidth := TScreen(CenterParent).Width;
CenterParHeight := TScreen(CenterParent).Height;
end
else
begin
with TWinControl(CenterParent) do
begin
CenterParLeft := Left;
CenterParTop := Top;
CenterParWidth := Width;
CenterParHeight := Height;
end;
end;
if HelpButton = High(Integer) then
HelpButton := High(Buttons);
Result := TDSAMessageForm.CreateNew(Screen.ActiveCustomForm);
try
with Result do
begin
Position := poDesigned; // Delphi 2005 has a new default
{$IFDEF VCL}
BiDiMode := Application.BiDiMode;
BorderStyle := bsDialog;
{$ENDIF VCL}
{$IFDEF VisualCLX}
BorderStyle := fbsDialog;
{$ENDIF VisualCLX}
Canvas.Font := Font;
KeyPreview := True;
OnKeyDown := CustomKeyDown;
OnShow := CustomShow;
OnMouseDown := CustomMouseDown;
DialogUnits := GetAveCharSize(Canvas);
HorzMargin := MulDiv(mcHorzMargin, DialogUnits.X, 4);
VertMargin := MulDiv(mcVertMargin, DialogUnits.Y, 8);
HorzSpacing := MulDiv(mcHorzSpacing, DialogUnits.X, 4);
VertSpacing := MulDiv(mcVertSpacing, DialogUnits.Y, 8);
ButtonWidth := MulDiv(mcButtonWidth, DialogUnits.X, 4);
Timeout := Abs(ATimeout);
for I := Low(Buttons) to High(Buttons) do
begin
TextRect := Rect(0, 0, 0, 0);
{Windows.}DrawText(Canvas.Handle, PChar(Buttons[I]), -1, TextRect,
DT_CALCRECT or DT_LEFT or DT_SINGLELINE or DrawTextBiDiModeFlagsReadingOnly);
with TextRect do
if (Right - Left + 8) > ButtonWidth then
ButtonWidth := (Right - Left + 8);
end;
ButtonHeight := MulDiv(mcButtonHeight, DialogUnits.Y, 8);
ButtonSpacing := MulDiv(mcButtonSpacing, DialogUnits.X, 4);
if (Screen.Width div 2) > (CenterParWidth + (2 * CenterParLeft)) then
SetRect(TextRect, 0, 0, CenterParWidth + (2 * CenterParLeft), 0)
else
SetRect(TextRect, 0, 0, Screen.Width div 2, 0);
{$IFDEF VCL}
DrawText(Canvas.Handle, PChar(Msg), Length(Msg) + 1, TextRect,
DT_EXPANDTABS or DT_CALCRECT or DT_WORDBREAK or DrawTextBiDiModeFlagsReadingOnly);
{$ENDIF VCL}
{$IFDEF VisualCLX}
DrawText(Canvas, Msg, Length(Msg) + 1, TextRect,
DT_EXPANDTABS or DT_CALCRECT or DT_WORDBREAK or DrawTextBiDiModeFlagsReadingOnly);
{$ENDIF VisualCLX}
IconTextWidth := TextRect.Right;
IconTextHeight := TextRect.Bottom;
if CheckCaption <> '' then
begin
SetRect(TempRect, 0, 0, Screen.Width div 2, 0);
{$IFDEF VCL}
DrawText(Canvas.Handle, PChar(CheckCaption), Length(CheckCaption) + 1, TempRect,
DT_EXPANDTABS or DT_CALCRECT or DT_WORDBREAK or DrawTextBiDiModeFlagsReadingOnly);
{$ENDIF VCL}
{$IFDEF VisualCLX}
DrawText(Canvas, CheckCaption, Length(CheckCaption) + 1, TempRect,
DT_EXPANDTABS or DT_CALCRECT or DT_WORDBREAK or DrawTextBiDiModeFlagsReadingOnly);
{$ENDIF VisualCLX}
ChkTextWidth := TempRect.Right;
end
else
ChkTextWidth := 0;
if ATimeout > 0 then
begin
SetRect(TempRect, 0, 0, Screen.Width div 2, 0);
{$IFDEF VCL}
DrawText(Canvas.Handle, PChar(TimeFormatter(Timeout)),
Length(TimeFormatter(Timeout)) + 1, TempRect,
DT_EXPANDTABS or DT_CALCRECT or DT_WORDBREAK or DrawTextBiDiModeFlagsReadingOnly);
{$ENDIF VCL}
{$IFDEF VisualCLX}
DrawText(Canvas, TimeFormatter(Timeout),
Length(TimeFormatter(Timeout)) + 1, TempRect,
DT_EXPANDTABS or DT_CALCRECT or DT_WORDBREAK or DrawTextBiDiModeFlagsReadingOnly);
{$ENDIF VisualCLX}
TimeoutTextWidth := TempRect.Right;
end
else
TimeoutTextWidth := 0;
if APicture <> nil then
begin
Inc(IconTextWidth, APicture.Width + HorzSpacing);
if IconTextHeight < APicture.Height then
IconTextHeight := APicture.Height;
end;
ButtonCount := Length(Buttons);
ButtonGroupWidth := 0;
if ButtonCount <> 0 then
ButtonGroupWidth := ButtonWidth * ButtonCount + ButtonSpacing * (ButtonCount - 1);
ClientWidth := Max(TimeoutTextWidth, Max(17 + ChkTextWidth, Max(IconTextWidth, ButtonGroupWidth))) + HorzMargin *
2;
ClientHeight := IconTextHeight + ButtonHeight + VertSpacing * 2 + VertMargin;
if CheckCaption <> '' then
Result.ClientHeight := Result.ClientHeight + VertMargin + 17;
if ATimeout > 0 then
Result.ClientHeight := Result.ClientHeight + VertMargin + 13;
Left := (CenterParWidth div 2) - (Width div 2) + CenterParLeft;
Top := (CenterParHeight div 2) - (Height div 2) + CenterParTop;
if ACaption <> '' then
Caption := ACaption
else
Caption := Application.Title;
Panel := DynControlEngine.CreatePanelControl(Result, Result, 'Panel', '', alClient);
if APicture <> nil then
begin
Image := DynControlEngine.CreateImageControl(Result, Panel, 'Image');
if Supports(Image, IJvDynControlImage, DynControlImage) then
begin
DynControlImage.ControlSetGraphic(APicture);
DynControlImage.ControlSetCenter(True);
end;
Image.SetBounds(HorzMargin - 2, VertMargin - 2, APicture.Width + 4, APicture.Height + 4);
end;
MessageLabel := DynControlEngine.CreateLabelControl(Result, Panel, 'Message', Msg, nil);
if Supports(MessageLabel, IJvDynControlAutoSize, DynControlAutoSize) then
DynControlAutoSize.ControlSetAutoSize(True);
if Supports(MessageLabel, IJvDynControlLabel, DynControlLabel) then
DynControlLabel.ControlSetWordWrap(True);
with MessageLabel do
begin
BoundsRect := TextRect;
{$IFDEF VCL}
BiDiMode := Result.BiDiMode;
{$ENDIF VCL}
ALeft := IconTextWidth - TextRect.Right + HorzMargin;
if UseRightToLeftAlignment then
ALeft := Result.ClientWidth - ALeft - Width;
SetBounds(ALeft, VertMargin,
TextRect.Right, TextRect.Bottom);
end;
X := (ClientWidth - ButtonGroupWidth) div 2;
for I := Low(Buttons) to High(Buttons) do
begin
with DynControlEngine.CreateButton(Result, Panel, 'Button' + IntToStr(I), Buttons[I], '', nil, False, False) do
begin
ModalResult := Results[I];
if I = DefaultButton then
Default := True;
if I = CancelButton then
Cancel := True;
SetBounds(X, IconTextHeight + VertMargin + VertSpacing, ButtonWidth, ButtonHeight);
Inc(X, ButtonWidth + ButtonSpacing);
if I = HelpButton then
OnClick := HelpButtonClick;
end;
end;
if CheckCaption <> '' then
with DynControlEngine.CreateCheckboxControl(Result, Panel, 'DontShowAgain', CheckCaption) do
begin
{$IFDEF VCL}
BiDiMode := Result.BiDiMode;
{$ENDIF VCL}
SetBounds(HorzMargin, IconTextHeight + VertMargin + VertSpacing * 2 + ButtonHeight,
Result.ClientWidth - 2 * HorzMargin, Height);
end;
if ATimeout > 0 then
begin
CountDownlabel := DynControlEngine.CreateLabelControl(Result, Panel, 'Countdown',
TimeFormatter(Timeout), nil);
with CountDownlabel do
begin
{$IFDEF VCL}
BiDiMode := Result.BiDiMode;
{$ENDIF VCL}
if CheckCaption = '' then
SetBounds(HorzMargin, IconTextHeight + VertMargin + VertSpacing * 2 + ButtonHeight,
Result.ClientWidth - 2 * HorzMargin, Height)
else
SetBounds(HorzMargin, IconTextHeight + 2 * VertMargin + VertSpacing * 2 + ButtonHeight + 17,
Result.ClientWidth - 2 * HorzMargin, Height);
end;
end;
end;
except
Result.Free;
raise;
end;
end;
//=== { TDSARegister } =======================================================
type
TAddResult = (arAdded, arExists, arDuplicateID, arDuplicateName);
TDSARegister = class
private
FList: array of TDSARegItem;
protected
function AddNew: Integer;
procedure Remove(const Index: Integer);
function IndexOf(const ID: Integer): Integer; overload;
function IndexOf(const Name: string): Integer; overload;
function IndexOf(const Item: TDSARegItem): Integer; overload;
public
destructor Destroy; override;
function Add(const Item: TDSARegItem): TAddResult; overload;
function Add(const ID: Integer; const Name, Description: string;
const Storage: TDSAStorage; const CheckTextKind:
TDSACheckTextKind = ctkShow): TAddResult; overload;
procedure Clear;
// procedure Delete(const Item: TDSARegItem); overload;
procedure Delete(const ID: Integer); overload;
// procedure Delete(const Name: string); overload;
function Locate(const ID: Integer): TDSARegItem; overload;
// function Locate(const Name: string): TDSARegItem; overload;
end;
const
EmptyItem: TDSARegItem = (ID: High(Integer); Name: ''; Storage: nil);
var
GlobalDSARegister: TDSARegister = nil;
function DSARegister: TDSARegister;
begin
if not Assigned(GlobalDSARegister) then
begin
GlobalDSARegister := TDSARegister.Create;
// register
RegisterDSACheckMarkText(ctkShow, RsDSActkShowText);
RegisterDSACheckMarkText(ctkAsk, RsDSActkAskText);
RegisterDSACheckMarkText(ctkWarn, RsDSActkWarnText);
end;
Result := GlobalDSARegister;
end;
destructor TDSARegister.Destroy;
begin
inherited Destroy;
Clear;
end;
function TDSARegister.AddNew: Integer;
begin
Result := Length(FList);
SetLength(FList, Result + 1);
end;
procedure TDSARegister.Remove(const Index: Integer);
var
I: Integer;
begin
for I := Index + 1 to High(FList) do
begin
FList[I-1].ID := FList[I].ID;
FList[I-1].Name := FList[I].Name;
FList[I-1].Description := FList[I].Description;
FList[I-1].ChkTextKind := FList[I].ChkTextKind;
FList[I-1].Storage := FList[I].Storage;
end;
SetLength(FList, High(FList));
end;
function TDSARegister.IndexOf(const ID: Integer): Integer;
begin
Result := High(FList);
while (Result > -1) and (FList[Result].ID <> ID) do
Dec(Result);
end;
function TDSARegister.IndexOf(const Name: string): Integer;
begin
Result := High(FList);
while (Result > -1) and not AnsiSameText(FList[Result].Name, Name) do
Dec(Result);
end;
function TDSARegister.IndexOf(const Item: TDSARegItem): Integer;
begin
Result := IndexOf(Item.ID);
if (Result > -1) and not AnsiSameText(FList[Result].Name, Item.Name) then
Result := -1;
end;
function TDSARegister.Add(const Item: TDSARegItem): TAddResult;
var
Idx: Integer;
begin
if IndexOf(Item) > -1 then
Result := arExists
else
if IndexOf(Item.ID) > -1 then
begin
Idx := IndexOf(Item.ID);
if AnsiSameText(FList[Idx].Name, Item.Name) then
Result := arExists
else
Result := arDuplicateID;
end
else
if IndexOf(Item.Name) > -1 then
Result := arDuplicateName
else
begin
Idx := AddNew;
FList[Idx].ID := Item.ID;
FList[Idx].Name := Item.Name;
FList[Idx].Description := Item.Description;
FList[Idx].Storage := Item.Storage;
FList[Idx].ChkTextKind := Item.ChkTextKind;
Result := arAdded;
end;
end;
function TDSARegister.Add(const ID: Integer; const Name, Description: string;
const Storage: TDSAStorage; const CheckTextKind: TDSACheckTextKind = ctkShow): TAddResult;
var
TmpItem: TDSARegItem;
begin
TmpItem.ID := ID;
TmpItem.Name := Name;
TmpItem.Description := Description;
TmpItem.Storage := Storage;
TmpItem.ChkTextKind := CheckTextKind;
Result := Add(TmpItem);
end;
procedure TDSARegister.Clear;
begin
SetLength(FList, 0);
end;
(* make Delphi 5 compiler happy // andreas
procedure TDSARegister.Delete(const Item: TDSARegItem);
var
Idx: Integer;
begin
Idx := IndexOf(Item.ID);
if (Idx > -1) and AnsiSameText(FList[Idx].Name, Item.Name) then
Remove(Idx);
end;
*)
procedure TDSARegister.Delete(const ID: Integer);
var
Idx: Integer;
begin
Idx := IndexOf(ID);
if Idx > -1 then
Remove(Idx);
end;
(* make Delphi 5 compiler happy // andreas
procedure TDSARegister.Delete(const Name: string);
var
Idx: Integer;
begin
Idx := IndexOf(Name);
if Idx > -1 then
Remove(Idx);
end;
*)
function TDSARegister.Locate(const ID: Integer): TDSARegItem;
var
Idx: Integer;
begin
Idx := IndexOf(ID);
if Idx > -1 then
Result := FList[Idx]
else
Result := EmptyItem;
end;
(* make Delphi 5 compiler happy // andreas
function TDSARegister.Locate(const Name: string): TDSARegItem;
var
Idx: Integer;
begin
Idx := IndexOf(Name);
if Idx > -1 then
Result := FList[Idx]
else
Result := EmptyItem;
end;
*)
//=== { TDSAStorage } ========================================================
constructor TDSAStorage.Create;
begin
inherited Create;
FStates := TStack.Create;
end;
destructor TDSAStorage.Destroy;
begin
FStates.Free;
inherited Create;
end;
procedure TDSAStorage.BeginCustomRead(const DSAInfo: TDSARegItem);
begin
FStates.Push(ssCustomRead);
end;
procedure TDSAStorage.BeginCustomWrite(const DSAInfo: TDSARegItem);
begin
FStates.Push(ssCustomWrite);
end;
procedure TDSAStorage.BeginRead(const DSAInfo: TDSARegItem);
begin
FStates.Push(ssRead);
end;
procedure TDSAStorage.BeginWrite(const DSAInfo: TDSARegItem);
begin
FStates.Push(ssWrite);
end;
procedure TDSAStorage.EndCustomRead(const DSAInfo: TDSARegItem);
begin
if FStates.Peek <> ssCustomRead then
raise EJvDSADialog.CreateRes(@RsECannotEndCustomReadIfNotInCustomRea);
FStates.Pop;
end;
procedure TDSAStorage.EndCustomWrite(const DSAInfo: TDSARegItem);
begin
if FStates.Peek <> ssCustomWrite then
raise EJvDSADialog.CreateRes(@RsECannotEndCustomWriteIfNotInCustomWr);
FStates.Pop;
end;
procedure TDSAStorage.EndRead(const DSAInfo: TDSARegItem);
begin
if FStates.Peek <> ssRead then
raise EJvDSADialog.CreateRes(@RsECannotEndReadIfNotInReadMode);
FStates.Pop;
end;
procedure TDSAStorage.EndWrite(const DSAInfo: TDSARegItem);
begin
if FStates.Peek <> ssWrite then
raise EJvDSADialog.CreateRes(@RsECannotEndWriteIfNotInWriteMode);
FStates.Pop;
end;
function TDSAStorage.IsKeyNameAllowed(const Key: string): Boolean;
begin
if AnsiSameText(Key, cDSAStateValueName) or AnsiSameText(Key, cDSAStateLastResultName) then
Result := Integer(FStates.Peek) in [Integer(ssRead), Integer(ssWrite)]
else
Result := Integer(FStates.Peek) in [Integer(ssCustomRead), Integer(ssCustomWrite)];
end;
function TDSAStorage.GetState(const DSAInfo: TDSARegItem; out LastResult: Integer;
const OnCustomData: TDSACustomData = nil): Boolean;
begin
BeginRead(DSAInfo);
try
LastResult := 0;
Result := ReadBoolDef(DSAInfo, cDSAStateValueName, False);
if Result then
begin
LastResult := ReadIntegerDef(DSAInfo, cDSAStateLastResultName, 0);
if Assigned(OnCustomData) then
begin
BeginCustomRead(DSAInfo);
try
OnCustomData(Self, DSAInfo);
finally
EndCustomRead(DSAInfo);
end;
end;
end;
finally
EndRead(DSAInfo);
end;
end;
procedure TDSAStorage.SetState(const DSAInfo: TDSARegItem; const DontShowAgain: Boolean;
const LastResult: Integer; const OnCustomData: TDSACustomData = nil);
begin
BeginWrite(DSAInfo);
try
WriteBool(DSAInfo, cDSAStateValueName, DontShowAgain);
if DontShowAgain then
begin
WriteInteger(DSAInfo, cDSAStateLastResultName, LastResult);
if Assigned(OnCustomData) then
begin
BeginCustomWrite(DSAInfo);
try
OnCustomData(Self, DSAInfo);
finally
EndCustomWrite(DSAInfo);
end;
end;
end;
finally
EndWrite(DSAInfo);
end;
end;
//=== { TDSARegStorage } =====================================================
{$IFDEF MSWINDOWS}
constructor TDSARegStorage.Create(const ARootKey: HKEY; const AKey: string);
begin
inherited Create;
FRootKey := ARootKey;
FKey := AKey;
end;
procedure TDSARegStorage.CreateKey(const DSAInfo: TDSARegItem);
begin
if not (RegKeyExists(RootKey, Key + '\' + DSAInfo.Name) or
(RegCreateKey(RootKey, Key + '\' + DSAInfo.Name, '') = ERROR_SUCCESS)) then
raise EJvDSADialog.CreateResFmt(@RsEDSARegKeyCreateError, [Key + '\' + DSAInfo.Name]);
end;
function TDSARegStorage.GetCheckMarkTextSuffix: string;
begin
Result := '';
end;
procedure TDSARegStorage.SetCheckMarkTextSuffix(const Value: string);
begin
end;
function TDSARegStorage.ReadBool(const DSAInfo: TDSARegItem; const Key: string): Boolean;
begin
Result := RegReadBool(RootKey, Self.Key + '\' + DSAInfo.Name, Key);
end;
function TDSARegStorage.ReadBoolDef(const DSAInfo: TDSARegItem; const Key: string;
const Default: Boolean): Boolean;
begin
Result := RegReadBoolDef(RootKey, Self.Key + '\' + DSAInfo.Name, Key, Default);
end;
function TDSARegStorage.ReadFloat(const DSAInfo: TDSARegItem; const Key: string): Extended;
begin
RegReadBinary(RootKey, Self.Key + '\' + DSAInfo.Name, Key, Result, SizeOf(Extended));
end;
function TDSARegStorage.ReadFloatDef(const DSAInfo: TDSARegItem; const Key: string;
const Default: Extended): Extended;
begin
if RegReadBinaryDef(RootKey, Self.Key + '\' + DSAInfo.Name, Key, Result, SizeOf(Extended), 0) = 0 then
Result := Default;
end;
function TDSARegStorage.ReadInt64(const DSAInfo: TDSARegItem; const Key: string): Int64;
begin
Result := RegReadInt64(RootKey, Self.Key + '\' + DSAInfo.Name, Key);
end;
function TDSARegStorage.ReadInt64Def(const DSAInfo: TDSARegItem; const Key: string; const Default: Int64): Int64;
begin
Result := RegReadInt64Def(RootKey, Self.Key + '\' + DSAInfo.Name, Key, Default);
end;
function TDSARegStorage.ReadInteger(const DSAInfo: TDSARegItem; const Key: string): Integer;
begin
Result := RegReadInteger(RootKey, Self.Key + '\' + DSAInfo.Name, Key);
end;
function TDSARegStorage.ReadIntegerDef(const DSAInfo: TDSARegItem; const Key: string;
const Default: Integer): Integer;
begin
Result := RegReadIntegerDef(RootKey, Self.Key + '\' + DSAInfo.Name, Key, Default);
end;
function TDSARegStorage.ReadString(const DSAInfo: TDSARegItem; const Key: string): string;
begin
Result := RegReadString(RootKey, Self.Key + '\' + DSAInfo.Name, Key);
end;
function TDSARegStorage.ReadStringDef(const DSAInfo: TDSARegItem; const Key: string;
const Default: string): string;
begin
Result := RegReadStringDef(RootKey, Self.Key + '\' + DSAInfo.Name, Key, Default);
end;
procedure TDSARegStorage.WriteBool(const DSAInfo: TDSARegItem; const Key: string;
const Value: Boolean);
begin
CreateKey(DSAInfo);
RegWriteBool(RootKey, Self.Key + '\' + DSAInfo.Name, Key, Value);
end;
procedure TDSARegStorage.WriteFloat(const DSAInfo: TDSARegItem; const Key: string;
const Value: Extended);
var
Temp: Extended;
begin
CreateKey(DSAInfo);
Temp := Value;
RegWriteBinary(RootKey, Self.Key + '\' + DSAInfo.Name, Key, Temp, SizeOf(Extended));
end;
procedure TDSARegStorage.WriteInt64(const DSAInfo: TDSARegItem; const Key: string;
const Value: Int64);
begin
CreateKey(DSAInfo);
RegWriteInt64(RootKey, Self.Key + '\' + DSAInfo.Name, Key, Value);
end;
procedure TDSARegStorage.WriteInteger(const DSAInfo: TDSARegItem; const Key: string;
const Value: Integer);
begin
CreateKey(DSAInfo);
RegWriteInteger(RootKey, Self.Key + '\' + DSAInfo.Name, Key, Value);
end;
procedure TDSARegStorage.WriteString(const DSAInfo: TDSARegItem; const Key: string;
const Value: string);
begin
CreateKey(DSAInfo);
RegWriteString(RootKey, Self.Key + '\' + DSAInfo.Name, Key, Value);
end;
{$ENDIF MSWINDOWS}
//=== { TDSAValues } =========================================================
const
DSABool = 1;
DSAFloat = 2;
DSAInt64 = 3;
DSAInt = 4;
DSAString = 5;
DSAKindTexts: array [DSABool..DSAString] of string =
(RsEDSAAccessBool, RsEDSAAccessFloat, RsEDSAAccessInt64, RsEDSAAccessInt, RsEDSAAccessString);
type
TDSAValues = class(TStringList)
public
constructor Create;
end;
constructor TDSAValues.Create;
begin
inherited Create;
Sorted := True;
end;
//=== { TDSAQueueStorage } ===================================================
constructor TDSAQueueStorage.Create;
begin
inherited Create;
FList := TStringList.Create;
FList.Sorted := True;
FCheckMarkSuffix := RsInTheCurrentQueue;
end;
destructor TDSAQueueStorage.Destroy;
begin
Clear;
FList.Free;
inherited Destroy;
end;
procedure TDSAQueueStorage.AddDSA(const DSAInfo: TDSARegItem);
begin
if FindDSA(DSAInfo) < 0 then
FList.AddObject(DSAInfo.Name, TDSAValues.Create);
end;
procedure TDSAQueueStorage.DeleteDSA(const Index: Integer);
begin
FList.Objects[Index].Free;
FList.Delete(Index);
end;
function TDSAQueueStorage.FindDSA(const DSAInfo: TDSARegItem): Integer;
begin
Result := FList.IndexOf(DSAInfo.Name);
end;
function TDSAQueueStorage.GetCheckMarkTextSuffix: string;
begin
Result := FCheckMarkSuffix;
end;
function TDSAQueueStorage.GetDSAValue(const DSAInfo: TDSARegItem; const Key: string;
const Kind: Integer): string;
var
I: Integer;
DSAKeys: TStrings;
begin
I := FindDSA(DSAInfo);
if I < 0 then
raise EJvDSADialog.CreateResFmt(@RsEDSADialogIDNotStored, [DSAInfo.ID]);
DSAKeys := TStrings(FList.Objects[I]);
I := DSAKeys.IndexOfName(Key);
if I < 0 then
raise EJvDSADialog.CreateResFmt(@RsEDSAKeyNotFound, [Key]);
if Integer(DSAKeys.Objects[I]) <> Kind then
raise EJvDSADialog.CreateResFmt(@RsEDSAKeyNoAccessAs, [Key, DSAKindTexts[Kind]]);
Result := DSAKeys.Values[Key];
end;
function TDSAQueueStorage.HasDSAKey(const DSAInfo: TDSARegItem; const Key: string): Boolean;
var
I: Integer;
DSAKeys: TStrings;
begin
I := FindDSA(DSAInfo);
Result := I > -1;
if Result then
begin
DSAKeys := TStrings(FList.Objects[I]);
Result := DSAKeys.IndexOfName(Key) > -1;
end;
end;
procedure TDSAQueueStorage.SetCheckMarkTextSuffix(const Value: string);
begin
if Value <> CheckMarkTextSuffix then
FCheckMarkSuffix := Value;
end;
procedure TDSAQueueStorage.SetDSAValue(const DSAInfo: TDSARegItem; const Key: string;
const Kind: Integer; const Value: string);
var
I: Integer;
DSAKeys: TStrings;
begin
AddDSA(DSAInfo);
I := FindDSA(DSAInfo);
if I < 0 then
raise EJvDSADialog.CreateResFmt(@RsEDSADialogIDNotStored, [DSAInfo.ID]);
DSAKeys := TStrings(FList.Objects[I]);
I := DSAKeys.IndexOfName(Key);
if I < 0 then
DSAKeys.AddObject(Key + '=' + Value, TObject(Kind))
else
begin
if Integer(DSAKeys.Objects[I]) <> Kind then
raise EJvDSADialog.CreateResFmt(@RsEDSAKeyNoAccessAs, [Key, DSAKindTexts[Kind]]);
DSAKeys.Values[Key] := Value;
end;
end;
procedure TDSAQueueStorage.Clear;
begin
while FList.Count > 0 do
DeleteDSA(FList.Count - 1);
end;
function TDSAQueueStorage.ReadBool(const DSAInfo: TDSARegItem; const Key: string): Boolean;
var
S: string;
begin
S := GetDSAValue(DSAInfo, Key, DSABool);
Result := AnsiSameText(S, 'True') or AnsiSameText(S, '1');
end;
function TDSAQueueStorage.ReadBoolDef(const DSAInfo: TDSARegItem; const Key: string;
const Default: Boolean): Boolean;
begin
if HasDSAKey(DSAInfo, Key) then
Result := ReadBool(DSAInfo, Key)
else
Result := Default;
end;
function TDSAQueueStorage.ReadFloat(const DSAInfo: TDSARegItem; const Key: string): Extended;
begin
Result := StrToFloat(StringReplace(GetDSAValue(DSAInfo, Key, DSAFloat),
ThousandSeparator, DecimalSeparator, [rfReplaceAll, rfIgnoreCase]));
end;
function TDSAQueueStorage.ReadFloatDef(const DSAInfo: TDSARegItem; const Key: string;
const Default: Extended): Extended;
begin
if HasDSAKey(DSAInfo, Key) then
Result := ReadFloat(DSAInfo, Key)
else
Result := Default;
end;
function TDSAQueueStorage.ReadInt64(const DSAInfo: TDSARegItem; const Key: string): Int64;
begin
Result := StrToInt64(GetDSAValue(DSAInfo, Key, DSAInt64));
end;
function TDSAQueueStorage.ReadInt64Def(const DSAInfo: TDSARegItem; const Key: string;
const Default: Int64): Int64;
begin
if HasDSAKey(DSAInfo, Key) then
Result := ReadInt64(DSAInfo, Key)
else
Result := Default;
end;
function TDSAQueueStorage.ReadInteger(const DSAInfo: TDSARegItem; const Key: string): Integer;
begin
Result := StrToInt(GetDSAValue(DSAInfo, Key, DSAInt));
end;
function TDSAQueueStorage.ReadIntegerDef(const DSAInfo: TDSARegItem; const Key: string;
const Default: Integer): Integer;
begin
if HasDSAKey(DSAInfo, Key) then
Result := ReadInteger(DSAInfo, Key)
else
Result := Default;
end;
function TDSAQueueStorage.ReadString(const DSAInfo: TDSARegItem; const Key: string): string;
begin
Result := GetDSAValue(DSAInfo, Key, DSAString);
end;
function TDSAQueueStorage.ReadStringDef(const DSAInfo: TDSARegItem; const Key: string;
const Default: string): string;
begin
if HasDSAKey(DSAInfo, Key) then
Result := ReadString(DSAInfo, Key)
else
Result := Default;
end;
procedure TDSAQueueStorage.WriteBool(const DSAInfo: TDSARegItem; const Key: string;
const Value: Boolean);
begin
if Value then
SetDSAValue(DSAInfo, Key, DSABool, '1')
else
SetDSAValue(DSAInfo, Key, DSABool, '0');
end;
procedure TDSAQueueStorage.WriteFloat(const DSAInfo: TDSARegItem; const Key: string;
const Value: Extended);
begin
SetDSAValue(DSAInfo, Key, DSAFloat, FloatToStr(Value));
end;
procedure TDSAQueueStorage.WriteInt64(const DSAInfo: TDSARegItem; const Key: string;
const Value: Int64);
begin
SetDSAValue(DSAInfo, Key, DSAInt64, IntToStr(Value));
end;
procedure TDSAQueueStorage.WriteInteger(const DSAInfo: TDSARegItem; const Key: string;
const Value: Integer);
begin
SetDSAValue(DSAInfo, Key, DSAInt, IntToStr(Value));
end;
procedure TDSAQueueStorage.WriteString(const DSAInfo: TDSARegItem; const Key: string;
const Value: string);
begin
SetDSAValue(DSAInfo, Key, DSAString, Value);
end;
//--------------------------------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------------------------------
const
Captions: array [TMsgDlgType] of string =
(SMsgDlgWarning, SMsgDlgError, SMsgDlgInformation, SMsgDlgConfirm, '');
{$IFDEF MSWINDOWS}
IconIDs: array [TMsgDlgType] of PChar =
(IDI_EXCLAMATION, IDI_HAND, IDI_ASTERISK, IDI_QUESTION, nil);
{$ENDIF MSWINDOWS}
{$IFDEF UNIX}
IconIDs: array [TMsgDlgType] of QMessageBoxIcon =
(QMessageBoxIcon_Warning, QMessageBoxIcon_Critical, QMessageBoxIcon_Information,
QMessageBoxIcon_NoIcon, QMessageBoxIcon_NoIcon);
{$ENDIF UNIX}
{$IFDEF VCL}
ButtonCaptions: array [TMsgDlgBtn] of string =
(SMsgDlgYes, SMsgDlgNo, SMsgDlgOK, SMsgDlgCancel, SMsgDlgAbort,
SMsgDlgRetry, SMsgDlgIgnore, SMsgDlgAll, SMsgDlgNoToAll, SMsgDlgYesToAll,
SMsgDlgHelp);
ModalResults: array [TMsgDlgBtn] of Integer =
(mrYes, mrNo, mrOk, mrCancel, mrAbort, mrRetry, mrIgnore, mrAll, mrNoToAll,
mrYesToAll, 0);
{$ENDIF VCL}
{$IFDEF VisualCLX}
// TMsgDlgType = (mtCustom, mtInformation, mtWarning, mtError, mtConfirmation);
ButtonCaptions: array [TMsgDlgBtn] of string =
(SMsgDlgHelp, SMsgDlgOK, SMsgDlgCancel, SMsgDlgYes,
SMsgDlgNo, SMsgDlgAbort, SMsgDlgRetry, SMsgDlgIgnore,
SMsgDlgAll, SMsgDlgNoToAll, SMsgDlgYesToAll);
ModalResults: array [TMsgDlgBtn] of Integer =
(0, mrOk, mrCancel, mrYes, mrNo, mrAbort, mrRetry, mrIgnore, mrAll, mrNoToAll,
mrYesToAll);
{$ENDIF VisualCLX}
function DlgCaption(const DlgType: TMsgDlgType): string;
begin
Result := Captions[DlgType];
end;
function DlgPic(const DlgType: TMsgDlgType): TGraphic;
begin
if IconIDs[DlgType] <> nil then
begin
Result := TIcon.Create;
try
{$IFDEF VCL}
TIcon(Result).Handle := LoadIcon(0, IconIDs[DlgType]);
{$ENDIF VCL}
{$IFDEF VisualCLX}
// TODO
{$ENDIF VisualCLX}
except
Result.Free;
raise;
end;
end
else
Result := nil;
end;
function DlgButtonCaptions(const Buttons: TMsgDlgButtons): TDynStringArray;
var
I: Integer;
B: TMsgDlgBtn;
begin
SetLength(Result, Ord(High(TMsgDlgBtn)) + 1);
I := 0;
for B := Low(TMsgDlgBtn) to High(TMsgDlgBtn) do
if B in Buttons then
begin
Result[I] := ButtonCaptions[B];
Inc(I);
end;
SetLength(Result, I);
end;
function DlgButtonResults(const Buttons: TMsgDlgButtons): TDynIntegerArray;
var
I: Integer;
B: TMsgDlgBtn;
begin
SetLength(Result, Ord(High(TMsgDlgBtn)) + 1);
I := 0;
for B := Low(TMsgDlgBtn) to High(TMsgDlgBtn) do
if B in Buttons then
begin
Result[I] := ModalResults[B];
Inc(I);
end;
SetLength(Result, I);
end;
function ButtonIndex(const Results: array of Integer; const ResCode: Integer): Integer; overload;
begin
Result := High(Results);
while (Result > -1) and (Results[Result] <> ResCode) do
Dec(Result);
end;
function ButtonIndex(const Results: array of Integer; const Button: TMsgDlgBtn): Integer; overload;
begin
Result := ButtonIndex(Results, ModalResults[Button]);
end;
//----------------------------------------------------------------------------
// MessageDlg replacements and extensions
//----------------------------------------------------------------------------
procedure ShowMessage(const Msg: string; const Center: TDlgCenterKind; const Timeout: Integer;
const ADynControlEngine: TJvDynControlEngine);
begin
MessageDlg(Msg, mtCustom, [mbOK], 0, Center, Timeout);
end;
procedure ShowMessageFmt(const Msg: string; const Params: array of const; const Center: TDlgCenterKind;
const Timeout: Integer; const ADynControlEngine: TJvDynControlEngine);
begin
MessageDlg(Format(Msg, Params), mtCustom, [mbOK], 0, Center, Timeout);
end;
function MessageDlg(const Msg: string; const DlgType: TMsgDlgType; const Buttons: TMsgDlgButtons;
const HelpCtx: Longint; const Center: TDlgCenterKind; const Timeout: Integer;
const DefaultButton: TMsgDlgBtn; const CancelButton: TMsgDlgBtn; const HelpButton: TMsgDlgBtn;
const ADynControlEngine: TJvDynControlEngine): TModalResult;
var
TmpPic: TGraphic;
begin
TmpPic := DlgPic(DlgType);
try
Result := MessageDlg(DlgCaption(DlgType), Msg, TmpPic, Buttons, HelpCtx, Center, Timeout, DefaultButton,
CancelButton, HelpButton, ADynControlEngine);
finally
TmpPic.Free;
end;
end;
function MessageDlg(const Caption, Msg: string; const DlgType: TMsgDlgType; const Buttons: TMsgDlgButtons;
const HelpCtx: Longint; const Center: TDlgCenterKind; const Timeout: Integer;
const DefaultButton: TMsgDlgBtn; const CancelButton: TMsgDlgBtn; const HelpButton: TMsgDlgBtn;
const ADynControlEngine: TJvDynControlEngine): TModalResult;
var
TmpPic: TGraphic;
begin
TmpPic := DlgPic(DlgType);
try
Result := MessageDlg(Caption, Msg, TmpPic, Buttons, HelpCtx, Center,
Timeout, DefaultButton, CancelButton, HelpButton, ADynControlEngine);
finally
TmpPic.Free;
end;
end;
function MessageDlg(const Caption, Msg: string; const Picture: TGraphic; const Buttons: TMsgDlgButtons;
const HelpCtx: Longint; const Center: TDlgCenterKind; const Timeout: Integer;
const DefaultButton: TMsgDlgBtn; const CancelButton: TMsgDlgBtn; const HelpButton: TMsgDlgBtn;
const ADynControlEngine: TJvDynControlEngine): TModalResult;
var
DefBtn: TMsgDlgBtn;
CanBtn: TMsgDlgBtn;
BtnResults: TDynIntegerArray;
begin
if DefaultButton = mbDefault then
begin
if mbOK in Buttons then
DefBtn := mbOK
else
if mbYes in Buttons then
DefBtn := mbYes
else
DefBtn := mbRetry;
end
else
DefBtn := DefaultButton;
if CancelButton = mbDefault then
begin
if mbCancel in Buttons then
CanBtn := mbCancel
else
if mbNo in Buttons then
CanBtn := mbNo
else
CanBtn := mbOK;
end
else
CanBtn := CancelButton;
BtnResults := DlgButtonResults(Buttons);
Result := MessageDlgEx(Caption, Msg, Picture, DlgButtonCaptions(Buttons),
BtnResults, HelpCtx, Center, Timeout, ButtonIndex(BtnResults, DefBtn),
ButtonIndex(BtnResults, CanBtn), ButtonIndex(BtnResults, HelpButton),
ADynControlEngine);
end;
function MessageDlgEx(const Msg: string; const DlgType: TMsgDlgType; const Buttons: array of string;
const Results: array of Integer; const HelpCtx: Longint; const Center: TDlgCenterKind;
const Timeout: Integer; const DefaultButton: Integer; const CancelButton: Integer;
const HelpButton: Integer; const ADynControlEngine: TJvDynControlEngine): TModalResult;
var
TmpPic: TGraphic;
begin
TmpPic := DlgPic(DlgType);
try
Result := MessageDlgEx(DlgCaption(DlgType), Msg, TmpPic, Buttons, Results, HelpCtx, Center, Timeout, DefaultButton,
CancelButton, HelpButton, ADynControlEngine);
finally
TmpPic.Free;
end;
end;
function MessageDlgEx(const Caption, Msg: string; const DlgType: TMsgDlgType;
const Buttons: array of string; const Results: array of Integer; const HelpCtx: Longint;
const Center: TDlgCenterKind; const Timeout: Integer; const DefaultButton: Integer;
const CancelButton: Integer; const HelpButton: Integer;
const ADynControlEngine: TJvDynControlEngine): TModalResult;
var
TmpPic: TGraphic;
begin
TmpPic := DlgPic(DlgType);
try
Result := MessageDlgEx(Caption, Msg, TmpPic, Buttons, Results, HelpCtx,
Center, Timeout, DefaultButton, CancelButton, HelpButton, ADynControlEngine);
finally
TmpPic.Free;
end;
end;
function MessageDlgEx(const Caption, Msg: string; const Picture: TGraphic;
const Buttons: array of string; const Results: array of Integer; const HelpCtx: Longint;
const Center: TDlgCenterKind; const Timeout: Integer; const DefaultButton: Integer;
const CancelButton: Integer; const HelpButton: Integer;
const ADynControlEngine: TJvDynControlEngine): TModalResult;
begin
with CreateDSAMessageForm(Caption, Msg, Picture, Buttons, Results, HelpCtx, '',
Center, Timeout, DefaultButton, CancelButton, HelpButton, ADynControlEngine) do
try
Result := ShowModal;
finally
Free;
end;
end;
//----------------------------------------------------------------------------
// "Don't Show Again" (DSA) dialogs
//----------------------------------------------------------------------------
procedure DSAShowMessage(const DlgID: Integer; const Msg: string;
const Center: TDlgCenterKind; const Timeout: Integer;
const ADynControlEngine: TJvDynControlEngine);
begin
DSAMessageDlg(DlgID, Msg, mtCustom, [mbOK], 0, Center, Timeout, mbDefault,
mbDefault, mbHelp, ADynControlEngine);
end;
procedure DSAShowMessageFmt(const DlgID: Integer; const Msg: string;
const Params: array of const; const Center: TDlgCenterKind;
const Timeout: Integer; const ADynControlEngine: TJvDynControlEngine);
begin
DSAMessageDlg(DlgID, Format(Msg, Params), mtCustom, [mbOK], 0, Center, Timeout,
mbDefault, mbDefault, mbHelp, ADynControlEngine);
end;
function DSAMessageDlg(const DlgID: Integer; const Msg: string; const DlgType: TMsgDlgType;
const Buttons: TMsgDlgButtons; const HelpCtx: Longint; const Center: TDlgCenterKind;
const Timeout: Integer; const DefaultButton: TMsgDlgBtn; const CancelButton: TMsgDlgBtn;
const HelpButton: TMsgDlgBtn; const ADynControlEngine: TJvDynControlEngine): TModalResult;
var
TmpPic: TGraphic;
begin
TmpPic := DlgPic(DlgType);
try
Result := DSAMessageDlg(DlgID, DlgCaption(DlgType), Msg, TmpPic, Buttons, HelpCtx,
Center, Timeout, DefaultButton, CancelButton, HelpButton, ADynControlEngine);
finally
TmpPic.Free;
end;
end;
function DSAMessageDlg(const DlgID: Integer; const Caption, Msg: string;
const DlgType: TMsgDlgType; const Buttons: TMsgDlgButtons; const HelpCtx: Longint;
const Center: TDlgCenterKind; const Timeout: Integer; const DefaultButton: TMsgDlgBtn;
const CancelButton: TMsgDlgBtn; const HelpButton: TMsgDlgBtn;
const ADynControlEngine: TJvDynControlEngine): TModalResult;
var
TmpPic: TGraphic;
begin
TmpPic := DlgPic(DlgType);
try
Result := DSAMessageDlg(DlgID, Caption, Msg, TmpPic, Buttons, HelpCtx, Center,
Timeout, DefaultButton, CancelButton, HelpButton, ADynControlEngine);
finally
TmpPic.Free;
end;
end;
function DSAMessageDlg(const DlgID: Integer; const Caption, Msg: string;
const Picture: TGraphic; const Buttons: TMsgDlgButtons; const HelpCtx: Longint;
const Center: TDlgCenterKind; const Timeout: Integer; const DefaultButton: TMsgDlgBtn;
const CancelButton: TMsgDlgBtn; const HelpButton: TMsgDlgBtn;
const ADynControlEngine: TJvDynControlEngine): TModalResult;
var
DefBtn: TMsgDlgBtn;
CanBtn: TMsgDlgBtn;
BtnResults: TDynIntegerArray;
begin
if DefaultButton = mbDefault then
begin
if mbOK in Buttons then
DefBtn := mbOK
else
if mbYes in Buttons then
DefBtn := mbYes
else
DefBtn := mbRetry;
end
else
DefBtn := DefaultButton;
if CancelButton = mbDefault then
begin
if mbCancel in Buttons then
CanBtn := mbCancel
else
if mbNo in Buttons then
CanBtn := mbNo
else
CanBtn := mbOK;
end
else
CanBtn := CancelButton;
BtnResults := DlgButtonResults(Buttons);
Result := DSAMessageDlgEx(DlgID, Caption, Msg, Picture, DlgButtonCaptions(Buttons),
BtnResults, HelpCtx, Center, Timeout, ButtonIndex(BtnResults, DefBtn),
ButtonIndex(BtnResults, CanBtn), ButtonIndex(BtnResults, HelpButton), ADynControlEngine);
end;
function DSAMessageDlgEx(const DlgID: Integer; const Msg: string; const DlgType: TMsgDlgType;
const Buttons: array of string; const Results: array of Integer; const HelpCtx: Longint;
const Center: TDlgCenterKind; const Timeout: Integer; const DefaultButton: Integer;
const CancelButton: Integer; const HelpButton: Integer;
const ADynControlEngine: TJvDynControlEngine): Integer;
var
TmpPic: TGraphic;
begin
TmpPic := DlgPic(DlgType);
try
Result := DSAMessageDlgEx(DlgID, DlgCaption(DlgType), Msg, TmpPic, Buttons,
Results, HelpCtx, Center, Timeout, DefaultButton, CancelButton,
HelpButton, ADynControlEngine);
finally
TmpPic.Free;
end;
end;
function DSAMessageDlgEx(const DlgID: Integer; const Caption, Msg: string; const DlgType: TMsgDlgType;
const Buttons: array of string; const Results: array of Integer; const HelpCtx: Longint;
const Center: TDlgCenterKind; const Timeout, DefaultButton, CancelButton, HelpButton: Integer;
const ADynControlEngine: TJvDynControlEngine): TModalResult;
var
TmpPic: TGraphic;
begin
TmpPic := DlgPic(DlgType);
try
Result := DSAMessageDlgEx(DlgID, Caption, Msg, TmpPic, Buttons, Results, HelpCtx,
Center, Timeout, DefaultButton, CancelButton, HelpButton, ADynControlEngine);
finally
TmpPic.Free;
end;
end;
function DSAMessageDlgEx(const DlgID: Integer; const Caption, Msg: string; const Picture: TGraphic;
const Buttons: array of string; const Results: array of Integer; const HelpCtx: Longint;
const Center: TDlgCenterKind; const Timeout, DefaultButton, CancelButton, HelpButton: Integer;
const ADynControlEngine: TJvDynControlEngine): Integer;
var
DSAItem: TDSARegItem;
CheckCaption: string;
Temp: string;
begin
if not GetDSAState(DlgID, Result) then
begin
Result := High(Integer);
DSAItem := LocateDSAReg(DlgID);
CheckCaption := GetCheckMarkText(DSAItem.ChkTextKind);
if CheckCaption = '' then
CheckCaption := GetCheckMarkText(ctkShow);
Temp := DSAItem.Storage.CheckMarkTextSuffix;
if Temp <> '' then
CheckCaption := CheckCaption + ' ' + Temp + '.'
else
CheckCaption := CheckCaption + '.';
// Create and show dialog
with CreateDSAMessageForm(Caption, Msg, Picture, Buttons, Results, HelpCtx, CheckCaption,
Center, Timeout, DefaultButton, CancelButton, HelpButton, ADynControlEngine) do
try
Result := ShowModal;
if IsDSAChecked then
SetDSAState(DlgID, True, Result);
finally
Free;
end;
end;
end;
//----------------------------------------------------------------------------
// DSA registration
//----------------------------------------------------------------------------
procedure RegisterDSA(const DlgID: Integer; const Name, Description: string;
const Storage: TDSAStorage; const CheckTextKind: TDSACheckTextKind = ctkShow);
begin
case DSARegister.Add(DlgID, Name, Description, Storage, CheckTextKind) of
arDuplicateID:
raise EJvDSADialog.CreateResFmt(@RsEDSADuplicateID, [DlgID]);
arDuplicateName:
raise EJvDSADialog.CreateResFmt(@RsEDSADuplicateName, [Name]);
end;
end;
procedure UnregisterDSA(const DlgID: Integer);
begin
DSARegister.Delete(DlgID);
end;
function LocateDSAReg(const DlgID: Integer): TDSARegItem;
begin
Result := DSARegister.Locate(DlgID);
end;
//----------------------------------------------------------------------------
// DSA state setting/retrieving
//----------------------------------------------------------------------------
function GetDSAState(const DlgID: Integer): Boolean;
var
Dummy: Integer;
begin
Result := GetDSAState(DlgID, Dummy);
end;
function GetDSAState(const DlgID: Integer; out ResCode: Integer;
const OnCustomData: TDSACustomData = nil): Boolean;
var
RegItem: TDSARegItem;
begin
RegItem := DSARegister.Locate(DlgID);
if RegItem.ID <> EmptyItem.ID then
Result := RegItem.Storage.GetState(RegItem, ResCode, OnCustomData)
else
raise EJvDSADialog.CreateResFmt(@RsEDSADialogIDNotFound, [DlgID]);
end;
procedure SetDSAState(const DlgID: Integer; const DontShowAgain: Boolean;
const LastResult: Integer = mrNone; const OnCustomData: TDSACustomData = nil);
var
RegItem: TDSARegItem;
begin
RegItem := DSARegister.Locate(DlgID);
if RegItem.ID <> EmptyItem.ID then
RegItem.Storage.SetState(RegItem, DontShowAgain, LastResult, OnCustomData)
else
raise EJvDSADialog.CreateResFmt(@RsEDSADialogIDNotFound, [DlgID]);
end;
//----------------------------------------------------------------------------
// Iterating the DSA registration
//----------------------------------------------------------------------------
function DSACount: Integer;
begin
Result := Length(DSARegister.FList);
end;
function DSAItem(const Index: Integer): TDSARegItem;
begin
Result := DSARegister.FList[Index];
end;
//----------------------------------------------------------------------------
// DSA check box text registration
//----------------------------------------------------------------------------
procedure RegisterDSACheckMarkText(const ID: TDSACheckTextKind; const Text: string);
begin
if CheckMarkTexts.IndexOfObject(TObject(ID)) < 0 then
CheckMarkTexts.AddObject(Text, TObject(ID))
else
raise EJvDSADialog.CreateResFmt(@RsEDSADuplicateCTK_ID, [ID]);
end;
procedure UnregisterDSACheckMarkText(const ID: TDSACheckTextKind);
var
Idx: Integer;
begin
Idx := CheckMarkTexts.IndexOfObject(TObject(ID));
if Idx > -1 then
CheckMarkTexts.Delete(Idx);
end;
function GetDSACheckMarkText(const ID: TDSACheckTextKind): string;
begin
Result := GetCheckMarkText(ID);
end;
//----------------------------------------------------------------------------
// Standard DSA storage devices
//----------------------------------------------------------------------------
{$IFDEF MSWINDOWS}
var
GlobalRegStore: TDSAStorage = nil;
function DSARegStore: TDSARegStorage;
begin
if GlobalRegStore = nil then
begin
GlobalRegStore :=
TDSARegStorage.Create(HKEY_CURRENT_USER, 'Software\' + Application.Title + '\DSA');
end;
Result := TDSARegStorage(GlobalRegStore);
end;
{$ENDIF MSWINDOWS}
var
GlobalQueueStore: TDSAStorage = nil;
function DSAQueueStore: TDSAQueueStorage;
begin
if GlobalQueueStore = nil then
GlobalQueueStore := TDSAQueueStorage.Create;
Result := TDSAQueueStorage(GlobalQueueStore);
end;
{ ShowModal patch }
procedure CallShowModal(const Frm: TCustomForm); // Helper to get the VMT index of ShowModal
begin
Frm.ShowModal;
end;
function FindShowModalVMT: Integer; // Locate the VMT index of ShowModal
var
Ptr: Pointer;
begin
Ptr := @CallShowModal;
if Ptr = nil then
begin
Result := -1;
Exit;
end
else
begin
Inc(Integer(Ptr), 4);
Result := PInteger(Ptr)^ div 4;
end;
end;
// Set the virtual method pointer for an instance, nice addition for JCL?
procedure SetVirtualMethodInstance(Instance: TObject; const VMTIdx: Integer;
const MethodPtr: Pointer);
var
WrittenBytes: Cardinal;
begin
WriteProtectedMemory(Pointer(PInteger(Instance)^ + VMTIdx * SizeOf(Pointer)), @MethodPtr, SizeOf(Pointer), WrittenBytes);
end;
//=== { TPatchedForm } =======================================================
type
TShowModalMethod = function: Integer of object; // So we can call the original ShowModal method.
TPatchedForm = class(TCustomForm) // To replace the orignal ShowModal method.
public
function ShowModal: Integer; override;
end;
function TPatchedForm.ShowModal: Integer;
var
I: Integer;
JvDSADialog: TJvDSADialog;
DSAItem: TDSARegItem;
CheckCaption: string;
Temp: string;
ShowModalMethod: TShowModalMethod;
begin
// retrieve the TJvDSADialog instance.
I := ComponentCount - 1;
while (I > -1) and not (Components[I] is TJvDSADialog) do
Dec(I);
if I = -1 then
raise EJvDSADialog.CreateRes(@RsEJvDSADialogPatchErrorJvDSADialogCom);
JvDSADialog := Components[I] as TJvDSADialog;
// Check the DSA state
if not JvDSADialog.GetDSAStateInternal(Result) then
begin
if (JvDSADialog.CheckControl <> nil) and not JvDSADialog.IgnoreDSAChkMrkTxt then
begin
// Get DSA checkmark caption
DSAItem := LocateDSAReg(JvDSADialog.DialogID);
CheckCaption := GetDSACheckMarkText(DSAItem.ChkTextKind);
if CheckCaption = '' then
CheckCaption := GetDSACheckMarkText(ctkShow);
Temp := DSAItem.Storage.CheckMarkTextSuffix;
if Temp <> '' then
CheckCaption := CheckCaption + ' ' + Temp + '.'
else
CheckCaption := CheckCaption + '.';
SetStrProp(JvDSADialog.CheckControl, 'Caption', CheckCaption);
end;
{ Notify the JvDSADialog component that we are about to show the form (may initialize the
auto-close timer) }
JvDSADialog.BeforeShow;
// Show the dialog by calling the original ShowModal method: setting up the method pointers.
TMethod(ShowModalMethod).Data := Self;
TMethod(ShowModalMethod).Code := JvDSADialog.GetOrgShowModalPtr;
// Show the dialog by calling the original ShowModal method: make the actual call.
Result := ShowModalMethod;
{ Notify the JvDSADialog component that we the form has closed (may clean up the
auto-close timer) }
JvDSADialog.AfterShow;
// Update the DSA state in storage.
JvDSADialog.UpdateDSAState;
end
else
// The dialog is suppressed. Apply the saved state.
JvDSADialog.ApplySavedState;
end;
//=== { TJvDSADialog } =======================================================
constructor TJvDSADialog.Create(AOwner: TComponent);
var
I: Integer;
begin
if AOwner is TCustomForm then
begin
I := AOwner.ComponentCount - 1;
while (I > -1) and not (AOwner.Components[I] is TJvDSADialog) do
Dec(I);
if I > -1 then
raise EJvDSADialog.CreateRes(@RsEAlreadyDSADialog);
inherited Create(AOwner);
end
else
raise EJvDSADialog.CreateRes(@RsEOnlyAllowedOnForms);
end;
destructor TJvDSADialog.Destroy;
begin
FormUnPatch;
inherited Destroy;
end;
procedure TJvDSADialog.AutoClose;
begin
CancelCountdown;
if not DoAutoClose then
(Owner as TCustomForm).Close;
end;
procedure TJvDSADialog.AfterShow;
begin
if FTimer <> nil then
FreeAndNil(FTimer);
end;
procedure TJvDSADialog.ApplySavedState;
var
ResCode: Integer;
begin
GetDSAState(DialogID, ResCode, DoApplyKeys);
TCustomForm(Owner).ModalResult := ResCode;
end;
procedure TJvDSADialog.BeforeShow;
begin
if FTimeout > 0 then
begin
FTimer := TTimer.Create(Self);
FTimer.Enabled := False;
FTimer.Interval := 1000;
FTimer.OnTimer := TimerEvent;
FTimerCount := FTimeout;
end;
end;
procedure TJvDSADialog.DoApplyKeys(const Storage: TDSAStorage; const DSAInfo: TDSARegItem);
begin
if Assigned(FOnApplyKeys) then
OnApplyKeys(Self, DSAInfo, Storage);
end;
function TJvDSADialog.DoAutoClose: Boolean;
begin
Result := False;
if Assigned(FOnAutoClose) then
FOnAutoClose(Self, Result);
end;
procedure TJvDSADialog.DoCountDown;
begin
if Assigned(FOnCountdown) then
OnCountdown(Self);
end;
procedure TJvDSADialog.DoUpdateKeys;
begin
if Assigned(FOnUpdateKeys) then
OnUpdateKeys(Self, DSAInfo, Storage);
end;
function TJvDSADialog.GetDSAStateInternal(out ModalResult: Integer): Boolean;
begin
Result := GetDSAState(DialogID, ModalResult);
end;
function TJvDSADialog.GetOrgOwner: TComponent;
begin
Result := FOrgOwner;
end;
function TJvDSADialog.GetOrgShowModalPtr: Pointer;
begin
Result := FOrgShowModalPtr;
end;
function TJvDSADialog.GetStorage: TDSAStorage;
begin
Result := LocateDSAReg(DialogID).Storage;
end;
procedure TJvDSADialog.FormPatch;
var
VMTIdx: Integer;
begin
VMTIdx := FindShowModalVMT;
SetOrgShowModalPtr(GetVirtualMethod(Owner.ClassType, VMTIdx));
SetOrgOwner(Owner);
SetVirtualMethodInstance(Owner, VMTIdx, @TPatchedForm.ShowModal);
end;
procedure TJvDSADialog.FormUnPatch;
var
VMTIdx: Integer;
begin
if GetOrgShowModalPtr <> nil then
begin
VMTIdx := FindShowModalVMT;
SetVirtualMethodInstance(GetOrgOwner, VMTIdx, GetOrgShowModalPtr);
SetOrgShowModalPtr(nil);
end;
end;
procedure TJvDSADialog.Notification(AComponent: TComponent; Operation: TOperation);
begin
if (Operation = opRemove) and (AComponent = CheckControl) then
CheckControl := nil;
inherited Notification(AComponent, Operation);
end;
procedure TJvDSADialog.SetCheckControl(Value: TWinControl);
begin
if Value <> CheckControl then
begin
if Value <> nil then
begin
if GetPropInfo(Value, 'Checked') = nil then
raise EJvDSADialog.CreateRes(@RsECtrlHasNoCheckedProp);
if GetPropInfo(Value, 'Caption') = nil then
raise EJvDSADialog.CreateRes(@RsECtrlHasNoCaptionProp);
end;
FCheckControl := Value;
end;
end;
procedure TJvDSADialog.SetDialogID(Value: Integer);
begin
if Value <> DialogID then
begin
if not (csDesigning in ComponentState) and not (csLoading in Owner.ComponentState) then
raise EJvDSADialog.CreateRes(@RsEDialogIDChangeOnlyInDesign);
FDialogID := Value;
end;
end;
procedure TJvDSADialog.SetOrgOwner(Value: TComponent);
begin
FOrgOwner := Value;
end;
procedure TJvDSADialog.SetOrgShowModalPtr(Value: Pointer);
begin
FOrgShowModalPtr := Value;
end;
procedure TJvDSADialog.TimerEvent(Sender: TObject);
begin
Dec(FTimerCount);
if FTimerCount = 0 then
AutoClose
else
DoCountDown;
end;
procedure TJvDSADialog.UpdateDSAState;
begin
SetDSAState(DialogID, IsDSAChecked, TCustomForm(Owner).ModalResult, DoUpdateKeys);
end;
function TJvDSADialog.GetModalResult: Integer;
begin
Result := TCustomForm(Owner).ModalResult;
end;
function TJvDSADialog.IsDSAChecked: Boolean;
begin
if CheckControl <> nil then
Result := GetOrdProp(CheckControl, 'Checked') <> 0
else
Result := False;
end;
procedure TJvDSADialog.Loaded;
begin
inherited Loaded;
if not (csDesigning in ComponentState) then
FormPatch;
end;
procedure TJvDSADialog.CancelCountdown;
begin
if FTimer <> nil then
begin
FTimer.Enabled := False;
FreeAndNil(FTimer);
end;
end;
function TJvDSADialog.SecondsLeft: Integer;
begin
if Timeout <> 0 then
Result := FTimerCount
else
Result := 0;
end;
initialization
{$IFDEF UNITVERSIONING}
RegisterUnitVersion(HInstance, UnitVersioning);
{$ENDIF UNITVERSIONING}
finalization
FreeAndNil(GlobalCheckMarkTexts);
FreeAndNil(GlobalDSARegister);
FreeAndNil(GlobalQueueStore);
{$IFDEF MSWINDOWS}
FreeAndNil(GlobalRegStore);
{$ENDIF MSWINDOWS}
{$IFDEF UNITVERSIONING}
UnregisterUnitVersion(HInstance);
{$ENDIF UNITVERSIONING}
end.