925 lines
29 KiB
ObjectPascal
925 lines
29 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: JvPropertyStore.pas, released on 2003-11-13.
|
|
|
|
The Initial Developer of the Original Code is Jens Fudickar
|
|
Portions created by Marcel Bestebroer are Copyright (C) 2003 Jens Fudickar
|
|
All Rights Reserved.
|
|
|
|
Contributor(s):
|
|
Marcel Bestebroer
|
|
|
|
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: JvPropertyStore.pas 11164 2007-01-25 23:29:17Z jfudickar $
|
|
|
|
unit JvPropertyStore;
|
|
|
|
{$I jvcl.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF UNITVERSIONING}
|
|
JclUnitVersioning,
|
|
{$ENDIF UNITVERSIONING}
|
|
Classes,
|
|
JvAppStorage, JvComponentBase;
|
|
|
|
type
|
|
TJvIgnorePropertiesStringList = class(TStringList)
|
|
public
|
|
procedure AddDelete(AItem: string; ADelete: Boolean);
|
|
end;
|
|
|
|
TJvCustomPropertyStore = class(TJvComponent)
|
|
private
|
|
FAppStoragePath: string;
|
|
FAppStorage: TJvCustomAppStorage;
|
|
FEnabled: Boolean;
|
|
FReadOnly: Boolean;
|
|
FDeleteBeforeStore: Boolean;
|
|
FClearBeforeLoad: Boolean;
|
|
FIntIgnoreProperties: TStringList;
|
|
FIgnoreProperties: TJvIgnorePropertiesStringList;
|
|
FAutoLoad: Boolean;
|
|
FLastLoadTime: TDateTime;
|
|
FIgnoreLastLoadTime: Boolean;
|
|
FCombinedIgnoreProperties: TStringList;
|
|
FOnBeforeLoadProperties: TNotifyEvent;
|
|
FOnAfterLoadProperties: TNotifyEvent;
|
|
FOnBeforeStoreProperties: TNotifyEvent;
|
|
FOnAfterStoreProperties: TNotifyEvent;
|
|
FSynchronizeStoreProperties: Boolean;
|
|
FSynchronizeLoadProperties: Boolean;
|
|
procedure SetAutoLoad(Value: Boolean);
|
|
function GetIgnoreProperties: TJvIgnorePropertiesStringList;
|
|
procedure SetIgnoreProperties(Value: TJvIgnorePropertiesStringList);
|
|
function GetPropCount(Instance: TPersistent): Integer;
|
|
function GetPropName(Instance: TPersistent; Index: Integer): string;
|
|
procedure CloneClass(Src, Dest: TPersistent);
|
|
function GetLastSaveTime: TDateTime;
|
|
protected
|
|
procedure UpdateChildPaths(OldPath: string = ''); virtual;
|
|
procedure SetPath(Value: string); virtual;
|
|
procedure SetAppStorage(Value: TJvCustomAppStorage); virtual;
|
|
procedure Loaded; override;
|
|
procedure DisableAutoLoadDown;
|
|
procedure LoadData; virtual;
|
|
procedure StoreData; virtual;
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
function GetCombinedIgnoreProperties: TStringList;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure StoreProperties; virtual;
|
|
procedure LoadProperties; virtual;
|
|
procedure Assign(Source: TPersistent); override;
|
|
procedure Clear; virtual;
|
|
function TranslatePropertyName(AName: string): string; virtual;
|
|
property AppStorage: TJvCustomAppStorage read FAppStorage write SetAppStorage;
|
|
property CombinedIgnoreProperties: TStringList read GetCombinedIgnoreProperties;
|
|
property IgnoreProperties: TJvIgnorePropertiesStringList read GetIgnoreProperties write SetIgnoreProperties;
|
|
property AutoLoad: Boolean read FAutoLoad write SetAutoLoad;
|
|
property AppStoragePath: string read FAppStoragePath write SetPath;
|
|
property Enabled: Boolean read FEnabled write FEnabled default True;
|
|
property ReadOnly: Boolean read FReadOnly write FReadOnly default False;
|
|
property DeleteBeforeStore: Boolean read FDeleteBeforeStore write FDeleteBeforeStore default False;
|
|
property ClearBeforeLoad: Boolean read FClearBeforeLoad write FClearBeforeLoad default False;
|
|
property IgnoreLastLoadTime: Boolean read FIgnoreLastLoadTime write FIgnoreLastLoadTime default False;
|
|
property OnBeforeLoadProperties: TNotifyEvent read FOnBeforeLoadProperties write FOnBeforeLoadProperties;
|
|
property OnAfterLoadProperties: TNotifyEvent read FOnAfterLoadProperties write FOnAfterLoadProperties;
|
|
property OnBeforeStoreProperties: TNotifyEvent read FOnBeforeStoreProperties write FOnBeforeStoreProperties;
|
|
property OnAfterStoreProperties: TNotifyEvent read FOnAfterStoreProperties write FOnAfterStoreProperties;
|
|
//1 Synchronize the StoreProperties procedure
|
|
/// Defines if the execution of the StoreProperties procedure for the current
|
|
/// AppStoragePath should be synchronized via a global mutex
|
|
property SynchronizeStoreProperties: Boolean read FSynchronizeStoreProperties
|
|
write FSynchronizeStoreProperties default False;
|
|
//1 Synchronize the LoadProperties procedure
|
|
/// Defines if the execution of the LoadProperties procedure for the current
|
|
/// AppStoragePath should be synchronized via a global mutex
|
|
property SynchronizeLoadProperties: Boolean read FSynchronizeLoadProperties
|
|
write FSynchronizeLoadProperties default False;
|
|
property Tag;
|
|
end;
|
|
|
|
TJvCustomPropertyListStore = class(TJvCustomPropertyStore)
|
|
private
|
|
FItems: TStringList;
|
|
FFreeObjects: Boolean;
|
|
FCreateListEntries: Boolean;
|
|
FItemName: string;
|
|
function GetItems: TStringList;
|
|
protected
|
|
function GetString(Index: Integer): string;
|
|
function GetObject(Index: Integer): TObject;
|
|
procedure SetString(Index: Integer; Value: string);
|
|
procedure SetObject(Index: Integer; Value: TObject);
|
|
function GetCount: Integer;
|
|
procedure ReadSLOItem(Sender: TJvCustomAppStorage; const Path: string;
|
|
const List: TObject;const Index: Integer; const ItemName: string);
|
|
procedure WriteSLOItem(Sender: TJvCustomAppStorage; const Path: string;
|
|
const List: TObject; const Index: Integer; const ItemName: string);
|
|
procedure DeleteSLOItems(Sender: TJvCustomAppStorage; const Path: string;
|
|
const List: TObject; const First, Last: Integer; const ItemName: string);
|
|
function CreateItemList: TStringList; virtual;
|
|
function CreateObject: TObject; virtual;
|
|
function GetSorted: Boolean;
|
|
procedure SetSorted(Value: Boolean);
|
|
function GetDuplicates: TDuplicates;
|
|
procedure SetDuplicates(Value: TDuplicates);
|
|
procedure StoreData; override;
|
|
procedure LoadData; override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Clear; override;
|
|
property Strings[Index: Integer]: string read GetString write SetString;
|
|
property Objects[Index: Integer]: TObject read GetObject write SetObject;
|
|
property Items: TStringList read GetItems;
|
|
property Count: Integer read GetCount;
|
|
{ Defines if the Items.Objects- Objects will be freed inside the clear procedure }
|
|
property FreeObjects: Boolean read FFreeObjects write FFreeObjects default True;
|
|
{ Defines if new List entries will be created if there are stored entries, which
|
|
are not in the current object }
|
|
property CreateListEntries: Boolean read FCreateListEntries write FCreateListEntries default True;
|
|
property ItemName: string read FItemName write FItemName;
|
|
property Sorted: Boolean read GetSorted write SetSorted;
|
|
end;
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
const
|
|
UnitVersioning: TUnitVersionInfo = (
|
|
RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/tags/JVCL3_32/run/JvPropertyStore.pas $';
|
|
Revision: '$Revision: 11164 $';
|
|
Date: '$Date: 2007-01-26 00:29:17 +0100 (ven., 26 janv. 2007) $';
|
|
LogPath: 'JVCL\run'
|
|
);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
implementation
|
|
|
|
uses
|
|
{$IFDEF HAS_UNIT_RTLCONSTS}
|
|
RTLConsts,
|
|
{$ENDIF HAS_UNIT_RTLCONSTS}
|
|
Consts, SysUtils, TypInfo,
|
|
JclSynch,
|
|
JvStrings, JvResources;
|
|
|
|
const
|
|
cLastSaveTime = 'Last Save Time';
|
|
cObject = 'Object';
|
|
cItem = 'Item';
|
|
|
|
//=== { TCombinedStrings } ===================================================
|
|
|
|
type
|
|
// Read-only TStrings combining multiple TStrings instances in a single list
|
|
TCombinedStrings = class(TStringList)
|
|
private
|
|
FList: TList;
|
|
protected
|
|
function Get(Index: Integer): string; override;
|
|
function GetObject(Index: Integer): TObject; override;
|
|
function GetCount: Integer; override;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure AddStrings(Strings: TStrings); override;
|
|
// procedure DeleteStrings(Strings: TStrings);
|
|
procedure Clear; override;
|
|
procedure Delete(Index: Integer); override;
|
|
procedure Insert(Index: Integer; const S: string); override;
|
|
end;
|
|
|
|
constructor TCombinedStrings.Create;
|
|
begin
|
|
inherited Create;
|
|
FList := TList.Create;
|
|
end;
|
|
|
|
destructor TCombinedStrings.Destroy;
|
|
begin
|
|
FreeAndNil(FList);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TCombinedStrings.Get(Index: Integer): string;
|
|
var
|
|
OrgIndex: Integer;
|
|
I: Integer;
|
|
begin
|
|
OrgIndex := Index;
|
|
I := 0;
|
|
if Index < 0 then
|
|
Error(SListIndexError, Index);
|
|
while (I < FList.Count) and (Index >= TStrings(FList[I]).Count) do
|
|
begin
|
|
Dec(Index, TStrings(FList[I]).Count);
|
|
Inc(I);
|
|
end;
|
|
if I >= FList.Count then
|
|
Error(SListIndexError, OrgIndex);
|
|
Result := TStrings(FList[I])[Index];
|
|
end;
|
|
|
|
function TCombinedStrings.GetObject(Index: Integer): TObject;
|
|
var
|
|
OrgIndex: Integer;
|
|
I: Integer;
|
|
begin
|
|
OrgIndex := Index;
|
|
I := 0;
|
|
if Index < 0 then
|
|
Error(SListIndexError, Index);
|
|
while (Index < TStrings(FList[I]).Count) and (I < FList.Count) do
|
|
begin
|
|
Dec(Index, TStrings(FList[I]).Count);
|
|
Inc(I);
|
|
end;
|
|
if I >= FList.Count then
|
|
Error(SListIndexError, OrgIndex);
|
|
Result := TStrings(FList[I]).Objects[Index];
|
|
end;
|
|
|
|
function TCombinedStrings.GetCount: Integer;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := 0;
|
|
for I := 0 to FList.Count - 1 do
|
|
Inc(Result, TStrings(FList[I]).Count);
|
|
end;
|
|
|
|
procedure TCombinedStrings.AddStrings(Strings: TStrings);
|
|
begin
|
|
if FList.IndexOf(Strings) = -1 then
|
|
FList.Add(Strings);
|
|
end;
|
|
|
|
(*
|
|
procedure TCombinedStrings.DeleteStrings(Strings: TStrings);
|
|
begin
|
|
FList.Remove(Strings);
|
|
end;
|
|
*)
|
|
|
|
procedure TCombinedStrings.Clear;
|
|
begin
|
|
FList.Clear;
|
|
end;
|
|
|
|
procedure TCombinedStrings.Delete(Index: Integer);
|
|
begin
|
|
end;
|
|
|
|
procedure TCombinedStrings.Insert(Index: Integer; const S: string);
|
|
begin
|
|
end;
|
|
|
|
//=== { TJvIgnorePropertiesStringList } ======================================
|
|
|
|
procedure TJvIgnorePropertiesStringList.AddDelete(AItem: string; ADelete: Boolean);
|
|
begin
|
|
if ADelete then
|
|
begin
|
|
if IndexOf(AItem) >= 0 then
|
|
Delete(IndexOf(AItem));
|
|
end
|
|
else
|
|
begin
|
|
if IndexOf(AItem) < 0 then
|
|
Add(AItem);
|
|
end;
|
|
end;
|
|
|
|
//=== { TJvCustomPropertyStore } =============================================
|
|
|
|
constructor TJvCustomPropertyStore.Create(AOwner: TComponent);
|
|
const
|
|
IgnorePropertyList: array [1..18] of string =
|
|
(
|
|
'AboutJVCL',
|
|
'AppStorage',
|
|
'AppStoragePath',
|
|
'AutoLoad',
|
|
'ClearBeforeLoad',
|
|
'Name',
|
|
'Tag',
|
|
'Enabled',
|
|
'ReadOnly',
|
|
'DeleteBeforeStore',
|
|
'IgnoreLastLoadTime',
|
|
'IgnoreProperties',
|
|
'OnBeforeLoadProperties',
|
|
'OnAfterLoadProperties',
|
|
'OnBeforeStoreProperties',
|
|
'OnAfterStoreProperties',
|
|
'SynchronizeLoadProperties',
|
|
'SynchronizeStoreProperties'
|
|
);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
inherited Create(AOwner);
|
|
FLastLoadTime := Now;
|
|
FAppStorage := nil;
|
|
FEnabled := True;
|
|
FReadOnly := False;
|
|
FDeleteBeforeStore := False;
|
|
FAutoLoad := False;
|
|
FIntIgnoreProperties := TStringList.Create;
|
|
FIgnoreProperties := TJvIgnorePropertiesStringList.Create;
|
|
FIgnoreLastLoadTime := False;
|
|
FCombinedIgnoreProperties := TCombinedStrings.Create;
|
|
for I := Low(IgnorePropertyList) to High(IgnorePropertyList) do
|
|
FIntIgnoreProperties.Add(IgnorePropertyList[I]);
|
|
FSynchronizeStoreProperties := False;
|
|
FSynchronizeLoadProperties := False;
|
|
end;
|
|
|
|
destructor TJvCustomPropertyStore.Destroy;
|
|
begin
|
|
if not (csDesigning in ComponentState) then
|
|
if AutoLoad then
|
|
StoreProperties;
|
|
FreeAndNil(FCombinedIgnoreProperties);
|
|
FreeAndNil(FIntIgnoreProperties);
|
|
FreeAndNil(FIgnoreProperties);
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyStore.Notification(AComponent: TComponent;
|
|
Operation: TOperation);
|
|
begin
|
|
inherited Notification(AComponent, Operation);
|
|
if (Operation = opRemove) and (AComponent = FAppStorage) then
|
|
FAppStorage := nil;
|
|
end;
|
|
|
|
function TJvCustomPropertyStore.GetCombinedIgnoreProperties: TStringList;
|
|
begin
|
|
FCombinedIgnoreProperties.Assign(FIntIgnoreProperties);
|
|
FCombinedIgnoreProperties.AddStrings(FIgnoreProperties);
|
|
Result := FCombinedIgnoreProperties;
|
|
end;
|
|
|
|
function TJvCustomPropertyStore.GetPropCount(Instance: TPersistent): Integer;
|
|
var
|
|
Data: PTypeData;
|
|
begin
|
|
Data := GetTypeData(Instance.ClassInfo);
|
|
Result := Data.PropCount;
|
|
end;
|
|
|
|
function TJvCustomPropertyStore.GetPropName(Instance: TPersistent; Index: Integer): string;
|
|
var
|
|
PropList: PPropList;
|
|
PropInfo: PPropInfo;
|
|
Data: PTypeData;
|
|
begin
|
|
Result := '';
|
|
Data := GetTypeData(Instance.ClassInfo);
|
|
{$IFDEF CLR}
|
|
PropList := GetPropInfos(Instance.ClassInfo);
|
|
PropInfo := PropList[Index];
|
|
Result := PropInfo.Name;
|
|
{$ELSE}
|
|
GetMem(PropList, Data^.PropCount * SizeOf(PPropInfo));
|
|
try
|
|
GetPropInfos(Instance.ClassInfo, PropList);
|
|
PropInfo := PropList^[Index];
|
|
Result := PropInfo^.Name;
|
|
finally
|
|
FreeMem(PropList, Data^.PropCount * SizeOf(PPropInfo));
|
|
end;
|
|
{$ENDIF CLR}
|
|
end;
|
|
|
|
procedure TJvCustomPropertyStore.CloneClass(Src, Dest: TPersistent);
|
|
var
|
|
Index: Integer;
|
|
SrcPropInfo: PPropInfo;
|
|
DestPropInfo: PPropInfo;
|
|
|
|
function GetPropKind(PropInfo: PPropInfo): TTypeKind;
|
|
begin
|
|
{$IFDEF CLR}
|
|
Result := PropInfo.TypeKind;
|
|
{$ELSE}
|
|
Result := PropInfo.PropType^.Kind;
|
|
{$ENDIF CLR}
|
|
end;
|
|
|
|
begin
|
|
for Index := 0 to GetPropCount(Src) - 1 do
|
|
if CompareText(GetPropName(Src, Index), 'Name') <> 0 then
|
|
begin
|
|
SrcPropInfo := GetPropInfo(Src.ClassInfo, GetPropName(Src, Index));
|
|
DestPropInfo := GetPropInfo(Dest.ClassInfo, GetPropName(Src, Index));
|
|
if (DestPropInfo <> nil) and (GetPropKind(DestPropInfo) = GetPropKind(SrcPropInfo)) then
|
|
case GetPropKind(DestPropInfo) of
|
|
tkLString, tkString:
|
|
SetStrProp(Dest, DestPropInfo, GetStrProp(Src, SrcPropInfo));
|
|
tkInteger, tkChar, tkEnumeration, tkSet:
|
|
SetOrdProp(Dest, DestPropInfo, GetOrdProp(Src, SrcPropInfo));
|
|
tkFloat:
|
|
SetFloatProp(Dest, DestPropInfo, GetFloatProp(Src, SrcPropInfo));
|
|
tkVariant:
|
|
SetVariantProp(Dest, DestPropInfo, GetVariantProp(Src, SrcPropInfo));
|
|
tkClass:
|
|
TPersistent(GetObjectProp(Dest, DestPropInfo)).Assign(TPersistent(GetObjectProp(Src, SrcPropInfo)));
|
|
tkMethod:
|
|
SetMethodProp(Dest, DestPropInfo, GetMethodProp(Src, SrcPropInfo));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyStore.Loaded;
|
|
begin
|
|
inherited Loaded;
|
|
if not (csDesigning in ComponentState) then
|
|
if AutoLoad then
|
|
LoadProperties;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyStore.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is Self.ClassType then
|
|
CloneClass(Source, Self)
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
procedure TJvCustomPropertyStore.Clear;
|
|
begin
|
|
end;
|
|
|
|
function TJvCustomPropertyStore.TranslatePropertyName(AName: string): string;
|
|
begin
|
|
Result := AName;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyStore.SetAutoLoad(Value: Boolean);
|
|
begin
|
|
if not Assigned(Owner) then
|
|
Exit;
|
|
if Owner is TJvCustomPropertyStore then
|
|
FAutoLoad := False
|
|
else
|
|
if Value <> AutoLoad then
|
|
FAutoLoad := Value;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyStore.DisableAutoLoadDown;
|
|
var
|
|
Index: Integer;
|
|
PropName: string;
|
|
begin
|
|
for Index := 0 to GetPropCount(Self) - 1 do
|
|
begin
|
|
PropName := GetPropName(Self, Index);
|
|
if IgnoreProperties.IndexOf(PropName) < 0 then
|
|
if FIntIgnoreProperties.IndexOf(PropName) < 0 then
|
|
if PropType(Self, GetPropName(Self, Index)) = tkClass then
|
|
if (TPersistent(GetObjectProp(Self, PropName)) is TJvCustomPropertyStore) then
|
|
TJvCustomPropertyStore(TPersistent(GetObjectProp(Self, PropName))).AutoLoad := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyStore.UpdateChildPaths(OldPath: string);
|
|
var
|
|
Index: Integer;
|
|
VisPropName: string;
|
|
PropName: string;
|
|
PropertyStore: TJvCustomPropertyStore;
|
|
begin
|
|
if Assigned(AppStorage) then
|
|
begin
|
|
if OldPath = '' then
|
|
OldPath := AppStoragePath;
|
|
for Index := 0 to GetPropCount(Self) - 1 do
|
|
begin
|
|
PropName := GetPropName(Self, Index);
|
|
VisPropName := AppStorage.TranslatePropertyName(Self, PropName, False);
|
|
// (rom) very bad style. Better stacked if chain like the other ones.
|
|
if IgnoreProperties.IndexOf(PropName) >= 0 then
|
|
Continue;
|
|
if FIntIgnoreProperties.IndexOf(PropName) >= 0 then
|
|
Continue;
|
|
if PropType(Self, PropName) = tkClass then
|
|
if (TPersistent(GetObjectProp(Self, PropName)) is TJvCustomPropertyStore) then
|
|
begin
|
|
PropertyStore := TJvCustomPropertyStore(TPersistent(GetObjectProp(Self, PropName)));
|
|
if (PropertyStore.AppStoragePath = AppStorage.ConcatPaths([OldPath, VisPropName])) or
|
|
(PropertyStore.AppStoragePath = '') then
|
|
PropertyStore.AppStoragePath := AppStorage.ConcatPaths([AppStoragePath, VisPropName]);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyStore.SetPath(Value: string);
|
|
var
|
|
OldPath: string;
|
|
begin
|
|
OldPath := FAppStoragePath;
|
|
if Value <> AppStoragePath then
|
|
FAppStoragePath := Value;
|
|
UpdateChildPaths(OldPath);
|
|
end;
|
|
|
|
procedure TJvCustomPropertyStore.SetAppStorage(Value: TJvCustomAppStorage);
|
|
var
|
|
Index: Integer;
|
|
PropName: string;
|
|
begin
|
|
if Value <> FAppStorage then
|
|
begin
|
|
for Index := 0 to GetPropCount(Self) - 1 do
|
|
begin
|
|
PropName := GetPropName(Self, Index);
|
|
// (rom) very bad style. Better stacked if chain like the other ones.
|
|
if IgnoreProperties.IndexOf(PropName) >= 0 then
|
|
Continue;
|
|
if FIntIgnoreProperties.IndexOf(PropName) >= 0 then
|
|
Continue;
|
|
if PropType(Self, PropName) = tkClass then
|
|
if (TPersistent(GetObjectProp(Self, PropName)) is TJvCustomPropertyStore) then
|
|
TJvCustomPropertyStore(TPersistent(GetObjectProp(Self, PropName))).AppStorage := Value;
|
|
end;
|
|
FAppStorage := Value;
|
|
UpdateChildPaths;
|
|
end;
|
|
end;
|
|
|
|
function TJvCustomPropertyStore.GetIgnoreProperties: TJvIgnorePropertiesStringList;
|
|
begin
|
|
Result := FIgnoreProperties;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyStore.SetIgnoreProperties(Value: TJvIgnorePropertiesStringList);
|
|
begin
|
|
FIgnoreProperties.Assign(Value);
|
|
end;
|
|
|
|
function TJvCustomPropertyStore.GetLastSaveTime: TDateTime;
|
|
begin
|
|
Result := 0;
|
|
if not Enabled then
|
|
Exit;
|
|
if AppStoragePath = '' then
|
|
Exit;
|
|
try
|
|
if AppStorage.ValueStored(AppStorage.ConcatPaths([AppStoragePath, cLastSaveTime])) then
|
|
Result := AppStorage.ReadDateTime(AppStorage.ConcatPaths([AppStoragePath, cLastSaveTime]));
|
|
except
|
|
Result := 0;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyStore.LoadProperties;
|
|
var
|
|
JclMutex: TJclMutex;
|
|
|
|
procedure ExecuteLoadProperties;
|
|
begin
|
|
AppStorage.BeginUpdate;
|
|
try
|
|
UpdateChildPaths;
|
|
FLastLoadTime := Now;
|
|
if ClearBeforeLoad then
|
|
Clear;
|
|
if Assigned(FOnBeforeLoadProperties) then
|
|
FOnBeforeLoadProperties(Self);
|
|
LoadData;
|
|
AppStorage.ReadPersistent(AppStoragePath, Self, True, True, CombinedIgnoreProperties);
|
|
if Assigned(FOnAfterLoadProperties) then
|
|
FOnAfterLoadProperties(Self);
|
|
finally
|
|
AppStorage.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
|
|
begin
|
|
if not Enabled then
|
|
Exit;
|
|
if not Assigned(AppStorage) then
|
|
Exit;
|
|
|
|
if SynchronizeLoadProperties then
|
|
begin
|
|
JclMutex := TJclMutex.Create(nil, False,
|
|
B64Encode(RsJvPropertyStoreMutexLoadPropertiesProcedureName + AppStoragePath));
|
|
try
|
|
if JclMutex.WaitForever = wrSignaled then
|
|
try
|
|
ExecuteLoadProperties;
|
|
finally
|
|
JclMutex.Release;
|
|
end
|
|
else
|
|
raise Exception.CreateResFmt(@RsJvPropertyStoreEnterMutexTimeout, [RsJvPropertyStoreMutexStorePropertiesProcedureName]);
|
|
finally
|
|
FreeAndNil(JclMutex);
|
|
end;
|
|
end
|
|
else
|
|
ExecuteLoadProperties;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyStore.StoreProperties;
|
|
var
|
|
SaveProperties: Boolean;
|
|
JclMutex: TJclMutex;
|
|
|
|
procedure ExecuteStoreProperties;
|
|
begin
|
|
AppStorage.BeginUpdate;
|
|
try
|
|
UpdateChildPaths;
|
|
DisableAutoLoadDown;
|
|
SaveProperties := IgnoreLastLoadTime or (GetLastSaveTime < FLastLoadTime);
|
|
if DeleteBeforeStore then
|
|
AppStorage.DeleteSubTree(AppStoragePath);
|
|
if not IgnoreLastLoadTime then
|
|
AppStorage.WriteString(AppStorage.ConcatPaths([AppStoragePath, cLastSaveTime]), DateTimeToStr(Now));
|
|
if Assigned(FOnBeforeStoreProperties) then
|
|
FOnBeforeStoreProperties(Self);
|
|
if SaveProperties then
|
|
StoreData;
|
|
AppStorage.WritePersistent(AppStoragePath, Self, True, CombinedIgnoreProperties);
|
|
if Assigned(FOnAfterStoreProperties) then
|
|
FOnAfterStoreProperties(Self);
|
|
finally
|
|
AppStorage.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if not Enabled then
|
|
Exit;
|
|
if ReadOnly then
|
|
Exit;
|
|
if not Assigned(AppStorage) then
|
|
Exit;
|
|
|
|
if SynchronizeStoreProperties then
|
|
begin
|
|
JclMutex := TJclMutex.Create(nil, False,
|
|
B64Encode(RsJvPropertyStoreMutexStorePropertiesProcedureName + AppStoragePath));
|
|
try
|
|
if JclMutex.WaitForever = wrSignaled then
|
|
try
|
|
ExecuteStoreProperties;
|
|
finally
|
|
JclMutex.Release;
|
|
end
|
|
else
|
|
raise Exception.CreateResFmt(@RsJvPropertyStoreEnterMutexTimeout, [RsJvPropertyStoreMutexStorePropertiesProcedureName]);
|
|
finally
|
|
FreeAndNil(JclMutex);
|
|
end;
|
|
end
|
|
else
|
|
ExecuteStoreProperties;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyStore.LoadData;
|
|
begin
|
|
end;
|
|
|
|
procedure TJvCustomPropertyStore.StoreData;
|
|
begin
|
|
end;
|
|
|
|
//=== { TJvCustomPropertyListStore } =========================================
|
|
|
|
constructor TJvCustomPropertyListStore.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FItems := CreateItemList;
|
|
CreateListEntries := True;
|
|
FreeObjects := True;
|
|
FItemName := cItem;
|
|
FIntIgnoreProperties.Add('ItemName');
|
|
FIntIgnoreProperties.Add('FreeObjects');
|
|
FIntIgnoreProperties.Add('CreateListEntries');
|
|
end;
|
|
|
|
destructor TJvCustomPropertyListStore.Destroy;
|
|
begin
|
|
Clear;
|
|
FreeAndNil(FItems);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJvCustomPropertyListStore.GetItems: TStringList;
|
|
begin
|
|
Result := FItems;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyListStore.StoreData;
|
|
begin
|
|
inherited StoreData;
|
|
AppStorage.WriteList(AppStoragePath, nil, Count, WriteSLOItem, DeleteSLOItems, ItemName);
|
|
end;
|
|
|
|
procedure TJvCustomPropertyListStore.LoadData;
|
|
begin
|
|
inherited LoadData;
|
|
AppStorage.ReadList(AppStoragePath, nil, ReadSLOItem, ItemName);
|
|
end;
|
|
|
|
procedure TJvCustomPropertyListStore.Clear;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if FreeObjects then
|
|
for I := 0 to Count - 1 do
|
|
if Assigned(Objects[I]) then
|
|
begin
|
|
Objects[I].Free;
|
|
Objects[I] := nil;
|
|
end;
|
|
if Assigned(Items) then
|
|
Items.Clear;
|
|
inherited Clear;
|
|
end;
|
|
|
|
function TJvCustomPropertyListStore.CreateItemList: TStringList;
|
|
begin
|
|
Result := TStringList.Create;
|
|
end;
|
|
|
|
function TJvCustomPropertyListStore.CreateObject: TObject;
|
|
begin
|
|
Result := nil;
|
|
end;
|
|
|
|
function TJvCustomPropertyListStore.GetString(Index: Integer): string;
|
|
begin
|
|
if Assigned(Items) then
|
|
Result := Items.Strings[Index]
|
|
else
|
|
Result := '';
|
|
end;
|
|
|
|
function TJvCustomPropertyListStore.GetObject(Index: Integer): TObject;
|
|
begin
|
|
if Assigned(Items) then
|
|
Result := Items.Objects[Index]
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyListStore.SetString(Index: Integer; Value: string);
|
|
begin
|
|
Items.Strings[Index] := Value;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyListStore.SetObject(Index: Integer; Value: TObject);
|
|
begin
|
|
Items.Objects[Index] := Value;
|
|
end;
|
|
|
|
function TJvCustomPropertyListStore.GetCount: Integer;
|
|
begin
|
|
if Assigned(Items) then
|
|
Result := Items.Count
|
|
else
|
|
Result := -1;
|
|
end;
|
|
|
|
function TJvCustomPropertyListStore.GetSorted: Boolean;
|
|
begin
|
|
Result := FItems.Sorted;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyListStore.SetSorted (Value: Boolean);
|
|
begin
|
|
FItems.Sorted := Value;
|
|
end;
|
|
|
|
function TJvCustomPropertyListStore.GetDuplicates: TDuplicates;
|
|
begin
|
|
Result := FItems.Duplicates;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyListStore.SetDuplicates (Value: TDuplicates);
|
|
begin
|
|
FItems.Duplicates := Value;
|
|
end;
|
|
|
|
procedure TJvCustomPropertyListStore.ReadSLOItem(Sender: TJvCustomAppStorage;
|
|
const Path: string; const List: TObject; const Index: Integer; const ItemName: string);
|
|
var
|
|
NewObject: TObject;
|
|
NewObjectName: string;
|
|
begin
|
|
if Index >= Count then
|
|
begin
|
|
if not CreateListEntries then
|
|
Exit;
|
|
NewObject := CreateObject;
|
|
if Assigned(NewObject) then
|
|
begin
|
|
if NewObject is TJvCustomPropertyStore then
|
|
begin
|
|
TJvCustomPropertyStore(NewObject).AppStoragePath :=
|
|
Sender.ConcatPaths([Path, ItemName + IntToStr(Index)]);
|
|
TJvCustomPropertyStore(NewObject).AppStorage := AppStorage;
|
|
TJvCustomPropertyStore(NewObject).LoadProperties;
|
|
end
|
|
else
|
|
if NewObject is TPersistent then
|
|
Sender.ReadPersistent(Sender.ConcatPaths([Path, ItemName + IntToStr(Index)]),
|
|
TPersistent(NewObject), True, True, CombinedIgnoreProperties);
|
|
if Sender.ValueStored(Sender.ConcatPaths([Path, ItemName + IntToStr(Index)])) then
|
|
NewObjectName := Sender.ReadString(Sender.ConcatPaths([Path, ItemName + IntToStr(Index)]))
|
|
else
|
|
NewObjectName := '';
|
|
Items.AddObject(NewObjectName, NewObject);
|
|
end
|
|
else
|
|
Items.Add(Sender.ReadString(Sender.ConcatPaths([Path, ItemName + IntToStr(Index)])))
|
|
end
|
|
else
|
|
if Assigned(Objects[Index]) then
|
|
begin
|
|
if Objects[Index] is TJvCustomPropertyStore then
|
|
begin
|
|
TJvCustomPropertyStore(Objects[Index]).AppStoragePath :=
|
|
Sender.ConcatPaths([Path, ItemName + IntToStr(Index)]);
|
|
TJvCustomPropertyStore(Objects[Index]).LoadProperties;
|
|
end
|
|
else
|
|
if Objects[Index] is TPersistent then
|
|
Sender.ReadPersistent(Sender.ConcatPaths([Path, ItemName + IntToStr(Index)]),
|
|
TPersistent(Objects[Index]), True, True, CombinedIgnoreProperties);
|
|
if Sender.ValueStored(Sender.ConcatPaths([Path, ItemName + IntToStr(Index)])) then
|
|
Strings[Index] := Sender.ReadString(Sender.ConcatPaths([Path, ItemName + IntToStr(Index)]))
|
|
else
|
|
Strings[Index] := '';
|
|
end
|
|
else
|
|
Strings[Index] := Sender.ReadString(Sender.ConcatPaths([Path, ItemName + IntToStr(Index)]));
|
|
end;
|
|
|
|
procedure TJvCustomPropertyListStore.WriteSLOItem(Sender: TJvCustomAppStorage;
|
|
const Path: string; const List: TObject; const Index: Integer; const ItemName: string);
|
|
begin
|
|
if Assigned(Objects[Index]) then
|
|
begin
|
|
if Objects[Index] is TJvCustomPropertyStore then
|
|
begin
|
|
TJvCustomPropertyStore(Objects[Index]).AppStoragePath :=
|
|
Sender.ConcatPaths([Path, ItemName + IntToStr(Index)]);
|
|
TJvCustomPropertyStore(Objects[Index]).AppStorage := AppStorage;
|
|
TJvCustomPropertyStore(Objects[Index]).StoreProperties;
|
|
end
|
|
else
|
|
if Objects[Index] is TPersistent then
|
|
Sender.WritePersistent(Sender.ConcatPaths([Path, ItemName + IntToStr(Index)]),
|
|
TPersistent(Objects[Index]), True, CombinedIgnoreProperties);
|
|
if Strings[Index] <> '' then
|
|
Sender.WriteString(Sender.ConcatPaths([Path, ItemName + IntToStr(Index)]), Strings[Index]);
|
|
end
|
|
else
|
|
Sender.WriteString(Sender.ConcatPaths([Path, ItemName + IntToStr(Index)]), Strings[Index]);
|
|
end;
|
|
|
|
procedure TJvCustomPropertyListStore.DeleteSLOItems(Sender: TJvCustomAppStorage;
|
|
const Path: string; const List: TObject; const First, Last: Integer; const ItemName: string);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := First to Last do
|
|
Sender.DeleteValue(Sender.ConcatPaths([Path, ItemName + IntToStr(I)]));
|
|
end;
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
initialization
|
|
RegisterUnitVersion(HInstance, UnitVersioning);
|
|
|
|
finalization
|
|
UnregisterUnitVersion(HInstance);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
end.
|