From cb3d20f96967b6ddcbd66df172595ccfef09ee4d Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 28 Oct 2024 14:57:50 +0000
Subject: [PATCH 001/222] Fix XMLDoc format error in UUserDBMove.pas
---
Src/UUserDBMove.pas | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Src/UUserDBMove.pas b/Src/UUserDBMove.pas
index 447594147..2af3f4056 100644
--- a/Src/UUserDBMove.pas
+++ b/Src/UUserDBMove.pas
@@ -47,8 +47,8 @@ TUserDBMove = class(TObject)
/// Instance of class used to perform directory move.
fDirCopier: TDirectoryCopier;
/// Validates source and destination directories.
- /// Raises EInOutError exception if either directory is not
- /// valid.
+ /// Raises EInOutError exception if either directory is not
+ /// valid.
procedure ValidateDirectories;
/// Handles TDirectoryCopier.OnAfterCopyDir event to update user
/// database location.
From b09981100ac3c8b42e83be46d5167ab9976511df Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 28 Oct 2024 19:03:19 +0000
Subject: [PATCH 002/222] Add database design documents
database-structure.md to describe the database structure
database-io to describe how the database's data sources are read/written
---
Docs/Design/database-io.md | 150 ++++++++++++++++++++++++++++++
Docs/Design/database-structure.md | 29 ++++++
2 files changed, 179 insertions(+)
create mode 100644 Docs/Design/database-io.md
create mode 100644 Docs/Design/database-structure.md
diff --git a/Docs/Design/database-io.md b/Docs/Design/database-io.md
new file mode 100644
index 000000000..200271862
--- /dev/null
+++ b/Docs/Design/database-io.md
@@ -0,0 +1,150 @@
+# Database IO Design
+
+Both user defined and "main" snippets are stored in the same data structure.
+
+## Loading
+
+When the database is loaded the following happens:
+
+### Top level
+
+`TDatabaseIOFactory` is called twice, in a predefined, significant order:
+
+1. `TDatabaseIOFactory.CreateMainDBLoader` is called to create a `IDatabaseLoader` object for the main database. That object's `Load` method is called.
+2. `TDatabaseIOFactory.CreateUserDBLoader` is called to create another `IDatabaseLoader` object, this time for the user databse. That object's `Load` method is then called.
+
+> ⭐ When adding further data sources, instead of hard wiring the `TDatabaseIOFactory.CreateXXX` methods, we will need to create `IDatabaseLoader` instances for each registered data source. It may be a good idea initially to hard wire the "main" and "user" databases at the start of the data source registry and ensure they are all called in the right order.
+
+The order the loading is done is to ensure any references to snippets in the main database are valid when the user database is loaded. This is because the user database can reference snippets in the main database, but not vice versa.
+
+> ⭐ When implementing additional data sources we may need to prevent references across data sources.
+
+### Level 2: `IDatabaseLoader`
+
+`IDatabaseLoader` is defined as:
+
+```pascal
+ IDatabaseLoader = interface(IInterface)
+ ['{C6AF94FC-F56F-44AE-9E79-3B0CD0BB21D4}']
+ procedure Load(const SnipList: TSnippetList;
+ const Categories: TCategoryList;
+ const DBDataItemFactory: IDBDataItemFactory);
+ end;
+```
+
+Implementations of the single `Load` method create and store loaded snippets and categories in `SnipList` & `Categories` respectively. They use `IDBDataItemFactory` methods to create snippet and category objects.
+
+There are the following `IDatabaseLoader` implementations:
+
+1. `TMainDatabaseLoader` for loading the main database from the main database directory.
+2. `TUserDatabaseLoader` for loading the user database from its directory.
+
+Both the above classes use the template design pattern and descend from an abstract parent class named `TDatabaseLoader`. One of the overridden template methods requires an object to be returned that can read data from the correct database format and expose methods that are called from `TDatabaseLoader`. These reader object are of type `IDataReader`.
+
+> ⭐ When implementing additional data formats we will need further `IDatabaseLoader` implementations that can read each supported format. If we choose to sub class `TDatabaseLoader` then we will need to provide a suitable `IDataReader` implementation.
+
+In either case, if no database of either type is found a null object of type `TNulDataReader` (sic) is created that implements `IDataReader` to do nothing.
+
+### Level 3: `IDataReader`
+
+`IDataReader` is defined as:
+
+```pascal
+ IDataReader = interface(IInterface)
+ ['{72A8EAD4-05CE-41BF-AE0F-33495757BBFC}']
+ function DatabaseExists: Boolean;
+ function GetAllCatIDs: IStringList;
+ procedure GetCatProps(const CatID: string; var Props: TCategoryData);
+ function GetCatSnippets(const CatID: string): IStringList;
+ procedure GetSnippetProps(const Snippet: string; var Props: TSnippetData);
+ function GetSnippetXRefs(const Snippet: string): IStringList;
+ function GetSnippetDepends(const Snippet: string): IStringList;
+ function GetSnippetUnits(const Snippet: string): IStringList;
+ end;
+```
+
+Where:
+
+* `DatabaseExists` -- Checks if the database exists. This method is always called first. No other methods of `IDataReader` are called if this method returns false.
+* `GetAllCatIDs` -- Gets the names of all categories defined in the database.
+* `GetCatProps` -- Gets the properties of the category identified by `CatID` and returns them in the `Props` record.
+* `GetCatSnippets` -- Returns a list of the names of all snippets in category with ID `CatID`.
+* `GetSnippetProps` -- Gets the properties if the snippet with unique `Snippet` and returns them in the `Props` record.
+* `GetSnippetXRefs` -- Returns a list of the names of all snippets XRefd by snippet with name `Snippet`.
+* `GetSnippetDepends` -- Returns a list of the names of all snippets on which the snippet with name `Snippet` depends.
+* `GetSnippetUnits` -- Returns a list of the names of all the units referenced by the snippet with name `Snippet`.
+
+There are the following `IDataReader` implementations:
+
+1. `TIniDataReader` that reads the main database's .ini based data format. Instances of this class are created by `TMainDatabaseLoader`.
+2. `TXMLDataReader` that read the user database's XML based data format. Instances of this class are created by `TUserDatabaseLoader`.
+
+> ⭐ Note that, although there is a one-one correspondence between `TMainDatabaseLoader` & `TIniDataReader` and `TUserDatabaseLoader` and `TXMLDataReader`, this does not generalise to other data sources and data format readers. More than one data source could use the same data format.
+
+> ⭐ When implementing additional data sources we will need `IDataReader` implementations that can read each supported data format.
+
+## Saving
+
+Only the user database gets saved, because only this database is editable. When the user database is saved, the following happens:
+
+`TDatabaseIOFactory` is called to create a `IDatabaseWriter` database writer object. That object's `Write` method is then called.
+
+> ⭐ When adding further data sources we will need to extend the factory class to create a suitable `IDatabaseWriter` object for the data format being written.
+
+### Level 2: `IDatabaseWriter`
+
+`IDatabaseWriter` is defined as:
+
+```pascal
+ IDatabaseWriter = interface(IInterface)
+ ['{F46EE2E3-68A7-4877-9E04-192D15D29BB1}']
+ procedure Write(const SnipList: TSnippetList;
+ const Categories: TCategoryList; const Provider: IDBDataProvider);
+ end;
+```
+
+The sole `Write` method writes user data from database object, where `SnipList` and `Categories` contain the snippets and categories to be saved, respectively, and the `Provider` object is used to get snippet and category properties to be written.
+
+There is just the one `IDatabaseWriter` implementation: `TDatabaseWriter` that saves the user database. It creates and uses a `IDataWriter` instance to perform the actual output.
+
+> ⭐ When adding further data formats we will need different `IDataWriter` implementations that can write data in the correct format.
+
+### Level 3: `IDataWriter`
+
+`IDataWriter` is defined as follows:
+
+```pascal
+ IDataWriter = interface(IInterface)
+ ['{71E892C4-6E0F-480A-9DF4-70835F83A0CA}']
+ procedure Initialise;
+ procedure WriteCatProps(const CatID: string; const Props: TCategoryData);
+ procedure WriteCatSnippets(const CatID: string;
+ const SnipList: IStringList);
+ procedure WriteSnippetProps(const SnippetName: string;
+ const Props: TSnippetData);
+ procedure WriteSnippetUnits(const SnippetName: string;
+ const Units: IStringList);
+ procedure WriteSnippetDepends(const SnippetName: string;
+ const Depends: IStringList);
+ procedure WriteSnippetXRefs(const SnippetName: string;
+ const XRefs: IStringList);
+ procedure Finalise;
+ end;
+```
+
+Where:
+
+* `Initialise` -- Initialise the output. Always called before any other methods.
+* `WriteCatProps` -- Writes the properties per `Props` of the category with ID `CatID`.
+* `WriteCatSnippets` -- Writes the list of snippets whose names are in `SnipList` belonging to category `CatID`. Always called after `WriteCatProps` for a given category.
+* `WriteSnippetProps` -- Writes the properties from `Props` for snippet named `SnippetName`. Always called after all categories are written and before `WriteSnippetUnits`, so can be used to perform any per-snippet intialisation.
+* `WriteSnippetUnits` -- Writes the list of units per `Units` referenced by the snippet named `SnippetName`.
+* `WriteSnippetDepends` -- Writes the list of snippets names in `Depends` that are depended upon by the snippet named `SnippetName`.
+* `WriteSnippetXRef` -- Writes the list of snippets names in `XRefs` that are cross referenced by the snippet named `SnippetName`.
+* `Finalise` -- Finalises the writing. Always called after all other methods.
+
+There is only the one `IDataWriter` implementation. That is `TXMLDataWriter` that writes the user database data in the required XML format.
+
+> ⭐ When adding further data formats we will need further data writer implementations
+
+> ⭐ There is not necessarily a one-one correspondence between data sources and formats, so the same `IDataWriter` implementation could be used for more than one data source.
diff --git a/Docs/Design/database-structure.md b/Docs/Design/database-structure.md
new file mode 100644
index 000000000..1a363d539
--- /dev/null
+++ b/Docs/Design/database-structure.md
@@ -0,0 +1,29 @@
+# Database Structure Design
+
+## Overview
+
+CodeSnip maintains a database comprising snippets from two data sources:
+
+1. The _"main"_ data source -- Read only snippets read from data downloaded from the [DelphiDabbler Code Snippets Collection](https://github.com/delphidabbler/code-snippets).
+
+2. The _"user"_ data source -- Snippets created by the user that can be created, edited and deleted from within CodeSnip. These snippets are stored on the user's computer in a special directory. It is possible to import snippets exported from another user's snippets collection or from the [SWAG Archive](https://github.com/delphidabbler/swag). Such imported snippets become part of the user's own "user" data source and retain no knowledge of where they originally came from.
+
+The database also contains various category records. Categories read from the main data source can't be edited. Categories created by the user are stored in the user data source. Snippets from the user data source can reference categories from the main data source, but the reverse never happens.
+
+Throughout much of CodeSnip's documentation, the "main" and "user" data sources will be referred to as the "main" and "user" databases. However, there is only one database that has two data sources: "main" and "user".
+
+## Tables
+
+Internally, CodeSnip maintains two in-memory tables:
+
+1. The _snippets_ table -- Contains a record for each snippet
+2. The _categories_ table -- Contains a record for each category
+
+Both Snippet and Category records identify which data source they belong to by means of a `UserDefined` field. This is true for the "user" data source and false for the "main" data source.
+
+> ⭐ When adding further data sources we will need to change the `UserDefined` fields to something like `DataSource` or `Origin` so we know which data source the snippet belongs to.
+
+> ⭐ When creating snippets we will need to get the user to specify a data source for. Since it's very likely that a snippet will be mis-allocated we will also need to provide a way to move snippets between data sources.
+
+> ⭐ For as long as the "main" data source is special, we will need a property or method for snippets like `IsEditable` or `IsMain` that can be used to prevent editing a snippet.
+
From 9066a07985ee494c6350d5a0ab1e54aef70d465b Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 28 Oct 2024 23:28:14 +0000
Subject: [PATCH 003/222] Add TryStrToByte function to UUtils unit
Also corrected XMLDoc comments for TryStrToWord.
---
Src/UUtils.pas | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/Src/UUtils.pas b/Src/UUtils.pas
index 279d62080..d3ec22136 100644
--- a/Src/UUtils.pas
+++ b/Src/UUtils.pas
@@ -3,7 +3,7 @@
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/
*
- * Copyright (C) 2005-2021, Peter Johnson (gravatar.com/delphidabbler).
+ * Copyright (C) 2005-2024, Peter Johnson (gravatar.com/delphidabbler).
*
* General utility routines.
}
@@ -174,13 +174,23 @@ function IsEqualBytes(const BA1, BA2: TBytes): Boolean; overload;
/// Attempts to convert string S into a Word value.
/// string [in] String to be converted.
-/// Cardinal [out] Value of converted string. Undefined if
+/// Word [out] Value of converted string. Undefined if
/// conversion fails.
/// Boolean. True if conversion succeeds, False if not.
/// String must represent a non-negative integer that is representable
/// as a Word.
function TryStrToWord(const S: string; out W: Word): Boolean;
+/// Attempts to convert string S into a Byye value.
+/// string [in] String to be converted.
+/// Byte [out] Value of converted string. Undefined if
+/// conversion fails.
+/// Boolean. True if conversion succeeds, False if not.
+/// String must represent a non-negative integer that is representable
+/// as a Byte.
+function TryStrToByte(const S: string; out B: Byte): Boolean;
+
+
implementation
@@ -473,5 +483,17 @@ function TryStrToWord(const S: string; out W: Word): Boolean;
W := Word(I);
end;
+function TryStrToByte(const S: string; out B: Byte): Boolean;
+var
+ I: Integer;
+begin
+ Result := TryStrToInt(S, I);
+ if not Result then
+ Exit;
+ if (I < Low(Byte)) or (I > High(Byte)) then
+ Exit(False);
+ B := Byte(I);
+end;
+
end.
From a5d2b5598ffddfe99174ad75318ce853ec16dfce Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 28 Oct 2024 23:48:09 +0000
Subject: [PATCH 004/222] Add methods to get & set byte arrays in settings
New methods added to ISettingsSection and TIniSettingsSection that store
byte arrays as comma delimited lists of decimal values in range 0..255.
---
Src/USettings.pas | 87 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 85 insertions(+), 2 deletions(-)
diff --git a/Src/USettings.pas b/Src/USettings.pas
index 5e38e3227..bd6227e62 100644
--- a/Src/USettings.pas
+++ b/Src/USettings.pas
@@ -119,6 +119,20 @@ interface
/// regardless of locale.
procedure SetDateTime(const Name: string; const Value: TDateTime);
+ /// Gets a named byte array from settings.
+ /// string [in] Name of value.
+ /// TBytes. The required array of bytes.
+ /// The value is stored as a comma separated sequence of decimal
+ /// values in the range 0..255.
+ function GetBytes(const Name: string): TBytes;
+
+ /// Stores a named byte array in settings.
+ /// string [in] Name of value.
+ /// TBytes [in] Byte array to be recorded.
+ /// The bytes must be stored as comma separated decimal values.
+ ///
+ procedure SetBytes(const Name: string; const Value: TBytes);
+
/// Gets a list of related string values from the section.
///
/// string [in] Name of an integer value that
@@ -222,7 +236,8 @@ implementation
UAppInfo,
UHexUtils,
UIOUtils,
- UStrUtils;
+ UStrUtils,
+ UUtils;
var
@@ -442,7 +457,7 @@ TIniSettingsSection = class(TIniSettingsBase, ISettingsSection)
/// Records a named date time value in settings.
/// string [in] Name of value.
- /// TDateTime [in] Value to be recored.
+ /// TDateTime [in] Value to be recorded.
///
/// The value must be stored in YYYY-MM-DD hh:mm:ss format
/// regardless of locale.
@@ -450,6 +465,26 @@ TIniSettingsSection = class(TIniSettingsBase, ISettingsSection)
///
procedure SetDateTime(const Name: string; const Value: TDateTime);
+ /// Gets a named byte array from settings.
+ /// string [in] Name of value.
+ /// TBytes. The required array of bytes.
+ ///
+ /// The value is stored as a comma separated sequence of decimal
+ /// values in the range 0..255.
+ /// Method of ISettingsSection.
+ ///
+ function GetBytes(const Name: string): TBytes;
+
+ /// Stores a named byte array in settings.
+ /// string [in] Name of value.
+ /// TBytes [in] Byte array to be recorded.
+ ///
+ /// The bytes must be stored as comma separated decimal values.
+ ///
+ /// Method of ISettingsSection.
+ ///
+ procedure SetBytes(const Name: string; const Value: TBytes);
+
/// Gets a list of related string values from the section.
///
/// string [in] Name of an integer value that
@@ -475,6 +510,7 @@ TIniSettingsSection = class(TIniSettingsBase, ISettingsSection)
/// Method of ISettingsSection.
procedure SetStrings(const CountName, ItemFmt: string;
Value: IStringList);
+
end;
function Settings: ISettings;
@@ -589,6 +625,35 @@ function TIniSettingsSection.GetBoolean(const Name: string;
Result := not StrMatchText(ValStr, ['0', 'false', 'no', 'n']);
end;
+function TIniSettingsSection.GetBytes(const Name: string): TBytes;
+var
+ ValStr: string;
+ ValSL: TStrings;
+ B: Byte;
+ Idx: Integer;
+begin
+ ValStr := StrTrim(GetItemValue(Name));
+ if ValStr = '' then
+ begin
+ SetLength(Result, 0);
+ Exit;
+ end;
+ ValSL := TStringList.Create;
+ try
+ StrExplode(ValStr, ',', ValSL, False, True);
+ SetLength(Result, ValSL.Count);
+ for Idx := 0 to Pred(ValSL.Count) do
+ begin
+ if TryStrToByte(ValSL[Idx], B) then
+ Result[Idx] := B
+ else
+ Result[Idx] := 0;
+ end;
+ finally
+ ValSL.Free;
+ end;
+end;
+
function TIniSettingsSection.GetDateTime(const Name: string;
const Default: TDateTime): TDateTime;
var
@@ -702,6 +767,24 @@ procedure TIniSettingsSection.SetBoolean(const Name: string;
SetItemValue(Name, BoolStrs[Value]);
end;
+procedure TIniSettingsSection.SetBytes(const Name: string;
+ const Value: TBytes);
+var
+ SL: TStrings;
+ B: Byte;
+begin
+ SL := TStringList.Create;
+ try
+ for B in Value do
+ begin
+ SL.Add(IntToStr(B));
+ end;
+ SetItemValue(Name, StrJoin(SL, ','));
+ finally
+ SL.Free;
+ end;
+end;
+
procedure TIniSettingsSection.SetDateTime(const Name: string;
const Value: TDateTime);
begin
From 2220309f3fb0fe73fb45a8702360a7efb161139d Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 29 Oct 2024 01:43:18 +0000
Subject: [PATCH 005/222] Add GUIDToBytes routine to UUtils unit
---
Src/UUtils.pas | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/Src/UUtils.pas b/Src/UUtils.pas
index d3ec22136..434fb0a4b 100644
--- a/Src/UUtils.pas
+++ b/Src/UUtils.pas
@@ -172,6 +172,11 @@ function IsEqualBytes(const BA1, BA2: TBytes; const Count: Cardinal):
/// If both arrays are empty they are considered equal.
function IsEqualBytes(const BA1, BA2: TBytes): Boolean; overload;
+/// Converts a TGUID record into an array of bytes.
+/// TGUID [in] GUID to be converted.
+/// TBytes. Required byte array.
+function GUIDToBytes(const AGUID: TGUID): TBytes;
+
/// Attempts to convert string S into a Word value.
/// string [in] String to be converted.
/// Word [out] Value of converted string. Undefined if
@@ -471,6 +476,19 @@ function IsEqualBytes(const BA1, BA2: TBytes): Boolean;
Result := True;
end;
+function GUIDToBytes(const AGUID: TGUID): TBytes;
+type
+ TGUIDCracker = array[1..SizeOf(TGUID) div SizeOf(Byte)] of Byte;
+var
+ Idx: Integer;
+begin
+ Assert(SizeOf(TGUID) = SizeOf(TGUIDCracker),
+ 'GUIDToBytes: Size of TGUID <> size of TGUIDCracker');
+ SetLength(Result, SizeOf(TGUIDCracker));
+ for Idx := Low(TGUIDCracker) to High(TGUIDCracker) do
+ Result[Idx - Low(TGUIDCracker)] := TGUIDCracker(AGUID)[Idx];
+end;
+
function TryStrToWord(const S: string; out W: Word): Boolean;
var
I: Integer;
From cee2aff0869b7d3f0ca69cb19407b90d1c7b22ef Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 29 Oct 2024 21:06:17 +0000
Subject: [PATCH 006/222] Add new hex conversion routines to UUtils unit
Added TryHexStringToBytes and BytesToHexString routines
---
Src/UUtils.pas | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/Src/UUtils.pas b/Src/UUtils.pas
index 434fb0a4b..285197f30 100644
--- a/Src/UUtils.pas
+++ b/Src/UUtils.pas
@@ -195,6 +195,27 @@ function TryStrToWord(const S: string; out W: Word): Boolean;
/// as a Byte.
function TryStrToByte(const S: string; out B: Byte): Boolean;
+/// Converts a byte array to a string that is a concatentation of the
+/// hex representation of the bytes of the array.
+/// TBytes [in] Byte array to convert.
+/// string. String of hex digits or empty string if BA is empty.
+///
+/// The returned string is twice the length of BA, since each byte
+/// occupies two hex digits.
+function BytesToHexString(const BA: TBytes): string;
+
+/// Attempts to convert a string of hex digits to an array of bytes.
+///
+/// string [in] String of hex digits. Alphabetic
+/// characters can be either upper or lower case.
+/// TBytes [out] Array of bytes converted from string.
+/// Undefined if conversion fails.
+/// Boolean. True if conversion succeeds, False if not.
+/// String must be composed of valid hex digits, with two characters
+/// per byte. Therefore the string must have an even number of characters.
+///
+function TryHexStringToBytes(const AHexStr: string; out ABytes: TBytes):
+ Boolean;
implementation
@@ -513,5 +534,41 @@ function TryStrToByte(const S: string; out B: Byte): Boolean;
B := Byte(I);
end;
+function BytesToHexString(const BA: TBytes): string;
+var
+ B: Byte;
+begin
+ Result := '';
+ for B in BA do
+ Result := Result + IntToHex(B, 2);
+end;
+
+function TryHexStringToBytes(const AHexStr: string; out ABytes: TBytes):
+ Boolean;
+const
+ HexByteStrLength = 2;
+var
+ HexByteStart: Integer;
+ HexByteStr: string;
+ ResIdx: Integer;
+ ConvertedByte: Byte;
+begin
+ Result := True;
+ if Length(AHexStr) mod HexByteStrLength <> 0 then
+ Exit(False);
+ SetLength(ABytes, Length(AHexStr) div HexByteStrLength);
+ ResIdx := 0;
+ HexByteStart := 1;
+ while HexByteStart < Length(AHexStr) do
+ begin
+ HexByteStr := Copy(AHexStr, HexByteStart, HexByteStrLength);
+ if not TryStrToByte('$' + HexByteStr, ConvertedByte) then
+ Exit(False);
+ ABytes[ResIdx] := ConvertedByte;
+ Inc(HexByteStart, HexByteStrLength);
+ Inc(ResIdx);
+ end;
+end;
+
end.
From 5d0550cf46f39b26a61ec3b4b24a62bccdb5534e Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 29 Oct 2024 21:10:20 +0000
Subject: [PATCH 007/222] Add new tests to TestUUtils unit
Added tests for:
* Two overloads for IsEqualBytes
* BytesToHexString
* TryHexStringToBytes
---
Tests/Src/DUnit/TestUUtils.pas | 87 ++++++++++++++++++++++++++++++++++
1 file changed, 87 insertions(+)
diff --git a/Tests/Src/DUnit/TestUUtils.pas b/Tests/Src/DUnit/TestUUtils.pas
index f4c117554..845dbcb10 100644
--- a/Tests/Src/DUnit/TestUUtils.pas
+++ b/Tests/Src/DUnit/TestUUtils.pas
@@ -24,6 +24,10 @@ TTestUtilsRoutines = class(TTestCase)
procedure TestIsValidDriveLetter;
procedure TestURIBaseName;
procedure TestTryStrToCardinal;
+ procedure TestIsEqualBytes_NoCount_overload;
+ procedure TestIsEqualBytes_Count_overload;
+ procedure TestBytesToHexString;
+ procedure TestTryHexStringToBytes;
end;
@@ -37,6 +41,22 @@ implementation
{ TTestUtilsRoutines }
+procedure TTestUtilsRoutines.TestBytesToHexString;
+const
+ B0Str = '';
+ B1Str = 'FA';
+ B2Str = '010EAA42B656';
+var
+ BA0, BA1, BA2: TBytes;
+begin
+ BA0 := TBytes.Create();
+ BA1 := TBytes.Create($fa);
+ BA2 := TBytes.Create($01, $0E, $AA, $42, $B6, $56);
+ CheckEquals(B0Str, BytesToHexString(BA0), 'BA0');
+ CheckEquals(B1Str, BytesToHexString(BA1), 'BA1');
+ CheckEquals(B2Str, BytesToHexString(BA2), 'BA2');
+end;
+
procedure TTestUtilsRoutines.TestFloatToInt;
begin
CheckEquals(42, FloatToInt(42.0), 'Test 1');
@@ -80,6 +100,50 @@ procedure TTestUtilsRoutines.TestIsBaseFileName;
CheckFalse(IsBaseFileName(''), 'Test 9');
end;
+procedure TTestUtilsRoutines.TestIsEqualBytes_Count_overload;
+var
+ B0, B0a, B1, B1a, B2, B3, B4: TBytes;
+begin
+ B0 := TBytes.Create();
+ B0a := TBytes.Create();
+ B1 := TBytes.Create(1,2,3,4,5,6,7,8,9,10);
+ B1a := TBytes.Create(1,2,3,4,5,6,7,8,9,10);
+ B2 := TBytes.Create(1,2,3,4,5,6,7,8,9,11);
+ B3 := TBytes.Create(1,2,3,4,5,6,7,8,9);
+ B4 := TBytes.Create(0,1,2,3,4,5,6,7,8,9,10);
+ CheckTrue(IsEqualBytes(B1, B1a, 10), 'B1 = B1a (10)');
+ CheckTrue(IsEqualBytes(B1, B2, 9), 'B1 = B2 (9)');
+ CheckFalse(IsEqualBytes(B1, B2, 10), 'B1 <> B2 (10)');
+ CheckFalse(IsEqualBytes(B1, B1a, 15), 'B1 <> B1a (15)');
+ CheckFalse(IsEqualBytes(B3, B4, 1), 'B3 <> B4 (1)');
+ CheckTrue(IsEqualBytes(B2, B3, 1), 'B2 <> B3 (1)');
+ CheckFalse(IsEqualBytes(B0, B0a, 1), 'B0 <> B0a (0)');
+end;
+
+procedure TTestUtilsRoutines.TestIsEqualBytes_NoCount_overload;
+var
+ B0, B0a, B1, B1a, B2, B3, B4, B5, B5a, B6: TBytes;
+begin
+ B0 := TBytes.Create();
+ B0a := TBytes.Create();
+ B1 := TBytes.Create(1,2,3,4,5,6,7,8,9,10);
+ B1a := TBytes.Create(1,2,3,4,5,6,7,8,9,10);
+ B2 := TBytes.Create(1,2,3,4,5,6,7,8,9,11);
+ B3 := TBytes.Create(1,2,3,4,5,6,7,8,9);
+ B4 := TBytes.Create(0,1,2,3,4,5,6,7,8,9,10);
+ B5 := TBytes.Create(7);
+ B5a := TBytes.Create(7);
+ B6 := TBytes.Create(6);
+ CheckTrue(IsEqualBytes(B1, B1a), 'B1 = B1a');
+ CheckTrue(IsEqualBytes(B5, B5a), 'B5 = B5a');
+ CheckTrue(IsEqualBytes(B0, B0a), 'B0 = B0a');
+ CheckFalse(IsEqualBytes(B1, B2), 'B1 <> B2');
+ CheckFalse(IsEqualBytes(B5, B6), 'B5 <> B6');
+ CheckFalse(IsEqualBytes(B2, B4), 'B2 <> B4');
+ CheckFalse(IsEqualBytes(B0, B4), 'B0 <> B4');
+ CheckFalse(IsEqualBytes(B0, B6), 'B0 <> B6');
+end;
+
procedure TTestUtilsRoutines.TestIsHexDigit;
const
GoodChars = '1234567890ABCDEFabcdef';
@@ -106,6 +170,29 @@ procedure TTestUtilsRoutines.TestIsValidDriveLetter;
CheckFalse(IsValidDriveLetter(BadChars[Idx]), 'Bad Test ' + IntToStr(Idx));
end;
+procedure TTestUtilsRoutines.TestTryHexStringToBytes;
+const
+ B0Str = '';
+ B1Str = 'FA';
+ B2Str = '010EAa42b656';
+ Bad1Str = '3abc7';
+ Bad2Str = '010EAbx2b656';
+var
+ BA0, BA1, BA2, Res: TBytes;
+begin
+ BA0 := TBytes.Create();
+ BA1 := TBytes.Create($fa);
+ BA2 := TBytes.Create($01, $0E, $AA, $42, $B6, $56);
+ CheckTrue(TryHexStringToBytes(B0Str, Res), '#1: Boolean');
+ CheckTrue(IsEqualBytes(BA0, Res), '#1: Array');
+ Checktrue(TryHexStringToBytes(B1Str, Res), '#2: Boolean');
+ CheckTrue(IsEqualBytes(BA1, Res), '#2: Array');
+ Checktrue(TryHexStringToBytes(B2Str, Res), '#3: Boolean');
+ CheckTrue(IsEqualBytes(BA2, Res), '#3: Array');
+ CheckFalse(TryHexStringToBytes(Bad1Str, Res), '#4: Bad length');
+ CheckFalse(TryHexStringToBytes(Bad2Str, Res), '#4: Bad digits');
+end;
+
procedure TTestUtilsRoutines.TestTryStrToCardinal;
var
V: Cardinal;
From e9db068576a45120da1606a6e34591fcd6cc7e8b Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 29 Oct 2024 21:15:32 +0000
Subject: [PATCH 008/222] Update settings unit to register new sections
Added new ssCollections & ssCollection sections.
---
Src/USettings.pas | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/Src/USettings.pas b/Src/USettings.pas
index bd6227e62..3f1d26ee8 100644
--- a/Src/USettings.pas
+++ b/Src/USettings.pas
@@ -179,11 +179,14 @@ interface
/// windows
/// -ssDatabase - database customisation info
/// -ssCompilers - info about all compilers
+ /// -ssCollections - info about all snippet collections
+ /// -ssCollection - info about a specific snippet collection
///
TSettingsSectionId = (
ssFindText, ssFindCompiler, ssFindXRefs, ssCompilerInfo,
ssPreferences, ssUnits, ssDuplicateSnippet,
- ssFavourites, ssWindowState, ssDatabase, ssCompilers
+ ssFavourites, ssWindowState, ssDatabase, ssCompilers, ssCollections,
+ ssCollection
);
type
@@ -577,7 +580,9 @@ function TIniSettings.SectionName(const Id: TSettingsSectionId;
'Favourites', // ssFavourites
'WindowState', // ssWindowState
'Database', // ssDatabase
- 'Compilers' // ssCompilers
+ 'Compilers', // ssCompilers
+ 'Collections', // ssCollections
+ 'Collection' // ssCollection
);
begin
Result := cSectionNames[Id];
From 2ed1f99c61ce28877fd7aefb1e2da935d4731b4a Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Wed, 30 Oct 2024 12:01:28 +0000
Subject: [PATCH 009/222] Add new DB.Collections unit
Provides support for multiple snippets collections.
Contains code to:
* Encapsulate a collection ID
* Encapsulate a collection location
* Encapsulate a collection, including ID, name, location and file format.
* Maintain a single list of available collections.
* Persist the collection list to settings.
Uses a singleton to maintain the list of collections.
Ensures that collections are always defined that are the equivalent of
the CodeSnip 4 "main" & "user" databases. This code may be removed when
the changeover from the two databases to multiple data sources is
achieved.
Some __TMP__ methods are provided to ease the changeover from
CodeSnip v4 to v5.
---
Src/CodeSnip.dpr | 3 +-
Src/CodeSnip.dproj | 1 +
Src/DB.UCollections.pas | 685 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 688 insertions(+), 1 deletion(-)
create mode 100644 Src/DB.UCollections.pas
diff --git a/Src/CodeSnip.dpr b/Src/CodeSnip.dpr
index 1fe24aca3..c2c6be15d 100644
--- a/Src/CodeSnip.dpr
+++ b/Src/CodeSnip.dpr
@@ -374,7 +374,8 @@ uses
Compilers.USettings in 'Compilers.USettings.pas',
FmRegisterCompilersDlg in 'FmRegisterCompilersDlg.pas' {RegisterCompilersDlg},
ClassHelpers.UGraphics in 'ClassHelpers.UGraphics.pas',
- ClassHelpers.UActions in 'ClassHelpers.UActions.pas';
+ ClassHelpers.UActions in 'ClassHelpers.UActions.pas',
+ DB.UCollections in 'DB.UCollections.pas';
// Include resources
{$Resource ExternalObj.tlb} // Type library file
diff --git a/Src/CodeSnip.dproj b/Src/CodeSnip.dproj
index dc6c27915..f0d0f83f1 100644
--- a/Src/CodeSnip.dproj
+++ b/Src/CodeSnip.dproj
@@ -581,6 +581,7 @@
+ Base
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
new file mode 100644
index 000000000..b32c1ed09
--- /dev/null
+++ b/Src/DB.UCollections.pas
@@ -0,0 +1,685 @@
+{
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/
+ *
+ * Copyright (C) 2024, Peter Johnson (gravatar.com/delphidabbler).
+ *
+ * Implements support for multiple snippet collections.
+}
+
+
+unit DB.UCollections;
+
+{$ScopedEnums ON}
+
+interface
+
+uses
+ SysUtils,
+ Generics.Collections,
+ UEncodings,
+ UExceptions,
+ USettings,
+ USingleton;
+
+type
+
+ /// Enumeration of the kinds of supported snippet collection data
+ /// formats.
+ ///
+ /// Error -- Invalid format. Used to indicate an unknown format
+ /// or other error.
+ /// DCSC_v2 -- Format used by the DelphiDabbler Code Snippets
+ /// Collection v2.
+ /// Native_v4 -- Native format used by CodeSnip v4 to store user
+ /// snippets.
+ ///
+ TCollectionFormatKind = ( // TODO: move to more appropriate unit
+ // NEVER specify a literal ordinal value in this enumeration.
+ // NEVER delete or re-order the enumeration items: the ordinal values may
+ // be written to a config file and changing the ordinal value here can
+ // cause hard to trace bugs. If an item goes out of use then leave it
+ // in place & possibly rename the item to indicate its redundancy.
+ // NEVER associate error with a format loader or saver class.
+ Error,
+ DCSC_v2,
+ Native_v4
+ );
+
+
+ TCollectionFormatInfo = record // TODO: move to more appropriate unit
+ strict private
+ type
+ TMapRecord = record
+ /// Collection data format kind.
+ Kind: TCollectionFormatKind;
+ /// Collection data format name.
+ Name: string;
+ end;
+ const
+ // There are so few entries in this table it's not worth the overhead
+ // of using a dicitionary for the lookup.
+ LookupTable: array[0..1] of TMapRecord = (
+ (Kind: TCollectionFormatKind.DCSC_v2;
+ Name: 'DelphiDabbler Code Snippets Collection format v2'),
+ (Kind: TCollectionFormatKind.Native_v4;
+ Name: 'CodeSnip v4 native snippet collection format')
+ );
+ class function IndexOf(const AKind: TCollectionFormatKind): Integer; static;
+ public
+ /// Gets the name of the data format specified by
+ /// AKind. Returns an empty string if no name is associated with
+ /// AKind.
+ class function GetName(const AKind: TCollectionFormatKind): string; static;
+ end;
+
+type
+
+ TCollectionID = record
+ strict private
+ var
+ fID: TBytes;
+ public
+ const
+ DCSC_v2_ID: TGUID = '{9F3A4A8A-0A2B-4088-B7C9-AE1D32D3FF9A}';
+ SWAG_v1_ID: TGUID = '{ADA985E0-0929-4986-A3FE-B2C981D430F1}';
+ Native_v4_ID: TGUID = '{E63E7160-2389-45F2-B712-EA0449D30B1F}';
+ constructor Create(const ABytes: TBytes); overload;
+ constructor Create(const AStr: string); overload;
+ constructor Create(const AGUID: TGUID); overload;
+ class function CreateFromHexString(const AHexStr: string): TCollectionID;
+ static;
+ class function CreateNull: TCollectionID; static;
+ function Clone: TCollectionID;
+ function ToArray: TBytes;
+ function ToHexString: string;
+ function IsBuiltInID: Boolean;
+ function IsNull: Boolean;
+ class function Compare(Left, Right: TCollectionID): Integer; static;
+ class operator Equal(Left, Right: TCollectionID): Boolean;
+ class operator NotEqual(Left, Right: TCollectionID): Boolean;
+ {TODO -c__TMP__: remove following __TMP__*** methods}
+ class function __TMP__MainDBCollectionID: TCollectionID; static;
+ class function __TMP__UserDBCollectionID: TCollectionID; static;
+ class function __TMP__DBCollectionID(const AUserDefined: Boolean): TCollectionID;
+ static;
+ end;
+
+ ECollectionID = class(ECodeSnip);
+
+ TCollectionLocation = record
+ strict private
+ var
+ fDirectory: string;
+ fMetaDataFile: string;
+ fEncodingHint: TEncodingType;
+ procedure SetDirectory(const ANewDirectory: string);
+ public
+
+ /// Instantiates a record with given values.
+ /// string [in] File system directory
+ /// containing the collection data. Must be non-empty and a valid directory
+ /// name.
+ /// string [in] Path to the collection's
+ /// meta data file, if any. May be empty if collection has no meta data
+ /// file or if the meta data file name is fixed. If non-empty the path must
+ /// be relative to ADirectory. Optional: default is empty string.
+ ///
+ /// TEncodingType [in] Hints at the
+ /// encoding used by text files in ADirectory. Only required if the
+ /// text files are not used in the collection or if the collection format
+ /// specifies the text format. Optional: default is system default
+ /// encoding.
+ constructor Create(const ADirectory: string;
+ const AMetaDataFile: string = '';
+ const AEncodingHint: TEncodingType = TEncodingType.etSysDefault);
+
+ /// File system directory containing the collection data.
+ ///
+ /// Must be a valid directory name and must exist.
+ property Directory: string read fDirectory write SetDirectory;
+
+ /// Name of any meta data file, relative to Directory.
+ ///
+ /// May be empty string. If non-empty must be a valid path name
+ /// and the file must exist.
+ property MetaDataFile: string read fMetaDataFile;
+
+ /// Hints at the type of encoding used by the text files in
+ /// Directory.
+ /// EncodingHint should only be used where the I/O code has
+ /// no knowledge of the expected text file encoding AND the where the files
+ /// do not contain preamble bytes that specify the encoding.
+ property EncodingHint: TEncodingType read fEncodingHint;
+
+ /// Checks if the record instance has valid fields.
+ function IsValid: Boolean;
+
+ end;
+
+ TCollection = record
+ strict private
+ var
+ fUID: TCollectionID;
+ fName: string;
+ fLocation: TCollectionLocation;
+ fCollectionFormatKind: TCollectionFormatKind;
+ public
+ /// Creates a collection record.
+ /// TCollectionID [in] Unique ID of the
+ /// collection. Must not be null.
+ /// string [in] Name of collection. Should be
+ /// unique. Must not be empty or only whitespace.
+ constructor Create(const AUID: TCollectionID; const AName: string;
+ const ALocation: TCollectionLocation;
+ const ACollectionFormatKind: TCollectionFormatKind);
+ /// Collection identifier. Must be unique.
+ property UID: TCollectionID
+ read fUID;
+ /// Collection name. Must be unique.
+ property Name: string read
+ fName;
+ /// Collection location information.
+ property Location: TCollectionLocation
+ read fLocation;
+ /// Kind of collection format used for to store data for this
+ /// collection.
+ property CollectionFormatKind: TCollectionFormatKind
+ read fCollectionFormatKind;
+ /// Checks if this record's fields are valid.
+ function IsValid: Boolean;
+ end;
+
+ TCollections = class sealed(TSingleton)
+ strict private
+ var
+ fItems: TList;
+ function GetItem(const Idx: Integer): TCollection;
+ class function GetInstance: TCollections; static;
+ strict protected
+ procedure Initialize; override;
+ procedure Finalize; override;
+ public
+ class property Instance: TCollections read GetInstance;
+ function GetEnumerator: TEnumerator;
+ function IndexOfID(const AUID: TCollectionID): Integer;
+ function ContainsID(const AUID: TCollectionID): Boolean;
+ function ContainsName(const AName: string): Boolean;
+ function GetCollection(const AUID: TCollectionID): TCollection;
+ procedure Add(const ACollection: TCollection);
+ procedure Update(const ACollection: TCollection);
+ procedure AddOrUpdate(const ACollection: TCollection);
+ procedure Delete(const AUID: TCollectionID);
+ procedure Clear;
+ procedure Save;
+ function ToArray: TArray;
+ function GetAllIDs: TArray;
+ function Count: Integer;
+ property Items[const Idx: Integer]: TCollection read GetItem; default;
+ end;
+
+ TCollectionsPersist = record
+ strict private
+ const
+ CountKey = 'Count';
+ UIDKey = 'UID';
+ NameKey = 'Name';
+ LocationDirectoryKey = 'Location.Directory';
+ LocationMetaDataFileKey = 'Location.MetaDataFile';
+ LocationEncodingHintKey = 'Location.EncodingHint';
+ DataFormatKey = 'DataFormat';
+ class procedure SaveCollection(const AOrdinal: Cardinal;
+ const ACollection: TCollection); static;
+ class procedure LoadCollection(const AOrdinal: Cardinal;
+ const ACollections: TCollections); static;
+ public
+ class procedure Save(const ACollections: TCollections); static;
+ class procedure Load(const ACollections: TCollections); static;
+ end;
+
+implementation
+
+uses
+ RTLConsts,
+ IOUtils,
+ Math,
+ UAppInfo, // TODO -cVault: needed only for v4 emulation
+ UStrUtils,
+ UUtils;
+
+resourcestring
+ SBadHexString = 'Invalid Hex String.';
+
+{ TCollectionLocation }
+
+constructor TCollectionLocation.Create(const ADirectory,
+ AMetaDataFile: string; const AEncodingHint: TEncodingType);
+begin
+ fDirectory := StrTrim(ADirectory);
+ fMetaDataFile := StrTrim(AMetaDataFile);
+ fEncodingHint := AEncodingHint;
+ Assert(IsValid, 'TCollectionLocation.Create: invalid parameter(s)');
+end;
+
+function TCollectionLocation.IsValid: Boolean;
+begin
+ Result := True;
+ if fDirectory = '' then
+ Exit(False);
+ if not TPath.HasValidPathChars(fDirectory, False) then
+ Exit(False);
+ if not TDirectory.Exists(fDirectory) then
+ Exit(False);
+ if (fMetaDataFile <> '') then
+ begin
+ if not TPath.IsRelativePath(fMetaDataFile) then
+ Exit(False);
+ if not TFile.Exists(TPath.Combine(fDirectory, fMetaDataFile)) then
+ Exit(False);
+ end;
+end;
+
+procedure TCollectionLocation.SetDirectory(const ANewDirectory: string);
+begin
+ fDirectory := ANewDirectory;
+end;
+
+{ TCollection }
+
+constructor TCollection.Create(const AUID: TCollectionID;
+ const AName: string; const ALocation: TCollectionLocation;
+ const ACollectionFormatKind: TCollectionFormatKind);
+var
+ TrimmedName: string;
+begin
+ TrimmedName := StrTrim(AName);
+ Assert(not AUID.IsNull, 'TCollection.Create: AUID is null');
+ Assert(TrimmedName <> '',
+ 'TCollection.Create: AName is empty or only whitespace');
+ Assert(ALocation.IsValid, 'TCollection.Create: ALocation is not valid');
+ Assert(ACollectionFormatKind <> TCollectionFormatKind.Error,
+ 'TCollection.Create: ACollectionFormatKind = TCollectionFormatKind.Error');
+ fUID := AUID.Clone;
+ fName := TrimmedName;
+ fLocation := ALocation;
+ fCollectionFormatKind := ACollectionFormatKind;
+end;
+
+function TCollection.IsValid: Boolean;
+begin
+ {TODO: Constructor enforces all these requirements, so #TCollection.IsValid
+ may not be needed.}
+ Result := not fUID.IsNull
+ and (fName <> '')
+ and fLocation.IsValid
+ and (fCollectionFormatKind <> TCollectionFormatKind.Error);
+end;
+
+{ TCollections }
+
+procedure TCollections.Add(const ACollection: TCollection);
+begin
+ if not ContainsID(ACollection.UID) then
+ fItems.Add(ACollection);
+end;
+
+procedure TCollections.AddOrUpdate(const ACollection: TCollection);
+var
+ Idx: Integer;
+begin
+ Idx := IndexOfID(ACollection.UID);
+ if Idx < 0 then
+ fItems.Add(ACollection)
+ else
+ fItems[Idx] := ACollection;
+end;
+
+procedure TCollections.Clear;
+begin
+ fItems.Clear;
+end;
+
+function TCollections.ContainsID(const AUID: TCollectionID):
+ Boolean;
+begin
+ Result := IndexOfID(AUID) >= 0;
+end;
+
+function TCollections.ContainsName(const AName: string): Boolean;
+var
+ Collection: TCollection;
+begin
+ Result := False;
+ for Collection in fItems do
+ if StrSameText(AName, Collection.Name) then
+ Exit(True);
+end;
+
+function TCollections.Count: Integer;
+begin
+ Result := fItems.Count;
+end;
+
+procedure TCollections.Delete(const AUID: TCollectionID);
+var
+ Idx: Integer;
+begin
+ Idx := IndexOfID(AUID);
+ if Idx >= 0 then
+ fItems.Delete(Idx);
+end;
+
+procedure TCollections.Finalize;
+begin
+ Save;
+ fItems.Free;
+end;
+
+function TCollections.GetAllIDs: TArray;
+var
+ Idx: Integer;
+begin
+ SetLength(Result, fItems.Count);
+ for Idx := 0 to Pred(fItems.Count) do
+ Result[Idx] := fItems[Idx].UID;
+end;
+
+function TCollections.GetCollection(const AUID: TCollectionID): TCollection;
+var
+ Idx: Integer;
+begin
+ Idx := IndexOfID(AUID);
+ if Idx < 0 then
+ raise EArgumentException.CreateRes(@SGenericItemNotFound);
+ Result := fItems[Idx];
+end;
+
+function TCollections.GetEnumerator: TEnumerator;
+begin
+ Result := fItems.GetEnumerator;
+end;
+
+class function TCollections.GetInstance: TCollections;
+begin
+ Result := TCollections.Create;
+end;
+
+function TCollections.GetItem(const Idx: Integer): TCollection;
+begin
+ Result := fItems[Idx];
+end;
+
+function TCollections.IndexOfID(const AUID: TCollectionID): Integer;
+var
+ Idx: Integer;
+begin
+ Result := -1;
+ for Idx := 0 to Pred(fItems.Count) do
+ if AUID = fItems[Idx].UID then
+ Exit(Idx);
+end;
+
+procedure TCollections.Initialize;
+begin
+ fItems := TList.Create;
+ TCollectionsPersist.Load(Self);
+ { TODO -cCollections: following lines are for v4 compatibility
+ Remove if not required in v5 }
+ if not ContainsID(TCollectionID.__TMP__MainDBCollectionID) then
+ Add(
+ TCollection.Create(
+ TCollectionID.__TMP__MainDBCollectionID,
+ { TODO -cVault: change name - this text matches name used in CodeSnip
+ v4}
+ 'DelphiDabbler Code Snippets Database',
+ TCollectionLocation.Create(TAppInfo.AppDataDir),
+ TCollectionFormatKind.DCSC_v2
+ )
+ );
+ if not ContainsID(TCollectionID.__TMP__UserDBCollectionID) then
+ Add(
+ TCollection.Create(
+ TCollectionID.__TMP__UserDBCollectionID,
+ { TODO -cVault: change name - this text matches name used in CodeSnip
+ v4}
+ 'User Database',
+ TCollectionLocation.Create(TAppInfo.DefaultUserDataDir, '', etUTF8),
+ TCollectionFormatKind.Native_v4
+ )
+ );
+end;
+
+procedure TCollections.Save;
+begin
+ TCollectionsPersist.Save(Self);
+end;
+
+function TCollections.ToArray: TArray;
+begin
+ Result := fItems.ToArray;
+end;
+
+procedure TCollections.Update(const ACollection: TCollection);
+var
+ Idx: Integer;
+begin
+ Idx := IndexOfID(ACollection.UID);
+ if Idx >= 0 then
+ fItems[Idx] := ACollection;
+end;
+
+{ TCollectionID }
+
+constructor TCollectionID.Create(const ABytes: TBytes);
+begin
+ fID := System.Copy(ABytes);
+end;
+
+constructor TCollectionID.Create(const AStr: string);
+begin
+ fID := TEncoding.UTF8.GetBytes(AStr);
+end;
+
+function TCollectionID.Clone: TCollectionID;
+begin
+ Result := TCollectionID.Create(fID);
+end;
+
+class function TCollectionID.Compare(Left, Right: TCollectionID): Integer;
+var
+ CompareLength: Integer;
+ Idx: Integer;
+begin
+ CompareLength := Min(Length(Left.fID), Length(Right.fID));
+ Result := 0;
+ for Idx := 0 to Pred(CompareLength) do
+ begin
+ Result := Left.fID[Idx] - Right.fID[Idx];
+ if Result <> 0 then
+ Exit;
+ end;
+ if Length(Left.fID) < Length(Right.fID) then
+ Exit(-1)
+ else if Length(Left.fID) > Length(Right.fID) then
+ Exit(1);
+end;
+
+constructor TCollectionID.Create(const AGUID: TGUID);
+begin
+ fID := System.Copy(GUIDToBytes(AGUID));
+end;
+
+class function TCollectionID.CreateFromHexString(
+ const AHexStr: string): TCollectionID;
+var
+ ConvertedBytes: TBytes;
+begin
+ if not TryHexStringToBytes(AHexStr, ConvertedBytes) then
+ raise ECollectionID.Create(SBadHexString);
+ Result := TCollectionID.Create(ConvertedBytes);
+end;
+
+class function TCollectionID.CreateNull: TCollectionID;
+var
+ NullID: TBytes;
+begin
+ SetLength(NullID, 0);
+ Result := TCollectionID.Create(NullID);
+end;
+
+class operator TCollectionID.Equal(Left, Right: TCollectionID):
+ Boolean;
+begin
+ Result := IsEqualBytes(Left.fID, Right.fID);
+end;
+
+function TCollectionID.IsBuiltInID: Boolean;
+begin
+ Result := (TCollectionID.Create(DCSC_v2_ID) = Self)
+ or (TCollectionID.Create(SWAG_v1_ID) = Self);
+end;
+
+function TCollectionID.IsNull: Boolean;
+begin
+ Result := Length(fID) = 0;
+end;
+
+class operator TCollectionID.NotEqual(Left, Right: TCollectionID):
+ Boolean;
+begin
+ Result := not IsEqualBytes(Left.fID, Right.fID);
+end;
+
+function TCollectionID.ToArray: TBytes;
+begin
+ Result := System.Copy(fID);
+end;
+
+function TCollectionID.ToHexString: string;
+begin
+ Result := BytesToHexString(fID);
+end;
+
+class function TCollectionID.__TMP__DBCollectionID(
+ const AUserDefined: Boolean): TCollectionID;
+begin
+ if AUserDefined then
+ Result := __TMP__UserDBCollectionID
+ else
+ Result := __TMP__MainDBCollectionID;
+end;
+
+class function TCollectionID.__TMP__MainDBCollectionID: TCollectionID;
+begin
+ Result := TCollectionID.Create(DCSC_v2_ID);
+end;
+
+class function TCollectionID.__TMP__UserDBCollectionID: TCollectionID;
+begin
+ Result := TCollectionID.Create(Native_v4_ID);
+end;
+
+{ TCollectionsPersist }
+
+class procedure TCollectionsPersist.Load(
+ const ACollections: TCollections);
+var
+ Storage: ISettingsSection;
+ Count: Integer;
+ Idx: Integer;
+begin
+ Storage := Settings.ReadSection(ssCollections);
+ Count := Storage.GetInteger(CountKey, 0);
+ for Idx := 0 to Pred(Count) do
+ LoadCollection(Idx, ACollections);
+end;
+
+class procedure TCollectionsPersist.LoadCollection(const AOrdinal: Cardinal;
+ const ACollections: TCollections);
+var
+ Storage: ISettingsSection;
+ Location: TCollectionLocation;
+ UID: TCollectionID;
+ Name: string;
+ Collection: TCollection;
+ DataFormat: TCollectionFormatKind;
+begin
+ Storage := Settings.ReadSection(ssCollection, IntToStr(AOrdinal));
+ UID := TCollectionID.Create(Storage.GetBytes(UIDKey));
+ Name := Storage.GetString(NameKey, '');
+ Location := TCollectionLocation.Create(
+ Storage.GetString(LocationDirectoryKey, ''),
+ Storage.GetString(LocationMetaDataFileKey, ''),
+ TEncodingType(
+ Storage.GetInteger(
+ LocationEncodingHintKey, Ord(TEncodingType.etSysDefault)
+ )
+ )
+ );
+ DataFormat := TCollectionFormatKind(
+ Storage.GetInteger(DataFormatKey, Ord(TCollectionFormatKind.Error))
+ );
+ Collection := TCollection.Create(UID, Name, Location, DataFormat);
+ ACollections.Add(Collection);
+end;
+
+class procedure TCollectionsPersist.Save(const
+ ACollections: TCollections);
+var
+ Storage: ISettingsSection;
+ Idx: Integer;
+begin
+ // Save number of collections
+ Storage := Settings.EmptySection(ssCollections);
+ Storage.SetInteger(CountKey, ACollections.Count);
+ Storage.Save;
+ // Save each collection's properties in its own section
+ for Idx := 0 to Pred(ACollections.Count) do
+ SaveCollection(Idx, ACollections[Idx]);
+end;
+
+class procedure TCollectionsPersist.SaveCollection(const AOrdinal: Cardinal;
+ const ACollection: TCollection);
+var
+ Storage: ISettingsSection;
+begin
+ // Save info about collection format in its own section
+ Storage := Settings.EmptySection(ssCollection, IntToStr(AOrdinal));
+ Storage.SetBytes(UIDKey, ACollection.UID.ToArray);
+ Storage.SetString(NameKey, ACollection.Name);
+ Storage.SetString(LocationDirectoryKey, ACollection.Location.Directory);
+ Storage.SetString(LocationMetaDataFileKey, ACollection.Location.MetaDataFile);
+ Storage.SetInteger(
+ LocationEncodingHintKey, Ord(ACollection.Location.EncodingHint)
+ );
+ Storage.SetInteger(DataFormatKey, Ord(ACollection.CollectionFormatKind));
+ Storage.Save;
+end;
+
+{ TCollectionFormatInfo }
+
+class function TCollectionFormatInfo.GetName(
+ const AKind: TCollectionFormatKind): string;
+var
+ Idx: Integer;
+begin
+ Idx := IndexOf(AKind);
+ if Idx < 0 then
+ Exit('');
+ Result := LookupTable[Idx].Name;
+end;
+
+class function TCollectionFormatInfo.IndexOf(
+ const AKind: TCollectionFormatKind): Integer;
+var
+ Idx: Integer;
+begin
+ Result := -1;
+ for Idx := Low(LookupTable) to High(LookupTable) do
+ if LookupTable[Idx].Kind = AKind then
+ Exit(Idx);
+end;
+
+end.
+
From 7ad5e4a240487145d22e45cd1179cba370210548 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Wed, 30 Oct 2024 12:54:26 +0000
Subject: [PATCH 010/222] Add CollectionID property to TSnippetID
Reimplemented UserDefined property in terms of CollectionID property.
Used __TMP__ getter and setter methods to achieve this
Removed fUserDefined field.
Added overloaded constructor to take collection ID as a parameter. Left
original constructor in place that takes UserDefined parameter.
Revised CompareTo method to compare CollectionID properties instead of
UserDefined properties.
Old code was commented out.
---
Src/USnippetIDs.pas | 59 ++++++++++++++++++++++++++++++++++++++-------
1 file changed, 50 insertions(+), 9 deletions(-)
diff --git a/Src/USnippetIDs.pas b/Src/USnippetIDs.pas
index 9d775ab89..892290a6f 100644
--- a/Src/USnippetIDs.pas
+++ b/Src/USnippetIDs.pas
@@ -20,10 +20,13 @@ interface
// Delphi
Generics.Collections,
// Project
- IntfCommon;
+ IntfCommon,
+ DB.UCollections;
type
+ {TODO -cNote: TSnippetID.UserDefined is now uses CollectionID property.}
+
/// Record that uniquely identifies a code snippet. Specifies name
/// and flag indicating whether snippet is user-defined.
@@ -32,17 +35,30 @@ TSnippetID = record
var
/// Value of Name property.
fName: string;
- /// Value of UserDefined property.
- fUserDefined: Boolean;
+// /// Value of UserDefined property.
+// fUserDefined: Boolean;
+ fCollectionID: TCollectionID;
+// function __TMP__GetUserDefined: Boolean;
+// procedure __TMP__SetUserDefined(const Value: Boolean);
+ procedure SetCollectionID(const AValue: TCollectionID);
public
/// Name of snippet.
property Name: string read fName write fName;
/// Whether snippet is user defined.
- property UserDefined: Boolean read fUserDefined write fUserDefined;
+// property UserDefined: Boolean read fUserDefined write fUserDefined;
+ {TODO -cCollections: Remove above property & getter/setter}
+
+ /// ID of the collection to which a snippet with this ID belongs.
+ ///
+ /// ID must not be null.
+ property CollectionID: TCollectionID
+ read fCollectionID write SetCollectionID;
/// Creates a record with given property values.
- constructor Create(const AName: string; const AUserDefined: Boolean);
+ /// ACollectionID must not be null.
+ constructor Create(const AName: string; const ACollectionID: TCollectionID);
+ overload; {TODO -cCollections: remove overload}
/// Creates copy of given snippet ID
constructor Clone(const Src: TSnippetID);
@@ -157,7 +173,7 @@ implementation
constructor TSnippetID.Clone(const Src: TSnippetID);
begin
- Create(Src.Name, Src.UserDefined);
+ Create(Src.Name, Src.CollectionID);
end;
class function TSnippetID.CompareNames(const Left, Right: string): Integer;
@@ -169,15 +185,24 @@ function TSnippetID.CompareTo(const SID: TSnippetID): Integer;
begin
Result := CompareNames(Name, SID.Name);
if Result = 0 then
- Result := Ord(UserDefined) - Ord(SID.UserDefined);
+ // TODO -cNote: New comparison changes ordering (no problem tho!)
+ Result := TCollectionID.Compare(CollectionID, SID.CollectionID);
+// Result := Ord(UserDefined) - Ord(SID.UserDefined);
end;
-constructor TSnippetID.Create(const AName: string; const AUserDefined: Boolean);
+constructor TSnippetID.Create(const AName: string;
+ const ACollectionID: TCollectionID);
begin
fName := AName;
- fUserDefined := AUserDefined;
+ SetCollectionID(ACollectionID);
end;
+//constructor TSnippetID.Create(const AName: string; const AUserDefined: Boolean);
+//begin
+// fName := AName;
+// __TMP__SetUserDefined(AUserDefined);
+//end;
+
class operator TSnippetID.Equal(const SID1, SID2: TSnippetID): Boolean;
begin
Result := SID1.CompareTo(SID2) = 0;
@@ -188,6 +213,22 @@ constructor TSnippetID.Create(const AName: string; const AUserDefined: Boolean);
Result := not (SID1 = SID2);
end;
+procedure TSnippetID.SetCollectionID(const AValue: TCollectionID);
+begin
+ Assert(not AValue.IsNull, 'TSnippetID.SetCollectionID: Value is null');
+ fCollectionID := AValue.Clone;
+end;
+
+//function TSnippetID.__TMP__GetUserDefined: Boolean;
+//begin
+// Result := fCollectionID = TCollectionID.__TMP__UserDBCollectionID;
+//end;
+//
+//procedure TSnippetID.__TMP__SetUserDefined(const Value: Boolean);
+//begin
+// fCollectionID := TCollectionID.__TMP__DBCollectionID(Value);
+//end;
+
{ TSnippetIDList }
function TSnippetIDList.Add(const SnippetID: TSnippetID): Integer;
From a68244085afa91648a3bf4641fd80a89456378c4 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Wed, 30 Oct 2024 13:02:27 +0000
Subject: [PATCH 011/222] Add TSnippet.CollectionID & update TSnippetList
Reimplemented TSnippet.UserDefined property in terms of new CollectionID
property. Used __TMP__ getter and setter methods to achieve this
Removed fUserDefined field from TSnippet.
Added overloaded TSnippet constructor to take collection ID as a
parameter. Left original constructor in place that takes UserDefined
parameter, but changed it to simply call the new constructor with a
suitable collection ID.
Revised TSnippet.GetID to create a snippet ID using the snippet's
CollectionID property instead of the UserDefined property.
Updated TSnippetList by adding overloads of all methods that take a
UserDefined parameter. Overloads all achieve a similar outcome, but by
acting on a TCollectionID parameter. Methods are:
* Count
* Find (two different overloads)
* IsEmpty
Reimplemented TSnippetList methods with UserDefined parameters in terms
of new methods that take collection ID parameters. Required some __TMP__
calls to do this.
Removed redundant private TSnippetList.Find method.
Old code was commented out.
---
Src/DB.USnippet.pas | 197 ++++++++++++++++++++++++++++++++++++--------
1 file changed, 161 insertions(+), 36 deletions(-)
diff --git a/Src/DB.USnippet.pas b/Src/DB.USnippet.pas
index 5af498162..8f9a6f8dc 100644
--- a/Src/DB.USnippet.pas
+++ b/Src/DB.USnippet.pas
@@ -18,10 +18,17 @@ interface
uses
// Delphi
- Classes, Generics.Collections, Generics.Defaults,
+ Classes,
+ Generics.Collections,
+ Generics.Defaults,
// Project
- ActiveText.UMain, Compilers.UGlobals, DB.USnippetKind, UContainers,
- UIStringList, USnippetIDs;
+ ActiveText.UMain,
+ Compilers.UGlobals,
+ DB.UCollections,
+ DB.USnippetKind,
+ UContainers,
+ UIStringList,
+ USnippetIDs;
type
/// Enumeration providing information about the level to which a
@@ -119,7 +126,8 @@ type TDisplayNameComparer = class(TComparer)
fXRef: TSnippetList; // List of cross-referenced snippets
fExtra: IActiveText; // Further information for snippet
fCompatibility: TCompileResults; // Snippet's compiler compatibility
- fUserDefined: Boolean; // If this snippet is user-defined
+// fUserDefined: Boolean; // If this snippet is user-defined
+ fCollectionID: TCollectionID; // Snippet's collection ID
fHiliteSource: Boolean; // If source is syntax highlighted
fTestInfo: TSnippetTestInfo; // Level of testing of snippet
function GetID: TSnippetID;
@@ -130,6 +138,7 @@ type TDisplayNameComparer = class(TComparer)
{Gets snippet's display name, or name if no display name is set
@return Required display name.
}
+ function __TMP__GetUserDefined: Boolean;
strict protected
procedure SetName(const Name: string);
{Sets Name property.
@@ -145,12 +154,24 @@ type TDisplayNameComparer = class(TComparer)
}
public
constructor Create(const Name: string; const UserDefined: Boolean;
- const Props: TSnippetData);
+ const Props: TSnippetData); overload; {TODO -cCollections: remove constructor}
{Class contructor. Sets up snippet object with given property values.
@param Name [in] Name of snippet.
@param UserDefined [in] Indicates if this is a user defined snippet.
@param Props [in] Values of various snippet properties.
}
+
+ /// Object constructor. Sets up snippet object with given property
+ /// values belonging to a specified collection.
+ /// string [in] Name of snippet.
+ /// TCollectionID [in] ID of collection
+ /// to which the snippet belongs. ID must not be null.
+ /// TSnippetData [in] Values of snippet
+ /// properties.
+ constructor Create(const Name: string; const ACollectionID: TCollectionID;
+ const Props: TSnippetData);
+ overload; {TODO -cCollections: remove overload;}
+
destructor Destroy; override;
{Destructor. Tears down object.
}
@@ -192,8 +213,11 @@ type TDisplayNameComparer = class(TComparer)
{List of any other snippet in database on which this snippet depends}
property XRef: TSnippetList read fXRef;
{List of cross referenced snippets in database}
- property UserDefined: Boolean read fUserDefined;
+// property UserDefined: Boolean read fUserDefined;;
+ property UserDefined: Boolean read __TMP__GetUserDefined;
+ {TODO -cCollections: Remove above property & getter/setter}
{Flag that indicates if this is a user defined snippet}
+ property CollectionID: TCollectionID read fCollectionID;
end;
{
@@ -249,16 +273,29 @@ TSnippetList = class(TObject)
@param Idx [in] Index of required snippet in list.
@return Snippet at specified index in list.
}
- function Find(const SnippetName: string;
- const UserDefined: Boolean; out Index: Integer): Boolean; overload;
- {Finds a snippet in the list that has a specified name and user defined
- property. Uses a binary search.
- @param SnippetName [in] Name of snippet to be found.
- @param UserDefined [in] Whether required snippet is user defined or not.
- @param Index [out] Index of required snippet in list. Valid only if
- method returns True.
- @return True if snippet found, False if not.
- }
+// function Find(const SnippetName: string;
+// const UserDefined: Boolean; out Index: Integer): Boolean; overload;
+// {Finds a snippet in the list that has a specified name and user defined
+// property. Uses a binary search.
+// @param SnippetName [in] Name of snippet to be found.
+// @param UserDefined [in] Whether required snippet is user defined or not.
+// @param Index [out] Index of required snippet in list. Valid only if
+// method returns True.
+// @return True if snippet found, False if not.
+// }
+
+ /// Finds a snippet in the list with whose name and collection ID
+ /// match.
+ /// string [in] Name of snippet.
+ /// TCollectionID [in] ID of collection
+ /// to which the snippet belongs.
+ /// Integer. [out] Set to the index of the
+ /// required snippet in the list. Valid only if the snippet was found.
+ ///
+ /// Boolean. True if snippet found, False if not.
+ function Find(const SnippetName: string; const ACollectionID: TCollectionID;
+ out Index: Integer): Boolean; overload;
+
strict protected
var fList: TSortedObjectList; // Sorted list of snippets
public
@@ -299,6 +336,17 @@ TSnippetList = class(TObject)
user defined snippet or one from main database.
@return Reference to required snippet or nil if not found.
}
+
+ /// Finds a snippet in the list with whose name and collection ID
+ /// match.
+ /// string [in] Name of snippet.
+ /// TCollectionID [in] ID of collection
+ /// to which the snippet belongs.
+ /// TSnippet. Reference to the required snippet or nil if
+ /// not found.
+ function Find(const SnippetName: string;
+ const ACollectionID: TCollectionID): TSnippet; overload;
+
function Contains(const Snippet: TSnippet): Boolean;
{Checks whether list contains a specified snippet.
@param Snippet [in] Required snippet.
@@ -324,6 +372,14 @@ TSnippetList = class(TObject)
(True) or in main database (False).
@return Number of snippets in specified database.
}
+
+ /// Counts number of snippets in list that belong to a specified
+ /// collection.
+ /// TCollectionID [in] Required
+ /// collection.
+ /// Integer Number of snippets in the collection.
+ function Count(const ACollectionID: TCollectionID): Integer; overload;
+
function Count: Integer; overload;
{Counts number of snippets in list.
@return Number of snippets in list.
@@ -332,13 +388,22 @@ TSnippetList = class(TObject)
{Checks if list is empty.
@return True if list is empty, False otehrwise.
}
- function IsEmpty(const UserDefined: Boolean): Boolean; overload; inline;
+ function IsEmpty(const UserDefined: Boolean): Boolean; overload; {__TMP__ inline;}
{Checks if sub-set of list from either from or not from use defined
database is empty.
@param UserDefined [in] Flags whether to check for snippets in user
database (True) or in main database (False).
@return True if required subset is empty, False if not empty.
}
+
+ /// Checks if the sub-set of snippets in the list belonging to a
+ /// specified collection is empty.
+ /// TCollectionID [in] ID of collection.
+ ///
+ /// Boolean True if the subset is empty, False otherwise.
+ ///
+ function IsEmpty(const ACollectionID: TCollectionID): Boolean; overload;
+
property Items[Idx: Integer]: TSnippet read GetItem; default;
{List of snippets}
end;
@@ -401,9 +466,17 @@ constructor TSnippet.Create(const Name: string; const UserDefined: Boolean;
@param UserDefined [in] Indicates if this is a user defined snippet.
@param Props [in] Values of various snippet properties.
}
+begin
+ Create(Name, TCollectionID.__TMP__DBCollectionID(UserDefined), Props);
+end;
+
+constructor TSnippet.Create(const Name: string;
+ const ACollectionID: TCollectionID; const Props: TSnippetData);
begin
Assert(ClassType <> TSnippet,
ClassName + '.Create: must only be called from descendants.');
+ Assert(not ACollectionID.IsNull,
+ ClassName + '.Create: ACollectionID is null');
inherited Create;
// Record simple property values
SetName(Name);
@@ -413,8 +486,8 @@ constructor TSnippet.Create(const Name: string; const UserDefined: Boolean;
// Create snippets lists for Depends and XRef properties
fDepends := TSnippetListEx.Create;
fXRef := TSnippetListEx.Create;
- // The following properties added to support user defined snippets
- fUserDefined := UserDefined;
+ // The following property added to support multiple snippet collections
+ fCollectionID := ACollectionID.Clone;
end;
destructor TSnippet.Destroy;
@@ -447,7 +520,7 @@ function TSnippet.GetID: TSnippetID;
@return Required ID.
}
begin
- Result := TSnippetID.Create(fName, fUserDefined);
+ Result := TSnippetID.Create(fName, fCollectionID);
end;
function TSnippet.IsEqual(const Snippet: TSnippet): Boolean;
@@ -484,6 +557,11 @@ procedure TSnippet.SetProps(const Data: TSnippetData);
fTestInfo := Data.TestInfo;
end;
+function TSnippet.__TMP__GetUserDefined: Boolean;
+begin
+ Result := fCollectionID = TCollectionID.__TMP__UserDBCollectionID;
+end;
+
{ TSnippet.TDisplayNameComparer }
function TSnippet.TDisplayNameComparer.Compare(const Left,
@@ -651,12 +729,23 @@ function TSnippetList.Count(const UserDefined: Boolean): Integer;
(True) or in main database (False).
@return Number of snippets in specified database.
}
+//var
+// Snippet: TSnippet; // refers to all snippets in list
+begin
+ Result := Count(TCollectionID.__TMP__DBCollectionID(UserDefined));
+// Result := 0;
+// for Snippet in Self do
+// if Snippet.UserDefined = UserDefined then
+// Inc(Result);
+end;
+
+function TSnippetList.Count(const ACollectionID: TCollectionID): Integer;
var
Snippet: TSnippet; // refers to all snippets in list
begin
Result := 0;
for Snippet in Self do
- if Snippet.UserDefined = UserDefined then
+ if Snippet.CollectionID = ACollectionID then
Inc(Result);
end;
@@ -695,24 +784,41 @@ destructor TSnippetList.Destroy;
inherited;
end;
+//function TSnippetList.Find(const SnippetName: string;
+// const UserDefined: Boolean; out Index: Integer): Boolean;
+// {Finds a snippet in the list that has a specified name and user defined
+// property. Uses a binary search.
+// @param SnippetName [in] Name of snippet to be found.
+// @param UserDefined [in] Whether required snippet is user defined or not.
+// @param Index [out] Index of required snippet in list. Valid only if
+// method returns True.
+// @return True if snippet found, False if not.
+// }
+//var
+// TempSnippet: TSnippet; // temp snippet used to perform search
+// NulData: TSnippetData; // nul data used to create snippet
+//begin
+// // We need a temporary snippet object in order to perform binary search using
+// // object list's built in search
+// NulData.Init;
+// TempSnippet := TTempSnippet.Create(SnippetName, UserDefined, NulData);
+// try
+// Result := fList.Find(TempSnippet, Index);
+// finally
+// TempSnippet.Free;
+// end;
+//end;
+
function TSnippetList.Find(const SnippetName: string;
- const UserDefined: Boolean; out Index: Integer): Boolean;
- {Finds a snippet in the list that has a specified name and user defined
- property. Uses a binary search.
- @param SnippetName [in] Name of snippet to be found.
- @param UserDefined [in] Whether required snippet is user defined or not.
- @param Index [out] Index of required snippet in list. Valid only if
- method returns True.
- @return True if snippet found, False if not.
- }
+ const ACollectionID: TCollectionID; out Index: Integer): Boolean;
var
TempSnippet: TSnippet; // temp snippet used to perform search
- NulData: TSnippetData; // nul data used to create snippet
+ NullData: TSnippetData; // nul data used to create snippet
begin
// We need a temporary snippet object in order to perform binary search using
// object list's built in search
- NulData.Init;
- TempSnippet := TTempSnippet.Create(SnippetName, UserDefined, NulData);
+ NullData.Init;
+ TempSnippet := TTempSnippet.Create(SnippetName, ACollectionID, NullData);
try
Result := fList.Find(TempSnippet, Index);
finally
@@ -731,7 +837,19 @@ function TSnippetList.Find(const SnippetName: string;
var
Idx: Integer; // index of snippet name in list
begin
- if Find(SnippetName, UserDefined, Idx) then
+ if Find(SnippetName, TCollectionID.__TMP__DBCollectionID(UserDefined), Idx) then
+// if Find(SnippetName, UserDefined, Idx) then
+ Result := Items[Idx]
+ else
+ Result := nil;
+end;
+
+function TSnippetList.Find(const SnippetName: string;
+ const ACollectionID: TCollectionID): TSnippet;
+var
+ Idx: Integer; // index of snippet name in list
+begin
+ if Find(SnippetName, ACollectionID, Idx) then
Result := Items[Idx]
else
Result := nil;
@@ -743,7 +861,8 @@ function TSnippetList.Find(const SnippetID: TSnippetID): TSnippet;
@return Reference to required snippet or nil if not found.
}
begin
- Result := Find(SnippetID.Name, SnippetID.UserDefined);
+// Result := Find(SnippetID.Name, SnippetID.UserDefined);
+ Result := Find(SnippetID.Name, SnippetID.CollectionID);
end;
function TSnippetList.GetEnumerator: TEnumerator;
@@ -773,7 +892,13 @@ function TSnippetList.IsEmpty: Boolean;
function TSnippetList.IsEmpty(const UserDefined: Boolean): Boolean;
begin
- Result := Count(UserDefined) = 0;
+// Result := Count(UserDefined) = 0;
+ Result := Count(TCollectionID.__TMP__DBCollectionID(UserDefined)) = 0;
+end;
+
+function TSnippetList.IsEmpty(const ACollectionID: TCollectionID): Boolean;
+begin
+ Result := Count(ACollectionID) = 0;
end;
function TSnippetList.IsEqual(const AList: TSnippetList): Boolean;
From 2f8b4eb0fe7121a3a550b61984c8a98a566f730b Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Wed, 30 Oct 2024 13:12:21 +0000
Subject: [PATCH 012/222] Update external object's DisplaySnippet method
Updated definition of the external object's DisplaySnippet method in
ExternalObj.ridl, by replacing Boolean UserDefined parameter with a
WideString CollectionIDAsHex parameter. This parameter takes a hex
string representation of the named snippet's collection ID.
Bumped external object version to 15, and renamed interface to
IWBExternal15.
Made changes to affected code as follows:
Updated TWBExternal re the changes in IWBExternal15.
Added overloaded DisplaySnippet method to INotifier and its
implementation in TNotifier. The new overload takes a TCollectionID
parameter which the revised TWBExternal.DisplaySnippet method calls
after converting its Hex string collection ID parameter back into a
TCollectionID. The old version of INotifier.DisplaySnippet, that takes a
Boolean UserDefined parameter was left in place.
The displaySnippet JavaScript function in external.js was modified to
take a hex string representation of a collection ID instead of a
user-defined boolean parameter. It passes along the new parameter to the
revised IWBExternal.DisplaySnippet method.
USnippetHTML was changed to pass the expected collection id hex string
to the JavaScript displaySnippet() function.
All old code was commented out.
---
Src/ExternalObj.ridl | 27 +++++++++++-----
Src/IntfNotifier.pas | 13 +++++++-
Src/Res/Scripts/external.js | 16 +++++++++-
Src/UNotifier.pas | 29 +++++++++++++++--
Src/USnippetHTML.pas | 2 +-
Src/UWBExternal.pas | 64 ++++++++++++++++++++++++++-----------
6 files changed, 120 insertions(+), 31 deletions(-)
diff --git a/Src/ExternalObj.ridl b/Src/ExternalObj.ridl
index fcf28f613..76c8ae4f6 100644
--- a/Src/ExternalObj.ridl
+++ b/Src/ExternalObj.ridl
@@ -3,7 +3,7 @@
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/
*
- * Copyright (C) 2006-2021, Peter Johnson (gravatar.com/delphidabbler).
+ * Copyright (C) 2006-2024, Peter Johnson (gravatar.com/delphidabbler).
*
* Source for type library that defines the interface to extensions to the
* browser control DOM's "external object".
@@ -12,7 +12,7 @@
[
uuid(DA95AEFB-3FB5-4A9E-9F9D-A53DD05CA7D4),
- version(14.0),
+ version(15.0),
helpstring("CodeSnip DOM External Object Extender Type Library"),
custom(DE77BA64-517C-11D1-A2DA-0000F8773CE9, 117441012),
custom(DE77BA63-517C-11D1-A2DA-0000F8773CE9, 1219706147)
@@ -24,19 +24,19 @@ library ExternalObj
importlib("stdole2.tlb");
/*
- * V14 interface of extension to browser DOM's "external" object.
+ * V15 interface of extension to browser DOM's "external" object.
*/
- interface IWBExternal14;
+ interface IWBExternal15;
[
uuid(BA971829-ED4D-4092-BCAE-4B5DB1A2D74A),
- version(14.0),
+ version(15.0),
helpstring("DOM external object extender"),
dual,
oleautomation
]
- interface IWBExternal14: IDispatch
+ interface IWBExternal15: IDispatch
{
/*
* Update database from internet.
@@ -44,14 +44,25 @@ library ExternalObj
[id(0x00000065)]
HRESULT _stdcall UpdateDbase(void);
- /*
+ /* - TODO: Delete following commented out method
* Display named snippet.
* @param SnippetName [in] Name of snippet to display.
* @param UserDefined [in] Whether snippet is user defined.
- */
+ *
[id(0x00000066)]
HRESULT _stdcall DisplaySnippet([in] BSTR SnippetName,
[in] VARIANT_BOOL UserDefined, [in] VARIANT_BOOL NewTab);
+ */
+
+ /*
+ * Display named snippet.
+ * @param SnippetName [in] Name of snippet to display.
+ * @param CollectionIDAsHex [in] Hex representation of snippet's
+ * collection ID.
+ */
+ [id(0x00000080)]
+ HRESULT _stdcall DisplaySnippet([in] BSTR SnippetName,
+ [in] BSTR CollectionIDAsHex, [in] VARIANT_BOOL NewTab);
/*
* Displays configure compilers dialog box.
diff --git a/Src/IntfNotifier.pas b/Src/IntfNotifier.pas
index cb0e460c9..1c15d9b03 100644
--- a/Src/IntfNotifier.pas
+++ b/Src/IntfNotifier.pas
@@ -20,6 +20,7 @@ interface
// Delphi
Classes, ActiveX, Windows,
// Project
+ DB.UCollections,
UView;
@@ -40,7 +41,17 @@ interface
/// WordBool [in] Whether to display snippet in a new
/// detail pane tab.
procedure DisplaySnippet(const SnippetName: WideString;
- UserDefined: WordBool; NewTab: WordBool);
+ UserDefined: WordBool; NewTab: WordBool); overload;
+
+ /// Displays a snippet.
+ /// WideString [in] Name of required snippet.
+ ///
+ /// TCollectionID [in] ID of the snippet's
+ /// collection.
+ /// WordBool [in] Whether to display snippet in a new
+ /// detail pane tab.
+ procedure DisplaySnippet(const SnippetName: WideString;
+ ACollectionID: TCollectionID; NewTab: WordBool); overload;
/// Displays a category.
/// WideString [in] ID of required category.
diff --git a/Src/Res/Scripts/external.js b/Src/Res/Scripts/external.js
index 0de9f998d..ffaf18be5 100644
--- a/Src/Res/Scripts/external.js
+++ b/Src/Res/Scripts/external.js
@@ -36,12 +36,26 @@ function updateDbase() {
* @param string snippet [in] Name of snippet to be displayed.
* @param boolean userdefined [in] Whether snippet is user defined.
* @return False.
- */
+ *
function displaySnippet(snippet, userdefined) {
var e = window.event;
external.DisplaySnippet(snippet, userdefined, e.ctrlKey);
return false;
}
+*/
+
+/*
+ * Calls external object to get host application to display a named snippet.
+ * @param string snippet [in] Name of snippet to be displayed.
+ * @param boolean collectionId [in] Hex string representation of collection
+ * to which the snippet belongs.
+ * @return False.
+ */
+function displaySnippet(snippet, collectionId) {
+ var e = window.event;
+ external.DisplaySnippet(snippet, collectionId, e.ctrlKey);
+ return false;
+}
/*
* Calls external object to get host application to display a category.
diff --git a/Src/UNotifier.pas b/Src/UNotifier.pas
index fe3871df4..81db10187 100644
--- a/Src/UNotifier.pas
+++ b/Src/UNotifier.pas
@@ -19,7 +19,9 @@ interface
// Delphi
Classes, ActiveX,
// Project
- IntfNotifier, UView;
+ DB.UCollections,
+ IntfNotifier,
+ UView;
type
@@ -80,7 +82,17 @@ TNotifier = class(TInterfacedObject, INotifier, ISetActions)
/// detail pane tab.
/// Methods of INotifier.
procedure DisplaySnippet(const SnippetName: WideString;
- UserDefined: WordBool; NewTab: WordBool);
+ UserDefined: WordBool; NewTab: WordBool); overload;
+
+ /// Displays a snippet.
+ /// WideString [in] Name of required snippet.
+ ///
+ /// TCollectionID [in] ID of the snippet's
+ /// collection.
+ /// WordBool [in] Whether to display snippet in a new
+ /// detail pane tab.
+ procedure DisplaySnippet(const SnippetName: WideString;
+ ACollectionID: TCollectionID; NewTab: WordBool); overload;
/// Displays a category.
/// WideString [in] ID of required category.
@@ -253,6 +265,19 @@ procedure TNotifier.DisplayCategory(const CatID: WideString; NewTab: WordBool);
end;
end;
+procedure TNotifier.DisplaySnippet(const SnippetName: WideString;
+ ACollectionID: TCollectionID; NewTab: WordBool);
+begin
+ if Assigned(fDisplaySnippetAction) then
+ begin
+ (fDisplaySnippetAction as TSnippetAction).SnippetName := SnippetName;
+ (fDisplaySnippetAction as TSnippetAction).UserDefined :=
+ ACollectionID <> TCollectionID.__TMP__MainDBCollectionID;
+ (fDisplaySnippetAction as TSnippetAction).NewTab := NewTab;
+ fDisplaySnippetAction.Execute;
+ end;
+end;
+
procedure TNotifier.DisplaySnippet(const SnippetName: WideString;
UserDefined: WordBool; NewTab: WordBool);
begin
diff --git a/Src/USnippetHTML.pas b/Src/USnippetHTML.pas
index a853e74f6..caaca05a7 100644
--- a/Src/USnippetHTML.pas
+++ b/Src/USnippetHTML.pas
@@ -207,7 +207,7 @@ class function TSnippetHTML.SnippetALink(const Snippet: TSnippet): string;
// Create javascript link enclosing snippet name
Result := JSALink(
TJavaScript.LiteralFunc(
- 'displaySnippet', [Snippet.Name, Snippet.UserDefined]
+ 'displaySnippet', [Snippet.Name, Snippet.CollectionID.ToHexString]
),
'snippet-link',
Snippet.DisplayName
diff --git a/Src/UWBExternal.pas b/Src/UWBExternal.pas
index 46c5fb12d..e219ecb10 100644
--- a/Src/UWBExternal.pas
+++ b/Src/UWBExternal.pas
@@ -26,7 +26,7 @@ interface
type
- /// COM object that implements the methods of the IWBExternal14
+ /// COM object that implements the methods of the IWBExternal15
/// interface that extend the browser control's 'external' object.
///
/// This class enables application code to be called from JavaScript
@@ -34,7 +34,7 @@ interface
/// The methods a declared in the type library that is defined in
/// External.idl.
///
- TWBExternal = class(TAutoIntfObject, IWBExternal14, ISetNotifier)
+ TWBExternal = class(TAutoIntfObject, IWBExternal15, ISetNotifier)
strict private
var
/// Object used to call application code in response to
@@ -54,22 +54,34 @@ TWBExternal = class(TAutoIntfObject, IWBExternal14, ISetNotifier)
constructor Create;
/// Updates database from internet.
- /// Method of IWBExternal14.
+ /// Method of IWBExternal15.
procedure UpdateDbase; safecall;
+// /// Displays a named snippet.
+// /// WideString [in] Name of snippet to be
+// /// displayed.
+// /// WordBool [in] Whether the snippet is user
+// /// defined.
+// /// WordBool [in] Whether to display snippet in a new
+// /// tab.
+// /// Method of IWBExternal14.
+// procedure DisplaySnippet(const SnippetName: WideString;
+// UserDefined: WordBool; NewTab: WordBool); safecall;
+
+ /// Displays the Configure Compilers dialogue box.
/// Displays a named snippet.
/// WideString [in] Name of snippet to be
/// displayed.
- /// WordBool [in] Whether the snippet is user
- /// defined.
+ /// WideString [in] Hex string
+ /// representation of the ID of the collection to which the snippet
+ /// belongs.
/// WordBool [in] Whether to display snippet in a new
/// tab.
- /// Method of IWBExternal14.
+ /// Method of IWBExternal15.
procedure DisplaySnippet(const SnippetName: WideString;
- UserDefined: WordBool; NewTab: WordBool); safecall;
+ const CollectionIDAsHex: WideString; NewTab: WordBool); safecall;
- /// Displays the Configure Compilers dialogue box.
- /// Method of IWBExternal14.
+ /// Method of IWBExternal15.
procedure ConfigCompilers; safecall;
/// Edits a named snippet.
@@ -77,7 +89,7 @@ TWBExternal = class(TAutoIntfObject, IWBExternal14, ISetNotifier)
///
///
/// The named snippet must be user defined.
- /// Method of IWBExternal14.
+ /// Method of IWBExternal15.
///
procedure EditSnippet(const SnippetName: WideString); safecall;
@@ -86,20 +98,20 @@ TWBExternal = class(TAutoIntfObject, IWBExternal14, ISetNotifier)
///
/// WordBool [in] Whether to display category in a new
/// tab.
- /// Method of IWBExternal14.
+ /// Method of IWBExternal15.
procedure DisplayCategory(const CatID: WideString; NewTab: WordBool);
safecall;
/// Opens Snippet Editor ready to create a new snippet.
- /// Method of IWBExternal14.
+ /// Method of IWBExternal15.
procedure NewSnippet; safecall;
/// Shows latest news items from CodeSnip news feed.
- /// Method of IWBExternal14.
+ /// Method of IWBExternal15.
procedure ShowNews; safecall;
/// Displays the program's About Box.
- /// Method of IWBExternal14.
+ /// Method of IWBExternal15.
procedure ShowAboutBox; safecall;
/// Records the notifier object that is used to call application
@@ -118,6 +130,7 @@ implementation
// Delphi
Forms,
// Project
+ DB.UCollections,
UAppInfo;
@@ -142,7 +155,7 @@ constructor TWBExternal.Create;
ExeName := TAppInfo.AppExeFilePath;
OleCheck(LoadTypeLib(PWideChar(ExeName), TypeLib));
// Create the object using type library
- inherited Create(TypeLib, IWBExternal14);
+ inherited Create(TypeLib, IWBExternal15);
end;
procedure TWBExternal.DisplayCategory(const CatID: WideString;
@@ -156,17 +169,32 @@ procedure TWBExternal.DisplayCategory(const CatID: WideString;
end;
end;
-procedure TWBExternal.DisplaySnippet(const SnippetName: WideString;
- UserDefined: WordBool; NewTab: WordBool);
+procedure TWBExternal.DisplaySnippet(const SnippetName,
+ CollectionIDAsHex: WideString; NewTab: WordBool);
begin
try
if Assigned(fNotifier) then
- fNotifier.DisplaySnippet(SnippetName, UserDefined, NewTab);
+ fNotifier.DisplaySnippet(
+ SnippetName,
+ TCollectionID.CreateFromHexString(CollectionIDAsHex),
+ NewTab
+ );
except
HandleException;
end;
end;
+//procedure TWBExternal.DisplaySnippet(const SnippetName: WideString;
+// UserDefined: WordBool; NewTab: WordBool);
+//begin
+// try
+// if Assigned(fNotifier) then
+// fNotifier.DisplaySnippet(SnippetName, UserDefined, NewTab);
+// except
+// HandleException;
+// end;
+//end;
+
procedure TWBExternal.EditSnippet(const SnippetName: WideString);
begin
try
From 0aa28e71d15d97a78c16f907ef4326ad7d471fcb Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Wed, 30 Oct 2024 14:44:13 +0000
Subject: [PATCH 013/222] Remove TSnippetID.UserDefined & related constructor
Removed TSnippetID.UserDefined property and constructor that took a
Boolean UserDefined parameter.
Modified affected units to use TSnippetID.CollectionID instead of
TSnippetID.UserDefined and to use the TSnippetID constructor that takes
a TCollectionID parameter instead of the constructor that took a Boolean
UserDefined parameter.
All affected units required __TMP__ code to acheive this.
Commented out replaced code.
---
Src/Favourites.UPersist.pas | 19 +++++++++++++++----
Src/FmFavouritesDlg.pas | 13 +++++++++----
Src/FmSnippetsEditorDlg.pas | 7 +++++--
Src/UCodeImportExport.pas | 11 ++++++++---
Src/UCodeImportMgr.pas | 23 ++++++++++++++++++-----
Src/USnippetIDListIOHandler.pas | 11 ++++++++---
Src/USnippetIDs.pas | 19 +++++--------------
7 files changed, 68 insertions(+), 35 deletions(-)
diff --git a/Src/Favourites.UPersist.pas b/Src/Favourites.UPersist.pas
index 9f73ab49d..d1aa43a0e 100644
--- a/Src/Favourites.UPersist.pas
+++ b/Src/Favourites.UPersist.pas
@@ -52,9 +52,18 @@ implementation
uses
// Delphi
- SysUtils, IOUtils, Classes,
+ SysUtils,
+ IOUtils,
+ Classes,
/// Project
- DB.UMain, UAppInfo, UConsts, UIOUtils, UIStringList, USnippetIDs, UStrUtils;
+ DB.UCollections,
+ DB.UMain,
+ UAppInfo,
+ UConsts,
+ UIOUtils,
+ UIStringList,
+ USnippetIDs,
+ UStrUtils;
{ TFavouritesPersist }
@@ -109,7 +118,8 @@ class procedure TFavouritesPersist.Load(Favourites: TFavourites);
raise EFavouritesPersist.Create(sBadFormat);
// only add to favourites if snippet in database
if Database.Snippets.Find(SnippetName, UserDef) <> nil then
- Favourites.Add(TSnippetID.Create(SnippetName, UserDef), LastAccess);
+// Favourites.Add(TSnippetID.Create(SnippetName, UserDef), LastAccess);
+ Favourites.Add(TSnippetID.Create(SnippetName, TCollectionID.__TMP__DBCollectionID(UserDef)), LastAccess);
end;
end;
@@ -125,7 +135,8 @@ class procedure TFavouritesPersist.Save(Favourites: TFavourites);
begin
SB.Append(Fav.SnippetID.Name);
SB.Append(TAB);
- SB.Append(BoolToStr(Fav.SnippetID.UserDefined, True));
+// SB.Append(BoolToStr(Fav.SnippetID.UserDefined, True));
+ SB.Append(BoolToStr(Fav.SnippetID.CollectionID <> TCollectionID.__TMP__MainDBCollectionID, True));
SB.Append(TAB);
SB.Append(DateTimeToStr(Fav.LastAccessed));
SB.AppendLine;
diff --git a/Src/FmFavouritesDlg.pas b/Src/FmFavouritesDlg.pas
index 7213d1852..0ee1c1364 100644
--- a/Src/FmFavouritesDlg.pas
+++ b/Src/FmFavouritesDlg.pas
@@ -273,6 +273,7 @@ implementation
// Delphi
SysUtils, DateUtils, Windows, Graphics,
// Project
+ DB.UCollections,
DB.UMain, DB.USnippet, UCtrlArranger, UMessageBox, UPreferences, USettings,
UStructs, UStrUtils;
@@ -344,7 +345,8 @@ procedure TFavouritesDlg.actDisplayExecute(Sender: TObject);
SelectedSnippet := LI.Favourite.SnippetID;
fNotifier.DisplaySnippet(
SelectedSnippet.Name,
- SelectedSnippet.UserDefined,
+// SelectedSnippet.UserDefined,
+ SelectedSnippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID,
chkNewTab.Checked
);
fFavourites.Touch(SelectedSnippet);
@@ -579,10 +581,13 @@ class function TFavouritesDlg.IsDisplayed: Boolean;
procedure TFavouritesDlg.LVCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
var
- UserDefined: Boolean;
+// UserDefined: Boolean;
+ IsMainDB: Boolean;
begin
- UserDefined := (Item as TFavouriteListItem).Favourite.SnippetID.UserDefined;
- fLVFavs.Canvas.Font.Color := Preferences.DBHeadingColours[UserDefined];
+// UserDefined := (Item as TFavouriteListItem).Favourite.SnippetID.UserDefined;
+// fLVFavs.Canvas.Font.Color := Preferences.DBHeadingColours[UserDefined];
+ IsMainDB := (Item as TFavouriteListItem).Favourite.SnippetID.CollectionID = TCollectionID.__TMP__MainDBCollectionID;
+ fLVFavs.Canvas.Font.Color := Preferences.DBHeadingColours[not IsMainDB];
end;
procedure TFavouritesDlg.LVCustomDrawSubItem(Sender: TCustomListView;
diff --git a/Src/FmSnippetsEditorDlg.pas b/Src/FmSnippetsEditorDlg.pas
index 45e9bc7d7..0e642a4a9 100644
--- a/Src/FmSnippetsEditorDlg.pas
+++ b/Src/FmSnippetsEditorDlg.pas
@@ -254,6 +254,7 @@ implementation
// Delphi
Windows {for inlining}, Graphics,
// Project
+ DB.UCollections,
DB.UMain, DB.USnippetKind, FmDependenciesDlg, IntfCommon, UColours, UConsts,
UCSSUtils, UCtrlArranger, UExceptions, UFontHelper, UIStringList,
UReservedCategories, USnippetExtraHelper, USnippetValidator, UMessageBox,
@@ -424,7 +425,8 @@ procedure TSnippetsEditorDlg.actViewDependenciesExecute(Sender: TObject);
fDependsCLBMgr.GetCheckedSnippets(DependsList);
TDependenciesDlg.Execute(
Self,
- TSnippetID.Create(StrTrim(edName.Text), True),
+// TSnippetID.Create(StrTrim(edName.Text), True),
+ TSnippetID.Create(StrTrim(edName.Text), TCollectionID.__TMP__UserDBCollectionID),
StrTrim(edDisplayName.Text),
DependsList,
[tiDependsUpon],
@@ -978,7 +980,8 @@ procedure TSnippetsEditorDlg.UpdateReferences;
fDependsCLBMgr.Clear;
fXRefsCLBMgr.Save;
fXRefsCLBMgr.Clear;
- EditSnippetID := TSnippetID.Create(fOrigName, True);
+// EditSnippetID := TSnippetID.Create(fOrigName, True);
+ EditSnippetID := TSnippetID.Create(fOrigName, TCollectionID.__TMP__UserDBCollectionID);
EditSnippetKind := fSnipKindList.SnippetKind(cbKind.ItemIndex);
for Snippet in Database.Snippets do
begin
diff --git a/Src/UCodeImportExport.pas b/Src/UCodeImportExport.pas
index e43346daa..580bae8b8 100644
--- a/Src/UCodeImportExport.pas
+++ b/Src/UCodeImportExport.pas
@@ -165,6 +165,7 @@ implementation
XMLDom,
// Project
ActiveText.UMain,
+ DB.UCollections,
DB.UMain,
DB.USnippetKind,
UAppInfo,
@@ -370,9 +371,13 @@ procedure TCodeImporter.Execute(const Data: TBytes);
TXMLDocHelper.GetPascalNameList(fXMLDoc, DependsNode, SnippetNames);
Depends.Clear;
for SnippetName in SnippetNames do
- // Note: in building snippet ID list we assume each snippet is user-
- // defined. It may not be, but there is no way of telling from XML.
- Depends.Add(TSnippetID.Create(SnippetName, True));
+// // Note: in building snippet ID list we assume each snippet is user-
+// // defined. It may not be, but there is no way of telling from XML.
+// Depends.Add(TSnippetID.Create(SnippetName, True));
+ // Note: in building snippet ID list we assume each snippet is from the
+ // standard user collection. It may not be, but there is no way of telling
+ // from XML.
+ Depends.Add(TSnippetID.Create(SnippetName, TCollectionID.__TMP__UserDBCollectionID));
end;
// Reads description node and converts to active text.
diff --git a/Src/UCodeImportMgr.pas b/Src/UCodeImportMgr.pas
index ba328ea9e..7f21d1fee 100644
--- a/Src/UCodeImportMgr.pas
+++ b/Src/UCodeImportMgr.pas
@@ -148,9 +148,16 @@ implementation
uses
// Delphi
- SysUtils, Classes,
+ SysUtils,
+ Classes,
// Project
- ActiveText.UMain, DB.UMain, DB.USnippet, UIOUtils, USnippetIDs, UStrUtils;
+ ActiveText.UMain,
+ DB.UCollections,
+ DB.UMain,
+ DB.USnippet,
+ UIOUtils,
+ USnippetIDs,
+ UStrUtils;
{ TCodeImportMgr }
@@ -178,7 +185,8 @@ function TCodeImportMgr.DisallowedNames(const ExcludedName: string):
Result := TIStringList.Create;
Result.CaseSensitive := False;
for Snippet in Database.Snippets do
- if Snippet.UserDefined then
+// if Snippet.UserDefined then
+ if Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
Result.Add(Snippet.Name);
for SnippetInfo in fSnippetInfoList do
if not StrSameText(SnippetInfo.Name, ExcludedName) then
@@ -241,6 +249,7 @@ procedure TCodeImportMgr.UpdateDatabase;
var
Idx: Integer; // loops through dependencies
SnippetID: TSnippetID; // each snippet ID in dependency list
+ CollectionID: TCollectionID;
begin
// NOTE: The data file format does not record which database a required
// snippet belongs to, so we first look in the user database and if it's
@@ -248,8 +257,12 @@ procedure TCodeImportMgr.UpdateDatabase;
for Idx := 0 to Pred(Depends.Count) do
begin
SnippetID := Depends[Idx];
- SnippetID.UserDefined :=
- Database.Snippets.Find(SnippetID.Name, True) <> nil;
+// SnippetID.UserDefined :=
+// Database.Snippets.Find(SnippetID.Name, True) <> nil;
+ CollectionID := TCollectionID.__TMP__UserDBCollectionID;
+ if Database.Snippets.Find(SnippetID.Name, CollectionID) = nil then
+ CollectionID := TCollectionID.__TMP__MainDBCollectionID;
+ SnippetID.CollectionID := CollectionID;
Depends[Idx] := SnippetID;
end;
end;
diff --git a/Src/USnippetIDListIOHandler.pas b/Src/USnippetIDListIOHandler.pas
index 4aed2f246..ac994fa35 100644
--- a/Src/USnippetIDListIOHandler.pas
+++ b/Src/USnippetIDListIOHandler.pas
@@ -66,7 +66,10 @@ implementation
// Delphi
Classes,
// Project
- UConsts, UIOUtils, UStrUtils;
+ DB.UCollections,
+ UConsts,
+ UIOUtils,
+ UStrUtils;
{ TSnippetIDListFileReader }
@@ -109,7 +112,8 @@ procedure TSnippetIDListFileReader.Parse;
if not TryStrToInt(UserDefStr, UserDefInt)
or not (UserDefInt in [0, 1]) then
raise ESnippetIDListFileReader.CreateFmt(sBadUserDef, [Line]);
- fSnippetIDs.Add(TSnippetID.Create(Name, Boolean(UserDefInt)));
+// fSnippetIDs.Add(TSnippetID.Create(Name, Boolean(UserDefInt)));
+ fSnippetIDs.Add(TSnippetID.Create(Name, TCollectionID.__TMP__DBCollectionID(Boolean(UserDefInt))));
end;
end;
@@ -157,7 +161,8 @@ procedure TSnippetIDListFileWriter.CreateContent(
fBuilder.Append(TAB);
// NOTE: TStringBuilder.Append(Boolean) override not used here since ordinal
// value wanted instead of "True" or "False" or localised equivalent.
- fBuilder.Append(Ord(SnippetID.UserDefined));
+// fBuilder.Append(Ord(SnippetID.UserDefined));
+ fBuilder.Append(Ord(SnippetID.CollectionID <> TCollectionID.__TMP__MainDBCollectionID));
fBuilder.AppendLine;
end;
end;
diff --git a/Src/USnippetIDs.pas b/Src/USnippetIDs.pas
index 892290a6f..620472dcb 100644
--- a/Src/USnippetIDs.pas
+++ b/Src/USnippetIDs.pas
@@ -38,8 +38,6 @@ TSnippetID = record
// /// Value of UserDefined property.
// fUserDefined: Boolean;
fCollectionID: TCollectionID;
-// function __TMP__GetUserDefined: Boolean;
-// procedure __TMP__SetUserDefined(const Value: Boolean);
procedure SetCollectionID(const AValue: TCollectionID);
public
/// Name of snippet.
@@ -55,10 +53,13 @@ TSnippetID = record
property CollectionID: TCollectionID
read fCollectionID write SetCollectionID;
+// /// Creates a record with given property values.
+// constructor Create(const AName: string; const AUserDefined: Boolean);
+// overload; {TODO -cCollections: remove constructor}
+
/// Creates a record with given property values.
/// ACollectionID must not be null.
constructor Create(const AName: string; const ACollectionID: TCollectionID);
- overload; {TODO -cCollections: remove overload}
/// Creates copy of given snippet ID
constructor Clone(const Src: TSnippetID);
@@ -200,7 +201,7 @@ constructor TSnippetID.Create(const AName: string;
//constructor TSnippetID.Create(const AName: string; const AUserDefined: Boolean);
//begin
// fName := AName;
-// __TMP__SetUserDefined(AUserDefined);
+// fUserDefined := AUserDefined);
//end;
class operator TSnippetID.Equal(const SID1, SID2: TSnippetID): Boolean;
@@ -219,16 +220,6 @@ procedure TSnippetID.SetCollectionID(const AValue: TCollectionID);
fCollectionID := AValue.Clone;
end;
-//function TSnippetID.__TMP__GetUserDefined: Boolean;
-//begin
-// Result := fCollectionID = TCollectionID.__TMP__UserDBCollectionID;
-//end;
-//
-//procedure TSnippetID.__TMP__SetUserDefined(const Value: Boolean);
-//begin
-// fCollectionID := TCollectionID.__TMP__DBCollectionID(Value);
-//end;
-
{ TSnippetIDList }
function TSnippetIDList.Add(const SnippetID: TSnippetID): Integer;
From 6a9d1d458a36e0ad5beec52e05dcf45ae3d17d3d Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Wed, 30 Oct 2024 17:15:37 +0000
Subject: [PATCH 014/222] Remove TSnippetList.IsEmpty Boolean method overload
Removed overload of TSnippetList.IsEmpty that took a Boolean UserDefined
parameter.
The only place this method was called was in FmMain. This code was
changed to call the TCollectionID overload of TSnippetList.IsEmpty.
Used __TMP__ methods to achieve this.
Removed source code was commented out.
---
Src/DB.USnippet.pas | 24 ++++++++++++------------
Src/FmMain.pas | 9 +++++++--
2 files changed, 19 insertions(+), 14 deletions(-)
diff --git a/Src/DB.USnippet.pas b/Src/DB.USnippet.pas
index 8f9a6f8dc..9ff222da0 100644
--- a/Src/DB.USnippet.pas
+++ b/Src/DB.USnippet.pas
@@ -388,13 +388,13 @@ TSnippetList = class(TObject)
{Checks if list is empty.
@return True if list is empty, False otehrwise.
}
- function IsEmpty(const UserDefined: Boolean): Boolean; overload; {__TMP__ inline;}
- {Checks if sub-set of list from either from or not from use defined
- database is empty.
- @param UserDefined [in] Flags whether to check for snippets in user
- database (True) or in main database (False).
- @return True if required subset is empty, False if not empty.
- }
+// function IsEmpty(const UserDefined: Boolean): Boolean; overload; {__TMP__ inline;}
+// {Checks if sub-set of list from either from or not from use defined
+// database is empty.
+// @param UserDefined [in] Flags whether to check for snippets in user
+// database (True) or in main database (False).
+// @return True if required subset is empty, False if not empty.
+// }
/// Checks if the sub-set of snippets in the list belonging to a
/// specified collection is empty.
@@ -890,11 +890,11 @@ function TSnippetList.IsEmpty: Boolean;
Result := Count = 0;
end;
-function TSnippetList.IsEmpty(const UserDefined: Boolean): Boolean;
-begin
-// Result := Count(UserDefined) = 0;
- Result := Count(TCollectionID.__TMP__DBCollectionID(UserDefined)) = 0;
-end;
+//function TSnippetList.IsEmpty(const UserDefined: Boolean): Boolean;
+//begin
+//// Result := Count(UserDefined) = 0;
+// Result := Count(TCollectionID.__TMP__DBCollectionID(UserDefined)) = 0;
+//end;
function TSnippetList.IsEmpty(const ACollectionID: TCollectionID): Boolean;
begin
diff --git a/Src/FmMain.pas b/Src/FmMain.pas
index 725d241aa..91163c63b 100644
--- a/Src/FmMain.pas
+++ b/Src/FmMain.pas
@@ -585,7 +585,9 @@ implementation
// Project
ClassHelpers.UControls,
ClassHelpers.UGraphics,
- DB.UCategory, DB.UMain, DB.USnippet, FmSplash, FmTrappedBugReportDlg,
+ DB.UCategory,
+ DB.UCollections,
+ DB.UMain, DB.USnippet, FmSplash, FmTrappedBugReportDlg,
FmWaitDlg, IntfFrameMgrs, UActionFactory, UAppInfo,
UCodeShareMgr, UCommandBars, UConsts, UCopyInfoMgr,
UCopySourceMgr, UDatabaseLoader, UDatabaseLoaderUI, UDetailTabAction,
@@ -940,7 +942,10 @@ procedure TMainForm.ActNonEmptyDBUpdate(Sender: TObject);
procedure TMainForm.ActNonEmptyUserDBUpdate(Sender: TObject);
begin
- (Sender as TAction).Enabled := not Database.Snippets.IsEmpty(True);
+// (Sender as TAction).Enabled := not Database.Snippets.IsEmpty(True);
+ (Sender as TAction).Enabled := not Database.Snippets.IsEmpty(
+ TCollectionID.__TMP__UserDBCollectionID
+ );
end;
procedure TMainForm.ActOverviewTabExecute(Sender: TObject);
From 3b61f8c4b058f3e291086c20faf2d0f9d8b4c183 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Wed, 30 Oct 2024 17:42:45 +0000
Subject: [PATCH 015/222] Remove TSnippetList.Count Boolean overload method
Removed overload of TSnippetList.Count that took a Boolean UserDefined
parameter.
Updated all affected code by changing to the TCollectionID overload of
either TSnippetList.Count or TSnippetList.IsEmpty, as appropriate.
Used __TMP__ methods to achieve this.
Removed source code was commented out.
---
Src/DB.USnippet.pas | 46 ++++++++++++++++++------------------
Src/FmAboutDlg.pas | 7 +++++-
Src/FmSelectionSearchDlg.pas | 10 ++++++--
Src/FrSelectUserSnippets.pas | 9 ++++++-
Src/UCodeShareMgr.pas | 12 ++++++++--
Src/UDetailPageHTML.pas | 33 +++++++++++++++++++++-----
Src/UStatusBarMgr.pas | 14 ++++++++---
7 files changed, 93 insertions(+), 38 deletions(-)
diff --git a/Src/DB.USnippet.pas b/Src/DB.USnippet.pas
index 9ff222da0..e47226230 100644
--- a/Src/DB.USnippet.pas
+++ b/Src/DB.USnippet.pas
@@ -365,13 +365,13 @@ TSnippetList = class(TObject)
{Gets an intialised snippet list enumerator.
@return Required enumerator.
}
- function Count(const UserDefined: Boolean): Integer; overload;
- {Counts number of snippets in list that are either from or not from user
- defined database.
- @param UserDefined [in] Flags whether to count snippets in user database
- (True) or in main database (False).
- @return Number of snippets in specified database.
- }
+// function Count(const UserDefined: Boolean): Integer; overload;
+// {Counts number of snippets in list that are either from or not from user
+// defined database.
+// @param UserDefined [in] Flags whether to count snippets in user database
+// (True) or in main database (False).
+// @return Number of snippets in specified database.
+// }
/// Counts number of snippets in list that belong to a specified
/// collection.
@@ -722,22 +722,22 @@ function TSnippetList.ContainsKinds(const Kinds: TSnippetKinds): Boolean;
end;
end;
-function TSnippetList.Count(const UserDefined: Boolean): Integer;
- {Counts number of snippets in list that are either from or not from user
- defined database.
- @param UserDefined [in] Flags whether to count snippets in user database
- (True) or in main database (False).
- @return Number of snippets in specified database.
- }
-//var
-// Snippet: TSnippet; // refers to all snippets in list
-begin
- Result := Count(TCollectionID.__TMP__DBCollectionID(UserDefined));
-// Result := 0;
-// for Snippet in Self do
-// if Snippet.UserDefined = UserDefined then
-// Inc(Result);
-end;
+//function TSnippetList.Count(const UserDefined: Boolean): Integer;
+// {Counts number of snippets in list that are either from or not from user
+// defined database.
+// @param UserDefined [in] Flags whether to count snippets in user database
+// (True) or in main database (False).
+// @return Number of snippets in specified database.
+// }
+////var
+//// Snippet: TSnippet; // refers to all snippets in list
+//begin
+// Result := Count(TCollectionID.__TMP__DBCollectionID(UserDefined));
+//// Result := 0;
+//// for Snippet in Self do
+//// if Snippet.UserDefined = UserDefined then
+//// Inc(Result);
+//end;
function TSnippetList.Count(const ACollectionID: TCollectionID): Integer;
var
diff --git a/Src/FmAboutDlg.pas b/Src/FmAboutDlg.pas
index 6584a4ffd..22b0eb8a0 100644
--- a/Src/FmAboutDlg.pas
+++ b/Src/FmAboutDlg.pas
@@ -179,6 +179,7 @@ implementation
ShellAPI,
IOUtils,
// Project
+ DB.UCollections,
DB.UMain,
FmEasterEgg,
FmPreviewDlg,
@@ -442,7 +443,11 @@ procedure TAboutDlg.InitHTMLFrames;
begin
// Resolve conditionally displayed block placeholders
- IsDBAvalable := Database.Snippets.Count(False) > 0;
+// IsDBAvalable := Database.Snippets.Count(False) > 0;
+ // check if DelphiDabbler Code Snippets Collection is in use
+ IsDBAvalable := not Database.Snippets.IsEmpty(
+ TCollectionID.__TMP__MainDBCollectionID
+ );
IsMetaDataAvailable := fMetaData.IsSupportedVersion
and not fMetaData.IsCorrupt;
IsLicenseInfoAvailable := IsMetaDataAvailable
diff --git a/Src/FmSelectionSearchDlg.pas b/Src/FmSelectionSearchDlg.pas
index a1dcf49bc..3aeaed97f 100644
--- a/Src/FmSelectionSearchDlg.pas
+++ b/Src/FmSelectionSearchDlg.pas
@@ -96,7 +96,10 @@ implementation
// Delphi
SysUtils,
// Project
- DB.UMain, UCtrlArranger, UQuery;
+ DB.UCollections,
+ DB.UMain,
+ UCtrlArranger,
+ UQuery;
{$R *.dfm}
@@ -225,7 +228,10 @@ procedure TSelectionSearchDlg.InitForm;
begin
inherited;
frmSelect.CollapseTree;
- btnUserDB.Enabled := Database.Snippets.Count(True) > 0;
+// btnUserDB.Enabled := Database.Snippets.Count(True) > 0;
+ btnUserDB.Enabled := not Database.Snippets.IsEmpty(
+ TCollectionID.__TMP__UserDBCollectionID
+ );
end;
procedure TSelectionSearchDlg.SelectDB(const UserDefined: Boolean);
diff --git a/Src/FrSelectUserSnippets.pas b/Src/FrSelectUserSnippets.pas
index 28c684c67..54177bbac 100644
--- a/Src/FrSelectUserSnippets.pas
+++ b/Src/FrSelectUserSnippets.pas
@@ -51,6 +51,10 @@ TSelectUserSnippetsFrame = class(TSelectSnippetsBaseFrame)
implementation
+uses
+ DB.UCollections;
+
+
{$R *.dfm}
@@ -62,7 +66,10 @@ function TSelectUserSnippetsFrame.CanAddCatNode(const Cat: TCategory): Boolean;
@return True if category contains any user-defined snippets.
}
begin
- Result := Cat.Snippets.Count(True) > 0;
+// Result := Cat.Snippets.Count(True) > 0;
+ Result := not Cat.Snippets.IsEmpty(
+ TCollectionID.__TMP__UserDBCollectionID
+ );
end;
function TSelectUserSnippetsFrame.CanAddSnippetNode(
diff --git a/Src/UCodeShareMgr.pas b/Src/UCodeShareMgr.pas
index 3f811b898..099cdf34d 100644
--- a/Src/UCodeShareMgr.pas
+++ b/Src/UCodeShareMgr.pas
@@ -62,7 +62,11 @@ implementation
// Delphi
SysUtils,
// Project
- DB.UMain, FmCodeExportDlg, FmCodeImportDlg, UCodeImportMgr;
+ DB.UCollections,
+ DB.UMain,
+ FmCodeExportDlg,
+ FmCodeImportDlg,
+ UCodeImportMgr;
{ TCodeShareMgr }
@@ -73,7 +77,10 @@ class function TCodeShareMgr.CanShare: Boolean;
@return True if user defined snippets exist in database.
}
begin
- Result := Database.Snippets.Count(True) > 0;
+// Result := Database.Snippets.Count(True) > 0;
+ Result := not Database.Snippets.IsEmpty(
+ TCollectionID.__TMP__UserDBCollectionID
+ );
end;
class procedure TCodeShareMgr.ExportCode(ViewItem: IView);
@@ -118,3 +125,4 @@ class procedure TCodeShareMgr.ImportCode;
end.
+
diff --git a/Src/UDetailPageHTML.pas b/Src/UDetailPageHTML.pas
index 718aa7032..9b50c4680 100644
--- a/Src/UDetailPageHTML.pas
+++ b/Src/UDetailPageHTML.pas
@@ -66,10 +66,25 @@ implementation
// Delphi
SysUtils, Generics.Defaults,
// Project
- Compilers.UGlobals, Compilers.UCompilers, DB.UMain, DB.USnippet, UConsts,
- UContainers, UCSSUtils, UEncodings, UHTMLTemplate, UHTMLUtils,
- UJavaScriptUtils, UPreferences, UQuery, UResourceUtils, USnippetHTML,
- USnippetPageHTML, UStrUtils, USystemInfo;
+ Compilers.UGlobals,
+ Compilers.UCompilers,
+ DB.UCollections,
+ DB.UMain,
+ DB.USnippet,
+ UConsts,
+ UContainers,
+ UCSSUtils,
+ UEncodings,
+ UHTMLTemplate,
+ UHTMLUtils,
+ UJavaScriptUtils,
+ UPreferences,
+ UQuery,
+ UResourceUtils,
+ USnippetHTML,
+ USnippetPageHTML,
+ UStrUtils,
+ USystemInfo;
type
@@ -418,7 +433,10 @@ procedure TWelcomePageHTML.ResolvePlaceholders(const Tplt: THTMLTemplate);
'externalScript', TJavaScript.LoadScript('external.js', etWindows1252)
);
- UserDBCount := Database.Snippets.Count(True);
+// UserDBCount := Database.Snippets.Count(True);
+ UserDBCount := Database.Snippets.Count(
+ TCollectionID.__TMP__UserDBCollectionID
+ );
Tplt.ResolvePlaceholderHTML(
'HaveUserDB', TCSS.BlockDisplayProp(UserDBCount > 0)
);
@@ -429,7 +447,10 @@ procedure TWelcomePageHTML.ResolvePlaceholders(const Tplt: THTMLTemplate);
'UserDBCount', IntToStr(UserDBCount)
);
- MainDBCount := Database.Snippets.Count(False);
+// MainDBCount := Database.Snippets.Count(False);
+ MainDBCount := Database.Snippets.Count(
+ TCollectionID.__TMP__MainDBCollectionID
+ );
Tplt.ResolvePlaceholderHTML(
'HaveMainDB', TCSS.BlockDisplayProp(MainDBCount > 0)
);
diff --git a/Src/UStatusBarMgr.pas b/Src/UStatusBarMgr.pas
index dc501db74..3cf6aad69 100644
--- a/Src/UStatusBarMgr.pas
+++ b/Src/UStatusBarMgr.pas
@@ -118,9 +118,14 @@ implementation
uses
// Delphi
- SysUtils, Forms,
+ SysUtils,
+ Forms,
// Project
- DB.UMain, UQuery, USearch, UStructs;
+ DB.UCollections,
+ DB.UMain,
+ UQuery,
+ USearch,
+ UStructs;
{ TStatusBarMgr }
@@ -357,7 +362,10 @@ procedure TStatusBarMgr.ShowSnippetsInfo;
begin
// Calculate database stats
TotalSnippets := Database.Snippets.Count;
- TotalUserSnippets := Database.Snippets.Count(True);
+// TotalUserSnippets := Database.Snippets.Count(True);
+ TotalUserSnippets := Database.Snippets.Count(
+ TCollectionID.__TMP__UserDBCollectionID
+ );
TotalMainSnippets := TotalSnippets - TotalUserSnippets;
// Build display text and display it
fStatusBar.Panels[cDBPanel].Text := Format(
From cddfe2b6156decf083c68195f29ab84668f04562 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Wed, 30 Oct 2024 21:42:01 +0000
Subject: [PATCH 016/222] Add collection IDs to TDatabaseLoader classes
Add TDatabaseLoader.CollectionID abstract method with implementation in
base classes.
Changed as much code as possible to use CollectionID instead of
IsUserDatabase.
Pulled some former abstract methods from descendant classes into base
class.
Required some __TMP__ methods to implement these changes.
Removed code was commented out.
---
Src/DB.UDatabaseIO.pas | 153 ++++++++++++++++++++++++++---------------
1 file changed, 97 insertions(+), 56 deletions(-)
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index 4fe633fbb..f93fba6b8 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -101,6 +101,7 @@ implementation
// Delphi
SysUtils,
// Project
+ DB.UCollections,
DBIO.UFileIOIntf, DBIO.UIniDataReader, DBIO.UNulDataReader, DBIO.UXMLDataIO,
UAppInfo, UConsts, UIStringList, UReservedCategories, USnippetIDs;
@@ -153,15 +154,20 @@ TDatabaseLoader = class(TInterfacedObject, IDatabaseLoader)
found.
}
function IsNativeSnippet(const Snippet: TSnippet): Boolean;
- virtual; abstract;
+ virtual;
{Checks if a snippet is native (belongs) to the database being read.
@param Snippet [in] Snippet to test.
@return True if snippet is native, False if not.
}
- function IsUserDatabase: Boolean; virtual; abstract;
+ function IsUserDatabase: Boolean; virtual;
{Checks if the database is the user database.
@return True if the database is the user database, False if not.
}
+
+ /// Returns the ID of the collection being loaded into the
+ /// database.
+ function CollectionID: TCollectionID; virtual; abstract;
+
function ErrorMessageHeading: string; virtual; abstract;
{Returns heading to use in error messages. Should identify the database.
@return Required heading.
@@ -211,15 +217,20 @@ TMainDatabaseLoader = class(TDatabaseLoader, IDatabaseLoader)
@return Reference to required snippet object or nil if snippet is not
found.
}
- function IsNativeSnippet(const Snippet: TSnippet): Boolean; override;
- {Checks if a snippet is native (belongs) to the main database.
- @param Snippet [in] Snippet to test.
- @return True if snippet is native, False if not.
- }
- function IsUserDatabase: Boolean; override;
- {Checks if the database is the user database.
- @return False - this is not the user database.
- }
+// function IsNativeSnippet(const Snippet: TSnippet): Boolean; override;
+// {Checks if a snippet is native (belongs) to the main database.
+// @param Snippet [in] Snippet to test.
+// @return True if snippet is native, False if not.
+// }
+// function IsUserDatabase: Boolean; override;
+// {Checks if the database is the user database.
+// @return False - this is not the user database.
+// }
+
+ /// Returns the ID of the collection being loaded into the
+ /// database.
+ function CollectionID: TCollectionID; override;
+
function ErrorMessageHeading: string; override;
{Returns heading to use in error messages. Identifies main database.
@return Required heading.
@@ -246,15 +257,20 @@ TUserDatabaseLoader = class(TDatabaseLoader, IDatabaseLoader)
@return Reference to required snippet object or nil if snippet is not
found.
}
- function IsNativeSnippet(const Snippet: TSnippet): Boolean; override;
- {Checks if a snippet is native (belongs) to the user database.
- @param Snippet [in] Snippet to test.
- @return True if snippet is native, False if not.
- }
- function IsUserDatabase: Boolean; override;
- {Checks if the database is the user database.
- @return True - this is the user database.
- }
+// function IsNativeSnippet(const Snippet: TSnippet): Boolean; override;
+// {Checks if a snippet is native (belongs) to the user database.
+// @param Snippet [in] Snippet to test.
+// @return True if snippet is native, False if not.
+// }
+// function IsUserDatabase: Boolean; override;
+// {Checks if the database is the user database.
+// @return True - this is the user database.
+// }
+
+ /// Returns the ID of the collection being loaded into the
+ /// database.
+ function CollectionID: TCollectionID; override;
+
function ErrorMessageHeading: string; override;
{Returns heading to use in error messages. Identifies main database.
@return Required heading.
@@ -354,6 +370,16 @@ procedure TDatabaseLoader.HandleException(const E: Exception);
raise E;
end;
+function TDatabaseLoader.IsNativeSnippet(const Snippet: TSnippet): Boolean;
+begin
+ Result := Snippet.CollectionID = CollectionID;
+end;
+
+function TDatabaseLoader.IsUserDatabase: Boolean;
+begin
+ Result := CollectionID <> TCollectionID.__TMP__MainDBCollectionID;
+end;
+
procedure TDatabaseLoader.Load(const SnipList: TSnippetList;
const Categories: TCategoryList; const DBDataItemFactory: IDBDataItemFactory);
{Loads data from storage and updates database object.
@@ -472,7 +498,8 @@ procedure TDatabaseLoader.LoadSnippets(const Cat: TCategory);
for SnippetName in SnippetNames do
begin
// Check if snippet exists in current database and add it to list if not
- Snippet := fSnipList.Find(SnippetName, IsUserDatabase);
+// Snippet := fSnipList.Find(SnippetName, IsUserDatabase);
+ Snippet := fSnipList.Find(SnippetName, CollectionID);
if not Assigned(Snippet) then
begin
fReader.GetSnippetProps(SnippetName, SnippetProps);
@@ -489,6 +516,11 @@ procedure TDatabaseLoader.LoadSnippets(const Cat: TCategory);
{ TMainDatabaseLoader }
+function TMainDatabaseLoader.CollectionID: TCollectionID;
+begin
+ Result := TCollectionID.__TMP__MainDBCollectionID;
+end;
+
function TMainDatabaseLoader.CreateReader: IDataReader;
{Creates reader object. If main database doesn't exist a nul reader is
created.
@@ -519,28 +551,34 @@ function TMainDatabaseLoader.FindSnippet(const SnippetName: string;
}
begin
// We only search main database
- Result := SnipList.Find(SnippetName, False);
+// Result := SnipList.Find(SnippetName, False);
+ Result := SnipList.Find(SnippetName, CollectionID);
end;
-function TMainDatabaseLoader.IsNativeSnippet(const Snippet: TSnippet): Boolean;
- {Checks if a snippet is native (belongs) to the main database.
- @param Snippet [in] Snippet to test.
- @return True if snippet is native, False if not.
- }
-begin
- Result := not Snippet.UserDefined;
-end;
+//function TMainDatabaseLoader.IsNativeSnippet(const Snippet: TSnippet): Boolean;
+// {Checks if a snippet is native (belongs) to the main database.
+// @param Snippet [in] Snippet to test.
+// @return True if snippet is native, False if not.
+// }
+//begin
+// Result := not Snippet.UserDefined;
+//end;
+
+//function TMainDatabaseLoader.IsUserDatabase: Boolean;
+// {Checks if the database is the user database.
+// @return False - this is not the user database.
+// }
+//begin
+// Result := False;
+//end;
-function TMainDatabaseLoader.IsUserDatabase: Boolean;
- {Checks if the database is the user database.
- @return False - this is not the user database.
- }
+{ TUserDatabaseLoader }
+
+function TUserDatabaseLoader.CollectionID: TCollectionID;
begin
- Result := False;
+ Result := TCollectionID.__TMP__UserDBCollectionID;
end;
-{ TUserDatabaseLoader }
-
function TUserDatabaseLoader.CreateReader: IDataReader;
{Creates reader object. If user database doesn't exist a nul reader is
created.
@@ -572,28 +610,30 @@ function TUserDatabaseLoader.FindSnippet(const SnippetName: string;
}
begin
// Search in user database
- Result := SnipList.Find(SnippetName, True);
+// Result := SnipList.Find(SnippetName, True);
+ Result := SnipList.Find(SnippetName, CollectionID);
if not Assigned(Result) then
// Not in user database: try main database
- Result := SnipList.Find(SnippetName, False);
+// Result := SnipList.Find(SnippetName, False);
+ Result := SnipList.Find(SnippetName, TCollectionID.__TMP__MainDBCollectionID);
end;
-function TUserDatabaseLoader.IsNativeSnippet(const Snippet: TSnippet): Boolean;
- {Checks if a snippet is native (belongs) to the user database.
- @param Snippet [in] Snippet to test.
- @return True if snippet is native, False if not.
- }
-begin
- Result := Snippet.UserDefined;
-end;
-
-function TUserDatabaseLoader.IsUserDatabase: Boolean;
- {Checks if the database is the user database.
- @return True - this is the user database.
- }
-begin
- Result := True;
-end;
+//function TUserDatabaseLoader.IsNativeSnippet(const Snippet: TSnippet): Boolean;
+// {Checks if a snippet is native (belongs) to the user database.
+// @param Snippet [in] Snippet to test.
+// @return True if snippet is native, False if not.
+// }
+//begin
+// Result := Snippet.UserDefined;
+//end;
+
+//function TUserDatabaseLoader.IsUserDatabase: Boolean;
+// {Checks if the database is the user database.
+// @return True - this is the user database.
+// }
+//begin
+// Result := True;
+//end;
procedure TUserDatabaseLoader.LoadCategories;
{Loads all categories from storage and adds user and imports categories if not
@@ -690,7 +730,8 @@ procedure TDatabaseWriter.WriteSnippets;
for Snippet in fSnipList do
begin
// Only write user-defined snippets
- if Snippet.UserDefined then
+// if Snippet.UserDefined then
+ if Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
begin
// Get and write a snippet's properties
Props := fProvider.GetSnippetProps(Snippet);
From 3116d2165d94a2c336c233cad9602ef125a00806 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Fri, 1 Nov 2024 12:05:29 +0000
Subject: [PATCH 017/222] Remove UserDefined params from TSnippetDoc classes
TSnippetDoc's abstract RenderHeading settings method was changed from
taking a Boolean UserDefined parameter to a TCollectionID parameter.
Implementations in descendant clases in TTextSnippetDoc and
TRTFSnippetDoc were changed accordingly.
TSnippetDoc and TRTFSnippetDoc both required __TMP__ method calls to
be used to implement the changes.
Removed code was commented out.
---
Src/URTFSnippetDoc.pas | 35 ++++++++++++++++++++++++++++-------
Src/USnippetDoc.pas | 27 +++++++++++++++++++--------
Src/UTextSnippetDoc.pas | 29 ++++++++++++++++++++++-------
3 files changed, 69 insertions(+), 22 deletions(-)
diff --git a/Src/URTFSnippetDoc.pas b/Src/URTFSnippetDoc.pas
index 4bb6399c1..185dc8ca9 100644
--- a/Src/URTFSnippetDoc.pas
+++ b/Src/URTFSnippetDoc.pas
@@ -18,6 +18,7 @@ interface
uses
// Project
+ DB.UCollections,
ActiveText.UMain, ActiveText.URTFRenderer, Hiliter.UGlobals, UEncodings,
UIStringList, USnippetDoc, URTFBuilder, URTFStyles;
@@ -75,12 +76,20 @@ TRTFSnippetDoc = class(TSnippetDoc)
strict protected
/// Initialises rich text document.
procedure InitialiseDoc; override;
- /// Adds given heading (i.e. snippet name) to document. Can be
- /// user defined or from main database.
- /// Heading is coloured according to whether user defined or not.
+
+// /// Adds given heading (i.e. snippet name) to document. Can be
+// /// user defined or from main database.
+// /// Heading is coloured according to whether user defined or not.
+// ///
+// procedure RenderHeading(const Heading: string; const UserDefined: Boolean);
+// override;
+
+ /// Output given heading, i.e. snippet name for snippet from a
+ /// given collection..
+ /// Heading is coloured according the the snippet's collection.
///
- procedure RenderHeading(const Heading: string; const UserDefined: Boolean);
- override;
+ procedure RenderHeading(const Heading: string;
+ const ACollectionID: TCollectionID); override;
/// Adds given snippet description to document.
/// Active text formatting is observed and styled to suit
/// document.
@@ -416,13 +425,25 @@ procedure TRTFSnippetDoc.RenderExtra(const ExtraText: IActiveText);
end;
end;
+//procedure TRTFSnippetDoc.RenderHeading(const Heading: string;
+// const UserDefined: Boolean);
+//begin
+// fBuilder.SetFontStyle([fsBold]);
+// fBuilder.SetFontSize(HeadingFontSize);
+// if fUseColour then
+// fBuilder.SetColour(Preferences.DBHeadingColours[UserDefined]);
+// fBuilder.SetParaSpacing(TRTFParaSpacing.Create(0.0, ParaSpacing));
+// fBuilder.AddText(Heading);
+// fBuilder.EndPara;
+//end;
+
procedure TRTFSnippetDoc.RenderHeading(const Heading: string;
- const UserDefined: Boolean);
+ const ACollectionID: TCollectionID);
begin
fBuilder.SetFontStyle([fsBold]);
fBuilder.SetFontSize(HeadingFontSize);
if fUseColour then
- fBuilder.SetColour(Preferences.DBHeadingColours[UserDefined]);
+ fBuilder.SetColour(Preferences.DBHeadingColours[ACollectionID <> TCollectionID.__TMP__MainDBCollectionID]);
fBuilder.SetParaSpacing(TRTFParaSpacing.Create(0.0, ParaSpacing));
fBuilder.AddText(Heading);
fBuilder.EndPara;
diff --git a/Src/USnippetDoc.pas b/Src/USnippetDoc.pas
index e11245322..7e679a52c 100644
--- a/Src/USnippetDoc.pas
+++ b/Src/USnippetDoc.pas
@@ -21,6 +21,7 @@ interface
// Delphi
Classes,
// Project
+ DB.UCollections,
ActiveText.UMain, Compilers.UGlobals, DB.USnippet, UEncodings, UIStringList;
@@ -60,12 +61,20 @@ TSnippetDoc = class(TObject)
/// Does nothing. Descendant classes should perform any required
/// initialisation here.
procedure InitialiseDoc; virtual;
- /// Output given heading, i.e. snippet name. Can be user defined
- /// or from main database.
- /// Heading may be rendered differently depending on whether user
- /// defined or not.
- procedure RenderHeading(const Heading: string; const UserDefined: Boolean);
- virtual; abstract;
+
+// /// Output given heading, i.e. snippet name. Can be user defined
+// /// or from main database.
+// /// Heading may be rendered differently depending on whether user
+// /// defined or not.
+// procedure RenderHeading(const Heading: string; const UserDefined: Boolean);
+// virtual; abstract;
+
+ /// Output given heading, i.e. snippet name for snippet from a
+ /// given collection..
+ /// Heading may be rendered differently depending on the snippet's
+ /// collection.
+ procedure RenderHeading(const Heading: string;
+ const ACollectionID: TCollectionID); virtual; abstract;
/// Output given snippet description.
procedure RenderDescription(const Desc: IActiveText); virtual; abstract;
/// Output given source code.
@@ -178,7 +187,8 @@ function TSnippetDoc.Generate(const Snippet: TSnippet): TEncodedData;
Assert(Assigned(Snippet), ClassName + '.Create: Snippet is nil');
// generate document
InitialiseDoc;
- RenderHeading(Snippet.DisplayName, Snippet.UserDefined);
+// RenderHeading(Snippet.DisplayName, Snippet.UserDefined);
+ RenderHeading(Snippet.DisplayName, Snippet.CollectionID);
RenderDescription(Snippet.Description);
RenderSourceCode(Snippet.SourceCode);
RenderTitledText(
@@ -200,7 +210,8 @@ function TSnippetDoc.Generate(const Snippet: TSnippet): TEncodedData;
end;
if Snippet.Extra.HasContent then
RenderExtra(Snippet.Extra);
- if not Snippet.UserDefined then
+// if not Snippet.UserDefined then
+ if Snippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID then
// database info written only if snippet is from main database
RenderDBInfo(MainDBInfo);
Result := FinaliseDoc;
diff --git a/Src/UTextSnippetDoc.pas b/Src/UTextSnippetDoc.pas
index 923637950..70babef0a 100644
--- a/Src/UTextSnippetDoc.pas
+++ b/Src/UTextSnippetDoc.pas
@@ -20,6 +20,7 @@ interface
// Delphi
Classes,
// Project
+ DB.UCollections,
ActiveText.UMain, UEncodings, UIStringList, USnippetDoc;
@@ -44,12 +45,20 @@ TTextSnippetDoc = class(TSnippetDoc)
strict protected
/// Initialises plain text document.
procedure InitialiseDoc; override;
- /// Adds given heading (i.e. snippet name) to document. Can be
- /// user defined or from main database.
- /// Heading is output the same whether user defined or not, so
- /// UserDefined parameter is ignored.
- procedure RenderHeading(const Heading: string; const UserDefined: Boolean);
- override;
+
+// /// Adds given heading (i.e. snippet name) to document. Can be
+// /// user defined or from main database.
+// /// Heading is output the same whether user defined or not, so
+// /// UserDefined parameter is ignored.
+// procedure RenderHeading(const Heading: string; const UserDefined: Boolean);
+// override;
+
+ /// Output given heading, i.e. snippet name for snippet from a
+ /// given collection.
+ /// Heading is output the same regardless of the snippet's
+ /// collection.
+ procedure RenderHeading(const Heading: string;
+ const ACollectionID: TCollectionID); override;
/// Interprets and adds given snippet description to document.
///
/// Active text is converted to word-wrapped plain text
@@ -165,11 +174,17 @@ procedure TTextSnippetDoc.RenderExtra(const ExtraText: IActiveText);
end;
procedure TTextSnippetDoc.RenderHeading(const Heading: string;
- const UserDefined: Boolean);
+ const ACollectionID: TCollectionID);
begin
fWriter.WriteLine(Heading);
end;
+//procedure TTextSnippetDoc.RenderHeading(const Heading: string;
+// const UserDefined: Boolean);
+//begin
+// fWriter.WriteLine(Heading);
+//end;
+
procedure TTextSnippetDoc.RenderNoCompilerInfo(const Heading,
NoCompileTests: string);
begin
From bf1cd51a04912ae54b13244baedbde10b2b1fa8f Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 2 Nov 2024 08:21:59 +0000
Subject: [PATCH 018/222] Remove INotifier.DisplaySnippet Boolean overload
Also removed method from TNotifier.
Updated FmFavouritesDlg to call TCollectionID version of DisplaySnippet
instead of removed overload.
Removed code was commented out.
---
Src/FmFavouritesDlg.pas | 2 +-
Src/IntfNotifier.pas | 20 +++++++++----------
Src/UNotifier.pas | 44 ++++++++++++++++++++---------------------
3 files changed, 33 insertions(+), 33 deletions(-)
diff --git a/Src/FmFavouritesDlg.pas b/Src/FmFavouritesDlg.pas
index 0ee1c1364..ac2b4f936 100644
--- a/Src/FmFavouritesDlg.pas
+++ b/Src/FmFavouritesDlg.pas
@@ -346,7 +346,7 @@ procedure TFavouritesDlg.actDisplayExecute(Sender: TObject);
fNotifier.DisplaySnippet(
SelectedSnippet.Name,
// SelectedSnippet.UserDefined,
- SelectedSnippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID,
+ SelectedSnippet.CollectionID,// <> TCollectionID.__TMP__MainDBCollectionID,
chkNewTab.Checked
);
fFavourites.Touch(SelectedSnippet);
diff --git a/Src/IntfNotifier.pas b/Src/IntfNotifier.pas
index 1c15d9b03..4c15ae69c 100644
--- a/Src/IntfNotifier.pas
+++ b/Src/IntfNotifier.pas
@@ -33,15 +33,15 @@ interface
/// Requests a database update.
procedure UpdateDbase;
- /// Displays a snippet.
- /// WideString [in] Name of required snippet.
- ///
- /// WordBool [in] Indicates whether snippet is
- /// user defined.
- /// WordBool [in] Whether to display snippet in a new
- /// detail pane tab.
- procedure DisplaySnippet(const SnippetName: WideString;
- UserDefined: WordBool; NewTab: WordBool); overload;
+// /// Displays a snippet.
+// /// WideString [in] Name of required snippet.
+// ///
+// /// WordBool [in] Indicates whether snippet is
+// /// user defined.
+// /// WordBool [in] Whether to display snippet in a new
+// /// detail pane tab.
+// procedure DisplaySnippet(const SnippetName: WideString;
+// UserDefined: WordBool; NewTab: WordBool); overload;
/// Displays a snippet.
/// WideString [in] Name of required snippet.
@@ -51,7 +51,7 @@ interface
/// WordBool [in] Whether to display snippet in a new
/// detail pane tab.
procedure DisplaySnippet(const SnippetName: WideString;
- ACollectionID: TCollectionID; NewTab: WordBool); overload;
+ ACollectionID: TCollectionID; NewTab: WordBool);
/// Displays a category.
/// WideString [in] ID of required category.
diff --git a/Src/UNotifier.pas b/Src/UNotifier.pas
index 81db10187..c0dcd22fa 100644
--- a/Src/UNotifier.pas
+++ b/Src/UNotifier.pas
@@ -73,16 +73,16 @@ TNotifier = class(TInterfacedObject, INotifier, ISetActions)
/// Methods of INotifier.
procedure UpdateDbase;
- /// Displays a snippet.
- /// WideString [in] Name of required snippet.
- ///
- /// WordBool [in] Indicates whether snippet is
- /// user defined.
- /// WordBool [in] Whether to display snippet in a new
- /// detail pane tab.
- /// Methods of INotifier.
- procedure DisplaySnippet(const SnippetName: WideString;
- UserDefined: WordBool; NewTab: WordBool); overload;
+// /// Displays a snippet.
+// /// WideString [in] Name of required snippet.
+// ///
+// /// WordBool [in] Indicates whether snippet is
+// /// user defined.
+// /// WordBool [in] Whether to display snippet in a new
+// /// detail pane tab.
+// /// Methods of INotifier.
+// procedure DisplaySnippet(const SnippetName: WideString;
+// UserDefined: WordBool; NewTab: WordBool); overload;
/// Displays a snippet.
/// WideString [in] Name of required snippet.
@@ -92,7 +92,7 @@ TNotifier = class(TInterfacedObject, INotifier, ISetActions)
/// WordBool [in] Whether to display snippet in a new
/// detail pane tab.
procedure DisplaySnippet(const SnippetName: WideString;
- ACollectionID: TCollectionID; NewTab: WordBool); overload;
+ ACollectionID: TCollectionID; NewTab: WordBool);
/// Displays a category.
/// WideString [in] ID of required category.
@@ -278,17 +278,17 @@ procedure TNotifier.DisplaySnippet(const SnippetName: WideString;
end;
end;
-procedure TNotifier.DisplaySnippet(const SnippetName: WideString;
- UserDefined: WordBool; NewTab: WordBool);
-begin
- if Assigned(fDisplaySnippetAction) then
- begin
- (fDisplaySnippetAction as TSnippetAction).SnippetName := SnippetName;
- (fDisplaySnippetAction as TSnippetAction).UserDefined := UserDefined;
- (fDisplaySnippetAction as TSnippetAction).NewTab := NewTab;
- fDisplaySnippetAction.Execute;
- end;
-end;
+//procedure TNotifier.DisplaySnippet(const SnippetName: WideString;
+// UserDefined: WordBool; NewTab: WordBool);
+//begin
+// if Assigned(fDisplaySnippetAction) then
+// begin
+// (fDisplaySnippetAction as TSnippetAction).SnippetName := SnippetName;
+// (fDisplaySnippetAction as TSnippetAction).UserDefined := UserDefined;
+// (fDisplaySnippetAction as TSnippetAction).NewTab := NewTab;
+// fDisplaySnippetAction.Execute;
+// end;
+//end;
procedure TNotifier.EditSnippet(const SnippetName: WideString);
begin
From b490893cf0739c70912f49f002e381247f95769a Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Wed, 30 Oct 2024 22:20:57 +0000
Subject: [PATCH 019/222] Add TCategory.CollectionID property
Reimplemented UserDefined property in terms of CollectionID property.
Used __TMP__ getter and setter methods to achieve this
Removed fUserDefined field.
Added overloaded constructor to take collection ID as a parameter. Left
original constructor in place that takes UserDefined parameter.
Old code was commented out.
---
Src/DB.UCategory.pas | 64 ++++++++++++++++++++++++++++++++++++++++----
1 file changed, 59 insertions(+), 5 deletions(-)
diff --git a/Src/DB.UCategory.pas b/Src/DB.UCategory.pas
index c5860d3c0..8a5741e85 100644
--- a/Src/DB.UCategory.pas
+++ b/Src/DB.UCategory.pas
@@ -20,6 +20,7 @@ interface
// Delphi
Generics.Collections,
// Project
+ DB.UCollections,
DB.USnippet;
@@ -51,7 +52,12 @@ TCategory = class(TObject)
fSnippets: TSnippetList; // List of snippet objects in category
fID: string; // Category id
fDescription: string; // Category description
- fUserDefined: Boolean; // Whether this is a user-defined snippet
+// fUserDefined: Boolean; // Whether this is a user-defined snippet
+ fCollectionID: TCollectionID;
+
+ function __TMP__GetUserDefined: Boolean;
+ procedure __TMP__SetUserDefined(const AValue: Boolean);
+ procedure SetCollectionID(const AValue: TCollectionID);
function CompareIDTo(const Cat: TCategory): Integer;
{Compares this category's ID to that of a given category. The check is not
case sensitive.
@@ -60,8 +66,20 @@ TCategory = class(TObject)
are equal or +1 if this category's ID is greater than Cat's.
}
public
- constructor Create(const CatID: string; const UserDefined: Boolean;
+ /// Object constructor. Sets up category object with given
+ /// property values.
+ /// CatID [in] Category ID.
+ /// TCollectionID [in] ID of collection
+ /// that defines this category. ID must not be null.
+ /// TCategoryData [in] category properties.
+ ///
+ constructor Create(const CatID: string; const ACollectionID: TCollectionID;
const Data: TCategoryData);
+ overload; {TODO -cCollections: remove overload }
+
+ constructor Create(const CatID: string; const UserDefined: Boolean;
+ const Data: TCategoryData); overload;
+ {TODO -cCollections: remove this constructor}
{Class contructor. Sets up category object with given property values.
@param Data [in] Contains required property values.
}
@@ -93,8 +111,14 @@ TCategory = class(TObject)
{Description of category}
property Snippets: TSnippetList read fSnippets;
{List of snippets in this category}
- property UserDefined: Boolean read fUserDefined;
+// property UserDefined: Boolean read fUserDefined;
+ property UserDefined: Boolean
+ read __TMP__GetUserDefined write __TMP__SetUserDefined;
{Flag that indicates if this is a user defined category}
+ /// ID of collection that defines this category.
+ /// ID must not be null.
+ property CollectionID: TCollectionID
+ read fCollectionID write SetCollectionID;
end;
{
@@ -194,7 +218,7 @@ function TCategory.CanDelete: Boolean;
@return True if deletion allowed, False if not.
}
begin
- Result := fUserDefined and fSnippets.IsEmpty
+ Result := __TMP__GetUserDefined and fSnippets.IsEmpty
and not TReservedCategories.IsReserved(Self);
end;
@@ -224,6 +248,19 @@ function TCategory.CompareIDTo(const Cat: TCategory): Integer;
Result := StrCompareText(Self.ID, Cat.ID);
end;
+constructor TCategory.Create(const CatID: string;
+ const ACollectionID: TCollectionID; const Data: TCategoryData);
+begin
+ Assert(ClassType <> TCategory,
+ ClassName + '.Create: must only be called from descendants.');
+ inherited Create;
+ fID := CatID;
+ fDescription := Data.Desc;
+ SetCollectionID(ACollectionID);
+ // Create list to store snippets in category
+ fSnippets := TSnippetListEx.Create;
+end;
+
constructor TCategory.Create(const CatID: string; const UserDefined: Boolean;
const Data: TCategoryData);
{Class contructor. Sets up category object with given property values.
@@ -235,7 +272,8 @@ constructor TCategory.Create(const CatID: string; const UserDefined: Boolean;
inherited Create;
fID := CatID;
fDescription := Data.Desc;
- fUserDefined := UserDefined;
+// fUserDefined := UserDefined;
+ __TMP__SetUserDefined(UserDefined); // sets CollectionID property
// Create list to store snippets in category
fSnippets := TSnippetListEx.Create;
end;
@@ -258,6 +296,22 @@ function TCategory.IsEqual(const Cat: TCategory): Boolean;
Result := CompareIDTo(Cat) = 0;
end;
+procedure TCategory.SetCollectionID(const AValue: TCollectionID);
+begin
+ Assert(not AValue.IsNull, ClassName + '.SetCollectionID: Value is null');
+ fCollectionID := AValue;
+end;
+
+function TCategory.__TMP__GetUserDefined: Boolean;
+begin
+ Result := fCollectionID <> TCollectionID.__TMP__MainDBCollectionID;
+end;
+
+procedure TCategory.__TMP__SetUserDefined(const AValue: Boolean);
+begin
+ fCollectionID := TCollectionID.__TMP__DBCollectionID(AValue);
+end;
+
{ TCategoryEx }
function TCategoryEx.GetEditData: TCategoryData;
From 42a49d3f99b2fe8dced73185a7a7e4ead1273d2f Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 2 Nov 2024 08:29:42 +0000
Subject: [PATCH 020/222] Remove TCategory's Boolean ctor overload
The Boolean constructor took a UserDefined parameter.
Modified TDatabase.InternalAddCategory and
TDBDataItemFactory.CreateCategory in DB.UMain to call the remaining
TCategory constructor that takes a TCollectionID parameter.
__TMP__ methods were required to achieve changes to DB.UMain.
Removed code was commented out.
---
Src/DB.UCategory.pas | 45 ++++++++++++++++++++++----------------------
Src/DB.UMain.pas | 12 +++++++++---
2 files changed, 31 insertions(+), 26 deletions(-)
diff --git a/Src/DB.UCategory.pas b/Src/DB.UCategory.pas
index 8a5741e85..663ad6da9 100644
--- a/Src/DB.UCategory.pas
+++ b/Src/DB.UCategory.pas
@@ -75,14 +75,13 @@ TCategory = class(TObject)
///
constructor Create(const CatID: string; const ACollectionID: TCollectionID;
const Data: TCategoryData);
- overload; {TODO -cCollections: remove overload }
- constructor Create(const CatID: string; const UserDefined: Boolean;
- const Data: TCategoryData); overload;
- {TODO -cCollections: remove this constructor}
- {Class contructor. Sets up category object with given property values.
- @param Data [in] Contains required property values.
- }
+// constructor Create(const CatID: string; const UserDefined: Boolean;
+// const Data: TCategoryData); overload;
+// {Class contructor. Sets up category object with given property values.
+// @param Data [in] Contains required property values.
+// }
+
destructor Destroy; override;
{Destructor. Tears down object.
}
@@ -261,22 +260,22 @@ constructor TCategory.Create(const CatID: string;
fSnippets := TSnippetListEx.Create;
end;
-constructor TCategory.Create(const CatID: string; const UserDefined: Boolean;
- const Data: TCategoryData);
- {Class contructor. Sets up category object with given property values.
- @param Data [in] Contains required property values.
- }
-begin
- Assert(ClassType <> TCategory,
- ClassName + '.Create: must only be called from descendants.');
- inherited Create;
- fID := CatID;
- fDescription := Data.Desc;
-// fUserDefined := UserDefined;
- __TMP__SetUserDefined(UserDefined); // sets CollectionID property
- // Create list to store snippets in category
- fSnippets := TSnippetListEx.Create;
-end;
+//constructor TCategory.Create(const CatID: string; const UserDefined: Boolean;
+// const Data: TCategoryData);
+// {Class contructor. Sets up category object with given property values.
+// @param Data [in] Contains required property values.
+// }
+//begin
+// Assert(ClassType <> TCategory,
+// ClassName + '.Create: must only be called from descendants.');
+// inherited Create;
+// fID := CatID;
+// fDescription := Data.Desc;
+//// fUserDefined := UserDefined;
+// __TMP__SetUserDefined(UserDefined); // sets CollectionID property
+// // Create list to store snippets in category
+// fSnippets := TSnippetListEx.Create;
+//end;
destructor TCategory.Destroy;
{Destructor. Tears down object.
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index 6b61183e1..f8bdb3a74 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -272,7 +272,12 @@ implementation
// Delphi
SysUtils, Generics.Defaults,
// Project
- DB.UDatabaseIO, IntfCommon, UExceptions, UQuery, UStrUtils;
+ DB.UCollections,
+ DB.UDatabaseIO,
+ IntfCommon,
+ UExceptions,
+ UQuery,
+ UStrUtils;
var
@@ -888,7 +893,8 @@ function TDatabase.InternalAddCategory(const CatID: string;
@return Reference to new category object.
}
begin
- Result := TCategoryEx.Create(CatID, True, Data);
+// Result := TCategoryEx.Create(CatID, True, Data);
+ Result := TCategoryEx.Create(CatID, TCollectionID.__TMP__DBCollectionID(True), Data);
fCategories.Add(Result);
end;
@@ -1152,7 +1158,7 @@ function TDBDataItemFactory.CreateCategory(const CatID: string;
@return Instance of new category object.
}
begin
- Result := TCategoryEx.Create(CatID, UserDefined, Data);
+ Result := TCategoryEx.Create(CatID, TCollectionID.__TMP__DBCollectionID(UserDefined), Data);
end;
function TDBDataItemFactory.CreateSnippet(const Name: string;
From 2c53e74887c4e68969806f919332a0c4e3170f72 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 2 Nov 2024 09:36:29 +0000
Subject: [PATCH 021/222] Remove TCategory.UserDefined property
Changed all units affected by the change to perform tests on
TCategory.CollectionID instead of checking UserDefined.
Used __TMP__ method calls to make these changes.
All removed code was commented out.
---
Src/DB.UCategory.pas | 25 ++++++-------------------
Src/DB.UMain.pas | 4 +++-
Src/FrSelectSnippetsBase.pas | 16 ++++++++++++----
Src/FrSelectUserSnippets.pas | 3 ++-
Src/UDetailPageHTML.pas | 3 ++-
Src/URTFCategoryDoc.pas | 5 +++--
Src/UUserDBMgr.pas | 5 +++--
7 files changed, 31 insertions(+), 30 deletions(-)
diff --git a/Src/DB.UCategory.pas b/Src/DB.UCategory.pas
index 663ad6da9..6aeeb9f8f 100644
--- a/Src/DB.UCategory.pas
+++ b/Src/DB.UCategory.pas
@@ -54,9 +54,6 @@ TCategory = class(TObject)
fDescription: string; // Category description
// fUserDefined: Boolean; // Whether this is a user-defined snippet
fCollectionID: TCollectionID;
-
- function __TMP__GetUserDefined: Boolean;
- procedure __TMP__SetUserDefined(const AValue: Boolean);
procedure SetCollectionID(const AValue: TCollectionID);
function CompareIDTo(const Cat: TCategory): Integer;
{Compares this category's ID to that of a given category. The check is not
@@ -111,9 +108,7 @@ TCategory = class(TObject)
property Snippets: TSnippetList read fSnippets;
{List of snippets in this category}
// property UserDefined: Boolean read fUserDefined;
- property UserDefined: Boolean
- read __TMP__GetUserDefined write __TMP__SetUserDefined;
- {Flag that indicates if this is a user defined category}
+// {Flag that indicates if this is a user defined category}
/// ID of collection that defines this category.
/// ID must not be null.
property CollectionID: TCollectionID
@@ -217,7 +212,10 @@ function TCategory.CanDelete: Boolean;
@return True if deletion allowed, False if not.
}
begin
- Result := __TMP__GetUserDefined and fSnippets.IsEmpty
+// Result := fUserDefined and fSnippets.IsEmpty
+// and not TReservedCategories.IsReserved(Self);
+ Result := (fCollectionID <> TCollectionID.__TMP__MainDBCollectionID)
+ and fSnippets.IsEmpty
and not TReservedCategories.IsReserved(Self);
end;
@@ -271,8 +269,7 @@ constructor TCategory.Create(const CatID: string;
// inherited Create;
// fID := CatID;
// fDescription := Data.Desc;
-//// fUserDefined := UserDefined;
-// __TMP__SetUserDefined(UserDefined); // sets CollectionID property
+// fUserDefined := UserDefined;
// // Create list to store snippets in category
// fSnippets := TSnippetListEx.Create;
//end;
@@ -301,16 +298,6 @@ procedure TCategory.SetCollectionID(const AValue: TCollectionID);
fCollectionID := AValue;
end;
-function TCategory.__TMP__GetUserDefined: Boolean;
-begin
- Result := fCollectionID <> TCollectionID.__TMP__MainDBCollectionID;
-end;
-
-procedure TCategory.__TMP__SetUserDefined(const AValue: Boolean);
-begin
- fCollectionID := TCollectionID.__TMP__DBCollectionID(AValue);
-end;
-
{ TCategoryEx }
function TCategoryEx.GetEditData: TCategoryData;
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index f8bdb3a74..03c6f433d 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -818,7 +818,9 @@ function TDatabase.GetEditableCategoryInfo(
@return Required data.
}
begin
- Assert(not Assigned(Category) or Category.UserDefined,
+// Assert(not Assigned(Category) or Category.UserDefined,
+// ClassName + '.GetEditableCategoryInfo: Category is not user-defined');
+ Assert(not Assigned(Category) or (Category.CollectionID <> TCollectionID.__TMP__MainDBCollectionID),
ClassName + '.GetEditableCategoryInfo: Category is not user-defined');
if Assigned(Category) then
Result := (Category as TCategoryEx).GetEditData
diff --git a/Src/FrSelectSnippetsBase.pas b/Src/FrSelectSnippetsBase.pas
index 4952a2ace..3074cf0d1 100644
--- a/Src/FrSelectSnippetsBase.pas
+++ b/Src/FrSelectSnippetsBase.pas
@@ -42,6 +42,9 @@ TSelectSnippetsBaseFrame = class(TCheckedTVFrame)
}
TTVDraw = class(TSnippetsTVDraw)
strict protected
+ {TODO -cCollections: Need to change following method in base class to
+ get collection ID and calling code then needs to take action based
+ on that instead of user-defined.}
function IsUserDefinedNode(const Node: TTreeNode): Boolean; override;
{Checks if a node represents a user defined snippets object.
@param Node [in] Node to be checked.
@@ -118,9 +121,12 @@ implementation
uses
// Delphi
- SysUtils, StdCtrls,
+ SysUtils,
+ StdCtrls,
// Project
- DB.UMain, UGroups;
+ DB.UCollections,
+ DB.UMain,
+ UGroups;
{$R *.dfm}
@@ -283,9 +289,11 @@ function TSelectSnippetsBaseFrame.TTVDraw.IsUserDefinedNode(
SnipObj := TObject(Node.Data);
Result := False;
if SnipObj is TSnippet then
- Result := (SnipObj as TSnippet).UserDefined
+// Result := (SnipObj as TSnippet).UserDefined
+ Result := (SnipObj as TSnippet).CollectionID <> TCollectionID.__TMP__MainDBCollectionID
else if SnipObj is TCategory then
- Result := (SnipObj as TCategory).UserDefined;
+// Result := (SnipObj as TCategory).UserDefined;
+ Result := (SnipObj as TCategory).CollectionID <> TCollectionID.__TMP__MainDBCollectionID;
end;
end.
diff --git a/Src/FrSelectUserSnippets.pas b/Src/FrSelectUserSnippets.pas
index 54177bbac..69ca8307e 100644
--- a/Src/FrSelectUserSnippets.pas
+++ b/Src/FrSelectUserSnippets.pas
@@ -79,7 +79,8 @@ function TSelectUserSnippetsFrame.CanAddSnippetNode(
@return True if snippet is user-defined.
}
begin
- Result := Snippet.UserDefined;
+// Result := Snippet.UserDefined;
+ Result := Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID;
end;
end.
diff --git a/Src/UDetailPageHTML.pas b/Src/UDetailPageHTML.pas
index 9b50c4680..d8149bae2 100644
--- a/Src/UDetailPageHTML.pas
+++ b/Src/UDetailPageHTML.pas
@@ -669,7 +669,8 @@ function TCategoryPageHTML.GetEmptyListNote: string;
function TCategoryPageHTML.GetH1ClassName: string;
begin
- if (View as ICategoryView).Category.UserDefined then
+// if (View as ICategoryView).Category.UserDefined then
+ if (View as ICategoryView).Category.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
Result := 'userdb'
else
Result := inherited GetH1ClassName;
diff --git a/Src/URTFCategoryDoc.pas b/Src/URTFCategoryDoc.pas
index c867c603a..e4d193f5e 100644
--- a/Src/URTFCategoryDoc.pas
+++ b/Src/URTFCategoryDoc.pas
@@ -90,7 +90,7 @@ implementation
uses
// Project
- ActiveText.UMain, UColours, UPreferences;
+ ActiveText.UMain, DB.UCollections, UColours, UPreferences;
{ TRTFCategoryDoc }
@@ -214,7 +214,8 @@ procedure TRTFCategoryDoc.OutputCategoryHeading(const Category: TCategory);
fBuilder.SetFont(MainFontName);
fBuilder.SetFontSize(HeadingFontSize);
fBuilder.SetFontStyle([fsBold]);
- SetColour(Preferences.DBHeadingColours[Category.UserDefined]);
+// SetColour(Preferences.DBHeadingColours[Category.UserDefined]);
+ SetColour(Preferences.DBHeadingColours[Category.CollectionID <> TCollectionID.__TMP__MainDBCollectionID]);
fBuilder.AddText(Category.Description);
fBuilder.EndPara;
fBuilder.EndGroup;
diff --git a/Src/UUserDBMgr.pas b/Src/UUserDBMgr.pas
index 48ce2ecd8..758d4af90 100644
--- a/Src/UUserDBMgr.pas
+++ b/Src/UUserDBMgr.pas
@@ -108,7 +108,7 @@ implementation
// Delphi
SysUtils, Dialogs, Windows {for inlining}, IOUtils,
// Project
- DB.UMain, DB.USnippet,
+ DB.UCollections, DB.UMain, DB.USnippet,
FmAddCategoryDlg, FmDeleteCategoryDlg, FmDuplicateSnippetDlg,
FmRenameCategoryDlg, FmSnippetsEditorDlg,
{$IFNDEF PORTABLE}
@@ -362,7 +362,8 @@ class function TUserDBMgr.CreateUserCatList(
begin
Result := TCategoryList.Create;
for Cat in Database.Categories do
- if Cat.UserDefined and
+// if Cat.UserDefined and
+ if (Cat.CollectionID <> TCollectionID.__TMP__MainDBCollectionID) and
(IncludeSpecial or not TReservedCategories.IsReserved(Cat)) then
Result.Add(Cat);
end;
From 2a6c6d5b07612b2f4e5b6ee000a47477f9565c14 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 3 Nov 2024 00:20:18 +0000
Subject: [PATCH 022/222] Remove TSnippet.UserDefined property
Updated all affected units by changing references to
TSnippet.UserDefined to checks on TSnippet.CollectionID.
Required many __TMP__ method calls to achieve this.
Removed redundant TODO from USnippetIDs unit.
Removed code was commented out.
---
Src/DB.UMain.pas | 19 ++++++++++++++-----
Src/DB.USnippet.pas | 8 --------
Src/FmCodeExportDlg.pas | 4 +++-
Src/FmDependenciesDlg.pas | 17 +++++++++++++----
Src/FmDuplicateSnippetDlg.pas | 4 +++-
Src/FmFindXRefsDlg.pas | 13 ++++++++++---
Src/FmSelectionSearchDlg.pas | 3 ++-
Src/FmSnippetsEditorDlg.pas | 3 ++-
Src/FmTestCompileDlg.pas | 14 +++++++++++---
Src/UCodeShareMgr.pas | 3 ++-
Src/UDetailPageHTML.pas | 12 ++++++++----
Src/URTFCategoryDoc.pas | 3 ++-
Src/USaveUnitMgr.pas | 4 +++-
Src/USnippetIDs.pas | 2 --
Src/USnippetSourceGen.pas | 7 +++++--
Src/USnippetsChkListMgr.pas | 11 ++++++++---
Src/UUserDBMgr.pas | 7 +++++--
17 files changed, 91 insertions(+), 43 deletions(-)
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index 03c6f433d..e77457457 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -666,8 +666,10 @@ function TDatabase.CreateTempSnippet(const Snippet: TSnippet): TSnippet;
Assert(Snippet is TSnippetEx,
ClassName + '.CreateTempSnippet: Snippet is a TSnippetEx');
Data := (Snippet as TSnippetEx).GetEditData;
+// Result := TTempSnippet.Create(
+// Snippet.Name, Snippet.UserDefined, (Snippet as TSnippetEx).GetProps);
Result := TTempSnippet.Create(
- Snippet.Name, Snippet.UserDefined, (Snippet as TSnippetEx).GetProps);
+ Snippet.Name, Snippet.CollectionID, (Snippet as TSnippetEx).GetProps);
(Result as TTempSnippet).UpdateRefs(
(Snippet as TSnippetEx).GetReferences, fSnippets
);
@@ -718,7 +720,9 @@ procedure TDatabase.DeleteSnippet(const Snippet: TSnippet);
Referrer: TSnippet; // loops thru snippets that cross references Snippet
Referrers: TSnippetList; // list of referencing snippets
begin
- Assert(Snippet.UserDefined,
+// Assert(Snippet.UserDefined,
+// ClassName + '.DeleteSnippet: Snippet is not user-defined');
+ Assert(Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID,
ClassName + '.DeleteSnippet: Snippet is not user-defined');
Assert(fSnippets.Contains(Snippet),
ClassName + '.DeleteSnippet: Snippet is not in the database');
@@ -837,8 +841,10 @@ function TDatabase.GetEditableSnippetInfo(
@return Required data.
}
begin
- Assert(not Assigned(Snippet) or Snippet.UserDefined,
+ Assert(not Assigned(Snippet) or (Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID),
ClassName + '.GetEditableSnippetInfo: Snippet is not user-defined');
+// Assert(not Assigned(Snippet) or Snippet.UserDefined,
+// ClassName + '.GetEditableSnippetInfo: Snippet is not user-defined');
if Assigned(Snippet) then
Result := (Snippet as TSnippetEx).GetEditData
else
@@ -1072,8 +1078,10 @@ function TDatabase.UpdateSnippet(const Snippet: TSnippet;
+ '%1:s already exists in user database';
begin
Result := Snippet; // keeps compiler happy
- Assert(Snippet.UserDefined,
+ Assert(Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID,
ClassName + '.UpdateSnippet: Snippet is not user-defined');
+// Assert(Snippet.UserDefined,
+// ClassName + '.UpdateSnippet: Snippet is not user-defined');
Referrers := nil;
Dependents := nil;
TriggerEvent(evChangeBegin);
@@ -1211,7 +1219,8 @@ function TUserDataProvider.GetCategorySnippets(
begin
Result := TIStringList.Create;
for Snippet in Cat.Snippets do
- if Snippet.UserDefined then
+// if Snippet.UserDefined then
+ if Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
Result.Add(Snippet.Name);
end;
diff --git a/Src/DB.USnippet.pas b/Src/DB.USnippet.pas
index e47226230..ad6cbfa3a 100644
--- a/Src/DB.USnippet.pas
+++ b/Src/DB.USnippet.pas
@@ -138,7 +138,6 @@ type TDisplayNameComparer = class(TComparer)
{Gets snippet's display name, or name if no display name is set
@return Required display name.
}
- function __TMP__GetUserDefined: Boolean;
strict protected
procedure SetName(const Name: string);
{Sets Name property.
@@ -214,8 +213,6 @@ type TDisplayNameComparer = class(TComparer)
property XRef: TSnippetList read fXRef;
{List of cross referenced snippets in database}
// property UserDefined: Boolean read fUserDefined;;
- property UserDefined: Boolean read __TMP__GetUserDefined;
- {TODO -cCollections: Remove above property & getter/setter}
{Flag that indicates if this is a user defined snippet}
property CollectionID: TCollectionID read fCollectionID;
end;
@@ -557,11 +554,6 @@ procedure TSnippet.SetProps(const Data: TSnippetData);
fTestInfo := Data.TestInfo;
end;
-function TSnippet.__TMP__GetUserDefined: Boolean;
-begin
- Result := fCollectionID = TCollectionID.__TMP__UserDBCollectionID;
-end;
-
{ TSnippet.TDisplayNameComparer }
function TSnippet.TDisplayNameComparer.Compare(const Left,
diff --git a/Src/FmCodeExportDlg.pas b/Src/FmCodeExportDlg.pas
index 39cfdae8e..48ffc385f 100644
--- a/Src/FmCodeExportDlg.pas
+++ b/Src/FmCodeExportDlg.pas
@@ -72,6 +72,7 @@ implementation
// Delphi
SysUtils, Dialogs,
// Project
+ DB.UCollections,
UCodeImportExport, UCtrlArranger, UEncodings, UExceptions, UIOUtils,
UMessageBox, UOpenDialogHelper, USaveDialogEx, UStrUtils, UUtils;
@@ -209,7 +210,8 @@ procedure TCodeExportDlg.SelectSnippet(const Snippet: TSnippet);
var
List: TSnippetList; // list containing only the provided snippet
begin
- if not Assigned(Snippet) or not Snippet.UserDefined then
+ if not Assigned(Snippet) or (Snippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID) then
+// if not Assigned(Snippet) or not Snippet.UserDefined then
// Snippet is nil or not user-defined: select nothing
frmSnippets.SelectedSnippets := nil
else
diff --git a/Src/FmDependenciesDlg.pas b/Src/FmDependenciesDlg.pas
index e1705a01e..ddc25ee40 100644
--- a/Src/FmDependenciesDlg.pas
+++ b/Src/FmDependenciesDlg.pas
@@ -158,9 +158,16 @@ implementation
uses
// Delphi
- SysUtils, Graphics,
+ SysUtils,
+ Graphics,
// Project
- DB.UMain, DB.USnippetKind, UBox, UColours, UCtrlArranger, UFontHelper,
+ DB.UCollections,
+ DB.UMain,
+ DB.USnippetKind,
+ UBox,
+ UColours,
+ UCtrlArranger,
+ UFontHelper,
UPreferences;
{$R *.dfm}
@@ -444,7 +451,8 @@ procedure TDependenciesDlg.PopulateRequiredByList;
Assert(Assigned(ASnippet),
ClassName + '.PopulateRequiredByList: Snippet id not found');
lbDependents.Items.AddObject(
- ASnippet.DisplayName, TBox.Create(ASnippet.UserDefined)
+ ASnippet.DisplayName, TBox.Create(ASnippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID)
+// ASnippet.DisplayName, TBox.Create(ASnippet.UserDefined)
);
end;
end;
@@ -514,7 +522,8 @@ function TDependenciesDlg.TTVDraw.IsUserDefinedNode(
if not Assigned(Node.Data) then
Result := True
else
- Result := TSnippet(Node.Data).UserDefined;
+// Result := TSnippet(Node.Data).UserDefined;
+ Result := TSnippet(Node.Data).CollectionID <> TCollectionID.__TMP__MainDBCollectionID;
end;
end.
diff --git a/Src/FmDuplicateSnippetDlg.pas b/Src/FmDuplicateSnippetDlg.pas
index 4c207e683..423c4d7e9 100644
--- a/Src/FmDuplicateSnippetDlg.pas
+++ b/Src/FmDuplicateSnippetDlg.pas
@@ -77,6 +77,7 @@ implementation
// Delphi
Math,
// Project
+ DB.UCollections,
DB.UCategory, DB.UMain, UCtrlArranger, UExceptions, UMessageBox, USettings,
USnippetValidator, UStructs, UStrUtils, UUserDBMgr;
@@ -131,7 +132,8 @@ function TDuplicateSnippetDlg.DisallowedNames: IStringList;
Result := TIStringList.Create;
Result.CaseSensitive := False;
for Snippet in Database.Snippets do
- if Snippet.UserDefined then
+// if Snippet.UserDefined then
+ if Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
Result.Add(Snippet.Name);
end;
diff --git a/Src/FmFindXRefsDlg.pas b/Src/FmFindXRefsDlg.pas
index 0d301ef98..45e280e72 100644
--- a/Src/FmFindXRefsDlg.pas
+++ b/Src/FmFindXRefsDlg.pas
@@ -127,9 +127,15 @@ implementation
uses
// Delphi
- SysUtils, Graphics,
+ SysUtils,
+ Graphics,
// Project
- UColours, UCtrlArranger, UPreferences, UQuery, USettings;
+ DB.UCollections,
+ UColours,
+ UCtrlArranger,
+ UPreferences,
+ UQuery,
+ USettings;
{$R *.dfm}
@@ -229,7 +235,8 @@ procedure TFindXRefsDlg.ConfigForm;
// Set label font styles and colours
lblSnippetName.Font.Style := [fsBold];
lblSnippetName.Font.Color :=
- Preferences.DBHeadingColours[fSnippet.UserDefined];
+// Preferences.DBHeadingColours[fSnippet.UserDefined];
+ Preferences.DBHeadingColours[fSnippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID];
// Display selected snippet name in appropriate controls
lblSnippetName.Caption := fSnippet.DisplayName;
chkIncludeSnippet.Caption := Format(
diff --git a/Src/FmSelectionSearchDlg.pas b/Src/FmSelectionSearchDlg.pas
index 3aeaed97f..bf0914b39 100644
--- a/Src/FmSelectionSearchDlg.pas
+++ b/Src/FmSelectionSearchDlg.pas
@@ -246,7 +246,8 @@ procedure TSelectionSearchDlg.SelectDB(const UserDefined: Boolean);
SnippetList := TSnippetList.Create;
try
for Snippet in Database.Snippets do
- if Snippet.UserDefined = UserDefined then
+// if Snippet.UserDefined = UserDefined then
+ if Snippet.CollectionID = TCollectionID.__TMP__DBCollectionID(UserDefined) then
SnippetList.Add(Snippet);
frmSelect.SelectedSnippets := SnippetList;
finally
diff --git a/Src/FmSnippetsEditorDlg.pas b/Src/FmSnippetsEditorDlg.pas
index 0e642a4a9..d8222f235 100644
--- a/Src/FmSnippetsEditorDlg.pas
+++ b/Src/FmSnippetsEditorDlg.pas
@@ -989,7 +989,8 @@ procedure TSnippetsEditorDlg.UpdateReferences;
// a user-defined one with same name
if (Snippet.ID <> EditSnippetID) and
(
- Snippet.UserDefined or
+// Snippet.UserDefined or
+ (Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID) or
not Assigned(Database.Snippets.Find(Snippet.Name, True))
) then
begin
diff --git a/Src/FmTestCompileDlg.pas b/Src/FmTestCompileDlg.pas
index 5066e2bff..0ed1ba053 100644
--- a/Src/FmTestCompileDlg.pas
+++ b/Src/FmTestCompileDlg.pas
@@ -155,9 +155,16 @@ implementation
uses
// Delphi
- Math, Windows, Graphics, Types {for inlining},
+ Math,
+ Windows,
+ Graphics,
+ Types {for inlining},
// Project
- UColours, UCtrlArranger, UFontHelper, UPreferences;
+ DB.UCollections,
+ UColours,
+ UCtrlArranger,
+ UFontHelper,
+ UPreferences;
{$R *.dfm}
@@ -282,7 +289,8 @@ procedure TTestCompileDlg.ConfigForm;
// Set required label fonts and captions
TFontHelper.SetDefaultBaseFont(lblSnippetName.Font);
lblSnippetName.Font.Color :=
- Preferences.DBHeadingColours[fSnippet.UserDefined];
+// Preferences.DBHeadingColours[fSnippet.UserDefined];
+ Preferences.DBHeadingColours[fSnippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID];
lblSnippetName.Caption := fSnippet.DisplayName;
end;
diff --git a/Src/UCodeShareMgr.pas b/Src/UCodeShareMgr.pas
index 099cdf34d..e510ef862 100644
--- a/Src/UCodeShareMgr.pas
+++ b/Src/UCodeShareMgr.pas
@@ -103,7 +103,8 @@ class function TCodeShareMgr.GetSnippetFromView(
SnippetView: ISnippetView; // ViewItem as snippet view if supported
begin
if Supports(ViewItem, ISnippetView, SnippetView)
- and (SnippetView.Snippet.UserDefined) then
+// and (SnippetView.Snippet.UserDefined) then
+ and (SnippetView.Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID) then
Result := SnippetView.Snippet
else
Result := nil;
diff --git a/Src/UDetailPageHTML.pas b/Src/UDetailPageHTML.pas
index d8149bae2..719ef7c11 100644
--- a/Src/UDetailPageHTML.pas
+++ b/Src/UDetailPageHTML.pas
@@ -528,15 +528,18 @@ procedure TSnippetInfoPageHTML.ResolvePlaceholders(const Tplt: THTMLTemplate);
'overflowXFixScript',
'window.onload = null;'
);
- if GetSnippet.UserDefined then
+// if GetSnippet.UserDefined then
+ if GetSnippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
Tplt.ResolvePlaceholderHTML('SnippetCSSClass', 'userdb')
else
Tplt.ResolvePlaceholderHTML('SnippetCSSClass', 'maindb');
Tplt.ResolvePlaceholderHTML(
- 'TestingInfo', TCSS.BlockDisplayProp(not GetSnippet.UserDefined)
+// 'TestingInfo', TCSS.BlockDisplayProp(not GetSnippet.UserDefined)
+ 'TestingInfo', TCSS.BlockDisplayProp(GetSnippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID)
);
Tplt.ResolvePlaceholderHTML(
- 'EditLink', TCSS.BlockDisplayProp(GetSnippet.UserDefined)
+// 'EditLink', TCSS.BlockDisplayProp(GetSnippet.UserDefined)
+ 'EditLink', TCSS.BlockDisplayProp(GetSnippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID)
);
Tplt.ResolvePlaceholderText(
'EditEventHandler',
@@ -544,7 +547,8 @@ procedure TSnippetInfoPageHTML.ResolvePlaceholders(const Tplt: THTMLTemplate);
);
SnippetHTML := TSnippetHTML.Create(GetSnippet);
try
- if not GetSnippet.UserDefined then
+// if not GetSnippet.UserDefined then
+ if GetSnippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID then
Tplt.ResolvePlaceholderHTML('TestingInfoImg', SnippetHTML.TestingImage);
Tplt.ResolvePlaceholderHTML('SnippetName', SnippetHTML.SnippetName);
finally
diff --git a/Src/URTFCategoryDoc.pas b/Src/URTFCategoryDoc.pas
index e4d193f5e..601f41ae0 100644
--- a/Src/URTFCategoryDoc.pas
+++ b/Src/URTFCategoryDoc.pas
@@ -228,7 +228,8 @@ procedure TRTFCategoryDoc.OutputSnippetSubHeading(const Snippet: TSnippet);
fBuilder.SetFont(MainFontName);
fBuilder.SetFontSize(SubHeadingFontSize);
fBuilder.SetFontStyle([fsBold]);
- SetColour(Preferences.DBHeadingColours[Snippet.UserDefined]);
+// SetColour(Preferences.DBHeadingColours[Snippet.UserDefined]);
+ SetColour(Preferences.DBHeadingColours[Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID]);
fBuilder.AddText(Snippet.DisplayName);
fBuilder.EndPara;
fBuilder.EndGroup;
diff --git a/Src/USaveUnitMgr.pas b/Src/USaveUnitMgr.pas
index 1cd7841d3..6c4207812 100644
--- a/Src/USaveUnitMgr.pas
+++ b/Src/USaveUnitMgr.pas
@@ -96,6 +96,7 @@ implementation
// Delphi
SysUtils,
// Project
+ DB.UCollections,
DB.UMetaData,
UAppInfo,
UConsts,
@@ -262,7 +263,8 @@ constructor TSaveUnitMgr.InternalCreate(const Snips: TSnippetList);
fContainsMainDBSnippets := False;
for Snippet in Snips do
begin
- if not Snippet.UserDefined then
+// if not Snippet.UserDefined then
+ if Snippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID then
begin
fContainsMainDBSnippets := True;
Break;
diff --git a/Src/USnippetIDs.pas b/Src/USnippetIDs.pas
index 620472dcb..9619e6543 100644
--- a/Src/USnippetIDs.pas
+++ b/Src/USnippetIDs.pas
@@ -25,8 +25,6 @@ interface
type
- {TODO -cNote: TSnippetID.UserDefined is now uses CollectionID property.}
-
/// Record that uniquely identifies a code snippet. Specifies name
/// and flag indicating whether snippet is user-defined.
diff --git a/Src/USnippetSourceGen.pas b/Src/USnippetSourceGen.pas
index e7739df85..b6cf42688 100644
--- a/Src/USnippetSourceGen.pas
+++ b/Src/USnippetSourceGen.pas
@@ -87,6 +87,7 @@ implementation
// Delphi
SysUtils,
// Project
+ DB.UCollections,
DB.UMetaData,
DB.USnippet,
DB.USnippetKind,
@@ -243,7 +244,8 @@ procedure TSnippetSourceGen.Initialize(View: IView);
// view is single snippet: just record that
Snippet := (View as ISnippetView).Snippet;
fGenerator.IncludeSnippet(Snippet);
- fContainsMainDBSnippets := not Snippet.UserDefined;
+// fContainsMainDBSnippets := not Snippet.UserDefined;
+ fContainsMainDBSnippets := Snippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID;
end
else
begin
@@ -254,7 +256,8 @@ procedure TSnippetSourceGen.Initialize(View: IView);
fGenerator.IncludeSnippets(Snips); // ignores freeform snippets
for Snippet in Snips do
begin
- if not Snippet.UserDefined then
+// if not Snippet.UserDefined then
+ if Snippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID then
begin
fContainsMainDBSnippets := True;
Break;
diff --git a/Src/USnippetsChkListMgr.pas b/Src/USnippetsChkListMgr.pas
index 71e5c0561..f6e828052 100644
--- a/Src/USnippetsChkListMgr.pas
+++ b/Src/USnippetsChkListMgr.pas
@@ -100,9 +100,13 @@ implementation
uses
// Delphi
- Graphics, StdCtrls,
+ Graphics,
+ StdCtrls,
// Project
- UColours, UGraphicUtils, UPreferences;
+ DB.UCollections,
+ UColours,
+ UGraphicUtils,
+ UPreferences;
{ TSnippetsChkListMgr }
@@ -200,7 +204,8 @@ procedure TSnippetsChkListMgr.DrawItem(Control: TWinControl; Index: Integer;
Canvas := fCLB.Canvas;
if not (odSelected in State) then
Canvas.Font.Color := Preferences.DBHeadingColours[
- (fCLB.Items.Objects[Index] as TSnippet).UserDefined
+// (fCLB.Items.Objects[Index] as TSnippet).UserDefined
+ (fCLB.Items.Objects[Index] as TSnippet).CollectionID <> TCollectionID.__TMP__MainDBCollectionID
];
Canvas.TextRect(
Rect,
diff --git a/Src/UUserDBMgr.pas b/Src/UUserDBMgr.pas
index 758d4af90..489d751a6 100644
--- a/Src/UUserDBMgr.pas
+++ b/Src/UUserDBMgr.pas
@@ -294,7 +294,8 @@ class function TUserDBMgr.CanEdit(ViewItem: IView): Boolean;
Assert(Assigned(ViewItem), ClassName + '.CanEdit: ViewItem is nil');
Result := Assigned(ViewItem)
and Supports(ViewItem, ISnippetView, SnippetView)
- and SnippetView.Snippet.UserDefined;
+// and SnippetView.Snippet.UserDefined;
+ and (SnippetView.Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID);
end;
class procedure TUserDBMgr.CanOpenDialogClose(Sender: TObject;
@@ -424,7 +425,9 @@ class procedure TUserDBMgr.DeleteSnippet(ViewItem: IView);
Assert(Supports(ViewItem, ISnippetView),
ClassName + '.Delete: Current view is not a snippet');
Snippet := (ViewItem as ISnippetView).Snippet;
- Assert(Snippet.UserDefined,
+// Assert(Snippet.UserDefined,
+// ClassName + '.Delete: Snippet must be user defined');
+ Assert(Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID,
ClassName + '.Delete: Snippet must be user defined');
// Check if snippet has dependents: don't allow deletion if so
Dependents := (Database as IDatabaseEdit).GetDependents(Snippet);
From c2b4a27a12036d14c875a663da1aec962a23f6c0 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 3 Nov 2024 01:43:53 +0000
Subject: [PATCH 023/222] Remove public TSnippetList.Find Boolean overload
Updated all affected code to use TSnippetList.Find TCollectionID
overload.
Used __TMP__ method calls to achieve this.
All removed code was commented out.
---
Src/DB.UMain.pas | 6 +++--
Src/DB.USnippet.pas | 50 ++++++++++++++++++-------------------
Src/Favourites.UPersist.pas | 3 ++-
Src/FmSnippetsEditorDlg.pas | 3 ++-
Src/UCodeImportMgr.pas | 3 ++-
Src/USnippetAction.pas | 8 ++++--
Src/USnippetValidator.pas | 8 ++++--
Src/UUserDBMgr.pas | 3 ++-
8 files changed, 49 insertions(+), 35 deletions(-)
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index e77457457..4c08911b6 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -623,7 +623,8 @@ function TDatabase.AddSnippet(const SnippetName: string;
TriggerEvent(evChangeBegin);
try
// Check if snippet with same name exists in user database: error if so
- if fSnippets.Find(SnippetName, True) <> nil then
+// if fSnippets.Find(SnippetName, True) <> nil then
+ if fSnippets.Find(SnippetName, TCollectionID.__TMP__DBCollectionID(True)) <> nil then
raise ECodeSnip.CreateFmt(sNameExists, [SnippetName]);
Result := InternalAddSnippet(SnippetName, Data);
Query.Update;
@@ -1094,7 +1095,8 @@ function TDatabase.UpdateSnippet(const Snippet: TSnippet;
SnippetName := Snippet.Name;
// If name has changed then new name musn't exist in user database
if not StrSameText(SnippetName, Snippet.Name) then
- if fSnippets.Find(SnippetName, True) <> nil then
+// if fSnippets.Find(SnippetName, True) <> nil then
+ if fSnippets.Find(SnippetName, TCollectionID.__TMP__DBCollectionID(True)) <> nil then
raise ECodeSnip.CreateFmt(sCantRename, [Snippet.Name, SnippetName]);
// We update by deleting old snippet and inserting new one
// get lists of snippets that cross reference or depend on this snippet
diff --git a/Src/DB.USnippet.pas b/Src/DB.USnippet.pas
index ad6cbfa3a..abc058d98 100644
--- a/Src/DB.USnippet.pas
+++ b/Src/DB.USnippet.pas
@@ -325,14 +325,14 @@ TSnippetList = class(TObject)
@param SnippetID [in] ID of snippet to find.
@return Reference to required snippet or nil if not found.
}
- function Find(const SnippetName: string;
- const UserDefined: Boolean): TSnippet; overload;
- {Finds a named snippet in list with a matching user defined property.
- @param SnippetName [in] Name of required snippet.
- @param UserDefined [in] Flag that determines if we are looking for a
- user defined snippet or one from main database.
- @return Reference to required snippet or nil if not found.
- }
+// function Find(const SnippetName: string;
+// const UserDefined: Boolean): TSnippet; overload;
+// {Finds a named snippet in list with a matching user defined property.
+// @param SnippetName [in] Name of required snippet.
+// @param UserDefined [in] Flag that determines if we are looking for a
+// user defined snippet or one from main database.
+// @return Reference to required snippet or nil if not found.
+// }
/// Finds a snippet in the list with whose name and collection ID
/// match.
@@ -818,23 +818,23 @@ function TSnippetList.Find(const SnippetName: string;
end;
end;
-function TSnippetList.Find(const SnippetName: string;
- const UserDefined: Boolean): TSnippet;
- {Finds a named snippet in list with a matching user defined property.
- @param SnippetName [in] Name of required snippet.
- @param UserDefined [in] Flag that determines if we are looking for a
- user defined snippet or one from main database.
- @return Reference to required snippet or nil if not found.
- }
-var
- Idx: Integer; // index of snippet name in list
-begin
- if Find(SnippetName, TCollectionID.__TMP__DBCollectionID(UserDefined), Idx) then
-// if Find(SnippetName, UserDefined, Idx) then
- Result := Items[Idx]
- else
- Result := nil;
-end;
+//function TSnippetList.Find(const SnippetName: string;
+// const UserDefined: Boolean): TSnippet;
+// {Finds a named snippet in list with a matching user defined property.
+// @param SnippetName [in] Name of required snippet.
+// @param UserDefined [in] Flag that determines if we are looking for a
+// user defined snippet or one from main database.
+// @return Reference to required snippet or nil if not found.
+// }
+//var
+// Idx: Integer; // index of snippet name in list
+//begin
+// if Find(SnippetName, TCollectionID.__TMP__DBCollectionID(UserDefined), Idx) then
+//// if Find(SnippetName, UserDefined, Idx) then
+// Result := Items[Idx]
+// else
+// Result := nil;
+//end;
function TSnippetList.Find(const SnippetName: string;
const ACollectionID: TCollectionID): TSnippet;
diff --git a/Src/Favourites.UPersist.pas b/Src/Favourites.UPersist.pas
index d1aa43a0e..b444c5274 100644
--- a/Src/Favourites.UPersist.pas
+++ b/Src/Favourites.UPersist.pas
@@ -117,7 +117,8 @@ class procedure TFavouritesPersist.Load(Favourites: TFavourites);
if not TryStrToDateTime(Fields[2], LastAccess) then
raise EFavouritesPersist.Create(sBadFormat);
// only add to favourites if snippet in database
- if Database.Snippets.Find(SnippetName, UserDef) <> nil then
+// if Database.Snippets.Find(SnippetName, UserDef) <> nil then
+ if Database.Snippets.Find(SnippetName, TCollectionID.__TMP__DBCollectionID(UserDef)) <> nil then
// Favourites.Add(TSnippetID.Create(SnippetName, UserDef), LastAccess);
Favourites.Add(TSnippetID.Create(SnippetName, TCollectionID.__TMP__DBCollectionID(UserDef)), LastAccess);
end;
diff --git a/Src/FmSnippetsEditorDlg.pas b/Src/FmSnippetsEditorDlg.pas
index d8222f235..599699e0b 100644
--- a/Src/FmSnippetsEditorDlg.pas
+++ b/Src/FmSnippetsEditorDlg.pas
@@ -991,7 +991,8 @@ procedure TSnippetsEditorDlg.UpdateReferences;
(
// Snippet.UserDefined or
(Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID) or
- not Assigned(Database.Snippets.Find(Snippet.Name, True))
+// not Assigned(Database.Snippets.Find(Snippet.Name, True))
+ not Assigned(Database.Snippets.Find(Snippet.Name, TCollectionID.__TMP__DBCollectionID(True)))
) then
begin
// Decide if snippet can be added to depends list: must be correct kind
diff --git a/Src/UCodeImportMgr.pas b/Src/UCodeImportMgr.pas
index 7f21d1fee..1ec3e6651 100644
--- a/Src/UCodeImportMgr.pas
+++ b/Src/UCodeImportMgr.pas
@@ -287,7 +287,8 @@ procedure TCodeImportMgr.UpdateDatabase;
AdjustDependsList(SnippetInfo.Data.Refs.Depends);
- Snippet := Database.Snippets.Find(ImportInfo.ImportAsName, True);
+// Snippet := Database.Snippets.Find(ImportInfo.ImportAsName, True);
+ Snippet := Database.Snippets.Find(ImportInfo.ImportAsName, TCollectionID.__TMP__DBCollectionID(True));
if Assigned(Snippet) then
// snippet already exists: overwrite it
Editor.UpdateSnippet(Snippet, SnippetInfo.Data)
diff --git a/Src/USnippetAction.pas b/Src/USnippetAction.pas
index 6c0cf81fe..80927a77d 100644
--- a/Src/USnippetAction.pas
+++ b/Src/USnippetAction.pas
@@ -72,7 +72,10 @@ implementation
uses
// Project
- DB.UMain, DB.USnippet, UView;
+ DB.UCollections,
+ DB.UMain,
+ DB.USnippet,
+ UView;
{ TSnippetAction }
@@ -83,7 +86,8 @@ function TSnippetAction.Execute: Boolean;
begin
Assert(Assigned(fNotifier), ClassName + '.Execute: Notifier not set');
Assert(SnippetName <> '', ClassName + '.Execute: SnippetName not provided');
- Snippet := Database.Snippets.Find(SnippetName, UserDefined);
+// Snippet := Database.Snippets.Find(SnippetName, UserDefined);
+ Snippet := Database.Snippets.Find(SnippetName, TCollectionID.__TMP__DBCollectionID(UserDefined));
Assert(Assigned(Snippet), ClassName + '.Execute: SnippetName not valid');
// Create a view item for snippet and get notifier to display it
fNotifier.ShowViewItem(TViewFactory.CreateSnippetView(Snippet), NewTab);
diff --git a/Src/USnippetValidator.pas b/Src/USnippetValidator.pas
index 83de1adf3..23a21ae67 100644
--- a/Src/USnippetValidator.pas
+++ b/Src/USnippetValidator.pas
@@ -140,7 +140,10 @@ implementation
// Delphi
SysUtils,
// Project
- ActiveText.UValidator, DB.UMain, UStrUtils;
+ ActiveText.UValidator,
+ DB.UCollections,
+ DB.UMain,
+ UStrUtils;
{ TSnippetValidator }
@@ -370,7 +373,8 @@ class function TSnippetValidator.ValidateName(const Name: string;
else if not IsValidIdent(TrimmedName) then
ErrorMsg := Format(sErrBadName, [TrimmedName])
else if CheckForUniqueness and
- (Database.Snippets.Find(TrimmedName, True) <> nil) then
+// (Database.Snippets.Find(TrimmedName, True) <> nil) then
+ (Database.Snippets.Find(TrimmedName, TCollectionID.__TMP__DBCollectionID(True)) <> nil) then
ErrorMsg := Format(sErrDupName, [TrimmedName])
else
Result := True;
diff --git a/Src/UUserDBMgr.pas b/Src/UUserDBMgr.pas
index 489d751a6..8ab42253a 100644
--- a/Src/UUserDBMgr.pas
+++ b/Src/UUserDBMgr.pas
@@ -469,7 +469,8 @@ class procedure TUserDBMgr.EditSnippet(const SnippetName: string);
var
Snippet: TSnippet; // reference to snippet to be edited
begin
- Snippet := Database.Snippets.Find(SnippetName, True);
+// Snippet := Database.Snippets.Find(SnippetName, True);
+ Snippet := Database.Snippets.Find(SnippetName, TCollectionID.__TMP__DBCollectionID(True));
if not Assigned(Snippet) then
raise EBug.Create(ClassName + '.EditSnippet: Snippet not in user database');
TSnippetsEditorDlg.EditSnippet(nil, Snippet);
From 0b94722c73388cfc4230cf23e8f7b63298bff6b6 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 3 Nov 2024 15:00:23 +0000
Subject: [PATCH 024/222] Remove TSnippet's Boolean ctor overload
The Boolean constructor took a UserDefined parameter.
Modified TDatabase.CreateTempSnippet and TDatabase.InternalAddSnippet in
DB.UMain to call the remaining TSnippet constructor that takes a
TCollectionID parameter.
__TMP__ methods were required to achieve changes to DB.UMain.
Removed code was commented out.
---
Src/DB.UMain.pas | 6 ++++--
Src/DB.USnippet.pas | 35 +++++++++++++++++------------------
2 files changed, 21 insertions(+), 20 deletions(-)
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index 4c08911b6..4663c7dab 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -686,7 +686,8 @@ function TDatabase.CreateTempSnippet(const SnippetName: string;
@return Reference to new snippet.
}
begin
- Result := TTempSnippet.Create(SnippetName, True, Data.Props);
+// Result := TTempSnippet.Create(SnippetName, True, Data.Props);
+ Result := TTempSnippet.Create(SnippetName, TCollectionID.__TMP__UserDBCollectionID, Data.Props);
(Result as TTempSnippet).UpdateRefs(Data.Refs, fSnippets);
end;
@@ -923,7 +924,8 @@ function TDatabase.InternalAddSnippet(const SnippetName: string;
sCatNotFound = 'Category "%0:s" referenced by new snippet named "%1:s" does '
+ 'not exist';
begin
- Result := TSnippetEx.Create(SnippetName, True, Data.Props);
+// Result := TSnippetEx.Create(SnippetName, True, Data.Props);
+ Result := TSnippetEx.Create(SnippetName, TCollectionID.__TMP__UserDBCollectionID, Data.Props);
(Result as TSnippetEx).UpdateRefs(Data.Refs, fSnippets);
Cat := fCategories.Find(Result.Category);
if not Assigned(Cat) then
diff --git a/Src/DB.USnippet.pas b/Src/DB.USnippet.pas
index abc058d98..0eacce540 100644
--- a/Src/DB.USnippet.pas
+++ b/Src/DB.USnippet.pas
@@ -152,13 +152,13 @@ type TDisplayNameComparer = class(TComparer)
@return Required field content.
}
public
- constructor Create(const Name: string; const UserDefined: Boolean;
- const Props: TSnippetData); overload; {TODO -cCollections: remove constructor}
- {Class contructor. Sets up snippet object with given property values.
- @param Name [in] Name of snippet.
- @param UserDefined [in] Indicates if this is a user defined snippet.
- @param Props [in] Values of various snippet properties.
- }
+// constructor Create(const Name: string; const UserDefined: Boolean;
+// const Props: TSnippetData);
+// {Class contructor. Sets up snippet object with given property values.
+// @param Name [in] Name of snippet.
+// @param UserDefined [in] Indicates if this is a user defined snippet.
+// @param Props [in] Values of various snippet properties.
+// }
/// Object constructor. Sets up snippet object with given property
/// values belonging to a specified collection.
@@ -169,7 +169,6 @@ type TDisplayNameComparer = class(TComparer)
/// properties.
constructor Create(const Name: string; const ACollectionID: TCollectionID;
const Props: TSnippetData);
- overload; {TODO -cCollections: remove overload;}
destructor Destroy; override;
{Destructor. Tears down object.
@@ -456,16 +455,16 @@ function TSnippet.CanCompile: Boolean;
Result := Kind <> skFreeform;
end;
-constructor TSnippet.Create(const Name: string; const UserDefined: Boolean;
- const Props: TSnippetData);
- {Class contructor. Sets up snippet object with given property values.
- @param Name [in] Name of snippet.
- @param UserDefined [in] Indicates if this is a user defined snippet.
- @param Props [in] Values of various snippet properties.
- }
-begin
- Create(Name, TCollectionID.__TMP__DBCollectionID(UserDefined), Props);
-end;
+//constructor TSnippet.Create(const Name: string; const UserDefined: Boolean;
+// const Props: TSnippetData);
+// {Class contructor. Sets up snippet object with given property values.
+// @param Name [in] Name of snippet.
+// @param UserDefined [in] Indicates if this is a user defined snippet.
+// @param Props [in] Values of various snippet properties.
+// }
+//begin
+// Create(Name, TCollectionID.__TMP__DBCollectionID(UserDefined), Props);
+//end;
constructor TSnippet.Create(const Name: string;
const ACollectionID: TCollectionID; const Props: TSnippetData);
From 5e21e4e6789d6915a7f228abe9ce467eea9a7130 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 3 Nov 2024 02:09:41 +0000
Subject: [PATCH 025/222] Replace TSnippetAction.UserDefined with CollectionID
Added CollectionID property to TSnippetAction.
Removed TSnippetAction.UserDefined property & modified code to use
CollectionID instead.
This enabled a __TMP__ method call to be removed.
Removed code was commented out.
---
Src/UNotifier.pas | 3 +--
Src/USnippetAction.pas | 19 ++++++++++++-------
2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/Src/UNotifier.pas b/Src/UNotifier.pas
index c0dcd22fa..913593762 100644
--- a/Src/UNotifier.pas
+++ b/Src/UNotifier.pas
@@ -271,8 +271,7 @@ procedure TNotifier.DisplaySnippet(const SnippetName: WideString;
if Assigned(fDisplaySnippetAction) then
begin
(fDisplaySnippetAction as TSnippetAction).SnippetName := SnippetName;
- (fDisplaySnippetAction as TSnippetAction).UserDefined :=
- ACollectionID <> TCollectionID.__TMP__MainDBCollectionID;
+ (fDisplaySnippetAction as TSnippetAction).CollectionID := ACollectionID;
(fDisplaySnippetAction as TSnippetAction).NewTab := NewTab;
fDisplaySnippetAction.Execute;
end;
diff --git a/Src/USnippetAction.pas b/Src/USnippetAction.pas
index 80927a77d..9030c671b 100644
--- a/Src/USnippetAction.pas
+++ b/Src/USnippetAction.pas
@@ -19,6 +19,7 @@ interface
// Delphi
Classes,
// Project
+ DB.UCollections,
IntfNotifier;
@@ -36,8 +37,10 @@ TSnippetAction = class(TBasicAction, ISetNotifier)
var
/// Value of SnippetName property.
fSnippetName: string;
- /// Value of UserDefined property.
- fUserDefined: Boolean;
+// /// Value of UserDefined property.
+// fUserDefined: Boolean;
+ /// Value of CollectionID property.
+ fCollectionID: TCollectionID;
/// Value of NewTab property.
fNewTab: Boolean;
/// Reference to Notifier object.
@@ -58,9 +61,12 @@ TSnippetAction = class(TBasicAction, ISetNotifier)
procedure SetNotifier(const Notifier: INotifier);
/// Name of snippet to be displayed.
property SnippetName: string read fSnippetName write fSnippetName;
- /// Flag indicating whether snippet to be displayed is user
- /// defined.
- property UserDefined: Boolean read fUserDefined write fUserDefined;
+// /// Flag indicating whether snippet to be displayed is user
+// /// defined.
+// property UserDefined: Boolean read fUserDefined write fUserDefined;
+ /// ID of the collection containing the snippet to be displayed.
+ ///
+ property CollectionID: TCollectionID read fCollectionID write fCollectionID;
/// Flag indicating if snippet is to be displayed in new detail
/// pane tab.
property NewTab: Boolean read fNewTab write fNewTab;
@@ -72,7 +78,6 @@ implementation
uses
// Project
- DB.UCollections,
DB.UMain,
DB.USnippet,
UView;
@@ -87,7 +92,7 @@ function TSnippetAction.Execute: Boolean;
Assert(Assigned(fNotifier), ClassName + '.Execute: Notifier not set');
Assert(SnippetName <> '', ClassName + '.Execute: SnippetName not provided');
// Snippet := Database.Snippets.Find(SnippetName, UserDefined);
- Snippet := Database.Snippets.Find(SnippetName, TCollectionID.__TMP__DBCollectionID(UserDefined));
+ Snippet := Database.Snippets.Find(SnippetName, fCollectionID);
Assert(Assigned(Snippet), ClassName + '.Execute: SnippetName not valid');
// Create a view item for snippet and get notifier to display it
fNotifier.ShowViewItem(TViewFactory.CreateSnippetView(Snippet), NewTab);
From 8d19fdf3b0ab69ae6bdcfd5103c8757e399e9874 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 3 Nov 2024 03:27:22 +0000
Subject: [PATCH 026/222] Change IDBDataItemFactory to use collection IDs
Both methods of IDBDataItemFactory, CreateCategory & CreateSnippet, were
both changed to accept a TCollectionID parameters instead of Boolean
UserDefind parameters. New implementations of the methods were created
in TDBDataItemFactory.
Revised TDatabaseLoader to use the revised IDBDataItemFactory methods.
This change removed a __TMP__method call.
Removed code was commented out.
---
Src/DB.UDatabaseIO.pas | 8 +-
Src/DB.UMain.pas | 178 ++++++++++++++++++++++++++++-------------
2 files changed, 128 insertions(+), 58 deletions(-)
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index f93fba6b8..296ee75ef 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -353,7 +353,8 @@ procedure TDatabaseLoader.CreateCategory(const CatID: string;
@param CatData [in] Properties of category.
}
begin
- fCategories.Add(fFactory.CreateCategory(CatID, IsUserDatabase, CatData));
+// fCategories.Add(fFactory.CreateCategory(CatID, IsUserDatabase, CatData));
+ fCategories.Add(fFactory.CreateCategory(CatID, CollectionID, CatData));
end;
procedure TDatabaseLoader.HandleException(const E: Exception);
@@ -503,8 +504,11 @@ procedure TDatabaseLoader.LoadSnippets(const Cat: TCategory);
if not Assigned(Snippet) then
begin
fReader.GetSnippetProps(SnippetName, SnippetProps);
+// Snippet := fFactory.CreateSnippet(
+// SnippetName, IsUserDatabase, SnippetProps
+// );
Snippet := fFactory.CreateSnippet(
- SnippetName, IsUserDatabase, SnippetProps
+ SnippetName, CollectionID, SnippetProps
);
fSnipList.Add(Snippet);
end;
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index 4663c7dab..3e792663d 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -18,10 +18,18 @@ interface
uses
// Delphi
- Classes, Generics.Collections,
+ Classes,
+ Generics.Collections,
// Project
- ActiveText.UMain, Compilers.UGlobals, DB.UCategory, DB.USnippet, UContainers,
- UIStringList, UMultiCastEvents, USnippetIDs;
+ ActiveText.UMain,
+ Compilers.UGlobals,
+ DB.UCategory,
+ DB.UCollections,
+ DB.USnippet,
+ UContainers,
+ UIStringList,
+ UMultiCastEvents,
+ USnippetIDs;
type
@@ -105,23 +113,46 @@ interface
}
IDBDataItemFactory = interface(IInterface)
['{C6DD85BD-E649-4A90-961C-4011D2714B3E}']
- function CreateCategory(const CatID: string; const UserDefined: Boolean;
- const Data: TCategoryData): TCategory;
- {Creates a new category object.
- @param CatID [in] ID of new category. Must be unique.
- @param UserDefined [in] True if category is user defined, False if not.
- @param Data [in] Record describing category's properties.
- @return Instance of new category object.
- }
- function CreateSnippet(const Name: string; const UserDefined: Boolean;
- const Props: TSnippetData): TSnippet;
- {Creates a new snippet object.
- @param Name [in] Name of new snippet. Must not exist in database
- specified by UserDefined parameter.
- @param UserDefined [in] True if snippet is user defined, False if not.
- @param Props [in] Record describing snippet's properties.
- @return Instance of new snippet with no references.
- }
+// function CreateCategory(const CatID: string; const UserDefined: Boolean;
+// const Data: TCategoryData): TCategory;
+// {Creates a new category object.
+// @param CatID [in] ID of new category. Must be unique.
+// @param UserDefined [in] True if category is user defined, False if not.
+// @param Data [in] Record describing category's properties.
+// @return Instance of new category object.
+// }
+// function CreateSnippet(const Name: string; const UserDefined: Boolean;
+// const Props: TSnippetData): TSnippet;
+// {Creates a new snippet object.
+// @param Name [in] Name of new snippet. Must not exist in database
+// specified by UserDefined parameter.
+// @param UserDefined [in] True if snippet is user defined, False if not.
+// @param Props [in] Record describing snippet's properties.
+// @return Instance of new snippet with no references.
+// }
+
+ /// Creates a new category object.
+ /// string [in] ID of new category. Must be
+ /// unique.
+ /// TCollectionID [in] Collection with
+ /// which the category is associated.
+ /// TCategoryData [in] Record describing
+ /// category's properties.
+ /// TCategory. Instance of new category object.
+ function CreateCategory(const CatID: string;
+ const ACollectionID: TCollectionID; const Data: TCategoryData): TCategory;
+
+ /// Creates a new snippet object.
+ /// string [in] Name of new snippet. Must not
+ /// exist in database
+ /// TCollectionID [in] Collection
+ /// containing the snippet.
+ /// TSnippetData [in] Record describing
+ /// snippet's properties.
+ /// Instance of new snippet with no references.
+ function CreateSnippet(const Name: string;
+ const ACollectionID: TCollectionID; const Props: TSnippetData): TSnippet;
+
end;
{
@@ -270,9 +301,9 @@ implementation
uses
// Delphi
- SysUtils, Generics.Defaults,
+ SysUtils,
+ Generics.Defaults,
// Project
- DB.UCollections,
DB.UDatabaseIO,
IntfCommon,
UExceptions,
@@ -293,23 +324,46 @@ implementation
}
TDBDataItemFactory = class(TInterfacedObject, IDBDataItemFactory)
public
- function CreateCategory(const CatID: string; const UserDefined: Boolean;
- const Data: TCategoryData): TCategory;
- {Creates a new category object.
- @param CatID [in] ID of new category. Must be unique.
- @param UserDefined [in] True if category is user defined, False if not.
- @param Data [in] Record describing category's properties.
- @return Instance of new category object.
- }
- function CreateSnippet(const Name: string; const UserDefined: Boolean;
- const Props: TSnippetData): TSnippet;
- {Creates a new snippet object.
- @param Name [in] Name of new snippet. Must not exist in database
- specified by UserDefined parameter.
- @param UserDefined [in] True if snippet is user defined, False if not.
- @param Props [in] Record describing snippet's properties.
- @return Instance of new snippet with no references.
- }
+// function CreateCategory(const CatID: string; const UserDefined: Boolean;
+// const Data: TCategoryData): TCategory;
+// {Creates a new category object.
+// @param CatID [in] ID of new category. Must be unique.
+// @param UserDefined [in] True if category is user defined, False if not.
+// @param Data [in] Record describing category's properties.
+// @return Instance of new category object.
+// }
+// function CreateSnippet(const Name: string; const UserDefined: Boolean;
+// const Props: TSnippetData): TSnippet;
+// {Creates a new snippet object.
+// @param Name [in] Name of new snippet. Must not exist in database
+// specified by UserDefined parameter.
+// @param UserDefined [in] True if snippet is user defined, False if not.
+// @param Props [in] Record describing snippet's properties.
+// @return Instance of new snippet with no references.
+// }
+
+ /// Creates a new category object.
+ /// string [in] ID of new category. Must be
+ /// unique.
+ /// TCollectionID [in] Collection with
+ /// which the category is associated.
+ /// TCategoryData [in] Record describing
+ /// category's properties.
+ /// TCategory. Instance of new category object.
+ function CreateCategory(const CatID: string;
+ const ACollectionID: TCollectionID; const Data: TCategoryData): TCategory;
+
+ /// Creates a new snippet object.
+ /// string [in] Name of new snippet. Must not
+ /// exist in database
+ /// TCollectionID [in] Collection
+ /// containing the snippet.
+ /// TSnippetData [in] Record describing
+ /// snippet's properties.
+ /// Instance of new snippet with no references.
+ function CreateSnippet(const Name: string;
+ const ACollectionID: TCollectionID; const Props: TSnippetData): TSnippet;
+
end;
{
@@ -1163,29 +1217,41 @@ function TDatabase.TEventInfo.GetKind: TDatabaseChangeEventKind;
{ TDBDataItemFactory }
+//function TDBDataItemFactory.CreateCategory(const CatID: string;
+// const UserDefined: Boolean; const Data: TCategoryData): TCategory;
+// {Creates a new category object.
+// @param CatID [in] ID of new category. Must be unique.
+// @param UserDefined [in] True if category is user defined, False if not.
+// @param Data [in] Record describing category's properties.
+// @return Instance of new category object.
+// }
+//begin
+// Result := TCategoryEx.Create(CatID, TCollectionID.__TMP__DBCollectionID(UserDefined), Data);
+//end;
+//
+//function TDBDataItemFactory.CreateSnippet(const Name: string;
+// const UserDefined: Boolean; const Props: TSnippetData): TSnippet;
+// {Creates a new snippet object.
+// @param Name [in] Name of new snippet. Must not exist in database specified
+// by UserDefined parameter.
+// @param UserDefined [in] True if snippet is user defined, False if not.
+// @param Props [in] Record describing snippet's properties.
+// @return Instance of new snippet with no references.
+// }
+//begin
+// Result := TSnippetEx.Create(Name, UserDefined, Props);
+//end;
+
function TDBDataItemFactory.CreateCategory(const CatID: string;
- const UserDefined: Boolean; const Data: TCategoryData): TCategory;
- {Creates a new category object.
- @param CatID [in] ID of new category. Must be unique.
- @param UserDefined [in] True if category is user defined, False if not.
- @param Data [in] Record describing category's properties.
- @return Instance of new category object.
- }
+ const ACollectionID: TCollectionID; const Data: TCategoryData): TCategory;
begin
- Result := TCategoryEx.Create(CatID, TCollectionID.__TMP__DBCollectionID(UserDefined), Data);
+ Result := TCategoryEx.Create(CatID, ACollectionID, Data);
end;
function TDBDataItemFactory.CreateSnippet(const Name: string;
- const UserDefined: Boolean; const Props: TSnippetData): TSnippet;
- {Creates a new snippet object.
- @param Name [in] Name of new snippet. Must not exist in database specified
- by UserDefined parameter.
- @param UserDefined [in] True if snippet is user defined, False if not.
- @param Props [in] Record describing snippet's properties.
- @return Instance of new snippet with no references.
- }
+ const ACollectionID: TCollectionID; const Props: TSnippetData): TSnippet;
begin
- Result := TSnippetEx.Create(Name, UserDefined, Props);
+ Result := TSnippetEx.Create(Name, ACollectionID, Props);
end;
{ TUserDataProvider }
From baca296064a15245035aeb3fa11891a15048ad83 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Fri, 1 Nov 2024 10:13:26 +0000
Subject: [PATCH 027/222] Remove IView.IsUserDefined method
IView.IsUserDefined was removed along with all its implementations.
The only place that IView.IsUserDefined was used was in
FrOverview.TOverviewFrame.TTVDraw.IsUserDefinedNode. This method was
modified to retrieve any collection ID associated with any snippet or
category view and to calculate its result using those, removing any
need for IView to provide a IsUserDefined method.
A __TMP__ method was required in the modified TTVDraw.IsUserDefinedNode
method.
Removed code was commented out.
---
Src/FrOverview.pas | 22 ++++++++++---
Src/UView.pas | 78 ++++++++++++++++++++++++----------------------
2 files changed, 59 insertions(+), 41 deletions(-)
diff --git a/Src/FrOverview.pas b/Src/FrOverview.pas
index e668c3007..575975387 100644
--- a/Src/FrOverview.pas
+++ b/Src/FrOverview.pas
@@ -235,9 +235,12 @@ implementation
uses
// Delphi
+ SysUtils,
Messages,
// Project
- UKeysHelper, UOverviewTreeBuilder;
+ DB.UCollections,
+ UKeysHelper,
+ UOverviewTreeBuilder;
{$R *.dfm}
@@ -976,11 +979,22 @@ function TOverviewFrame.TTVDraw.IsUserDefinedNode(
@return True if node represents user defined object, False if not.
}
var
- ViewItem: IView; // view item represented by node
+ ViewItem: IView; // view item represented by node
+ SnippetView: ISnippetView; // view item if node represents a snippet
+ CategoryView: ICategoryView; // view item if node represents a category
+ CollectionID: TCollectionID; // ID of collection node item belongs to, if any
begin
- ViewItem := (Node as TViewItemTreeNode).ViewItem;
// TODO -cBug: Exception reported as issue #70 seems to be triggered here
- Result := ViewItem.IsUserDefined;
+ ViewItem := (Node as TViewItemTreeNode).ViewItem;
+// Result := ViewItem.IsUserDefined;
+ if Supports(ViewItem, ISnippetView, SnippetView) then
+ CollectionID := SnippetView.Snippet.CollectionID
+ else if Supports(ViewItem, ICategoryView, CategoryView) then
+ CollectionID := CategoryView.Category.CollectionID
+ else
+ CollectionID := TCollectionID.CreateNull;
+ Result := (CollectionID <> TCollectionID.__TMP__MainDBCollectionID)
+ and not CollectionID.IsNull;
end;
end.
diff --git a/Src/UView.pas b/Src/UView.pas
index b3425318a..db192a255 100644
--- a/Src/UView.pas
+++ b/Src/UView.pas
@@ -20,7 +20,11 @@ interface
// Delphi
Generics.Collections,
// Project
- DB.UCategory, DB.USnippet, DB.USnippetKind, UBaseObjects, UInitialLetter;
+ DB.UCategory,
+ DB.USnippet,
+ DB.USnippetKind,
+ UBaseObjects,
+ UInitialLetter;
type
@@ -56,8 +60,8 @@ interface
/// without having have an instance of any object wrapped by the view.
///
function GetKey: IViewKey;
- /// Checks if view is user-defined.
- function IsUserDefined: Boolean;
+// /// Checks if view is user-defined.
+// function IsUserDefined: Boolean;
/// Checks if view is a grouping.
/// A grouping is a view that groups views together.
///
@@ -230,9 +234,9 @@ TKey = class(TInterfacedObject, IViewKey)
/// Gets object containing view's unique key.
/// Method of IView.
function GetKey: IViewKey;
- /// Checks if view is user-defined.
- /// Method of IView.
- function IsUserDefined: Boolean;
+// /// Checks if view is user-defined.
+// /// Method of IView.
+// function IsUserDefined: Boolean;
/// Checks if view is a grouping.
/// Method of IView.
function IsGrouping: Boolean;
@@ -320,8 +324,8 @@ TKey = class(TInterfacedObject, IViewKey)
/// Gets object containing view's unique key.
/// Method of IView.
function GetKey: IViewKey;
- /// Checks if view is user-defined.
- function IsUserDefined: Boolean;
+// /// Checks if view is user-defined.
+// function IsUserDefined: Boolean;
/// Checks if view is a grouping.
/// Method of IView.
function IsGrouping: Boolean;
@@ -367,9 +371,9 @@ TKey = class(TInterfacedObject, IViewKey)
/// Gets object containing view's unique key.
/// Method of IView.
function GetKey: IViewKey;
- /// Checks if view is user-defined.
- /// Method of IView.
- function IsUserDefined: Boolean;
+// /// Checks if view is user-defined.
+// /// Method of IView.
+// function IsUserDefined: Boolean;
/// Checks if view is a grouping.
/// Method of IView.
function IsGrouping: Boolean;
@@ -417,9 +421,9 @@ TKey = class(TInterfacedObject, IViewKey)
/// Gets object containing view's unique key.
/// Method of IView.
function GetKey: IViewKey;
- /// Checks if view is user-defined.
- /// Method of IView.
- function IsUserDefined: Boolean;
+// /// Checks if view is user-defined.
+// /// Method of IView.
+// function IsUserDefined: Boolean;
/// Checks if view is a grouping.
/// Method of IView.
function IsGrouping: Boolean;
@@ -467,9 +471,9 @@ TKey = class(TInterfacedObject, IViewKey)
/// Gets object containing view's unique key.
/// Method of IView.
function GetKey: IViewKey;
- /// Checks if view is user-defined.
- /// Method of IView.
- function IsUserDefined: Boolean;
+// /// Checks if view is user-defined.
+// /// Method of IView.
+// function IsUserDefined: Boolean;
/// Checks if view is a grouping.
/// Method of IView.
function IsGrouping: Boolean;
@@ -495,10 +499,10 @@ function TSimpleView.IsGrouping: Boolean;
Result := False;
end;
-function TSimpleView.IsUserDefined: Boolean;
-begin
- Result := False;
-end;
+//function TSimpleView.IsUserDefined: Boolean;
+//begin
+// Result := False;
+//end;
{ TSimpleView.TKey }
@@ -586,10 +590,10 @@ function TSnippetView.IsGrouping: Boolean;
Result := False;
end;
-function TSnippetView.IsUserDefined: Boolean;
-begin
- Result := GetSnippet.UserDefined;
-end;
+//function TSnippetView.IsUserDefined: Boolean;
+//begin
+// Result := GetSnippet.UserDefined;
+//end;
{ TSnippetView.TKey }
@@ -645,10 +649,10 @@ function TCategoryView.IsGrouping: Boolean;
Result := True;
end;
-function TCategoryView.IsUserDefined: Boolean;
-begin
- Result := GetCategory.UserDefined;
-end;
+//function TCategoryView.IsUserDefined: Boolean;
+//begin
+// Result := GetCategory.UserDefined;
+//end;
{ TCategoryView.TKey }
@@ -702,10 +706,10 @@ function TSnippetKindView.IsGrouping: Boolean;
Result := True;
end;
-function TSnippetKindView.IsUserDefined: Boolean;
-begin
- Result := False;
-end;
+//function TSnippetKindView.IsUserDefined: Boolean;
+//begin
+// Result := False;
+//end;
{ TSnippetKindView.TKey }
@@ -759,10 +763,10 @@ function TInitialLetterView.IsGrouping: Boolean;
Result := True;
end;
-function TInitialLetterView.IsUserDefined: Boolean;
-begin
- Result := False;
-end;
+//function TInitialLetterView.IsUserDefined: Boolean;
+//begin
+// Result := False;
+//end;
{ TInitialLetterView.TKey }
From f946baeb4109cccf709891b42f9ba4de81e6e14b Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 3 Nov 2024 13:21:02 +0000
Subject: [PATCH 028/222] Change interface used to set collection colour prefs
Changed IPreferences and its implementation to remove DBHeadingColours[]
property & getter and setter that took Boolean (user-defined) parameter
and to replace with new Getter & Setter methods that work with
collections IDS.
Made similar changes re DBHeadingCustomColours[] property & getter and
setter.
The new setter and getter methods for both above still access the
existing fDBHeadingColours[] and fDBHeadingCustomColours[] fields which
remain array[Boolean] types, which must be changed to support a variable
number of collections.
Updated TPreferencesPersist to use the new TCollectionID version of the
getters and setter methods, while retaining the CodeSnip 4 setting
keys (something else that needs changing when moving to a variable
number of collections).
Made changes to all code that uses the removed properties to work with
the new getters and setters.
Several __TMP__ method calls were required to make this work, although
a few were able to be removed.
Introduced new __TMP__ method within UPreferences to map collection IDs
to the colour preferences for the CodeSnip 4 main and user databases.
Removed code was commented out.
---
Src/FmDependenciesDlg.pas | 3 +-
Src/FmFavouritesDlg.pas | 6 +-
Src/FmFindXRefsDlg.pas | 2 +-
Src/FmTestCompileDlg.pas | 2 +-
Src/FrDetailView.pas | 12 +-
Src/FrDisplayPrefs.pas | 29 +++-
Src/UPreferences.pas | 291 +++++++++++++++++++++++++++---------
Src/URTFCategoryDoc.pas | 14 +-
Src/URTFSnippetDoc.pas | 11 +-
Src/USnippetsChkListMgr.pas | 10 +-
Src/USnippetsTVDraw.pas | 7 +-
11 files changed, 286 insertions(+), 101 deletions(-)
diff --git a/Src/FmDependenciesDlg.pas b/Src/FmDependenciesDlg.pas
index ddc25ee40..abc91e9db 100644
--- a/Src/FmDependenciesDlg.pas
+++ b/Src/FmDependenciesDlg.pas
@@ -414,7 +414,8 @@ procedure TDependenciesDlg.lbDependentsDrawItem(Control: TWinControl;
LB := Control as TListBox;
Canvas := LB.Canvas;
if not (odSelected in State) then
- Canvas.Font.Color := Preferences.DBHeadingColours[IsUserDefinedItem];
+// Canvas.Font.Color := Preferences.DBHeadingColours[IsUserDefinedItem];
+ Canvas.Font.Color := Preferences.GetDBHeadingColour(TCollectionID.__TMP__DBCollectionID(IsUserDefinedItem));
Canvas.TextRect(
Rect,
Rect.Left + 2,
diff --git a/Src/FmFavouritesDlg.pas b/Src/FmFavouritesDlg.pas
index ac2b4f936..0a6af9efc 100644
--- a/Src/FmFavouritesDlg.pas
+++ b/Src/FmFavouritesDlg.pas
@@ -582,12 +582,12 @@ procedure TFavouritesDlg.LVCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
var
// UserDefined: Boolean;
- IsMainDB: Boolean;
+ CollectionID: TCollectionID;
begin
// UserDefined := (Item as TFavouriteListItem).Favourite.SnippetID.UserDefined;
// fLVFavs.Canvas.Font.Color := Preferences.DBHeadingColours[UserDefined];
- IsMainDB := (Item as TFavouriteListItem).Favourite.SnippetID.CollectionID = TCollectionID.__TMP__MainDBCollectionID;
- fLVFavs.Canvas.Font.Color := Preferences.DBHeadingColours[not IsMainDB];
+ CollectionID := (Item as TFavouriteListItem).Favourite.SnippetID.CollectionID;
+ fLVFavs.Canvas.Font.Color := Preferences.GetDBHeadingColour(CollectionID);
end;
procedure TFavouritesDlg.LVCustomDrawSubItem(Sender: TCustomListView;
diff --git a/Src/FmFindXRefsDlg.pas b/Src/FmFindXRefsDlg.pas
index 45e280e72..a2f406629 100644
--- a/Src/FmFindXRefsDlg.pas
+++ b/Src/FmFindXRefsDlg.pas
@@ -236,7 +236,7 @@ procedure TFindXRefsDlg.ConfigForm;
lblSnippetName.Font.Style := [fsBold];
lblSnippetName.Font.Color :=
// Preferences.DBHeadingColours[fSnippet.UserDefined];
- Preferences.DBHeadingColours[fSnippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID];
+ Preferences.GetDBHeadingColour(fSnippet.CollectionID);
// Display selected snippet name in appropriate controls
lblSnippetName.Caption := fSnippet.DisplayName;
chkIncludeSnippet.Caption := Format(
diff --git a/Src/FmTestCompileDlg.pas b/Src/FmTestCompileDlg.pas
index 0ed1ba053..08be15372 100644
--- a/Src/FmTestCompileDlg.pas
+++ b/Src/FmTestCompileDlg.pas
@@ -290,7 +290,7 @@ procedure TTestCompileDlg.ConfigForm;
TFontHelper.SetDefaultBaseFont(lblSnippetName.Font);
lblSnippetName.Font.Color :=
// Preferences.DBHeadingColours[fSnippet.UserDefined];
- Preferences.DBHeadingColours[fSnippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID];
+ Preferences.GetDBHeadingColour(fSnippet.CollectionID);
lblSnippetName.Caption := fSnippet.DisplayName;
end;
diff --git a/Src/FrDetailView.pas b/Src/FrDetailView.pas
index 8aa41a592..1e93d52b3 100644
--- a/Src/FrDetailView.pas
+++ b/Src/FrDetailView.pas
@@ -109,7 +109,9 @@ implementation
// Delphi
SysUtils, Graphics, Menus, Math,
// Project
- ActiveText.UHTMLRenderer, Browser.UHighlighter, Hiliter.UAttrs, Hiliter.UCSS,
+ ActiveText.UHTMLRenderer, Browser.UHighlighter,
+ DB.UCollections,
+ Hiliter.UAttrs, Hiliter.UCSS,
Hiliter.UGlobals, UColours, UCSSUtils, UFontHelper, UPreferences, UQuery,
USystemInfo, UUtils, UWBCommandBars;
@@ -226,10 +228,14 @@ procedure TDetailViewFrame.BuildCSS(const CSSBuilder: TCSSBuilder);
.AddProperty(TCSS.BorderProp(cssAll, 1, cbsSolid, clBorder));
// Heading colours for user & main databases
+// CSSBuilder.AddSelector('.userdb')
+// .AddProperty(TCSS.ColorProp(Preferences.DBHeadingColours[True]));
+// CSSBuilder.AddSelector('.maindb')
+// .AddProperty(TCSS.ColorProp(Preferences.DBHeadingColours[False]));
CSSBuilder.AddSelector('.userdb')
- .AddProperty(TCSS.ColorProp(Preferences.DBHeadingColours[True]));
+ .AddProperty(TCSS.ColorProp(Preferences.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID)));
CSSBuilder.AddSelector('.maindb')
- .AddProperty(TCSS.ColorProp(Preferences.DBHeadingColours[False]));
+ .AddProperty(TCSS.ColorProp(Preferences.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID)));
// Sets CSS for style of New Tab text
CSSFont.Assign(ContentFont);
diff --git a/Src/FrDisplayPrefs.pas b/Src/FrDisplayPrefs.pas
index 015d1ea02..a540d9e93 100644
--- a/Src/FrDisplayPrefs.pas
+++ b/Src/FrDisplayPrefs.pas
@@ -107,6 +107,7 @@ implementation
// Delphi
SysUtils, Math, Graphics, ExtCtrls,
// Project
+ DB.UCollections,
FmPreferencesDlg, UColours, UCtrlArranger, UFontHelper, UGraphicUtils,
UMessageBox;
@@ -133,11 +134,15 @@ procedure TDisplayPrefsFrame.Activate(const Prefs: IPreferences;
chkHideEmptySections.Checked := not Prefs.ShowEmptySections;
chkHideEmptySections.OnClick := chkHideEmptySectionsClick;
chkSnippetsInNewTab.Checked := Prefs.ShowNewSnippetsInNewTabs;
- fMainColourBox.Selected := Prefs.DBHeadingColours[False];
- fUserColourBox.Selected := Prefs.DBHeadingColours[True];
+// fMainColourBox.Selected := Prefs.DBHeadingColours[False];
+// fUserColourBox.Selected := Prefs.DBHeadingColours[True];
+ fMainColourBox.Selected := Prefs.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID);
+ fUserColourBox.Selected := Prefs.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID);
fSourceBGColourBox.Selected := Prefs.SourceCodeBGcolour;
- Prefs.DBHeadingCustomColours[False].CopyTo(fMainColourDlg.CustomColors, True);
- Prefs.DBHeadingCustomColours[True].CopyTo(fUserColourDlg.CustomColors, True);
+// Prefs.DBHeadingCustomColours[False].CopyTo(fMainColourDlg.CustomColors, True);
+// Prefs.DBHeadingCustomColours[True].CopyTo(fUserColourDlg.CustomColors, True);
+ Prefs.GetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID).CopyTo(fMainColourDlg.CustomColors, True);
+ Prefs.GetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID).CopyTo(fUserColourDlg.CustomColors, True);
Prefs.SourceCodeBGCustomColours.CopyTo(fSourceBGColourDlg.CustomColors, True);
cbOverviewFontSize.Tag := Prefs.OverviewFontSize; // store font size in .Tag
cbOverviewFontSize.Text := IntToStr(Prefs.OverviewFontSize);
@@ -294,13 +299,21 @@ procedure TDisplayPrefsFrame.Deactivate(const Prefs: IPreferences);
Prefs.OverviewStartState := TOverviewStartState(
cbOverviewTree.Items.Objects[cbOverviewTree.ItemIndex]
);
- Prefs.DBHeadingColours[False] := fMainColourBox.Selected;
- Prefs.DBHeadingColours[True] := fUserColourBox.Selected;
+// Prefs.DBHeadingColours[False] := fMainColourBox.Selected;
+// Prefs.DBHeadingColours[True] := fUserColourBox.Selected;
+ Prefs.SetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID, fMainColourBox.Selected);
+ Prefs.SetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID, fUserColourBox.Selected);
Prefs.SourceCodeBGcolour := fSourceBGColourBox.Selected;
- Prefs.DBHeadingCustomColours[False].CopyFrom(
+// Prefs.DBHeadingCustomColours[False].CopyFrom(
+// fMainColourDlg.CustomColors, True
+// );
+// Prefs.DBHeadingCustomColours[True].CopyFrom(
+// fUserColourDlg.CustomColors, True
+// );
+ Prefs.GetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID).CopyFrom(
fMainColourDlg.CustomColors, True
);
- Prefs.DBHeadingCustomColours[True].CopyFrom(
+ Prefs.GetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID).CopyFrom(
fUserColourDlg.CustomColors, True
);
Prefs.SourceCodeBGCustomColours.CopyFrom(
diff --git a/Src/UPreferences.pas b/Src/UPreferences.pas
index 26a412804..3d3d17632 100644
--- a/Src/UPreferences.pas
+++ b/Src/UPreferences.pas
@@ -19,6 +19,7 @@ interface
// Delphi
Graphics,
// Project
+ DB.UCollections,
Hiliter.UGlobals, UIStringList, UMeasurement, UPrintInfo,
USnippetPageStructure, USourceFileInfo, USourceGen, UWarnings;
@@ -136,44 +137,74 @@ interface
property ShowNewSnippetsInNewTabs: Boolean
read GetShowNewSnippetsInNewTabs write SetShowNewSnippetsInNewTabs;
+// /// Gets heading colour used for snippets from a specified
+// /// database.
+// /// Boolean [in] Required database: True for user
+// /// database and False for inline database.
+// /// TColor. Required colour.
+// function GetDBHeadingColour(UserDefined: Boolean): TColor;
+// /// Sets heading colour used for snippets from a specified
+// /// database.
+// /// Boolean [in] Required database: True for user
+// /// database and False for online database.
+// /// TColor [in] Required heading colour.
+// procedure SetDBHeadingColour(UserDefined: Boolean;
+// const Value: TColor);
+// /// Records colour to be used for headings of items from either
+// /// online database (UserDefined = False) or user database (UserDefined =
+// /// True).
+// property DBHeadingColours[UserDefined: Boolean]: TColor
+// read GetDBHeadingColour write SetDBHeadingColour;
+
/// Gets heading colour used for snippets from a specified
- /// database.
- /// Boolean [in] Required database: True for user
- /// database and False for inline database.
+ /// collection.
+ /// TCollectionID [in] ID of required
+ /// collection.
/// TColor. Required colour.
- function GetDBHeadingColour(UserDefined: Boolean): TColor;
+ function GetDBHeadingColour(const ACollectionID: TCollectionID): TColor;
/// Sets heading colour used for snippets from a specified
- /// database.
- /// Boolean [in] Required database: True for user
- /// database and False for online database.
- /// TColor [in] Required heading colour.
- procedure SetDBHeadingColour(UserDefined: Boolean;
+ /// collection.
+ /// TCollectionID [in] ID of required
+ /// collection.
+ /// TColor. Required colour.
+ procedure SetDBHeadingColour(const ACollectionID: TCollectionID;
const Value: TColor);
- /// Records colour to be used for headings of items from either
- /// online database (UserDefined = False) or user database (UserDefined =
- /// True).
- property DBHeadingColours[UserDefined: Boolean]: TColor
- read GetDBHeadingColour write SetDBHeadingColour;
+
+// /// Gets custom colours available for headings for specified
+// /// database.
+// /// Boolean [in] Required database: True for user
+// /// database and False for online database.
+// /// IStringList. String list containing custom colours.
+// function GetDBHeadingCustomColours(UserDefined: Boolean): IStringList;
+// /// Sets custom colours available for headings for specified
+// /// database.
+// /// Boolean [in] Required database: True for user
+// /// database and False for online database.
+// /// IStringList [in] String list containing custom
+// /// colours.
+// procedure SetDBHeadingCustomColours(UserDefined: Boolean;
+// Value: IStringList);
+// /// Records custom colours available for headings of items from
+// /// either online database (UserDefined = False) or user database
+// /// (UserDefined = True).
+// property DBHeadingCustomColours[UserDefined: Boolean]: IStringList
+// read GetDBHeadingCustomColours write SetDBHeadingCustomColours;
/// Gets custom colours available for headings for specified
- /// database.
- /// Boolean [in] Required database: True for user
- /// database and False for online database.
+ /// collection.
+ /// TCollectionID [in] ID of required
+ /// collection.
/// IStringList. String list containing custom colours.
- function GetDBHeadingCustomColours(UserDefined: Boolean): IStringList;
+ function GetDBHeadingCustomColours(const ACollectionID: TCollectionID):
+ IStringList;
/// Sets custom colours available for headings for specified
- /// database.
- /// Boolean [in] Required database: True for user
- /// database and False for online database.
+ /// collection.
+ /// TCollectionID [in] ID of required
+ /// collection.
/// IStringList [in] String list containing custom
/// colours.
- procedure SetDBHeadingCustomColours(UserDefined: Boolean;
+ procedure SetDBHeadingCustomColours(const ACollectionID: TCollectionID;
Value: IStringList);
- /// Records custom colours available for headings of items from
- /// either online database (UserDefined = False) or user database
- /// (UserDefined = True).
- property DBHeadingCustomColours[UserDefined: Boolean]: IStringList
- read GetDBHeadingCustomColours write SetDBHeadingCustomColours;
/// Gets size of font used in overview pane tree view.
function GetOverviewFontSize: Integer;
@@ -340,13 +371,17 @@ TPreferences = class(TInterfacedObject,
/// in new tabs in details pane.
fShowNewSnippetsInNewTabs: Boolean;
/// Records colour to be used for headings of items from either
- /// online database (UserDefined = False) or user database (UserDefined =
- /// True).
+ /// main (False) or user (True) collections.
fDBHeadingColours: array[Boolean] of TColor;
+ {TODO -cCollections: WARNING. The fDBHeadingColours field only supports
+ the two original main & user collections. This MUST be changed
+ once more than two snippet collections are supported}
/// Records custom colours available for headings of items from
- /// either online database (UserDefined = False) or user database
- /// (UserDefined = True).
+ /// either main (False) or user (True) collections.
fDBHeadingCustomColours: array[Boolean] of IStringList;
+ {TODO -cCollections: WARNING. The fDBHeadingCustomColours field only
+ supports the two original main & user collections. This MUST be
+ changed once more than two snippet collections are supported}
/// Records size of font used in overview pane tree view.
///
fOverviewFontSize: Integer;
@@ -381,6 +416,9 @@ TPreferences = class(TInterfacedObject,
function DefaultOverviewFontSize: Integer;
/// Returns default font size for details pane.
function DefaultDetailFontSize: Integer;
+
+ function __TMP__UseUserDBHeadingColour(const ACollectionID: TCollectionID):
+ Boolean;
public
/// Constructs a new object instance.
constructor Create;
@@ -482,39 +520,75 @@ TPreferences = class(TInterfacedObject,
/// Method of IPreferences.
procedure SetShowNewSnippetsInNewTabs(const Value: Boolean);
+// /// Gets heading colour used for snippets from a specified
+// /// database.
+// /// Boolean [in] Required database: True for user
+// /// database and False for inline database.
+// /// TColor. Required colour.
+// /// Method of IPreferences.
+// function GetDBHeadingColour(UserDefined: Boolean): TColor;
+
/// Gets heading colour used for snippets from a specified
- /// database.
- /// Boolean [in] Required database: True for user
- /// database and False for inline database.
+ /// collection.
+ /// TCollectionID [in] ID of required
+ /// collection.
/// TColor. Required colour.
/// Method of IPreferences.
- function GetDBHeadingColour(UserDefined: Boolean): TColor;
+ function GetDBHeadingColour(const ACollectionID: TCollectionID): TColor;
+
+// /// Sets heading colour used for snippets from a specified
+// /// database.
+// /// Boolean [in] Required database: True for user
+// /// database and False for online database.
+// /// TColor [in] Required heading colour.
+// /// Method of IPreferences.
+// procedure SetDBHeadingColour(UserDefined: Boolean;
+// const Value: TColor);
/// Sets heading colour used for snippets from a specified
- /// database.
- /// Boolean [in] Required database: True for user
- /// database and False for online database.
- /// TColor [in] Required heading colour.
+ /// collection.
+ /// TCollectionID [in] ID of required
+ /// collection.
+ /// TColor. Required colour.
/// Method of IPreferences.
- procedure SetDBHeadingColour(UserDefined: Boolean;
+ procedure SetDBHeadingColour(const ACollectionID: TCollectionID;
const Value: TColor);
+// /// Gets custom colours available for headings for specified
+// /// database.
+// /// Boolean [in] Required database: True for user
+// /// database and False for online database.
+// /// IStringList. String list containing custom colours.
+// /// Method of IPreferences.
+// function GetDBHeadingCustomColours(UserDefined: Boolean): IStringList;
+
/// Gets custom colours available for headings for specified
- /// database.
- /// Boolean [in] Required database: True for user
- /// database and False for online database.
+ /// collection.
+ /// TCollectionID [in] ID of required
+ /// collection.
/// IStringList. String list containing custom colours.
/// Method of IPreferences.
- function GetDBHeadingCustomColours(UserDefined: Boolean): IStringList;
+ function GetDBHeadingCustomColours(const ACollectionID: TCollectionID):
+ IStringList;
+
+// /// Sets custom colours available for headings for specified
+// /// database.
+// /// Boolean [in] Required database: True for user
+// /// database and False for online database.
+// /// IStringList [in] String list containing custom
+// /// colours.
+// /// Method of IPreferences.
+// procedure SetDBHeadingCustomColours(UserDefined: Boolean;
+// Value: IStringList);
/// Sets custom colours available for headings for specified
- /// database.
- /// Boolean [in] Required database: True for user
- /// database and False for online database.
+ /// collection.
+ /// TCollectionID [in] ID of required
+ /// collection.
/// IStringList [in] String list containing custom
/// colours.
/// Method of IPreferences.
- procedure SetDBHeadingCustomColours(UserDefined: Boolean;
+ procedure SetDBHeadingCustomColours(const ACollectionID: TCollectionID;
Value: IStringList);
/// Gets size of font used in overview pane tree view.
@@ -695,10 +769,14 @@ procedure TPreferences.Assign(const Src: IInterface);
Self.fOverviewStartState := SrcPref.OverviewStartState;
Self.fShowEmptySections := SrcPref.ShowEmptySections;
Self.fShowNewSnippetsInNewTabs := SrcPref.ShowNewSnippetsInNewTabs;
- Self.fDBHeadingColours[False] := SrcPref.DBHeadingColours[False];
- Self.fDBHeadingCustomColours[False] := SrcPref.DBHeadingCustomColours[False];
- Self.fDBHeadingColours[True] := SrcPref.DBHeadingColours[True];
- Self.fDBHeadingCustomColours[True] := SrcPref.DBHeadingCustomColours[True];
+// Self.fDBHeadingColours[False] := SrcPref.DBHeadingColours[False];
+ Self.SetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID, SrcPref.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID));
+// Self.fDBHeadingCustomColours[False] := SrcPref.DBHeadingCustomColours[False];
+ Self.SetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID, SrcPref.GetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID));
+// Self.fDBHeadingColours[True] := SrcPref.DBHeadingColours[True];
+ Self.SetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID, SrcPref.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID));
+// Self.fDBHeadingCustomColours[True] := SrcPref.DBHeadingCustomColours[True];
+ Self.SetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID, SrcPref.GetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID));
Self.fOverviewFontSize := SrcPref.OverviewFontSize;
Self.fDetailFontSize := SrcPref.DetailFontSize;
Self.fSourceCodeBGColour := SrcPref.SourceCodeBGColour;
@@ -746,17 +824,39 @@ function TPreferences.GetCustomHiliteColours: IStringList;
Result := fHiliteCustomColours;
end;
-function TPreferences.GetDBHeadingColour(UserDefined: Boolean): TColor;
+//function TPreferences.GetDBHeadingColour(UserDefined: Boolean): TColor;
+//begin
+// Result := fDBHeadingColours[UserDefined];
+//end;
+
+function TPreferences.GetDBHeadingColour(
+ const ACollectionID: TCollectionID): TColor;
begin
- Result := fDBHeadingColours[UserDefined];
+ {TODO -cCollections: WARNING: This implementation of GetDBHeadingColour only
+ supports the old main and user collections. It will break when further
+ collections are added.
+ }
+ Result := fDBHeadingColours[__TMP__UseUserDBHeadingColour(ACollectionID)];
end;
function TPreferences.GetDBHeadingCustomColours(
- UserDefined: Boolean): IStringList;
+ const ACollectionID: TCollectionID): IStringList;
begin
- Result := fDBHeadingCustomColours[UserDefined];
+ {TODO -cCollections: WARNING: This implementation of GetDBHeadingCustomColours
+ only supports the old main and user collections. It will break when
+ further collections are added.
+ }
+ Result := fDBHeadingCustomColours[
+ __TMP__UseUserDBHeadingColour(ACollectionID)
+ ];
end;
+//function TPreferences.GetDBHeadingCustomColours(
+// UserDefined: Boolean): IStringList;
+//begin
+// Result := fDBHeadingCustomColours[UserDefined];
+//end;
+
function TPreferences.GetDetailFontSize: Integer;
begin
Result := fDetailFontSize;
@@ -857,18 +957,40 @@ procedure TPreferences.SetCustomHiliteColours(const Colours: IStringList);
fHiliteCustomColours := Colours;
end;
-procedure TPreferences.SetDBHeadingColour(UserDefined: Boolean;
+//procedure TPreferences.SetDBHeadingColour(UserDefined: Boolean;
+// const Value: TColor);
+//begin
+// fDBHeadingColours[UserDefined] := Value;
+//end;
+
+procedure TPreferences.SetDBHeadingColour(const ACollectionID: TCollectionID;
const Value: TColor);
begin
- fDBHeadingColours[UserDefined] := Value;
+ {TODO -cCollections: WARNING: This implementation of SetDBHeadingColour only
+ supports the old main and user collections. It will break when further
+ collections are added.
+ }
+ fDBHeadingColours[__TMP__UseUserDBHeadingColour(ACollectionID)] := Value;
end;
-procedure TPreferences.SetDBHeadingCustomColours(UserDefined: Boolean;
- Value: IStringList);
+procedure TPreferences.SetDBHeadingCustomColours(
+ const ACollectionID: TCollectionID; Value: IStringList);
begin
- fDBHeadingCustomColours[UserDefined] := Value;
+ {TODO -cCollections: WARNING: This implementation of SetDBHeadingCustomColours
+ only supports the old main and user collections. It will break when
+ further collections are added.
+ }
+ fDBHeadingCustomColours[
+ __TMP__UseUserDBHeadingColour(ACollectionID)
+ ] := Value;
end;
+//procedure TPreferences.SetDBHeadingCustomColours(UserDefined: Boolean;
+// Value: IStringList);
+//begin
+// fDBHeadingCustomColours[UserDefined] := Value;
+//end;
+
procedure TPreferences.SetDetailFontSize(const Value: Integer);
begin
if TFontHelper.IsInCommonFontSizeRange(Value) then
@@ -971,6 +1093,13 @@ procedure TPreferences.SetWarnings(Warnings: IWarnings);
(fWarnings as IAssignable).Assign(Warnings);
end;
+function TPreferences.__TMP__UseUserDBHeadingColour(
+ const ACollectionID: TCollectionID): Boolean;
+begin
+ Result := (ACollectionID <> TCollectionID.__TMP__MainDBCollectionID)
+ and not ACollectionID.IsNull;
+end;
+
{ TPreferencesPersist }
function TPreferencesPersist.Clone: IInterface;
@@ -990,10 +1119,14 @@ function TPreferencesPersist.Clone: IInterface;
NewPref.OverviewStartState := Self.fOverviewStartState;
NewPref.ShowEmptySections := Self.fShowEmptySections;
NewPref.ShowNewSnippetsInNewTabs := Self.fShowNewSnippetsInNewTabs;
- NewPref.DBHeadingColours[False] := Self.fDBHeadingColours[False];
- NewPref.DBHeadingCustomColours[False] := Self.fDBHeadingCustomColours[False];
- NewPref.DBHeadingColours[True] := Self.fDBHeadingColours[True];
- NewPref.DBHeadingCustomColours[True] := Self.fDBHeadingCustomColours[True];
+// NewPref.DBHeadingColours[False] := Self.fDBHeadingColours[False];
+ NewPref.SetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID, Self.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID));
+// NewPref.DBHeadingCustomColours[False] := Self.fDBHeadingCustomColours[False];
+ NewPref.SetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID, Self.GetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID));
+// NewPref.DBHeadingColours[True] := Self.fDBHeadingColours[True];
+ NewPref.SetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID, Self.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID));
+// NewPref.DBHeadingCustomColours[True] := Self.fDBHeadingCustomColours[True];
+ NewPref.SetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID, Self.GetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID));
NewPref.OverviewFontSize := Self.fOverviewFontSize;
NewPref.DetailFontSize := Self.fDetailFontSize;
NewPref.SourceCodeBGColour := Self.fSourceCodeBGColour;
@@ -1035,11 +1168,19 @@ constructor TPreferencesPersist.Create;
fShowNewSnippetsInNewTabs := Storage.GetBoolean(
'ShowNewSnippetsInNewTabs', False
);
- fDBHeadingColours[False] := TColor(
- Storage.GetInteger('MainDBHeadingColour', clMainSnippet)
+// fDBHeadingColours[False] := TColor(
+// Storage.GetInteger('MainDBHeadingColour', clMainSnippet)
+// );
+ SetDBHeadingColour(
+ TCollectionID.__TMP__MainDBCollectionID,
+ TColor(Storage.GetInteger('MainDBHeadingColour', clMainSnippet))
);
- fDBHeadingColours[True] := TColor(
- Storage.GetInteger('UserDBHeadingColour', clUserSnippet)
+// fDBHeadingColours[True] := TColor(
+// Storage.GetInteger('UserDBHeadingColour', clUserSnippet)
+// );
+ SetDBHeadingColour(
+ TCollectionID.__TMP__UserDBCollectionID,
+ TColor(Storage.GetInteger('UserDBHeadingColour', clUserSnippet))
);
fSourceCodeBGColour := TColor(
Storage.GetInteger('SourceCodeBGColour', clSourceBg)
@@ -1124,8 +1265,16 @@ destructor TPreferencesPersist.Destroy;
Storage.SetInteger('OverviewStartState', Ord(fOverviewStartState));
Storage.SetBoolean('ShowEmptySections', fShowEmptySections);
Storage.SetBoolean('ShowNewSnippetsInNewTabs', fShowNewSnippetsInNewTabs);
- Storage.SetInteger('MainDBHeadingColour', fDBHeadingColours[False]);
- Storage.SetInteger('UserDBHeadingColour', fDBHeadingColours[True]);
+// Storage.SetInteger('MainDBHeadingColour', fDBHeadingColours[False]);
+ Storage.SetInteger(
+ 'MainDBHeadingColour',
+ GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID)
+ );
+// Storage.SetInteger('UserDBHeadingColour', fDBHeadingColours[True]);
+ Storage.SetInteger(
+ 'UserDBHeadingColour',
+ GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID)
+ );
Storage.SetInteger('OverviewFontSize', fOverviewFontSize);
Storage.SetInteger('DetailFontSize', fDetailFontSize);
Storage.SetInteger('SourceCodeBGColour', fSourceCodeBGColour);
diff --git a/Src/URTFCategoryDoc.pas b/Src/URTFCategoryDoc.pas
index 601f41ae0..6e2b0a6ea 100644
--- a/Src/URTFCategoryDoc.pas
+++ b/Src/URTFCategoryDoc.pas
@@ -104,8 +104,12 @@ constructor TRTFCategoryDoc.Create(const UseColour: Boolean);
fBuilder.FontTable.Add(MainFontName, rgfSwiss, 0);
fBuilder.FontTable.Add(MonoFontName, rgfModern, 0);
// Set up colour table
- fBuilder.ColourTable.Add(Preferences.DBHeadingColours[False]);
- fBuilder.ColourTable.Add(Preferences.DBHeadingColours[True]);
+// fBuilder.ColourTable.Add(Preferences.DBHeadingColours[False]);
+// fBuilder.ColourTable.Add(Preferences.DBHeadingColours[True]);
+ {TODO -cCollection: Replace following 2 statements with loop that iterates
+ over all collections.}
+ fBuilder.ColourTable.Add(Preferences.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID));
+ fBuilder.ColourTable.Add(Preferences.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID));
fBuilder.ColourTable.Add(clExternalLink);
fDescStyles := TActiveTextRTFStyleMap.Create;
InitStyles;
@@ -215,7 +219,8 @@ procedure TRTFCategoryDoc.OutputCategoryHeading(const Category: TCategory);
fBuilder.SetFontSize(HeadingFontSize);
fBuilder.SetFontStyle([fsBold]);
// SetColour(Preferences.DBHeadingColours[Category.UserDefined]);
- SetColour(Preferences.DBHeadingColours[Category.CollectionID <> TCollectionID.__TMP__MainDBCollectionID]);
+// SetColour(Preferences.DBHeadingColours[Category.CollectionID <> TCollectionID.__TMP__MainDBCollectionID]);
+ SetColour(Preferences.GetDBHeadingColour(Category.CollectionID));
fBuilder.AddText(Category.Description);
fBuilder.EndPara;
fBuilder.EndGroup;
@@ -229,7 +234,8 @@ procedure TRTFCategoryDoc.OutputSnippetSubHeading(const Snippet: TSnippet);
fBuilder.SetFontSize(SubHeadingFontSize);
fBuilder.SetFontStyle([fsBold]);
// SetColour(Preferences.DBHeadingColours[Snippet.UserDefined]);
- SetColour(Preferences.DBHeadingColours[Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID]);
+// SetColour(Preferences.DBHeadingColours[Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID]);
+ SetColour(Preferences.GetDBHeadingColour(Snippet.CollectionID));
fBuilder.AddText(Snippet.DisplayName);
fBuilder.EndPara;
fBuilder.EndGroup;
diff --git a/Src/URTFSnippetDoc.pas b/Src/URTFSnippetDoc.pas
index 185dc8ca9..948fc31cb 100644
--- a/Src/URTFSnippetDoc.pas
+++ b/Src/URTFSnippetDoc.pas
@@ -181,8 +181,13 @@ procedure TRTFSnippetDoc.InitialiseDoc;
fBuilder.ColourTable.Add(clWarningText);
fBuilder.ColourTable.Add(clVarText);
fBuilder.ColourTable.Add(clExternalLink);
- fBuilder.ColourTable.Add(Preferences.DBHeadingColours[False]);
- fBuilder.ColourTable.Add(Preferences.DBHeadingColours[True]);
+// fBuilder.ColourTable.Add(Preferences.DBHeadingColours[False]);
+// fBuilder.ColourTable.Add(Preferences.DBHeadingColours[True]);
+ { TODO -cCollections: Replace following two statements with iteration over all
+ supported collections when support for multiple collections is added.
+ }
+ fBuilder.ColourTable.Add(Preferences.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID));
+ fBuilder.ColourTable.Add(Preferences.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID));
end;
procedure TRTFSnippetDoc.InitStyles;
@@ -443,7 +448,7 @@ procedure TRTFSnippetDoc.RenderHeading(const Heading: string;
fBuilder.SetFontStyle([fsBold]);
fBuilder.SetFontSize(HeadingFontSize);
if fUseColour then
- fBuilder.SetColour(Preferences.DBHeadingColours[ACollectionID <> TCollectionID.__TMP__MainDBCollectionID]);
+ fBuilder.SetColour(Preferences.GetDBHeadingColour(ACollectionID));
fBuilder.SetParaSpacing(TRTFParaSpacing.Create(0.0, ParaSpacing));
fBuilder.AddText(Heading);
fBuilder.EndPara;
diff --git a/Src/USnippetsChkListMgr.pas b/Src/USnippetsChkListMgr.pas
index f6e828052..d1bd0c842 100644
--- a/Src/USnippetsChkListMgr.pas
+++ b/Src/USnippetsChkListMgr.pas
@@ -203,10 +203,12 @@ procedure TSnippetsChkListMgr.DrawItem(Control: TWinControl; Index: Integer;
Assert(fCLB = Control, ClassName + '.DrawItem: Control <> fCLB');
Canvas := fCLB.Canvas;
if not (odSelected in State) then
- Canvas.Font.Color := Preferences.DBHeadingColours[
-// (fCLB.Items.Objects[Index] as TSnippet).UserDefined
- (fCLB.Items.Objects[Index] as TSnippet).CollectionID <> TCollectionID.__TMP__MainDBCollectionID
- ];
+// Canvas.Font.Color := Preferences.DBHeadingColours[
+//// (fCLB.Items.Objects[Index] as TSnippet).UserDefined
+// ];
+ Canvas.Font.Color := Preferences.GetDBHeadingColour(
+ (fCLB.Items.Objects[Index] as TSnippet).CollectionID
+ );
Canvas.TextRect(
Rect,
Rect.Left + 2,
diff --git a/Src/USnippetsTVDraw.pas b/Src/USnippetsTVDraw.pas
index be4c22bb4..2888ab4d6 100644
--- a/Src/USnippetsTVDraw.pas
+++ b/Src/USnippetsTVDraw.pas
@@ -70,7 +70,9 @@ implementation
// Delphi
Graphics,
// Project
- UColours, UPreferences;
+ DB.UCollections,
+ UColours,
+ UPreferences;
{ TSnippetsTVDraw }
@@ -118,7 +120,8 @@ procedure TSnippetsTVDraw.CustomDrawItem(Sender: TCustomTreeView;
TV.Canvas.Font.Color := clWarningText
else
TV.Canvas.Font.Color :=
- Preferences.DBHeadingColours[IsUserDefinedNode(Node)];
+// Preferences.DBHeadingColours[IsUserDefinedNode(Node)];
+ Preferences.GetDBHeadingColour(TCollectionID.__TMP__DBCollectionID(IsUserDefinedNode(Node)));
TV.Canvas.Brush.Color := TV.Color;
end;
if IsSectionHeadNode(Node) then
From 16da8d4f6899a547552343d3a35c0ec02a16a0c5 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 3 Nov 2024 16:10:45 +0000
Subject: [PATCH 029/222] Change TSnippetsTVDraw to use collection IDs
TSnippetsTVDraw used a IsUserDefinedNode abstract class overridden by
descendant classes. This has been replaced by an abstract
GetCollectionID method that gets the collection ID associated with a
tree node, or a null collection ID if the node doesn't relate to any
collection.
TSnippetsTVDraw & descendant classes were modified re the above changes.
Decisions about which CodeSnip 4 database the collections relate to have
effectively been pushed down into the preferences code in UPreferences.
Some __TMP__ method calls were removed by these changes.
Removed code was commented out.
---
Src/FmDependenciesDlg.pas | 53 ++++++++++++++++--------
Src/FrOverview.pas | 74 ++++++++++++++++++++-------------
Src/FrSelectSnippetsBase.pas | 80 ++++++++++++++++++++++++------------
Src/USnippetsTVDraw.pas | 27 ++++++++----
4 files changed, 152 insertions(+), 82 deletions(-)
diff --git a/Src/FmDependenciesDlg.pas b/Src/FmDependenciesDlg.pas
index abc91e9db..786f7d5da 100644
--- a/Src/FmDependenciesDlg.pas
+++ b/Src/FmDependenciesDlg.pas
@@ -20,6 +20,7 @@ interface
// Delphi
ComCtrls, StdCtrls, Controls, ExtCtrls, Classes, Windows, ActnList,
// Project
+ DB.UCollections,
DB.USnippet, FmGenericViewDlg, UBaseObjects, USearch, USnippetIDs,
USnippetsTVDraw;
@@ -65,12 +66,21 @@ TTVDraw = class(TSnippetsTVDraw)
strict private
fRootID: TSnippetID; // ID of snippet whose dependency nodes displayed
strict protected
- function IsUserDefinedNode(const Node: TTreeNode): Boolean;
+ /// Gets the collection ID, if any, associated with a tree
+ /// node.
+ /// TTreeNode [in] Node to be checked.
+ ///
+ /// TCollectionID. Associated collection ID. If
+ /// Node has no associated collection then a null collection ID
+ /// is returned.
+ function GetCollectionID(const Node: TTreeNode): TCollectionID;
override;
- {Checks if a node represents a user defined snippets object.
- @param Node [in] Node to be checked.
- @return True if node represents user defined object, False if not.
- }
+// function IsUserDefinedNode(const Node: TTreeNode): Boolean;
+// override;
+// {Checks if a node represents a user defined snippets object.
+// @param Node [in] Node to be checked.
+// @return True if node represents user defined object, False if not.
+// }
function IsErrorNode(const Node: TTreeNode): Boolean;
override;
{Checks if a node represents an error condition.
@@ -161,7 +171,6 @@ implementation
SysUtils,
Graphics,
// Project
- DB.UCollections,
DB.UMain,
DB.USnippetKind,
UBox,
@@ -503,6 +512,15 @@ constructor TDependenciesDlg.TTVDraw.Create(
fRootID := RootID;
end;
+function TDependenciesDlg.TTVDraw.GetCollectionID(
+ const Node: TTreeNode): TCollectionID;
+begin
+ if not Assigned(Node.Data) then
+ Result := TCollectionID.CreateNull
+ else
+ Result := TSnippet(Node.Data).CollectionID;
+end;
+
function TDependenciesDlg.TTVDraw.IsErrorNode(
const Node: TTreeNode): Boolean;
{Checks if a node represents an error condition.
@@ -513,19 +531,18 @@ function TDependenciesDlg.TTVDraw.IsErrorNode(
Result := Assigned(Node.Data) and (TSnippet(Node.Data).ID = fRootID);
end;
-function TDependenciesDlg.TTVDraw.IsUserDefinedNode(
- const Node: TTreeNode): Boolean;
- {Checks if a node represents a user defined snippets object.
- @param Node [in] Node to be checked.
- @return True if node represents user defined object, False if not.
- }
-begin
- if not Assigned(Node.Data) then
- Result := True
- else
+//function TDependenciesDlg.TTVDraw.IsUserDefinedNode(
+// const Node: TTreeNode): Boolean;
+// {Checks if a node represents a user defined snippets object.
+// @param Node [in] Node to be checked.
+// @return True if node represents user defined object, False if not.
+// }
+//begin
+// if not Assigned(Node.Data) then
+// Result := True
+// else
// Result := TSnippet(Node.Data).UserDefined;
- Result := TSnippet(Node.Data).CollectionID <> TCollectionID.__TMP__MainDBCollectionID;
-end;
+//end;
end.
diff --git a/Src/FrOverview.pas b/Src/FrOverview.pas
index 575975387..481b6351b 100644
--- a/Src/FrOverview.pas
+++ b/Src/FrOverview.pas
@@ -20,6 +20,7 @@ interface
// Delphi
ComCtrls, Controls, Classes, Windows, ExtCtrls, StdCtrls, ToolWin, Menus,
// Project
+ DB.UCollections,
DB.USnippet, FrTitled, IntfFrameMgrs, IntfNotifier, UCommandBars,
UOverviewTreeState, USnippetsTVDraw, UView, UViewItemTreeNode;
@@ -74,11 +75,20 @@ TOverviewFrame = class(TTitledFrame,
}
TTVDraw = class(TSnippetsTVDraw)
strict protected
- function IsUserDefinedNode(const Node: TTreeNode): Boolean; override;
- {Checks if a node represents a user defined snippets object.
- @param Node [in] Node to be checked.
- @return True if node represents user defined object, False if not.
- }
+ /// Gets the collection ID, if any, associated with a tree
+ /// node.
+ /// TTreeNode [in] Node to be checked.
+ ///
+ /// TCollectionID. Associated collection ID. If
+ /// Node has no associated collection then a null collection ID
+ /// is returned.
+ function GetCollectionID(const Node: TTreeNode): TCollectionID;
+ override;
+// function IsUserDefinedNode(const Node: TTreeNode): Boolean; override;
+// {Checks if a node represents a user defined snippets object.
+// @param Node [in] Node to be checked.
+// @return True if node represents user defined object, False if not.
+// }
function IsSectionHeadNode(const Node: TTreeNode): Boolean;
override;
{Checks if a node represents a section header.
@@ -238,7 +248,6 @@ implementation
SysUtils,
Messages,
// Project
- DB.UCollections,
UKeysHelper,
UOverviewTreeBuilder;
@@ -959,6 +968,23 @@ procedure TOverviewFrame.UpdateTreeState(const State: TTreeNodeAction);
{ TOverviewFrame.TTVDraw }
+function TOverviewFrame.TTVDraw.GetCollectionID(const Node: TTreeNode):
+ TCollectionID;
+var
+ ViewItem: IView; // view item represented by node
+ SnippetView: ISnippetView; // view item if node represents a snippet
+ CategoryView: ICategoryView; // view item if node represents a category
+begin
+ // TODO -cBug: Exception reported as issue #70 could have moved here
+ ViewItem := (Node as TViewItemTreeNode).ViewItem;
+ if Supports(ViewItem, ISnippetView, SnippetView) then
+ Result := SnippetView.Snippet.CollectionID
+ else if Supports(ViewItem, ICategoryView, CategoryView) then
+ Result := CategoryView.Category.CollectionID
+ else
+ Result := TCollectionID.CreateNull;
+end;
+
function TOverviewFrame.TTVDraw.IsSectionHeadNode(
const Node: TTreeNode): Boolean;
{Checks if a node represents a section header.
@@ -972,30 +998,20 @@ function TOverviewFrame.TTVDraw.IsSectionHeadNode(
Result := ViewItem.IsGrouping;
end;
-function TOverviewFrame.TTVDraw.IsUserDefinedNode(
- const Node: TTreeNode): Boolean;
- {Checks if a node represents a user defined snippets object.
- @param Node [in] Node to be checked.
- @return True if node represents user defined object, False if not.
- }
-var
- ViewItem: IView; // view item represented by node
- SnippetView: ISnippetView; // view item if node represents a snippet
- CategoryView: ICategoryView; // view item if node represents a category
- CollectionID: TCollectionID; // ID of collection node item belongs to, if any
-begin
- // TODO -cBug: Exception reported as issue #70 seems to be triggered here
- ViewItem := (Node as TViewItemTreeNode).ViewItem;
+//function TOverviewFrame.TTVDraw.IsUserDefinedNode(
+// const Node: TTreeNode): Boolean;
+// {Checks if a node represents a user defined snippets object.
+// @param Node [in] Node to be checked.
+// @return True if node represents user defined object, False if not.
+// }
+//var
+// ViewItem: IView; // view item represented by node
+// CollectionID: TCollectionID; // ID of collection node item belongs to, if any
+//begin
+// // TODO -cBug: Exception reported as issue #70 seems to be triggered here
+// ViewItem := (Node as TViewItemTreeNode).ViewItem;
// Result := ViewItem.IsUserDefined;
- if Supports(ViewItem, ISnippetView, SnippetView) then
- CollectionID := SnippetView.Snippet.CollectionID
- else if Supports(ViewItem, ICategoryView, CategoryView) then
- CollectionID := CategoryView.Category.CollectionID
- else
- CollectionID := TCollectionID.CreateNull;
- Result := (CollectionID <> TCollectionID.__TMP__MainDBCollectionID)
- and not CollectionID.IsNull;
-end;
+//end;
end.
diff --git a/Src/FrSelectSnippetsBase.pas b/Src/FrSelectSnippetsBase.pas
index 3074cf0d1..04782b63f 100644
--- a/Src/FrSelectSnippetsBase.pas
+++ b/Src/FrSelectSnippetsBase.pas
@@ -18,9 +18,16 @@ interface
uses
// Delphi
- ImgList, Controls, Classes, ComCtrls,
+ ImgList,
+ Controls,
+ Classes,
+ ComCtrls,
// Project
- DB.UCategory, DB.USnippet, FrCheckedTV, USnippetsTVDraw;
+ DB.UCollections,
+ DB.UCategory,
+ DB.USnippet,
+ FrCheckedTV,
+ USnippetsTVDraw;
type
@@ -42,14 +49,22 @@ TSelectSnippetsBaseFrame = class(TCheckedTVFrame)
}
TTVDraw = class(TSnippetsTVDraw)
strict protected
- {TODO -cCollections: Need to change following method in base class to
- get collection ID and calling code then needs to take action based
- on that instead of user-defined.}
- function IsUserDefinedNode(const Node: TTreeNode): Boolean; override;
- {Checks if a node represents a user defined snippets object.
- @param Node [in] Node to be checked.
- @return True if node represents user defined object, False if not.
- }
+ /// Gets the collection ID, if any, associated with a tree
+ /// node.
+ /// TTreeNode [in] Node to be checked.
+ ///
+ /// TCollectionID. Associated collection ID. If
+ /// Node has no associated collection then a null collection ID
+ /// is returned.
+ function GetCollectionID(const Node: TTreeNode): TCollectionID;
+ override;
+
+// function IsUserDefinedNode(const Node: TTreeNode): Boolean; override;
+// {Checks if a node represents a user defined snippets object.
+// @param Node [in] Node to be checked.
+// @return True if node represents user defined object, False if not.
+// }
+
function IsSectionHeadNode(const Node: TTreeNode): Boolean;
override;
{Checks if a node represents a section header.
@@ -124,7 +139,6 @@ implementation
SysUtils,
StdCtrls,
// Project
- DB.UCollections,
DB.UMain,
UGroups;
@@ -266,6 +280,20 @@ function TSelectSnippetsBaseFrame.SnippetFromNode(
{ TSelectSnippetsBaseFrame.TTVDraw }
+function TSelectSnippetsBaseFrame.TTVDraw.GetCollectionID(
+ const Node: TTreeNode): TCollectionID;
+var
+ SnipObj: TObject; // object referenced in Node.Data
+begin
+ SnipObj := TObject(Node.Data);
+ if SnipObj is TSnippet then
+ Result := (SnipObj as TSnippet).CollectionID
+ else if SnipObj is TCategory then
+ Result := (SnipObj as TCategory).CollectionID
+ else
+ Result := TCollectionID.CreateNull
+end;
+
function TSelectSnippetsBaseFrame.TTVDraw.IsSectionHeadNode(
const Node: TTreeNode): Boolean;
{Checks if a node represents a section header.
@@ -277,24 +305,22 @@ function TSelectSnippetsBaseFrame.TTVDraw.IsSectionHeadNode(
Result := TObject(Node.Data) is TCategory;
end;
-function TSelectSnippetsBaseFrame.TTVDraw.IsUserDefinedNode(
- const Node: TTreeNode): Boolean;
- {Checks if a node represents a user defined snippets object.
- @param Node [in] Node to be checked.
- @return True if node represents user defined object, False if not.
- }
-var
- SnipObj: TObject; // object referenced in Node.Data
-begin
- SnipObj := TObject(Node.Data);
- Result := False;
- if SnipObj is TSnippet then
+//function TSelectSnippetsBaseFrame.TTVDraw.IsUserDefinedNode(
+// const Node: TTreeNode): Boolean;
+// {Checks if a node represents a user defined snippets object.
+// @param Node [in] Node to be checked.
+// @return True if node represents user defined object, False if not.
+// }
+//var
+// SnipObj: TObject; // object referenced in Node.Data
+//begin
+// SnipObj := TObject(Node.Data);
+// Result := False;
+// if SnipObj is TSnippet then
// Result := (SnipObj as TSnippet).UserDefined
- Result := (SnipObj as TSnippet).CollectionID <> TCollectionID.__TMP__MainDBCollectionID
- else if SnipObj is TCategory then
+// else if SnipObj is TCategory then
// Result := (SnipObj as TCategory).UserDefined;
- Result := (SnipObj as TCategory).CollectionID <> TCollectionID.__TMP__MainDBCollectionID;
-end;
+//end;
end.
diff --git a/Src/USnippetsTVDraw.pas b/Src/USnippetsTVDraw.pas
index 2888ab4d6..99f1c9950 100644
--- a/Src/USnippetsTVDraw.pas
+++ b/Src/USnippetsTVDraw.pas
@@ -18,7 +18,9 @@ interface
uses
// Delphi
- ComCtrls;
+ ComCtrls,
+ // Project
+ DB.UCollections;
type
@@ -30,12 +32,22 @@ interface
}
TSnippetsTVDraw = class abstract(TObject)
strict protected
- function IsUserDefinedNode(const Node: TTreeNode): Boolean;
+ /// Gets the collection ID, if any, associated with a tree node.
+ ///
+ /// TTreeNode [in] Node to be checked.
+ /// TCollectionID. Associated collection ID. If Node
+ /// has no associated collection then a null collection ID is returned.
+ ///
+ function GetCollectionID(const Node: TTreeNode): TCollectionID;
virtual; abstract;
- {Checks if a node represents a user defined snippets object.
- @param Node [in] Node to be checked.
- @return True if node represents user defined object, False if not.
- }
+
+// function IsUserDefinedNode(const Node: TTreeNode): Boolean;
+// virtual; abstract;
+// {Checks if a node represents a user defined snippets object.
+// @param Node [in] Node to be checked.
+// @return True if node represents user defined object, False if not.
+// }
+
function IsSectionHeadNode(const Node: TTreeNode): Boolean;
virtual;
{Checks if a node represents a section header.
@@ -70,7 +82,6 @@ implementation
// Delphi
Graphics,
// Project
- DB.UCollections,
UColours,
UPreferences;
@@ -121,7 +132,7 @@ procedure TSnippetsTVDraw.CustomDrawItem(Sender: TCustomTreeView;
else
TV.Canvas.Font.Color :=
// Preferences.DBHeadingColours[IsUserDefinedNode(Node)];
- Preferences.GetDBHeadingColour(TCollectionID.__TMP__DBCollectionID(IsUserDefinedNode(Node)));
+ Preferences.GetDBHeadingColour(GetCollectionID(Node));
TV.Canvas.Brush.Color := TV.Color;
end;
if IsSectionHeadNode(Node) then
From 73a7e777de67f9d2a3820e26963329b6901c56d8 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 3 Nov 2024 17:50:43 +0000
Subject: [PATCH 030/222] Store collection IDs in FmDependenciesDlg's listbox
FmDependenciesDlg used to record TBox objects in the Objects[]
array properties of the list box that displays dependent snippets. This
was used to set the colour of a snippet depending on whether it was user
defined or not. This was changed to store a TBox object
instead of the boxed Boolean object so that collection ID can be used to
get the required snippet colour from preferences.
Eliminated a __TMP__ method call.
Removed code was commented out.
---
Src/FmDependenciesDlg.pas | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/Src/FmDependenciesDlg.pas b/Src/FmDependenciesDlg.pas
index 786f7d5da..5058a6cb4 100644
--- a/Src/FmDependenciesDlg.pas
+++ b/Src/FmDependenciesDlg.pas
@@ -414,9 +414,14 @@ procedure TDependenciesDlg.lbDependentsDrawItem(Control: TWinControl;
LB: TListBox;
Canvas: TCanvas;
- function IsUserDefinedItem: Boolean;
+// function IsUserDefinedItem: Boolean;
+// begin
+// Result := (LB.Items.Objects[Index] as TBox).Value;
+// end;
+
+ function ExtractCollectionItem: TCollectionID;
begin
- Result := (LB.Items.Objects[Index] as TBox).Value;
+ Result := (LB.Items.Objects[Index] as TBox).Value;
end;
begin
@@ -424,7 +429,7 @@ procedure TDependenciesDlg.lbDependentsDrawItem(Control: TWinControl;
Canvas := LB.Canvas;
if not (odSelected in State) then
// Canvas.Font.Color := Preferences.DBHeadingColours[IsUserDefinedItem];
- Canvas.Font.Color := Preferences.GetDBHeadingColour(TCollectionID.__TMP__DBCollectionID(IsUserDefinedItem));
+ Canvas.Font.Color := Preferences.GetDBHeadingColour(ExtractCollectionItem);
Canvas.TextRect(
Rect,
Rect.Left + 2,
@@ -461,7 +466,7 @@ procedure TDependenciesDlg.PopulateRequiredByList;
Assert(Assigned(ASnippet),
ClassName + '.PopulateRequiredByList: Snippet id not found');
lbDependents.Items.AddObject(
- ASnippet.DisplayName, TBox.Create(ASnippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID)
+ ASnippet.DisplayName, TBox.Create(ASnippet.CollectionID)
// ASnippet.DisplayName, TBox.Create(ASnippet.UserDefined)
);
end;
From 71b94e83064c317cec23b52adb1f66e5e3302b23 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 3 Nov 2024 21:22:33 +0000
Subject: [PATCH 031/222] Change FmSelectionSearchDlg to use collection IDs
FmSelectionSearchDlg has buttons to select all "user" or all "main"
snippets. The events these buttons trigger have been changed from using
Boolean UserDefined flags to passing the collection IDs of the CodeSnip
4 "main" and "user" collections.
Some __TMP__ methods were required to implement this.
Removed code was commented out.
---
Src/FmSelectionSearchDlg.pas | 56 ++++++++++++++++++++++++++----------
1 file changed, 41 insertions(+), 15 deletions(-)
diff --git a/Src/FmSelectionSearchDlg.pas b/Src/FmSelectionSearchDlg.pas
index bf0914b39..cacdc99ea 100644
--- a/Src/FmSelectionSearchDlg.pas
+++ b/Src/FmSelectionSearchDlg.pas
@@ -20,6 +20,7 @@ interface
// Delphi
Forms, StdCtrls, Controls, ExtCtrls, Classes,
// Project
+ DB.UCollections,
DB.USnippet, FmGenericOKDlg, FrCheckedTV, FrSelectSnippets,
FrSelectSnippetsBase, UBaseObjects, USearch;
@@ -61,12 +62,20 @@ TSelectionSearchDlg = class(TGenericOKDlg, INoPublicConstruct)
no snippet selected.
@param Sender [in] Not used.
}
- procedure SelectDB(const UserDefined: Boolean);
- {Selects all snippets from either main or user defined database.
- @param UserDefined [in] Flag true if user-defined snippets are to be
- selected, False if main database snippets are to be selected.
- }
+
+// procedure SelectDB(const UserDefined: Boolean);
+// {Selects all snippets from either main or user defined database.
+// @param UserDefined [in] Flag true if user-defined snippets are to be
+// selected, False if main database snippets are to be selected.
+// }
+
+ /// Selects all snippets from the given collection.
+ /// TCollectionID ID of the required
+ /// collection.
+ procedure SelectDB(const ACollectionID: TCollectionID);
+
strict protected
+
procedure ConfigForm; override;
procedure InitForm; override;
{Initialises form. Disables User Defined button if there are no user
@@ -96,7 +105,6 @@ implementation
// Delphi
SysUtils,
// Project
- DB.UCollections,
DB.UMain,
UCtrlArranger,
UQuery;
@@ -140,7 +148,8 @@ procedure TSelectionSearchDlg.btnMainDBClick(Sender: TObject);
@param Sender [in] Not used.
}
begin
- SelectDB(False);
+// SelectDB(False);
+ SelectDB(TCollectionID.__TMP__MainDBCollectionID);
end;
procedure TSelectionSearchDlg.btnOKClick(Sender: TObject);
@@ -175,7 +184,8 @@ procedure TSelectionSearchDlg.btnUserDBClick(Sender: TObject);
@param Sender [in] Not used.
}
begin
- SelectDB(True);
+// SelectDB(True);
+ SelectDB(TCollectionID.__TMP__UserDBCollectionID);
end;
procedure TSelectionSearchDlg.ConfigForm;
@@ -234,11 +244,28 @@ procedure TSelectionSearchDlg.InitForm;
);
end;
-procedure TSelectionSearchDlg.SelectDB(const UserDefined: Boolean);
- {Selects all snippets from either main or user defined database.
- @param UserDefined [in] Flag true if user-defined snippets are to be
- selected, False if main database snippets are to be selected.
- }
+//procedure TSelectionSearchDlg.SelectDB(const UserDefined: Boolean);
+// {Selects all snippets from either main or user defined database.
+// @param UserDefined [in] Flag true if user-defined snippets are to be
+// selected, False if main database snippets are to be selected.
+// }
+//var
+// Snippet: TSnippet; // references each snippet in database
+// SnippetList: TSnippetList; // list of selected snippets
+//begin
+// SnippetList := TSnippetList.Create;
+// try
+// for Snippet in Database.Snippets do
+//// if Snippet.UserDefined = UserDefined then
+// if Snippet.CollectionID = TCollectionID.__TMP__DBCollectionID(UserDefined) then
+// SnippetList.Add(Snippet);
+// frmSelect.SelectedSnippets := SnippetList;
+// finally
+// FreeAndNil(SnippetList);
+// end;
+//end;
+
+procedure TSelectionSearchDlg.SelectDB(const ACollectionID: TCollectionID);
var
Snippet: TSnippet; // references each snippet in database
SnippetList: TSnippetList; // list of selected snippets
@@ -246,8 +273,7 @@ procedure TSelectionSearchDlg.SelectDB(const UserDefined: Boolean);
SnippetList := TSnippetList.Create;
try
for Snippet in Database.Snippets do
-// if Snippet.UserDefined = UserDefined then
- if Snippet.CollectionID = TCollectionID.__TMP__DBCollectionID(UserDefined) then
+ if Snippet.CollectionID = ACollectionID then
SnippetList.Add(Snippet);
frmSelect.SelectedSnippets := SnippetList;
finally
From e837f7da429c016e85acb6ab6fd422b8ff295fcf Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 3 Nov 2024 23:20:02 +0000
Subject: [PATCH 032/222] Remove TCollectionID.__TMP__DBCollectionID
This temporary method was removed and all code that used it was modified
to call either __TMP__UserDBCollectionID or __TMP__MainDBCollectionID
from TCollectionID. The advantage of this change was to removed some
more UserDefined Boolean parameters.
---
Src/DB.UCollections.pas | 11 -----------
Src/DB.UMain.pas | 10 ++++++----
Src/Favourites.UPersist.pas | 15 ++++++++++-----
Src/FmSnippetsEditorDlg.pas | 2 +-
Src/UCodeImportMgr.pas | 2 +-
Src/USnippetIDListIOHandler.pas | 15 ++++++++++++---
Src/USnippetValidator.pas | 2 +-
Src/UUserDBMgr.pas | 2 +-
8 files changed, 32 insertions(+), 27 deletions(-)
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
index b32c1ed09..3793168f0 100644
--- a/Src/DB.UCollections.pas
+++ b/Src/DB.UCollections.pas
@@ -102,8 +102,6 @@ TCollectionID = record
{TODO -c__TMP__: remove following __TMP__*** methods}
class function __TMP__MainDBCollectionID: TCollectionID; static;
class function __TMP__UserDBCollectionID: TCollectionID; static;
- class function __TMP__DBCollectionID(const AUserDefined: Boolean): TCollectionID;
- static;
end;
ECollectionID = class(ECodeSnip);
@@ -561,15 +559,6 @@ function TCollectionID.ToHexString: string;
Result := BytesToHexString(fID);
end;
-class function TCollectionID.__TMP__DBCollectionID(
- const AUserDefined: Boolean): TCollectionID;
-begin
- if AUserDefined then
- Result := __TMP__UserDBCollectionID
- else
- Result := __TMP__MainDBCollectionID;
-end;
-
class function TCollectionID.__TMP__MainDBCollectionID: TCollectionID;
begin
Result := TCollectionID.Create(DCSC_v2_ID);
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index 3e792663d..b711690e6 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -3,7 +3,7 @@
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/
*
- * Copyright (C) 2005-2023, Peter Johnson (gravatar.com/delphidabbler).
+ * Copyright (C) 2005-2024, Peter Johnson (gravatar.com/delphidabbler).
*
* Defines a singleton object and subsidiary classes that encapsulate the
* snippets and categories in the CodeSnip database and user defined databases.
@@ -678,7 +678,7 @@ function TDatabase.AddSnippet(const SnippetName: string;
try
// Check if snippet with same name exists in user database: error if so
// if fSnippets.Find(SnippetName, True) <> nil then
- if fSnippets.Find(SnippetName, TCollectionID.__TMP__DBCollectionID(True)) <> nil then
+ if fSnippets.Find(SnippetName, TCollectionID.__TMP__UserDBCollectionID) <> nil then
raise ECodeSnip.CreateFmt(sNameExists, [SnippetName]);
Result := InternalAddSnippet(SnippetName, Data);
Query.Update;
@@ -958,7 +958,7 @@ function TDatabase.InternalAddCategory(const CatID: string;
}
begin
// Result := TCategoryEx.Create(CatID, True, Data);
- Result := TCategoryEx.Create(CatID, TCollectionID.__TMP__DBCollectionID(True), Data);
+ Result := TCategoryEx.Create(CatID, TCollectionID.__TMP__UserDBCollectionID, Data);
fCategories.Add(Result);
end;
@@ -1152,7 +1152,7 @@ function TDatabase.UpdateSnippet(const Snippet: TSnippet;
// If name has changed then new name musn't exist in user database
if not StrSameText(SnippetName, Snippet.Name) then
// if fSnippets.Find(SnippetName, True) <> nil then
- if fSnippets.Find(SnippetName, TCollectionID.__TMP__DBCollectionID(True)) <> nil then
+ if fSnippets.Find(SnippetName, TCollectionID.__TMP__UserDBCollectionID) <> nil then
raise ECodeSnip.CreateFmt(sCantRename, [Snippet.Name, SnippetName]);
// We update by deleting old snippet and inserting new one
// get lists of snippets that cross reference or depend on this snippet
@@ -1188,6 +1188,8 @@ function TDatabase.UpdateSnippet(const Snippet: TSnippet;
constructor TDatabase.TEventInfo.Create(const Kind: TDatabaseChangeEventKind;
const Info: TObject);
+
+
{Constructor. Creates an event information object.
@param Kind [in] Kind of event.
@param Info [in] Reference to further information about the event. May be
diff --git a/Src/Favourites.UPersist.pas b/Src/Favourites.UPersist.pas
index b444c5274..69c03ff24 100644
--- a/Src/Favourites.UPersist.pas
+++ b/Src/Favourites.UPersist.pas
@@ -80,8 +80,9 @@ class procedure TFavouritesPersist.Load(Favourites: TFavourites);
Line: string;
Fields: IStringList;
SnippetName: string;
- UserDef: Boolean;
+// UserDef: Boolean;
LastAccess: TDateTime;
+ CollectionID: TCollectionID;
resourcestring
sBadFormat = 'Invalid favourites file format';
begin
@@ -111,16 +112,20 @@ class procedure TFavouritesPersist.Load(Favourites: TFavourites);
if Fields.Count <> 3 then
raise EFavouritesPersist.Create(sBadFormat);
SnippetName := Fields[0];
- UserDef := True; // accept any text as true excpet "false"
+// UserDef := True; // accept any text as true excpet "false"
+ // accept any text as user collection, except "false"
+ CollectionID := TCollectionID.__TMP__UserDBCollectionID;
if StrSameText(Fields[1], 'false') then
- UserDef := False;
+ // we have "false" so main collection
+// UserDef := False;
+ CollectionID := TCollectionID.__TMP__MainDBCollectionID;
if not TryStrToDateTime(Fields[2], LastAccess) then
raise EFavouritesPersist.Create(sBadFormat);
// only add to favourites if snippet in database
// if Database.Snippets.Find(SnippetName, UserDef) <> nil then
- if Database.Snippets.Find(SnippetName, TCollectionID.__TMP__DBCollectionID(UserDef)) <> nil then
+ if Database.Snippets.Find(SnippetName, CollectionID) <> nil then
// Favourites.Add(TSnippetID.Create(SnippetName, UserDef), LastAccess);
- Favourites.Add(TSnippetID.Create(SnippetName, TCollectionID.__TMP__DBCollectionID(UserDef)), LastAccess);
+ Favourites.Add(TSnippetID.Create(SnippetName, CollectionID), LastAccess);
end;
end;
diff --git a/Src/FmSnippetsEditorDlg.pas b/Src/FmSnippetsEditorDlg.pas
index 599699e0b..ca6fea0bc 100644
--- a/Src/FmSnippetsEditorDlg.pas
+++ b/Src/FmSnippetsEditorDlg.pas
@@ -992,7 +992,7 @@ procedure TSnippetsEditorDlg.UpdateReferences;
// Snippet.UserDefined or
(Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID) or
// not Assigned(Database.Snippets.Find(Snippet.Name, True))
- not Assigned(Database.Snippets.Find(Snippet.Name, TCollectionID.__TMP__DBCollectionID(True)))
+ not Assigned(Database.Snippets.Find(Snippet.Name, TCollectionID.__TMP__UserDBCollectionID))
) then
begin
// Decide if snippet can be added to depends list: must be correct kind
diff --git a/Src/UCodeImportMgr.pas b/Src/UCodeImportMgr.pas
index 1ec3e6651..6c8f545f2 100644
--- a/Src/UCodeImportMgr.pas
+++ b/Src/UCodeImportMgr.pas
@@ -288,7 +288,7 @@ procedure TCodeImportMgr.UpdateDatabase;
AdjustDependsList(SnippetInfo.Data.Refs.Depends);
// Snippet := Database.Snippets.Find(ImportInfo.ImportAsName, True);
- Snippet := Database.Snippets.Find(ImportInfo.ImportAsName, TCollectionID.__TMP__DBCollectionID(True));
+ Snippet := Database.Snippets.Find(ImportInfo.ImportAsName, TCollectionID.__TMP__UserDBCollectionID);
if Assigned(Snippet) then
// snippet already exists: overwrite it
Editor.UpdateSnippet(Snippet, SnippetInfo.Data)
diff --git a/Src/USnippetIDListIOHandler.pas b/Src/USnippetIDListIOHandler.pas
index ac994fa35..ef527540e 100644
--- a/Src/USnippetIDListIOHandler.pas
+++ b/Src/USnippetIDListIOHandler.pas
@@ -95,6 +95,7 @@ procedure TSnippetIDListFileReader.Parse;
Name: string; // name of each snippet
UserDefStr: string; // user defined value of each snippet as string
UserDefInt: Integer; // user defined value of each snippet as integer
+ CollectionID: TCollectionID;
begin
fSnippetIDs.Clear;
if (fLines.Count <= 1) or (fLines[0] <> fWatermark) then
@@ -109,11 +110,19 @@ procedure TSnippetIDListFileReader.Parse;
raise ESnippetIDListFileReader.CreateFmt(sMissingName, [Line]);
if UserDefStr = '' then
raise ESnippetIDListFileReader.CreateFmt(sMissingUserDef, [Line]);
- if not TryStrToInt(UserDefStr, UserDefInt)
- or not (UserDefInt in [0, 1]) then
+// if not TryStrToInt(UserDefStr, UserDefInt)
+// or not (UserDefInt in [0, 1]) then
+// raise ESnippetIDListFileReader.CreateFmt(sBadUserDef, [Line]);
+ if not TryStrToInt(UserDefStr, UserDefInt) then
raise ESnippetIDListFileReader.CreateFmt(sBadUserDef, [Line]);
+ case UserDefInt of
+ 0: CollectionID := TCollectionID.__TMP__MainDBCollectionID;
+ 1: CollectionID := TCollectionID.__TMP__UserDBCollectionID;
+ else
+ raise ESnippetIDListFileReader.CreateFmt(sBadUserDef, [Line]);
+ end;
// fSnippetIDs.Add(TSnippetID.Create(Name, Boolean(UserDefInt)));
- fSnippetIDs.Add(TSnippetID.Create(Name, TCollectionID.__TMP__DBCollectionID(Boolean(UserDefInt))));
+ fSnippetIDs.Add(TSnippetID.Create(Name, CollectionID));
end;
end;
diff --git a/Src/USnippetValidator.pas b/Src/USnippetValidator.pas
index 23a21ae67..b5204b771 100644
--- a/Src/USnippetValidator.pas
+++ b/Src/USnippetValidator.pas
@@ -374,7 +374,7 @@ class function TSnippetValidator.ValidateName(const Name: string;
ErrorMsg := Format(sErrBadName, [TrimmedName])
else if CheckForUniqueness and
// (Database.Snippets.Find(TrimmedName, True) <> nil) then
- (Database.Snippets.Find(TrimmedName, TCollectionID.__TMP__DBCollectionID(True)) <> nil) then
+ (Database.Snippets.Find(TrimmedName, TCollectionID.__TMP__UserDBCollectionID) <> nil) then
ErrorMsg := Format(sErrDupName, [TrimmedName])
else
Result := True;
diff --git a/Src/UUserDBMgr.pas b/Src/UUserDBMgr.pas
index 8ab42253a..88fda6c5c 100644
--- a/Src/UUserDBMgr.pas
+++ b/Src/UUserDBMgr.pas
@@ -470,7 +470,7 @@ class procedure TUserDBMgr.EditSnippet(const SnippetName: string);
Snippet: TSnippet; // reference to snippet to be edited
begin
// Snippet := Database.Snippets.Find(SnippetName, True);
- Snippet := Database.Snippets.Find(SnippetName, TCollectionID.__TMP__DBCollectionID(True));
+ Snippet := Database.Snippets.Find(SnippetName, TCollectionID.__TMP__UserDBCollectionID);
if not Assigned(Snippet) then
raise EBug.Create(ClassName + '.EditSnippet: Snippet not in user database');
TSnippetsEditorDlg.EditSnippet(nil, Snippet);
From b007481045c75a05444f211060d77307783dccf5 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 4 Nov 2024 00:36:03 +0000
Subject: [PATCH 033/222] Remove commented out code
A lot of redundant commented out code from numerous units was deleted.
---
Src/DB.UCategory.pas | 27 -------
Src/DB.UDatabaseIO.pas | 60 ----------------
Src/DB.UMain.pas | 78 --------------------
Src/DB.USnippet.pas | 121 +-------------------------------
Src/ExternalObj.ridl | 12 +---
Src/Favourites.UPersist.pas | 6 --
Src/FmCodeExportDlg.pas | 1 -
Src/FmDependenciesDlg.pas | 28 +-------
Src/FmDuplicateSnippetDlg.pas | 1 -
Src/FmFavouritesDlg.pas | 6 +-
Src/FmFindXRefsDlg.pas | 1 -
Src/FmMain.pas | 1 -
Src/FmSelectionSearchDlg.pas | 30 --------
Src/FmSnippetsEditorDlg.pas | 5 +-
Src/FmTestCompileDlg.pas | 1 -
Src/FrDetailView.pas | 4 --
Src/FrDisplayPrefs.pas | 12 ----
Src/FrOverview.pas | 21 +-----
Src/FrSelectSnippetsBase.pas | 24 +------
Src/FrSelectUserSnippets.pas | 2 -
Src/IntfNotifier.pas | 10 ---
Src/UCodeImportExport.pas | 3 -
Src/UCodeImportMgr.pas | 4 --
Src/UCodeShareMgr.pas | 2 -
Src/UDetailPageHTML.pas | 7 --
Src/UNotifier.pas | 23 ------
Src/UPreferences.pas | 113 -----------------------------
Src/URTFCategoryDoc.pas | 6 --
Src/URTFSnippetDoc.pas | 22 ------
Src/USaveUnitMgr.pas | 1 -
Src/USnippetAction.pas | 6 --
Src/USnippetDoc.pas | 9 ---
Src/USnippetIDListIOHandler.pas | 7 --
Src/USnippetIDs.pas | 17 -----
Src/USnippetSourceGen.pas | 2 -
Src/USnippetValidator.pas | 1 -
Src/USnippetsChkListMgr.pas | 3 -
Src/USnippetsTVDraw.pas | 8 ---
Src/UStatusBarMgr.pas | 1 -
Src/UTextSnippetDoc.pas | 13 ----
Src/UUserDBMgr.pas | 5 --
Src/UView.pas | 41 -----------
Src/UWBExternal.pas | 22 ------
43 files changed, 8 insertions(+), 759 deletions(-)
diff --git a/Src/DB.UCategory.pas b/Src/DB.UCategory.pas
index 6aeeb9f8f..11415a8f6 100644
--- a/Src/DB.UCategory.pas
+++ b/Src/DB.UCategory.pas
@@ -52,7 +52,6 @@ TCategory = class(TObject)
fSnippets: TSnippetList; // List of snippet objects in category
fID: string; // Category id
fDescription: string; // Category description
-// fUserDefined: Boolean; // Whether this is a user-defined snippet
fCollectionID: TCollectionID;
procedure SetCollectionID(const AValue: TCollectionID);
function CompareIDTo(const Cat: TCategory): Integer;
@@ -73,12 +72,6 @@ TCategory = class(TObject)
constructor Create(const CatID: string; const ACollectionID: TCollectionID;
const Data: TCategoryData);
-// constructor Create(const CatID: string; const UserDefined: Boolean;
-// const Data: TCategoryData); overload;
-// {Class contructor. Sets up category object with given property values.
-// @param Data [in] Contains required property values.
-// }
-
destructor Destroy; override;
{Destructor. Tears down object.
}
@@ -107,8 +100,6 @@ TCategory = class(TObject)
{Description of category}
property Snippets: TSnippetList read fSnippets;
{List of snippets in this category}
-// property UserDefined: Boolean read fUserDefined;
-// {Flag that indicates if this is a user defined category}
/// ID of collection that defines this category.
/// ID must not be null.
property CollectionID: TCollectionID
@@ -212,8 +203,6 @@ function TCategory.CanDelete: Boolean;
@return True if deletion allowed, False if not.
}
begin
-// Result := fUserDefined and fSnippets.IsEmpty
-// and not TReservedCategories.IsReserved(Self);
Result := (fCollectionID <> TCollectionID.__TMP__MainDBCollectionID)
and fSnippets.IsEmpty
and not TReservedCategories.IsReserved(Self);
@@ -258,22 +247,6 @@ constructor TCategory.Create(const CatID: string;
fSnippets := TSnippetListEx.Create;
end;
-//constructor TCategory.Create(const CatID: string; const UserDefined: Boolean;
-// const Data: TCategoryData);
-// {Class contructor. Sets up category object with given property values.
-// @param Data [in] Contains required property values.
-// }
-//begin
-// Assert(ClassType <> TCategory,
-// ClassName + '.Create: must only be called from descendants.');
-// inherited Create;
-// fID := CatID;
-// fDescription := Data.Desc;
-// fUserDefined := UserDefined;
-// // Create list to store snippets in category
-// fSnippets := TSnippetListEx.Create;
-//end;
-
destructor TCategory.Destroy;
{Destructor. Tears down object.
}
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index 296ee75ef..b94509019 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -217,15 +217,6 @@ TMainDatabaseLoader = class(TDatabaseLoader, IDatabaseLoader)
@return Reference to required snippet object or nil if snippet is not
found.
}
-// function IsNativeSnippet(const Snippet: TSnippet): Boolean; override;
-// {Checks if a snippet is native (belongs) to the main database.
-// @param Snippet [in] Snippet to test.
-// @return True if snippet is native, False if not.
-// }
-// function IsUserDatabase: Boolean; override;
-// {Checks if the database is the user database.
-// @return False - this is not the user database.
-// }
/// Returns the ID of the collection being loaded into the
/// database.
@@ -257,15 +248,6 @@ TUserDatabaseLoader = class(TDatabaseLoader, IDatabaseLoader)
@return Reference to required snippet object or nil if snippet is not
found.
}
-// function IsNativeSnippet(const Snippet: TSnippet): Boolean; override;
-// {Checks if a snippet is native (belongs) to the user database.
-// @param Snippet [in] Snippet to test.
-// @return True if snippet is native, False if not.
-// }
-// function IsUserDatabase: Boolean; override;
-// {Checks if the database is the user database.
-// @return True - this is the user database.
-// }
/// Returns the ID of the collection being loaded into the
/// database.
@@ -499,14 +481,10 @@ procedure TDatabaseLoader.LoadSnippets(const Cat: TCategory);
for SnippetName in SnippetNames do
begin
// Check if snippet exists in current database and add it to list if not
-// Snippet := fSnipList.Find(SnippetName, IsUserDatabase);
Snippet := fSnipList.Find(SnippetName, CollectionID);
if not Assigned(Snippet) then
begin
fReader.GetSnippetProps(SnippetName, SnippetProps);
-// Snippet := fFactory.CreateSnippet(
-// SnippetName, IsUserDatabase, SnippetProps
-// );
Snippet := fFactory.CreateSnippet(
SnippetName, CollectionID, SnippetProps
);
@@ -555,27 +533,9 @@ function TMainDatabaseLoader.FindSnippet(const SnippetName: string;
}
begin
// We only search main database
-// Result := SnipList.Find(SnippetName, False);
Result := SnipList.Find(SnippetName, CollectionID);
end;
-//function TMainDatabaseLoader.IsNativeSnippet(const Snippet: TSnippet): Boolean;
-// {Checks if a snippet is native (belongs) to the main database.
-// @param Snippet [in] Snippet to test.
-// @return True if snippet is native, False if not.
-// }
-//begin
-// Result := not Snippet.UserDefined;
-//end;
-
-//function TMainDatabaseLoader.IsUserDatabase: Boolean;
-// {Checks if the database is the user database.
-// @return False - this is not the user database.
-// }
-//begin
-// Result := False;
-//end;
-
{ TUserDatabaseLoader }
function TUserDatabaseLoader.CollectionID: TCollectionID;
@@ -614,31 +574,12 @@ function TUserDatabaseLoader.FindSnippet(const SnippetName: string;
}
begin
// Search in user database
-// Result := SnipList.Find(SnippetName, True);
Result := SnipList.Find(SnippetName, CollectionID);
if not Assigned(Result) then
// Not in user database: try main database
-// Result := SnipList.Find(SnippetName, False);
Result := SnipList.Find(SnippetName, TCollectionID.__TMP__MainDBCollectionID);
end;
-//function TUserDatabaseLoader.IsNativeSnippet(const Snippet: TSnippet): Boolean;
-// {Checks if a snippet is native (belongs) to the user database.
-// @param Snippet [in] Snippet to test.
-// @return True if snippet is native, False if not.
-// }
-//begin
-// Result := Snippet.UserDefined;
-//end;
-
-//function TUserDatabaseLoader.IsUserDatabase: Boolean;
-// {Checks if the database is the user database.
-// @return True - this is the user database.
-// }
-//begin
-// Result := True;
-//end;
-
procedure TUserDatabaseLoader.LoadCategories;
{Loads all categories from storage and adds user and imports categories if not
present.
@@ -734,7 +675,6 @@ procedure TDatabaseWriter.WriteSnippets;
for Snippet in fSnipList do
begin
// Only write user-defined snippets
-// if Snippet.UserDefined then
if Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
begin
// Get and write a snippet's properties
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index b711690e6..f60ef54ae 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -113,23 +113,6 @@ interface
}
IDBDataItemFactory = interface(IInterface)
['{C6DD85BD-E649-4A90-961C-4011D2714B3E}']
-// function CreateCategory(const CatID: string; const UserDefined: Boolean;
-// const Data: TCategoryData): TCategory;
-// {Creates a new category object.
-// @param CatID [in] ID of new category. Must be unique.
-// @param UserDefined [in] True if category is user defined, False if not.
-// @param Data [in] Record describing category's properties.
-// @return Instance of new category object.
-// }
-// function CreateSnippet(const Name: string; const UserDefined: Boolean;
-// const Props: TSnippetData): TSnippet;
-// {Creates a new snippet object.
-// @param Name [in] Name of new snippet. Must not exist in database
-// specified by UserDefined parameter.
-// @param UserDefined [in] True if snippet is user defined, False if not.
-// @param Props [in] Record describing snippet's properties.
-// @return Instance of new snippet with no references.
-// }
/// Creates a new category object.
/// string [in] ID of new category. Must be
@@ -324,24 +307,6 @@ implementation
}
TDBDataItemFactory = class(TInterfacedObject, IDBDataItemFactory)
public
-// function CreateCategory(const CatID: string; const UserDefined: Boolean;
-// const Data: TCategoryData): TCategory;
-// {Creates a new category object.
-// @param CatID [in] ID of new category. Must be unique.
-// @param UserDefined [in] True if category is user defined, False if not.
-// @param Data [in] Record describing category's properties.
-// @return Instance of new category object.
-// }
-// function CreateSnippet(const Name: string; const UserDefined: Boolean;
-// const Props: TSnippetData): TSnippet;
-// {Creates a new snippet object.
-// @param Name [in] Name of new snippet. Must not exist in database
-// specified by UserDefined parameter.
-// @param UserDefined [in] True if snippet is user defined, False if not.
-// @param Props [in] Record describing snippet's properties.
-// @return Instance of new snippet with no references.
-// }
-
/// Creates a new category object.
/// string [in] ID of new category. Must be
/// unique.
@@ -677,7 +642,6 @@ function TDatabase.AddSnippet(const SnippetName: string;
TriggerEvent(evChangeBegin);
try
// Check if snippet with same name exists in user database: error if so
-// if fSnippets.Find(SnippetName, True) <> nil then
if fSnippets.Find(SnippetName, TCollectionID.__TMP__UserDBCollectionID) <> nil then
raise ECodeSnip.CreateFmt(sNameExists, [SnippetName]);
Result := InternalAddSnippet(SnippetName, Data);
@@ -721,8 +685,6 @@ function TDatabase.CreateTempSnippet(const Snippet: TSnippet): TSnippet;
Assert(Snippet is TSnippetEx,
ClassName + '.CreateTempSnippet: Snippet is a TSnippetEx');
Data := (Snippet as TSnippetEx).GetEditData;
-// Result := TTempSnippet.Create(
-// Snippet.Name, Snippet.UserDefined, (Snippet as TSnippetEx).GetProps);
Result := TTempSnippet.Create(
Snippet.Name, Snippet.CollectionID, (Snippet as TSnippetEx).GetProps);
(Result as TTempSnippet).UpdateRefs(
@@ -740,7 +702,6 @@ function TDatabase.CreateTempSnippet(const SnippetName: string;
@return Reference to new snippet.
}
begin
-// Result := TTempSnippet.Create(SnippetName, True, Data.Props);
Result := TTempSnippet.Create(SnippetName, TCollectionID.__TMP__UserDBCollectionID, Data.Props);
(Result as TTempSnippet).UpdateRefs(Data.Refs, fSnippets);
end;
@@ -776,8 +737,6 @@ procedure TDatabase.DeleteSnippet(const Snippet: TSnippet);
Referrer: TSnippet; // loops thru snippets that cross references Snippet
Referrers: TSnippetList; // list of referencing snippets
begin
-// Assert(Snippet.UserDefined,
-// ClassName + '.DeleteSnippet: Snippet is not user-defined');
Assert(Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID,
ClassName + '.DeleteSnippet: Snippet is not user-defined');
Assert(fSnippets.Contains(Snippet),
@@ -878,8 +837,6 @@ function TDatabase.GetEditableCategoryInfo(
@return Required data.
}
begin
-// Assert(not Assigned(Category) or Category.UserDefined,
-// ClassName + '.GetEditableCategoryInfo: Category is not user-defined');
Assert(not Assigned(Category) or (Category.CollectionID <> TCollectionID.__TMP__MainDBCollectionID),
ClassName + '.GetEditableCategoryInfo: Category is not user-defined');
if Assigned(Category) then
@@ -899,8 +856,6 @@ function TDatabase.GetEditableSnippetInfo(
begin
Assert(not Assigned(Snippet) or (Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID),
ClassName + '.GetEditableSnippetInfo: Snippet is not user-defined');
-// Assert(not Assigned(Snippet) or Snippet.UserDefined,
-// ClassName + '.GetEditableSnippetInfo: Snippet is not user-defined');
if Assigned(Snippet) then
Result := (Snippet as TSnippetEx).GetEditData
else
@@ -957,7 +912,6 @@ function TDatabase.InternalAddCategory(const CatID: string;
@return Reference to new category object.
}
begin
-// Result := TCategoryEx.Create(CatID, True, Data);
Result := TCategoryEx.Create(CatID, TCollectionID.__TMP__UserDBCollectionID, Data);
fCategories.Add(Result);
end;
@@ -978,7 +932,6 @@ function TDatabase.InternalAddSnippet(const SnippetName: string;
sCatNotFound = 'Category "%0:s" referenced by new snippet named "%1:s" does '
+ 'not exist';
begin
-// Result := TSnippetEx.Create(SnippetName, True, Data.Props);
Result := TSnippetEx.Create(SnippetName, TCollectionID.__TMP__UserDBCollectionID, Data.Props);
(Result as TSnippetEx).UpdateRefs(Data.Refs, fSnippets);
Cat := fCategories.Find(Result.Category);
@@ -1137,8 +1090,6 @@ function TDatabase.UpdateSnippet(const Snippet: TSnippet;
Result := Snippet; // keeps compiler happy
Assert(Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID,
ClassName + '.UpdateSnippet: Snippet is not user-defined');
-// Assert(Snippet.UserDefined,
-// ClassName + '.UpdateSnippet: Snippet is not user-defined');
Referrers := nil;
Dependents := nil;
TriggerEvent(evChangeBegin);
@@ -1151,7 +1102,6 @@ function TDatabase.UpdateSnippet(const Snippet: TSnippet;
SnippetName := Snippet.Name;
// If name has changed then new name musn't exist in user database
if not StrSameText(SnippetName, Snippet.Name) then
-// if fSnippets.Find(SnippetName, True) <> nil then
if fSnippets.Find(SnippetName, TCollectionID.__TMP__UserDBCollectionID) <> nil then
raise ECodeSnip.CreateFmt(sCantRename, [Snippet.Name, SnippetName]);
// We update by deleting old snippet and inserting new one
@@ -1188,8 +1138,6 @@ function TDatabase.UpdateSnippet(const Snippet: TSnippet;
constructor TDatabase.TEventInfo.Create(const Kind: TDatabaseChangeEventKind;
const Info: TObject);
-
-
{Constructor. Creates an event information object.
@param Kind [in] Kind of event.
@param Info [in] Reference to further information about the event. May be
@@ -1219,31 +1167,6 @@ function TDatabase.TEventInfo.GetKind: TDatabaseChangeEventKind;
{ TDBDataItemFactory }
-//function TDBDataItemFactory.CreateCategory(const CatID: string;
-// const UserDefined: Boolean; const Data: TCategoryData): TCategory;
-// {Creates a new category object.
-// @param CatID [in] ID of new category. Must be unique.
-// @param UserDefined [in] True if category is user defined, False if not.
-// @param Data [in] Record describing category's properties.
-// @return Instance of new category object.
-// }
-//begin
-// Result := TCategoryEx.Create(CatID, TCollectionID.__TMP__DBCollectionID(UserDefined), Data);
-//end;
-//
-//function TDBDataItemFactory.CreateSnippet(const Name: string;
-// const UserDefined: Boolean; const Props: TSnippetData): TSnippet;
-// {Creates a new snippet object.
-// @param Name [in] Name of new snippet. Must not exist in database specified
-// by UserDefined parameter.
-// @param UserDefined [in] True if snippet is user defined, False if not.
-// @param Props [in] Record describing snippet's properties.
-// @return Instance of new snippet with no references.
-// }
-//begin
-// Result := TSnippetEx.Create(Name, UserDefined, Props);
-//end;
-
function TDBDataItemFactory.CreateCategory(const CatID: string;
const ACollectionID: TCollectionID; const Data: TCategoryData): TCategory;
begin
@@ -1291,7 +1214,6 @@ function TUserDataProvider.GetCategorySnippets(
begin
Result := TIStringList.Create;
for Snippet in Cat.Snippets do
-// if Snippet.UserDefined then
if Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
Result.Add(Snippet.Name);
end;
diff --git a/Src/DB.USnippet.pas b/Src/DB.USnippet.pas
index 0eacce540..7032f436d 100644
--- a/Src/DB.USnippet.pas
+++ b/Src/DB.USnippet.pas
@@ -126,7 +126,6 @@ type TDisplayNameComparer = class(TComparer)
fXRef: TSnippetList; // List of cross-referenced snippets
fExtra: IActiveText; // Further information for snippet
fCompatibility: TCompileResults; // Snippet's compiler compatibility
-// fUserDefined: Boolean; // If this snippet is user-defined
fCollectionID: TCollectionID; // Snippet's collection ID
fHiliteSource: Boolean; // If source is syntax highlighted
fTestInfo: TSnippetTestInfo; // Level of testing of snippet
@@ -152,13 +151,6 @@ type TDisplayNameComparer = class(TComparer)
@return Required field content.
}
public
-// constructor Create(const Name: string; const UserDefined: Boolean;
-// const Props: TSnippetData);
-// {Class contructor. Sets up snippet object with given property values.
-// @param Name [in] Name of snippet.
-// @param UserDefined [in] Indicates if this is a user defined snippet.
-// @param Props [in] Values of various snippet properties.
-// }
/// Object constructor. Sets up snippet object with given property
/// values belonging to a specified collection.
@@ -211,8 +203,7 @@ type TDisplayNameComparer = class(TComparer)
{List of any other snippet in database on which this snippet depends}
property XRef: TSnippetList read fXRef;
{List of cross referenced snippets in database}
-// property UserDefined: Boolean read fUserDefined;;
- {Flag that indicates if this is a user defined snippet}
+ /// ID of collection to which the snippet belongs.
property CollectionID: TCollectionID read fCollectionID;
end;
@@ -269,16 +260,6 @@ TSnippetList = class(TObject)
@param Idx [in] Index of required snippet in list.
@return Snippet at specified index in list.
}
-// function Find(const SnippetName: string;
-// const UserDefined: Boolean; out Index: Integer): Boolean; overload;
-// {Finds a snippet in the list that has a specified name and user defined
-// property. Uses a binary search.
-// @param SnippetName [in] Name of snippet to be found.
-// @param UserDefined [in] Whether required snippet is user defined or not.
-// @param Index [out] Index of required snippet in list. Valid only if
-// method returns True.
-// @return True if snippet found, False if not.
-// }
/// Finds a snippet in the list with whose name and collection ID
/// match.
@@ -324,14 +305,6 @@ TSnippetList = class(TObject)
@param SnippetID [in] ID of snippet to find.
@return Reference to required snippet or nil if not found.
}
-// function Find(const SnippetName: string;
-// const UserDefined: Boolean): TSnippet; overload;
-// {Finds a named snippet in list with a matching user defined property.
-// @param SnippetName [in] Name of required snippet.
-// @param UserDefined [in] Flag that determines if we are looking for a
-// user defined snippet or one from main database.
-// @return Reference to required snippet or nil if not found.
-// }
/// Finds a snippet in the list with whose name and collection ID
/// match.
@@ -361,13 +334,6 @@ TSnippetList = class(TObject)
{Gets an intialised snippet list enumerator.
@return Required enumerator.
}
-// function Count(const UserDefined: Boolean): Integer; overload;
-// {Counts number of snippets in list that are either from or not from user
-// defined database.
-// @param UserDefined [in] Flags whether to count snippets in user database
-// (True) or in main database (False).
-// @return Number of snippets in specified database.
-// }
/// Counts number of snippets in list that belong to a specified
/// collection.
@@ -384,13 +350,6 @@ TSnippetList = class(TObject)
{Checks if list is empty.
@return True if list is empty, False otehrwise.
}
-// function IsEmpty(const UserDefined: Boolean): Boolean; overload; {__TMP__ inline;}
-// {Checks if sub-set of list from either from or not from use defined
-// database is empty.
-// @param UserDefined [in] Flags whether to check for snippets in user
-// database (True) or in main database (False).
-// @return True if required subset is empty, False if not empty.
-// }
/// Checks if the sub-set of snippets in the list belonging to a
/// specified collection is empty.
@@ -455,17 +414,6 @@ function TSnippet.CanCompile: Boolean;
Result := Kind <> skFreeform;
end;
-//constructor TSnippet.Create(const Name: string; const UserDefined: Boolean;
-// const Props: TSnippetData);
-// {Class contructor. Sets up snippet object with given property values.
-// @param Name [in] Name of snippet.
-// @param UserDefined [in] Indicates if this is a user defined snippet.
-// @param Props [in] Values of various snippet properties.
-// }
-//begin
-// Create(Name, TCollectionID.__TMP__DBCollectionID(UserDefined), Props);
-//end;
-
constructor TSnippet.Create(const Name: string;
const ACollectionID: TCollectionID; const Props: TSnippetData);
begin
@@ -713,23 +661,6 @@ function TSnippetList.ContainsKinds(const Kinds: TSnippetKinds): Boolean;
end;
end;
-//function TSnippetList.Count(const UserDefined: Boolean): Integer;
-// {Counts number of snippets in list that are either from or not from user
-// defined database.
-// @param UserDefined [in] Flags whether to count snippets in user database
-// (True) or in main database (False).
-// @return Number of snippets in specified database.
-// }
-////var
-//// Snippet: TSnippet; // refers to all snippets in list
-//begin
-// Result := Count(TCollectionID.__TMP__DBCollectionID(UserDefined));
-//// Result := 0;
-//// for Snippet in Self do
-//// if Snippet.UserDefined = UserDefined then
-//// Inc(Result);
-//end;
-
function TSnippetList.Count(const ACollectionID: TCollectionID): Integer;
var
Snippet: TSnippet; // refers to all snippets in list
@@ -775,31 +706,6 @@ destructor TSnippetList.Destroy;
inherited;
end;
-//function TSnippetList.Find(const SnippetName: string;
-// const UserDefined: Boolean; out Index: Integer): Boolean;
-// {Finds a snippet in the list that has a specified name and user defined
-// property. Uses a binary search.
-// @param SnippetName [in] Name of snippet to be found.
-// @param UserDefined [in] Whether required snippet is user defined or not.
-// @param Index [out] Index of required snippet in list. Valid only if
-// method returns True.
-// @return True if snippet found, False if not.
-// }
-//var
-// TempSnippet: TSnippet; // temp snippet used to perform search
-// NulData: TSnippetData; // nul data used to create snippet
-//begin
-// // We need a temporary snippet object in order to perform binary search using
-// // object list's built in search
-// NulData.Init;
-// TempSnippet := TTempSnippet.Create(SnippetName, UserDefined, NulData);
-// try
-// Result := fList.Find(TempSnippet, Index);
-// finally
-// TempSnippet.Free;
-// end;
-//end;
-
function TSnippetList.Find(const SnippetName: string;
const ACollectionID: TCollectionID; out Index: Integer): Boolean;
var
@@ -817,24 +723,6 @@ function TSnippetList.Find(const SnippetName: string;
end;
end;
-//function TSnippetList.Find(const SnippetName: string;
-// const UserDefined: Boolean): TSnippet;
-// {Finds a named snippet in list with a matching user defined property.
-// @param SnippetName [in] Name of required snippet.
-// @param UserDefined [in] Flag that determines if we are looking for a
-// user defined snippet or one from main database.
-// @return Reference to required snippet or nil if not found.
-// }
-//var
-// Idx: Integer; // index of snippet name in list
-//begin
-// if Find(SnippetName, TCollectionID.__TMP__DBCollectionID(UserDefined), Idx) then
-//// if Find(SnippetName, UserDefined, Idx) then
-// Result := Items[Idx]
-// else
-// Result := nil;
-//end;
-
function TSnippetList.Find(const SnippetName: string;
const ACollectionID: TCollectionID): TSnippet;
var
@@ -852,7 +740,6 @@ function TSnippetList.Find(const SnippetID: TSnippetID): TSnippet;
@return Reference to required snippet or nil if not found.
}
begin
-// Result := Find(SnippetID.Name, SnippetID.UserDefined);
Result := Find(SnippetID.Name, SnippetID.CollectionID);
end;
@@ -881,12 +768,6 @@ function TSnippetList.IsEmpty: Boolean;
Result := Count = 0;
end;
-//function TSnippetList.IsEmpty(const UserDefined: Boolean): Boolean;
-//begin
-//// Result := Count(UserDefined) = 0;
-// Result := Count(TCollectionID.__TMP__DBCollectionID(UserDefined)) = 0;
-//end;
-
function TSnippetList.IsEmpty(const ACollectionID: TCollectionID): Boolean;
begin
Result := Count(ACollectionID) = 0;
diff --git a/Src/ExternalObj.ridl b/Src/ExternalObj.ridl
index 76c8ae4f6..47a60868b 100644
--- a/Src/ExternalObj.ridl
+++ b/Src/ExternalObj.ridl
@@ -16,8 +16,8 @@
helpstring("CodeSnip DOM External Object Extender Type Library"),
custom(DE77BA64-517C-11D1-A2DA-0000F8773CE9, 117441012),
custom(DE77BA63-517C-11D1-A2DA-0000F8773CE9, 1219706147)
-
]
+
library ExternalObj
{
@@ -44,16 +44,6 @@ library ExternalObj
[id(0x00000065)]
HRESULT _stdcall UpdateDbase(void);
- /* - TODO: Delete following commented out method
- * Display named snippet.
- * @param SnippetName [in] Name of snippet to display.
- * @param UserDefined [in] Whether snippet is user defined.
- *
- [id(0x00000066)]
- HRESULT _stdcall DisplaySnippet([in] BSTR SnippetName,
- [in] VARIANT_BOOL UserDefined, [in] VARIANT_BOOL NewTab);
- */
-
/*
* Display named snippet.
* @param SnippetName [in] Name of snippet to display.
diff --git a/Src/Favourites.UPersist.pas b/Src/Favourites.UPersist.pas
index 69c03ff24..9fb4937dc 100644
--- a/Src/Favourites.UPersist.pas
+++ b/Src/Favourites.UPersist.pas
@@ -80,7 +80,6 @@ class procedure TFavouritesPersist.Load(Favourites: TFavourites);
Line: string;
Fields: IStringList;
SnippetName: string;
-// UserDef: Boolean;
LastAccess: TDateTime;
CollectionID: TCollectionID;
resourcestring
@@ -112,19 +111,15 @@ class procedure TFavouritesPersist.Load(Favourites: TFavourites);
if Fields.Count <> 3 then
raise EFavouritesPersist.Create(sBadFormat);
SnippetName := Fields[0];
-// UserDef := True; // accept any text as true excpet "false"
// accept any text as user collection, except "false"
CollectionID := TCollectionID.__TMP__UserDBCollectionID;
if StrSameText(Fields[1], 'false') then
// we have "false" so main collection
-// UserDef := False;
CollectionID := TCollectionID.__TMP__MainDBCollectionID;
if not TryStrToDateTime(Fields[2], LastAccess) then
raise EFavouritesPersist.Create(sBadFormat);
// only add to favourites if snippet in database
-// if Database.Snippets.Find(SnippetName, UserDef) <> nil then
if Database.Snippets.Find(SnippetName, CollectionID) <> nil then
-// Favourites.Add(TSnippetID.Create(SnippetName, UserDef), LastAccess);
Favourites.Add(TSnippetID.Create(SnippetName, CollectionID), LastAccess);
end;
end;
@@ -141,7 +136,6 @@ class procedure TFavouritesPersist.Save(Favourites: TFavourites);
begin
SB.Append(Fav.SnippetID.Name);
SB.Append(TAB);
-// SB.Append(BoolToStr(Fav.SnippetID.UserDefined, True));
SB.Append(BoolToStr(Fav.SnippetID.CollectionID <> TCollectionID.__TMP__MainDBCollectionID, True));
SB.Append(TAB);
SB.Append(DateTimeToStr(Fav.LastAccessed));
diff --git a/Src/FmCodeExportDlg.pas b/Src/FmCodeExportDlg.pas
index 48ffc385f..948f109a4 100644
--- a/Src/FmCodeExportDlg.pas
+++ b/Src/FmCodeExportDlg.pas
@@ -211,7 +211,6 @@ procedure TCodeExportDlg.SelectSnippet(const Snippet: TSnippet);
List: TSnippetList; // list containing only the provided snippet
begin
if not Assigned(Snippet) or (Snippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID) then
-// if not Assigned(Snippet) or not Snippet.UserDefined then
// Snippet is nil or not user-defined: select nothing
frmSnippets.SelectedSnippets := nil
else
diff --git a/Src/FmDependenciesDlg.pas b/Src/FmDependenciesDlg.pas
index 5058a6cb4..00742823a 100644
--- a/Src/FmDependenciesDlg.pas
+++ b/Src/FmDependenciesDlg.pas
@@ -66,6 +66,7 @@ TTVDraw = class(TSnippetsTVDraw)
strict private
fRootID: TSnippetID; // ID of snippet whose dependency nodes displayed
strict protected
+
/// Gets the collection ID, if any, associated with a tree
/// node.
/// TTreeNode [in] Node to be checked.
@@ -75,12 +76,7 @@ TTVDraw = class(TSnippetsTVDraw)
/// is returned.
function GetCollectionID(const Node: TTreeNode): TCollectionID;
override;
-// function IsUserDefinedNode(const Node: TTreeNode): Boolean;
-// override;
-// {Checks if a node represents a user defined snippets object.
-// @param Node [in] Node to be checked.
-// @return True if node represents user defined object, False if not.
-// }
+
function IsErrorNode(const Node: TTreeNode): Boolean;
override;
{Checks if a node represents an error condition.
@@ -414,11 +410,6 @@ procedure TDependenciesDlg.lbDependentsDrawItem(Control: TWinControl;
LB: TListBox;
Canvas: TCanvas;
-// function IsUserDefinedItem: Boolean;
-// begin
-// Result := (LB.Items.Objects[Index] as TBox).Value;
-// end;
-
function ExtractCollectionItem: TCollectionID;
begin
Result := (LB.Items.Objects[Index] as TBox).Value;
@@ -428,7 +419,6 @@ procedure TDependenciesDlg.lbDependentsDrawItem(Control: TWinControl;
LB := Control as TListBox;
Canvas := LB.Canvas;
if not (odSelected in State) then
-// Canvas.Font.Color := Preferences.DBHeadingColours[IsUserDefinedItem];
Canvas.Font.Color := Preferences.GetDBHeadingColour(ExtractCollectionItem);
Canvas.TextRect(
Rect,
@@ -467,7 +457,6 @@ procedure TDependenciesDlg.PopulateRequiredByList;
ClassName + '.PopulateRequiredByList: Snippet id not found');
lbDependents.Items.AddObject(
ASnippet.DisplayName, TBox.Create(ASnippet.CollectionID)
-// ASnippet.DisplayName, TBox.Create(ASnippet.UserDefined)
);
end;
end;
@@ -536,18 +525,5 @@ function TDependenciesDlg.TTVDraw.IsErrorNode(
Result := Assigned(Node.Data) and (TSnippet(Node.Data).ID = fRootID);
end;
-//function TDependenciesDlg.TTVDraw.IsUserDefinedNode(
-// const Node: TTreeNode): Boolean;
-// {Checks if a node represents a user defined snippets object.
-// @param Node [in] Node to be checked.
-// @return True if node represents user defined object, False if not.
-// }
-//begin
-// if not Assigned(Node.Data) then
-// Result := True
-// else
-// Result := TSnippet(Node.Data).UserDefined;
-//end;
-
end.
diff --git a/Src/FmDuplicateSnippetDlg.pas b/Src/FmDuplicateSnippetDlg.pas
index 423c4d7e9..f3a9831e3 100644
--- a/Src/FmDuplicateSnippetDlg.pas
+++ b/Src/FmDuplicateSnippetDlg.pas
@@ -132,7 +132,6 @@ function TDuplicateSnippetDlg.DisallowedNames: IStringList;
Result := TIStringList.Create;
Result.CaseSensitive := False;
for Snippet in Database.Snippets do
-// if Snippet.UserDefined then
if Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
Result.Add(Snippet.Name);
end;
diff --git a/Src/FmFavouritesDlg.pas b/Src/FmFavouritesDlg.pas
index 0a6af9efc..02fca4a25 100644
--- a/Src/FmFavouritesDlg.pas
+++ b/Src/FmFavouritesDlg.pas
@@ -345,8 +345,7 @@ procedure TFavouritesDlg.actDisplayExecute(Sender: TObject);
SelectedSnippet := LI.Favourite.SnippetID;
fNotifier.DisplaySnippet(
SelectedSnippet.Name,
-// SelectedSnippet.UserDefined,
- SelectedSnippet.CollectionID,// <> TCollectionID.__TMP__MainDBCollectionID,
+ SelectedSnippet.CollectionID,
chkNewTab.Checked
);
fFavourites.Touch(SelectedSnippet);
@@ -581,11 +580,8 @@ class function TFavouritesDlg.IsDisplayed: Boolean;
procedure TFavouritesDlg.LVCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
var
-// UserDefined: Boolean;
CollectionID: TCollectionID;
begin
-// UserDefined := (Item as TFavouriteListItem).Favourite.SnippetID.UserDefined;
-// fLVFavs.Canvas.Font.Color := Preferences.DBHeadingColours[UserDefined];
CollectionID := (Item as TFavouriteListItem).Favourite.SnippetID.CollectionID;
fLVFavs.Canvas.Font.Color := Preferences.GetDBHeadingColour(CollectionID);
end;
diff --git a/Src/FmFindXRefsDlg.pas b/Src/FmFindXRefsDlg.pas
index a2f406629..b85259741 100644
--- a/Src/FmFindXRefsDlg.pas
+++ b/Src/FmFindXRefsDlg.pas
@@ -235,7 +235,6 @@ procedure TFindXRefsDlg.ConfigForm;
// Set label font styles and colours
lblSnippetName.Font.Style := [fsBold];
lblSnippetName.Font.Color :=
-// Preferences.DBHeadingColours[fSnippet.UserDefined];
Preferences.GetDBHeadingColour(fSnippet.CollectionID);
// Display selected snippet name in appropriate controls
lblSnippetName.Caption := fSnippet.DisplayName;
diff --git a/Src/FmMain.pas b/Src/FmMain.pas
index 91163c63b..5b06ad27a 100644
--- a/Src/FmMain.pas
+++ b/Src/FmMain.pas
@@ -942,7 +942,6 @@ procedure TMainForm.ActNonEmptyDBUpdate(Sender: TObject);
procedure TMainForm.ActNonEmptyUserDBUpdate(Sender: TObject);
begin
-// (Sender as TAction).Enabled := not Database.Snippets.IsEmpty(True);
(Sender as TAction).Enabled := not Database.Snippets.IsEmpty(
TCollectionID.__TMP__UserDBCollectionID
);
diff --git a/Src/FmSelectionSearchDlg.pas b/Src/FmSelectionSearchDlg.pas
index cacdc99ea..dae1bc8ce 100644
--- a/Src/FmSelectionSearchDlg.pas
+++ b/Src/FmSelectionSearchDlg.pas
@@ -63,12 +63,6 @@ TSelectionSearchDlg = class(TGenericOKDlg, INoPublicConstruct)
@param Sender [in] Not used.
}
-// procedure SelectDB(const UserDefined: Boolean);
-// {Selects all snippets from either main or user defined database.
-// @param UserDefined [in] Flag true if user-defined snippets are to be
-// selected, False if main database snippets are to be selected.
-// }
-
/// Selects all snippets from the given collection.
/// TCollectionID ID of the required
/// collection.
@@ -148,7 +142,6 @@ procedure TSelectionSearchDlg.btnMainDBClick(Sender: TObject);
@param Sender [in] Not used.
}
begin
-// SelectDB(False);
SelectDB(TCollectionID.__TMP__MainDBCollectionID);
end;
@@ -184,7 +177,6 @@ procedure TSelectionSearchDlg.btnUserDBClick(Sender: TObject);
@param Sender [in] Not used.
}
begin
-// SelectDB(True);
SelectDB(TCollectionID.__TMP__UserDBCollectionID);
end;
@@ -238,33 +230,11 @@ procedure TSelectionSearchDlg.InitForm;
begin
inherited;
frmSelect.CollapseTree;
-// btnUserDB.Enabled := Database.Snippets.Count(True) > 0;
btnUserDB.Enabled := not Database.Snippets.IsEmpty(
TCollectionID.__TMP__UserDBCollectionID
);
end;
-//procedure TSelectionSearchDlg.SelectDB(const UserDefined: Boolean);
-// {Selects all snippets from either main or user defined database.
-// @param UserDefined [in] Flag true if user-defined snippets are to be
-// selected, False if main database snippets are to be selected.
-// }
-//var
-// Snippet: TSnippet; // references each snippet in database
-// SnippetList: TSnippetList; // list of selected snippets
-//begin
-// SnippetList := TSnippetList.Create;
-// try
-// for Snippet in Database.Snippets do
-//// if Snippet.UserDefined = UserDefined then
-// if Snippet.CollectionID = TCollectionID.__TMP__DBCollectionID(UserDefined) then
-// SnippetList.Add(Snippet);
-// frmSelect.SelectedSnippets := SnippetList;
-// finally
-// FreeAndNil(SnippetList);
-// end;
-//end;
-
procedure TSelectionSearchDlg.SelectDB(const ACollectionID: TCollectionID);
var
Snippet: TSnippet; // references each snippet in database
diff --git a/Src/FmSnippetsEditorDlg.pas b/Src/FmSnippetsEditorDlg.pas
index ca6fea0bc..6e1c15192 100644
--- a/Src/FmSnippetsEditorDlg.pas
+++ b/Src/FmSnippetsEditorDlg.pas
@@ -425,7 +425,6 @@ procedure TSnippetsEditorDlg.actViewDependenciesExecute(Sender: TObject);
fDependsCLBMgr.GetCheckedSnippets(DependsList);
TDependenciesDlg.Execute(
Self,
-// TSnippetID.Create(StrTrim(edName.Text), True),
TSnippetID.Create(StrTrim(edName.Text), TCollectionID.__TMP__UserDBCollectionID),
StrTrim(edDisplayName.Text),
DependsList,
@@ -980,7 +979,7 @@ procedure TSnippetsEditorDlg.UpdateReferences;
fDependsCLBMgr.Clear;
fXRefsCLBMgr.Save;
fXRefsCLBMgr.Clear;
-// EditSnippetID := TSnippetID.Create(fOrigName, True);
+
EditSnippetID := TSnippetID.Create(fOrigName, TCollectionID.__TMP__UserDBCollectionID);
EditSnippetKind := fSnipKindList.SnippetKind(cbKind.ItemIndex);
for Snippet in Database.Snippets do
@@ -989,9 +988,7 @@ procedure TSnippetsEditorDlg.UpdateReferences;
// a user-defined one with same name
if (Snippet.ID <> EditSnippetID) and
(
-// Snippet.UserDefined or
(Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID) or
-// not Assigned(Database.Snippets.Find(Snippet.Name, True))
not Assigned(Database.Snippets.Find(Snippet.Name, TCollectionID.__TMP__UserDBCollectionID))
) then
begin
diff --git a/Src/FmTestCompileDlg.pas b/Src/FmTestCompileDlg.pas
index 08be15372..c35ea4c24 100644
--- a/Src/FmTestCompileDlg.pas
+++ b/Src/FmTestCompileDlg.pas
@@ -289,7 +289,6 @@ procedure TTestCompileDlg.ConfigForm;
// Set required label fonts and captions
TFontHelper.SetDefaultBaseFont(lblSnippetName.Font);
lblSnippetName.Font.Color :=
-// Preferences.DBHeadingColours[fSnippet.UserDefined];
Preferences.GetDBHeadingColour(fSnippet.CollectionID);
lblSnippetName.Caption := fSnippet.DisplayName;
end;
diff --git a/Src/FrDetailView.pas b/Src/FrDetailView.pas
index 1e93d52b3..65411bf8f 100644
--- a/Src/FrDetailView.pas
+++ b/Src/FrDetailView.pas
@@ -228,10 +228,6 @@ procedure TDetailViewFrame.BuildCSS(const CSSBuilder: TCSSBuilder);
.AddProperty(TCSS.BorderProp(cssAll, 1, cbsSolid, clBorder));
// Heading colours for user & main databases
-// CSSBuilder.AddSelector('.userdb')
-// .AddProperty(TCSS.ColorProp(Preferences.DBHeadingColours[True]));
-// CSSBuilder.AddSelector('.maindb')
-// .AddProperty(TCSS.ColorProp(Preferences.DBHeadingColours[False]));
CSSBuilder.AddSelector('.userdb')
.AddProperty(TCSS.ColorProp(Preferences.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID)));
CSSBuilder.AddSelector('.maindb')
diff --git a/Src/FrDisplayPrefs.pas b/Src/FrDisplayPrefs.pas
index a540d9e93..3f0433599 100644
--- a/Src/FrDisplayPrefs.pas
+++ b/Src/FrDisplayPrefs.pas
@@ -134,13 +134,9 @@ procedure TDisplayPrefsFrame.Activate(const Prefs: IPreferences;
chkHideEmptySections.Checked := not Prefs.ShowEmptySections;
chkHideEmptySections.OnClick := chkHideEmptySectionsClick;
chkSnippetsInNewTab.Checked := Prefs.ShowNewSnippetsInNewTabs;
-// fMainColourBox.Selected := Prefs.DBHeadingColours[False];
-// fUserColourBox.Selected := Prefs.DBHeadingColours[True];
fMainColourBox.Selected := Prefs.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID);
fUserColourBox.Selected := Prefs.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID);
fSourceBGColourBox.Selected := Prefs.SourceCodeBGcolour;
-// Prefs.DBHeadingCustomColours[False].CopyTo(fMainColourDlg.CustomColors, True);
-// Prefs.DBHeadingCustomColours[True].CopyTo(fUserColourDlg.CustomColors, True);
Prefs.GetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID).CopyTo(fMainColourDlg.CustomColors, True);
Prefs.GetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID).CopyTo(fUserColourDlg.CustomColors, True);
Prefs.SourceCodeBGCustomColours.CopyTo(fSourceBGColourDlg.CustomColors, True);
@@ -299,17 +295,9 @@ procedure TDisplayPrefsFrame.Deactivate(const Prefs: IPreferences);
Prefs.OverviewStartState := TOverviewStartState(
cbOverviewTree.Items.Objects[cbOverviewTree.ItemIndex]
);
-// Prefs.DBHeadingColours[False] := fMainColourBox.Selected;
-// Prefs.DBHeadingColours[True] := fUserColourBox.Selected;
Prefs.SetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID, fMainColourBox.Selected);
Prefs.SetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID, fUserColourBox.Selected);
Prefs.SourceCodeBGcolour := fSourceBGColourBox.Selected;
-// Prefs.DBHeadingCustomColours[False].CopyFrom(
-// fMainColourDlg.CustomColors, True
-// );
-// Prefs.DBHeadingCustomColours[True].CopyFrom(
-// fUserColourDlg.CustomColors, True
-// );
Prefs.GetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID).CopyFrom(
fMainColourDlg.CustomColors, True
);
diff --git a/Src/FrOverview.pas b/Src/FrOverview.pas
index 481b6351b..d097cff68 100644
--- a/Src/FrOverview.pas
+++ b/Src/FrOverview.pas
@@ -84,11 +84,7 @@ TTVDraw = class(TSnippetsTVDraw)
/// is returned.
function GetCollectionID(const Node: TTreeNode): TCollectionID;
override;
-// function IsUserDefinedNode(const Node: TTreeNode): Boolean; override;
-// {Checks if a node represents a user defined snippets object.
-// @param Node [in] Node to be checked.
-// @return True if node represents user defined object, False if not.
-// }
+
function IsSectionHeadNode(const Node: TTreeNode): Boolean;
override;
{Checks if a node represents a section header.
@@ -998,20 +994,5 @@ function TOverviewFrame.TTVDraw.IsSectionHeadNode(
Result := ViewItem.IsGrouping;
end;
-//function TOverviewFrame.TTVDraw.IsUserDefinedNode(
-// const Node: TTreeNode): Boolean;
-// {Checks if a node represents a user defined snippets object.
-// @param Node [in] Node to be checked.
-// @return True if node represents user defined object, False if not.
-// }
-//var
-// ViewItem: IView; // view item represented by node
-// CollectionID: TCollectionID; // ID of collection node item belongs to, if any
-//begin
-// // TODO -cBug: Exception reported as issue #70 seems to be triggered here
-// ViewItem := (Node as TViewItemTreeNode).ViewItem;
-// Result := ViewItem.IsUserDefined;
-//end;
-
end.
diff --git a/Src/FrSelectSnippetsBase.pas b/Src/FrSelectSnippetsBase.pas
index 04782b63f..50b233e4d 100644
--- a/Src/FrSelectSnippetsBase.pas
+++ b/Src/FrSelectSnippetsBase.pas
@@ -49,6 +49,7 @@ TSelectSnippetsBaseFrame = class(TCheckedTVFrame)
}
TTVDraw = class(TSnippetsTVDraw)
strict protected
+
/// Gets the collection ID, if any, associated with a tree
/// node.
/// TTreeNode [in] Node to be checked.
@@ -59,12 +60,6 @@ TTVDraw = class(TSnippetsTVDraw)
function GetCollectionID(const Node: TTreeNode): TCollectionID;
override;
-// function IsUserDefinedNode(const Node: TTreeNode): Boolean; override;
-// {Checks if a node represents a user defined snippets object.
-// @param Node [in] Node to be checked.
-// @return True if node represents user defined object, False if not.
-// }
-
function IsSectionHeadNode(const Node: TTreeNode): Boolean;
override;
{Checks if a node represents a section header.
@@ -305,22 +300,5 @@ function TSelectSnippetsBaseFrame.TTVDraw.IsSectionHeadNode(
Result := TObject(Node.Data) is TCategory;
end;
-//function TSelectSnippetsBaseFrame.TTVDraw.IsUserDefinedNode(
-// const Node: TTreeNode): Boolean;
-// {Checks if a node represents a user defined snippets object.
-// @param Node [in] Node to be checked.
-// @return True if node represents user defined object, False if not.
-// }
-//var
-// SnipObj: TObject; // object referenced in Node.Data
-//begin
-// SnipObj := TObject(Node.Data);
-// Result := False;
-// if SnipObj is TSnippet then
-// Result := (SnipObj as TSnippet).UserDefined
-// else if SnipObj is TCategory then
-// Result := (SnipObj as TCategory).UserDefined;
-//end;
-
end.
diff --git a/Src/FrSelectUserSnippets.pas b/Src/FrSelectUserSnippets.pas
index 69ca8307e..b29044d09 100644
--- a/Src/FrSelectUserSnippets.pas
+++ b/Src/FrSelectUserSnippets.pas
@@ -66,7 +66,6 @@ function TSelectUserSnippetsFrame.CanAddCatNode(const Cat: TCategory): Boolean;
@return True if category contains any user-defined snippets.
}
begin
-// Result := Cat.Snippets.Count(True) > 0;
Result := not Cat.Snippets.IsEmpty(
TCollectionID.__TMP__UserDBCollectionID
);
@@ -79,7 +78,6 @@ function TSelectUserSnippetsFrame.CanAddSnippetNode(
@return True if snippet is user-defined.
}
begin
-// Result := Snippet.UserDefined;
Result := Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID;
end;
diff --git a/Src/IntfNotifier.pas b/Src/IntfNotifier.pas
index 4c15ae69c..40141c9bd 100644
--- a/Src/IntfNotifier.pas
+++ b/Src/IntfNotifier.pas
@@ -33,16 +33,6 @@ interface
/// Requests a database update.
procedure UpdateDbase;
-// /// Displays a snippet.
-// /// WideString [in] Name of required snippet.
-// ///
-// /// WordBool [in] Indicates whether snippet is
-// /// user defined.
-// /// WordBool [in] Whether to display snippet in a new
-// /// detail pane tab.
-// procedure DisplaySnippet(const SnippetName: WideString;
-// UserDefined: WordBool; NewTab: WordBool); overload;
-
/// Displays a snippet.
/// WideString [in] Name of required snippet.
///
diff --git a/Src/UCodeImportExport.pas b/Src/UCodeImportExport.pas
index 580bae8b8..d190fc852 100644
--- a/Src/UCodeImportExport.pas
+++ b/Src/UCodeImportExport.pas
@@ -371,9 +371,6 @@ procedure TCodeImporter.Execute(const Data: TBytes);
TXMLDocHelper.GetPascalNameList(fXMLDoc, DependsNode, SnippetNames);
Depends.Clear;
for SnippetName in SnippetNames do
-// // Note: in building snippet ID list we assume each snippet is user-
-// // defined. It may not be, but there is no way of telling from XML.
-// Depends.Add(TSnippetID.Create(SnippetName, True));
// Note: in building snippet ID list we assume each snippet is from the
// standard user collection. It may not be, but there is no way of telling
// from XML.
diff --git a/Src/UCodeImportMgr.pas b/Src/UCodeImportMgr.pas
index 6c8f545f2..a347b21d3 100644
--- a/Src/UCodeImportMgr.pas
+++ b/Src/UCodeImportMgr.pas
@@ -185,7 +185,6 @@ function TCodeImportMgr.DisallowedNames(const ExcludedName: string):
Result := TIStringList.Create;
Result.CaseSensitive := False;
for Snippet in Database.Snippets do
-// if Snippet.UserDefined then
if Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
Result.Add(Snippet.Name);
for SnippetInfo in fSnippetInfoList do
@@ -257,8 +256,6 @@ procedure TCodeImportMgr.UpdateDatabase;
for Idx := 0 to Pred(Depends.Count) do
begin
SnippetID := Depends[Idx];
-// SnippetID.UserDefined :=
-// Database.Snippets.Find(SnippetID.Name, True) <> nil;
CollectionID := TCollectionID.__TMP__UserDBCollectionID;
if Database.Snippets.Find(SnippetID.Name, CollectionID) = nil then
CollectionID := TCollectionID.__TMP__MainDBCollectionID;
@@ -287,7 +284,6 @@ procedure TCodeImportMgr.UpdateDatabase;
AdjustDependsList(SnippetInfo.Data.Refs.Depends);
-// Snippet := Database.Snippets.Find(ImportInfo.ImportAsName, True);
Snippet := Database.Snippets.Find(ImportInfo.ImportAsName, TCollectionID.__TMP__UserDBCollectionID);
if Assigned(Snippet) then
// snippet already exists: overwrite it
diff --git a/Src/UCodeShareMgr.pas b/Src/UCodeShareMgr.pas
index e510ef862..367a02b27 100644
--- a/Src/UCodeShareMgr.pas
+++ b/Src/UCodeShareMgr.pas
@@ -77,7 +77,6 @@ class function TCodeShareMgr.CanShare: Boolean;
@return True if user defined snippets exist in database.
}
begin
-// Result := Database.Snippets.Count(True) > 0;
Result := not Database.Snippets.IsEmpty(
TCollectionID.__TMP__UserDBCollectionID
);
@@ -103,7 +102,6 @@ class function TCodeShareMgr.GetSnippetFromView(
SnippetView: ISnippetView; // ViewItem as snippet view if supported
begin
if Supports(ViewItem, ISnippetView, SnippetView)
-// and (SnippetView.Snippet.UserDefined) then
and (SnippetView.Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID) then
Result := SnippetView.Snippet
else
diff --git a/Src/UDetailPageHTML.pas b/Src/UDetailPageHTML.pas
index 719ef7c11..d34ec1f5b 100644
--- a/Src/UDetailPageHTML.pas
+++ b/Src/UDetailPageHTML.pas
@@ -433,7 +433,6 @@ procedure TWelcomePageHTML.ResolvePlaceholders(const Tplt: THTMLTemplate);
'externalScript', TJavaScript.LoadScript('external.js', etWindows1252)
);
-// UserDBCount := Database.Snippets.Count(True);
UserDBCount := Database.Snippets.Count(
TCollectionID.__TMP__UserDBCollectionID
);
@@ -447,7 +446,6 @@ procedure TWelcomePageHTML.ResolvePlaceholders(const Tplt: THTMLTemplate);
'UserDBCount', IntToStr(UserDBCount)
);
-// MainDBCount := Database.Snippets.Count(False);
MainDBCount := Database.Snippets.Count(
TCollectionID.__TMP__MainDBCollectionID
);
@@ -528,17 +526,14 @@ procedure TSnippetInfoPageHTML.ResolvePlaceholders(const Tplt: THTMLTemplate);
'overflowXFixScript',
'window.onload = null;'
);
-// if GetSnippet.UserDefined then
if GetSnippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
Tplt.ResolvePlaceholderHTML('SnippetCSSClass', 'userdb')
else
Tplt.ResolvePlaceholderHTML('SnippetCSSClass', 'maindb');
Tplt.ResolvePlaceholderHTML(
-// 'TestingInfo', TCSS.BlockDisplayProp(not GetSnippet.UserDefined)
'TestingInfo', TCSS.BlockDisplayProp(GetSnippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID)
);
Tplt.ResolvePlaceholderHTML(
-// 'EditLink', TCSS.BlockDisplayProp(GetSnippet.UserDefined)
'EditLink', TCSS.BlockDisplayProp(GetSnippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID)
);
Tplt.ResolvePlaceholderText(
@@ -547,7 +542,6 @@ procedure TSnippetInfoPageHTML.ResolvePlaceholders(const Tplt: THTMLTemplate);
);
SnippetHTML := TSnippetHTML.Create(GetSnippet);
try
-// if not GetSnippet.UserDefined then
if GetSnippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID then
Tplt.ResolvePlaceholderHTML('TestingInfoImg', SnippetHTML.TestingImage);
Tplt.ResolvePlaceholderHTML('SnippetName', SnippetHTML.SnippetName);
@@ -673,7 +667,6 @@ function TCategoryPageHTML.GetEmptyListNote: string;
function TCategoryPageHTML.GetH1ClassName: string;
begin
-// if (View as ICategoryView).Category.UserDefined then
if (View as ICategoryView).Category.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
Result := 'userdb'
else
diff --git a/Src/UNotifier.pas b/Src/UNotifier.pas
index 913593762..310c570e2 100644
--- a/Src/UNotifier.pas
+++ b/Src/UNotifier.pas
@@ -73,17 +73,6 @@ TNotifier = class(TInterfacedObject, INotifier, ISetActions)
/// Methods of INotifier.
procedure UpdateDbase;
-// /// Displays a snippet.
-// /// WideString [in] Name of required snippet.
-// ///
-// /// WordBool [in] Indicates whether snippet is
-// /// user defined.
-// /// WordBool [in] Whether to display snippet in a new
-// /// detail pane tab.
-// /// Methods of INotifier.
-// procedure DisplaySnippet(const SnippetName: WideString;
-// UserDefined: WordBool; NewTab: WordBool); overload;
-
/// Displays a snippet.
/// WideString [in] Name of required snippet.
///
@@ -277,18 +266,6 @@ procedure TNotifier.DisplaySnippet(const SnippetName: WideString;
end;
end;
-//procedure TNotifier.DisplaySnippet(const SnippetName: WideString;
-// UserDefined: WordBool; NewTab: WordBool);
-//begin
-// if Assigned(fDisplaySnippetAction) then
-// begin
-// (fDisplaySnippetAction as TSnippetAction).SnippetName := SnippetName;
-// (fDisplaySnippetAction as TSnippetAction).UserDefined := UserDefined;
-// (fDisplaySnippetAction as TSnippetAction).NewTab := NewTab;
-// fDisplaySnippetAction.Execute;
-// end;
-//end;
-
procedure TNotifier.EditSnippet(const SnippetName: WideString);
begin
if Assigned(fEditSnippetAction) then
diff --git a/Src/UPreferences.pas b/Src/UPreferences.pas
index 3d3d17632..1137db604 100644
--- a/Src/UPreferences.pas
+++ b/Src/UPreferences.pas
@@ -137,25 +137,6 @@ interface
property ShowNewSnippetsInNewTabs: Boolean
read GetShowNewSnippetsInNewTabs write SetShowNewSnippetsInNewTabs;
-// /// Gets heading colour used for snippets from a specified
-// /// database.
-// /// Boolean [in] Required database: True for user
-// /// database and False for inline database.
-// /// TColor. Required colour.
-// function GetDBHeadingColour(UserDefined: Boolean): TColor;
-// /// Sets heading colour used for snippets from a specified
-// /// database.
-// /// Boolean [in] Required database: True for user
-// /// database and False for online database.
-// /// TColor [in] Required heading colour.
-// procedure SetDBHeadingColour(UserDefined: Boolean;
-// const Value: TColor);
-// /// Records colour to be used for headings of items from either
-// /// online database (UserDefined = False) or user database (UserDefined =
-// /// True).
-// property DBHeadingColours[UserDefined: Boolean]: TColor
-// read GetDBHeadingColour write SetDBHeadingColour;
-
/// Gets heading colour used for snippets from a specified
/// collection.
/// TCollectionID [in] ID of required
@@ -170,26 +151,6 @@ interface
procedure SetDBHeadingColour(const ACollectionID: TCollectionID;
const Value: TColor);
-// /// Gets custom colours available for headings for specified
-// /// database.
-// /// Boolean [in] Required database: True for user
-// /// database and False for online database.
-// /// IStringList. String list containing custom colours.
-// function GetDBHeadingCustomColours(UserDefined: Boolean): IStringList;
-// /// Sets custom colours available for headings for specified
-// /// database.
-// /// Boolean [in] Required database: True for user
-// /// database and False for online database.
-// /// IStringList [in] String list containing custom
-// /// colours.
-// procedure SetDBHeadingCustomColours(UserDefined: Boolean;
-// Value: IStringList);
-// /// Records custom colours available for headings of items from
-// /// either online database (UserDefined = False) or user database
-// /// (UserDefined = True).
-// property DBHeadingCustomColours[UserDefined: Boolean]: IStringList
-// read GetDBHeadingCustomColours write SetDBHeadingCustomColours;
-
/// Gets custom colours available for headings for specified
/// collection.
/// TCollectionID [in] ID of required
@@ -520,14 +481,6 @@ TPreferences = class(TInterfacedObject,
/// Method of IPreferences.
procedure SetShowNewSnippetsInNewTabs(const Value: Boolean);
-// /// Gets heading colour used for snippets from a specified
-// /// database.
-// /// Boolean [in] Required database: True for user
-// /// database and False for inline database.
-// /// TColor. Required colour.
-// /// Method of IPreferences.
-// function GetDBHeadingColour(UserDefined: Boolean): TColor;
-
/// Gets heading colour used for snippets from a specified
/// collection.
/// TCollectionID [in] ID of required
@@ -536,15 +489,6 @@ TPreferences = class(TInterfacedObject,
/// Method of IPreferences.
function GetDBHeadingColour(const ACollectionID: TCollectionID): TColor;
-// /// Sets heading colour used for snippets from a specified
-// /// database.
-// /// Boolean [in] Required database: True for user
-// /// database and False for online database.
-// /// TColor [in] Required heading colour.
-// /// Method of IPreferences.
-// procedure SetDBHeadingColour(UserDefined: Boolean;
-// const Value: TColor);
-
/// Sets heading colour used for snippets from a specified
/// collection.
/// TCollectionID [in] ID of required
@@ -554,14 +498,6 @@ TPreferences = class(TInterfacedObject,
procedure SetDBHeadingColour(const ACollectionID: TCollectionID;
const Value: TColor);
-// /// Gets custom colours available for headings for specified
-// /// database.
-// /// Boolean [in] Required database: True for user
-// /// database and False for online database.
-// /// IStringList. String list containing custom colours.
-// /// Method of IPreferences.
-// function GetDBHeadingCustomColours(UserDefined: Boolean): IStringList;
-
/// Gets custom colours available for headings for specified
/// collection.
/// TCollectionID [in] ID of required
@@ -571,16 +507,6 @@ TPreferences = class(TInterfacedObject,
function GetDBHeadingCustomColours(const ACollectionID: TCollectionID):
IStringList;
-// /// Sets custom colours available for headings for specified
-// /// database.
-// /// Boolean [in] Required database: True for user
-// /// database and False for online database.
-// /// IStringList [in] String list containing custom
-// /// colours.
-// /// Method of IPreferences.
-// procedure SetDBHeadingCustomColours(UserDefined: Boolean;
-// Value: IStringList);
-
/// Sets custom colours available for headings for specified
/// collection.
/// TCollectionID [in] ID of required
@@ -769,13 +695,9 @@ procedure TPreferences.Assign(const Src: IInterface);
Self.fOverviewStartState := SrcPref.OverviewStartState;
Self.fShowEmptySections := SrcPref.ShowEmptySections;
Self.fShowNewSnippetsInNewTabs := SrcPref.ShowNewSnippetsInNewTabs;
-// Self.fDBHeadingColours[False] := SrcPref.DBHeadingColours[False];
Self.SetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID, SrcPref.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID));
-// Self.fDBHeadingCustomColours[False] := SrcPref.DBHeadingCustomColours[False];
Self.SetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID, SrcPref.GetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID));
-// Self.fDBHeadingColours[True] := SrcPref.DBHeadingColours[True];
Self.SetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID, SrcPref.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID));
-// Self.fDBHeadingCustomColours[True] := SrcPref.DBHeadingCustomColours[True];
Self.SetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID, SrcPref.GetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID));
Self.fOverviewFontSize := SrcPref.OverviewFontSize;
Self.fDetailFontSize := SrcPref.DetailFontSize;
@@ -824,11 +746,6 @@ function TPreferences.GetCustomHiliteColours: IStringList;
Result := fHiliteCustomColours;
end;
-//function TPreferences.GetDBHeadingColour(UserDefined: Boolean): TColor;
-//begin
-// Result := fDBHeadingColours[UserDefined];
-//end;
-
function TPreferences.GetDBHeadingColour(
const ACollectionID: TCollectionID): TColor;
begin
@@ -851,12 +768,6 @@ function TPreferences.GetDBHeadingCustomColours(
];
end;
-//function TPreferences.GetDBHeadingCustomColours(
-// UserDefined: Boolean): IStringList;
-//begin
-// Result := fDBHeadingCustomColours[UserDefined];
-//end;
-
function TPreferences.GetDetailFontSize: Integer;
begin
Result := fDetailFontSize;
@@ -957,12 +868,6 @@ procedure TPreferences.SetCustomHiliteColours(const Colours: IStringList);
fHiliteCustomColours := Colours;
end;
-//procedure TPreferences.SetDBHeadingColour(UserDefined: Boolean;
-// const Value: TColor);
-//begin
-// fDBHeadingColours[UserDefined] := Value;
-//end;
-
procedure TPreferences.SetDBHeadingColour(const ACollectionID: TCollectionID;
const Value: TColor);
begin
@@ -985,12 +890,6 @@ procedure TPreferences.SetDBHeadingCustomColours(
] := Value;
end;
-//procedure TPreferences.SetDBHeadingCustomColours(UserDefined: Boolean;
-// Value: IStringList);
-//begin
-// fDBHeadingCustomColours[UserDefined] := Value;
-//end;
-
procedure TPreferences.SetDetailFontSize(const Value: Integer);
begin
if TFontHelper.IsInCommonFontSizeRange(Value) then
@@ -1119,13 +1018,9 @@ function TPreferencesPersist.Clone: IInterface;
NewPref.OverviewStartState := Self.fOverviewStartState;
NewPref.ShowEmptySections := Self.fShowEmptySections;
NewPref.ShowNewSnippetsInNewTabs := Self.fShowNewSnippetsInNewTabs;
-// NewPref.DBHeadingColours[False] := Self.fDBHeadingColours[False];
NewPref.SetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID, Self.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID));
-// NewPref.DBHeadingCustomColours[False] := Self.fDBHeadingCustomColours[False];
NewPref.SetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID, Self.GetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID));
-// NewPref.DBHeadingColours[True] := Self.fDBHeadingColours[True];
NewPref.SetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID, Self.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID));
-// NewPref.DBHeadingCustomColours[True] := Self.fDBHeadingCustomColours[True];
NewPref.SetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID, Self.GetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID));
NewPref.OverviewFontSize := Self.fOverviewFontSize;
NewPref.DetailFontSize := Self.fDetailFontSize;
@@ -1168,16 +1063,10 @@ constructor TPreferencesPersist.Create;
fShowNewSnippetsInNewTabs := Storage.GetBoolean(
'ShowNewSnippetsInNewTabs', False
);
-// fDBHeadingColours[False] := TColor(
-// Storage.GetInteger('MainDBHeadingColour', clMainSnippet)
-// );
SetDBHeadingColour(
TCollectionID.__TMP__MainDBCollectionID,
TColor(Storage.GetInteger('MainDBHeadingColour', clMainSnippet))
);
-// fDBHeadingColours[True] := TColor(
-// Storage.GetInteger('UserDBHeadingColour', clUserSnippet)
-// );
SetDBHeadingColour(
TCollectionID.__TMP__UserDBCollectionID,
TColor(Storage.GetInteger('UserDBHeadingColour', clUserSnippet))
@@ -1265,12 +1154,10 @@ destructor TPreferencesPersist.Destroy;
Storage.SetInteger('OverviewStartState', Ord(fOverviewStartState));
Storage.SetBoolean('ShowEmptySections', fShowEmptySections);
Storage.SetBoolean('ShowNewSnippetsInNewTabs', fShowNewSnippetsInNewTabs);
-// Storage.SetInteger('MainDBHeadingColour', fDBHeadingColours[False]);
Storage.SetInteger(
'MainDBHeadingColour',
GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID)
);
-// Storage.SetInteger('UserDBHeadingColour', fDBHeadingColours[True]);
Storage.SetInteger(
'UserDBHeadingColour',
GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID)
diff --git a/Src/URTFCategoryDoc.pas b/Src/URTFCategoryDoc.pas
index 6e2b0a6ea..35070366e 100644
--- a/Src/URTFCategoryDoc.pas
+++ b/Src/URTFCategoryDoc.pas
@@ -104,8 +104,6 @@ constructor TRTFCategoryDoc.Create(const UseColour: Boolean);
fBuilder.FontTable.Add(MainFontName, rgfSwiss, 0);
fBuilder.FontTable.Add(MonoFontName, rgfModern, 0);
// Set up colour table
-// fBuilder.ColourTable.Add(Preferences.DBHeadingColours[False]);
-// fBuilder.ColourTable.Add(Preferences.DBHeadingColours[True]);
{TODO -cCollection: Replace following 2 statements with loop that iterates
over all collections.}
fBuilder.ColourTable.Add(Preferences.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID));
@@ -218,8 +216,6 @@ procedure TRTFCategoryDoc.OutputCategoryHeading(const Category: TCategory);
fBuilder.SetFont(MainFontName);
fBuilder.SetFontSize(HeadingFontSize);
fBuilder.SetFontStyle([fsBold]);
-// SetColour(Preferences.DBHeadingColours[Category.UserDefined]);
-// SetColour(Preferences.DBHeadingColours[Category.CollectionID <> TCollectionID.__TMP__MainDBCollectionID]);
SetColour(Preferences.GetDBHeadingColour(Category.CollectionID));
fBuilder.AddText(Category.Description);
fBuilder.EndPara;
@@ -233,8 +229,6 @@ procedure TRTFCategoryDoc.OutputSnippetSubHeading(const Snippet: TSnippet);
fBuilder.SetFont(MainFontName);
fBuilder.SetFontSize(SubHeadingFontSize);
fBuilder.SetFontStyle([fsBold]);
-// SetColour(Preferences.DBHeadingColours[Snippet.UserDefined]);
-// SetColour(Preferences.DBHeadingColours[Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID]);
SetColour(Preferences.GetDBHeadingColour(Snippet.CollectionID));
fBuilder.AddText(Snippet.DisplayName);
fBuilder.EndPara;
diff --git a/Src/URTFSnippetDoc.pas b/Src/URTFSnippetDoc.pas
index 948fc31cb..6781dd3a6 100644
--- a/Src/URTFSnippetDoc.pas
+++ b/Src/URTFSnippetDoc.pas
@@ -76,14 +76,6 @@ TRTFSnippetDoc = class(TSnippetDoc)
strict protected
/// Initialises rich text document.
procedure InitialiseDoc; override;
-
-// /// Adds given heading (i.e. snippet name) to document. Can be
-// /// user defined or from main database.
-// /// Heading is coloured according to whether user defined or not.
-// ///
-// procedure RenderHeading(const Heading: string; const UserDefined: Boolean);
-// override;
-
/// Output given heading, i.e. snippet name for snippet from a
/// given collection..
/// Heading is coloured according the the snippet's collection.
@@ -181,8 +173,6 @@ procedure TRTFSnippetDoc.InitialiseDoc;
fBuilder.ColourTable.Add(clWarningText);
fBuilder.ColourTable.Add(clVarText);
fBuilder.ColourTable.Add(clExternalLink);
-// fBuilder.ColourTable.Add(Preferences.DBHeadingColours[False]);
-// fBuilder.ColourTable.Add(Preferences.DBHeadingColours[True]);
{ TODO -cCollections: Replace following two statements with iteration over all
supported collections when support for multiple collections is added.
}
@@ -430,18 +420,6 @@ procedure TRTFSnippetDoc.RenderExtra(const ExtraText: IActiveText);
end;
end;
-//procedure TRTFSnippetDoc.RenderHeading(const Heading: string;
-// const UserDefined: Boolean);
-//begin
-// fBuilder.SetFontStyle([fsBold]);
-// fBuilder.SetFontSize(HeadingFontSize);
-// if fUseColour then
-// fBuilder.SetColour(Preferences.DBHeadingColours[UserDefined]);
-// fBuilder.SetParaSpacing(TRTFParaSpacing.Create(0.0, ParaSpacing));
-// fBuilder.AddText(Heading);
-// fBuilder.EndPara;
-//end;
-
procedure TRTFSnippetDoc.RenderHeading(const Heading: string;
const ACollectionID: TCollectionID);
begin
diff --git a/Src/USaveUnitMgr.pas b/Src/USaveUnitMgr.pas
index 6c4207812..eb6c2f9d7 100644
--- a/Src/USaveUnitMgr.pas
+++ b/Src/USaveUnitMgr.pas
@@ -263,7 +263,6 @@ constructor TSaveUnitMgr.InternalCreate(const Snips: TSnippetList);
fContainsMainDBSnippets := False;
for Snippet in Snips do
begin
-// if not Snippet.UserDefined then
if Snippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID then
begin
fContainsMainDBSnippets := True;
diff --git a/Src/USnippetAction.pas b/Src/USnippetAction.pas
index 9030c671b..6f801e5bc 100644
--- a/Src/USnippetAction.pas
+++ b/Src/USnippetAction.pas
@@ -37,8 +37,6 @@ TSnippetAction = class(TBasicAction, ISetNotifier)
var
/// Value of SnippetName property.
fSnippetName: string;
-// /// Value of UserDefined property.
-// fUserDefined: Boolean;
/// Value of CollectionID property.
fCollectionID: TCollectionID;
/// Value of NewTab property.
@@ -61,9 +59,6 @@ TSnippetAction = class(TBasicAction, ISetNotifier)
procedure SetNotifier(const Notifier: INotifier);
/// Name of snippet to be displayed.
property SnippetName: string read fSnippetName write fSnippetName;
-// /// Flag indicating whether snippet to be displayed is user
-// /// defined.
-// property UserDefined: Boolean read fUserDefined write fUserDefined;
/// ID of the collection containing the snippet to be displayed.
///
property CollectionID: TCollectionID read fCollectionID write fCollectionID;
@@ -91,7 +86,6 @@ function TSnippetAction.Execute: Boolean;
begin
Assert(Assigned(fNotifier), ClassName + '.Execute: Notifier not set');
Assert(SnippetName <> '', ClassName + '.Execute: SnippetName not provided');
-// Snippet := Database.Snippets.Find(SnippetName, UserDefined);
Snippet := Database.Snippets.Find(SnippetName, fCollectionID);
Assert(Assigned(Snippet), ClassName + '.Execute: SnippetName not valid');
// Create a view item for snippet and get notifier to display it
diff --git a/Src/USnippetDoc.pas b/Src/USnippetDoc.pas
index 7e679a52c..7d9e9763b 100644
--- a/Src/USnippetDoc.pas
+++ b/Src/USnippetDoc.pas
@@ -62,13 +62,6 @@ TSnippetDoc = class(TObject)
/// initialisation here.
procedure InitialiseDoc; virtual;
-// /// Output given heading, i.e. snippet name. Can be user defined
-// /// or from main database.
-// /// Heading may be rendered differently depending on whether user
-// /// defined or not.
-// procedure RenderHeading(const Heading: string; const UserDefined: Boolean);
-// virtual; abstract;
-
/// Output given heading, i.e. snippet name for snippet from a
/// given collection..
/// Heading may be rendered differently depending on the snippet's
@@ -187,7 +180,6 @@ function TSnippetDoc.Generate(const Snippet: TSnippet): TEncodedData;
Assert(Assigned(Snippet), ClassName + '.Create: Snippet is nil');
// generate document
InitialiseDoc;
-// RenderHeading(Snippet.DisplayName, Snippet.UserDefined);
RenderHeading(Snippet.DisplayName, Snippet.CollectionID);
RenderDescription(Snippet.Description);
RenderSourceCode(Snippet.SourceCode);
@@ -210,7 +202,6 @@ function TSnippetDoc.Generate(const Snippet: TSnippet): TEncodedData;
end;
if Snippet.Extra.HasContent then
RenderExtra(Snippet.Extra);
-// if not Snippet.UserDefined then
if Snippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID then
// database info written only if snippet is from main database
RenderDBInfo(MainDBInfo);
diff --git a/Src/USnippetIDListIOHandler.pas b/Src/USnippetIDListIOHandler.pas
index ef527540e..a67a37b67 100644
--- a/Src/USnippetIDListIOHandler.pas
+++ b/Src/USnippetIDListIOHandler.pas
@@ -110,9 +110,6 @@ procedure TSnippetIDListFileReader.Parse;
raise ESnippetIDListFileReader.CreateFmt(sMissingName, [Line]);
if UserDefStr = '' then
raise ESnippetIDListFileReader.CreateFmt(sMissingUserDef, [Line]);
-// if not TryStrToInt(UserDefStr, UserDefInt)
-// or not (UserDefInt in [0, 1]) then
-// raise ESnippetIDListFileReader.CreateFmt(sBadUserDef, [Line]);
if not TryStrToInt(UserDefStr, UserDefInt) then
raise ESnippetIDListFileReader.CreateFmt(sBadUserDef, [Line]);
case UserDefInt of
@@ -121,7 +118,6 @@ procedure TSnippetIDListFileReader.Parse;
else
raise ESnippetIDListFileReader.CreateFmt(sBadUserDef, [Line]);
end;
-// fSnippetIDs.Add(TSnippetID.Create(Name, Boolean(UserDefInt)));
fSnippetIDs.Add(TSnippetID.Create(Name, CollectionID));
end;
end;
@@ -168,9 +164,6 @@ procedure TSnippetIDListFileWriter.CreateContent(
begin
fBuilder.Append(SnippetID.Name);
fBuilder.Append(TAB);
- // NOTE: TStringBuilder.Append(Boolean) override not used here since ordinal
- // value wanted instead of "True" or "False" or localised equivalent.
-// fBuilder.Append(Ord(SnippetID.UserDefined));
fBuilder.Append(Ord(SnippetID.CollectionID <> TCollectionID.__TMP__MainDBCollectionID));
fBuilder.AppendLine;
end;
diff --git a/Src/USnippetIDs.pas b/Src/USnippetIDs.pas
index 9619e6543..81b5c7bc7 100644
--- a/Src/USnippetIDs.pas
+++ b/Src/USnippetIDs.pas
@@ -33,28 +33,18 @@ TSnippetID = record
var
/// Value of Name property.
fName: string;
-// /// Value of UserDefined property.
-// fUserDefined: Boolean;
fCollectionID: TCollectionID;
procedure SetCollectionID(const AValue: TCollectionID);
public
/// Name of snippet.
property Name: string read fName write fName;
- /// Whether snippet is user defined.
-// property UserDefined: Boolean read fUserDefined write fUserDefined;
- {TODO -cCollections: Remove above property & getter/setter}
-
/// ID of the collection to which a snippet with this ID belongs.
///
/// ID must not be null.
property CollectionID: TCollectionID
read fCollectionID write SetCollectionID;
-// /// Creates a record with given property values.
-// constructor Create(const AName: string; const AUserDefined: Boolean);
-// overload; {TODO -cCollections: remove constructor}
-
/// Creates a record with given property values.
/// ACollectionID must not be null.
constructor Create(const AName: string; const ACollectionID: TCollectionID);
@@ -186,7 +176,6 @@ function TSnippetID.CompareTo(const SID: TSnippetID): Integer;
if Result = 0 then
// TODO -cNote: New comparison changes ordering (no problem tho!)
Result := TCollectionID.Compare(CollectionID, SID.CollectionID);
-// Result := Ord(UserDefined) - Ord(SID.UserDefined);
end;
constructor TSnippetID.Create(const AName: string;
@@ -196,12 +185,6 @@ constructor TSnippetID.Create(const AName: string;
SetCollectionID(ACollectionID);
end;
-//constructor TSnippetID.Create(const AName: string; const AUserDefined: Boolean);
-//begin
-// fName := AName;
-// fUserDefined := AUserDefined);
-//end;
-
class operator TSnippetID.Equal(const SID1, SID2: TSnippetID): Boolean;
begin
Result := SID1.CompareTo(SID2) = 0;
diff --git a/Src/USnippetSourceGen.pas b/Src/USnippetSourceGen.pas
index b6cf42688..d0bcd3721 100644
--- a/Src/USnippetSourceGen.pas
+++ b/Src/USnippetSourceGen.pas
@@ -244,7 +244,6 @@ procedure TSnippetSourceGen.Initialize(View: IView);
// view is single snippet: just record that
Snippet := (View as ISnippetView).Snippet;
fGenerator.IncludeSnippet(Snippet);
-// fContainsMainDBSnippets := not Snippet.UserDefined;
fContainsMainDBSnippets := Snippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID;
end
else
@@ -256,7 +255,6 @@ procedure TSnippetSourceGen.Initialize(View: IView);
fGenerator.IncludeSnippets(Snips); // ignores freeform snippets
for Snippet in Snips do
begin
-// if not Snippet.UserDefined then
if Snippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID then
begin
fContainsMainDBSnippets := True;
diff --git a/Src/USnippetValidator.pas b/Src/USnippetValidator.pas
index b5204b771..0fc8ef764 100644
--- a/Src/USnippetValidator.pas
+++ b/Src/USnippetValidator.pas
@@ -373,7 +373,6 @@ class function TSnippetValidator.ValidateName(const Name: string;
else if not IsValidIdent(TrimmedName) then
ErrorMsg := Format(sErrBadName, [TrimmedName])
else if CheckForUniqueness and
-// (Database.Snippets.Find(TrimmedName, True) <> nil) then
(Database.Snippets.Find(TrimmedName, TCollectionID.__TMP__UserDBCollectionID) <> nil) then
ErrorMsg := Format(sErrDupName, [TrimmedName])
else
diff --git a/Src/USnippetsChkListMgr.pas b/Src/USnippetsChkListMgr.pas
index d1bd0c842..b8b8b708a 100644
--- a/Src/USnippetsChkListMgr.pas
+++ b/Src/USnippetsChkListMgr.pas
@@ -203,9 +203,6 @@ procedure TSnippetsChkListMgr.DrawItem(Control: TWinControl; Index: Integer;
Assert(fCLB = Control, ClassName + '.DrawItem: Control <> fCLB');
Canvas := fCLB.Canvas;
if not (odSelected in State) then
-// Canvas.Font.Color := Preferences.DBHeadingColours[
-//// (fCLB.Items.Objects[Index] as TSnippet).UserDefined
-// ];
Canvas.Font.Color := Preferences.GetDBHeadingColour(
(fCLB.Items.Objects[Index] as TSnippet).CollectionID
);
diff --git a/Src/USnippetsTVDraw.pas b/Src/USnippetsTVDraw.pas
index 99f1c9950..073444c3d 100644
--- a/Src/USnippetsTVDraw.pas
+++ b/Src/USnippetsTVDraw.pas
@@ -41,13 +41,6 @@ TSnippetsTVDraw = class abstract(TObject)
function GetCollectionID(const Node: TTreeNode): TCollectionID;
virtual; abstract;
-// function IsUserDefinedNode(const Node: TTreeNode): Boolean;
-// virtual; abstract;
-// {Checks if a node represents a user defined snippets object.
-// @param Node [in] Node to be checked.
-// @return True if node represents user defined object, False if not.
-// }
-
function IsSectionHeadNode(const Node: TTreeNode): Boolean;
virtual;
{Checks if a node represents a section header.
@@ -131,7 +124,6 @@ procedure TSnippetsTVDraw.CustomDrawItem(Sender: TCustomTreeView;
TV.Canvas.Font.Color := clWarningText
else
TV.Canvas.Font.Color :=
-// Preferences.DBHeadingColours[IsUserDefinedNode(Node)];
Preferences.GetDBHeadingColour(GetCollectionID(Node));
TV.Canvas.Brush.Color := TV.Color;
end;
diff --git a/Src/UStatusBarMgr.pas b/Src/UStatusBarMgr.pas
index 3cf6aad69..f6aa4fa1d 100644
--- a/Src/UStatusBarMgr.pas
+++ b/Src/UStatusBarMgr.pas
@@ -362,7 +362,6 @@ procedure TStatusBarMgr.ShowSnippetsInfo;
begin
// Calculate database stats
TotalSnippets := Database.Snippets.Count;
-// TotalUserSnippets := Database.Snippets.Count(True);
TotalUserSnippets := Database.Snippets.Count(
TCollectionID.__TMP__UserDBCollectionID
);
diff --git a/Src/UTextSnippetDoc.pas b/Src/UTextSnippetDoc.pas
index 70babef0a..4e7710b5b 100644
--- a/Src/UTextSnippetDoc.pas
+++ b/Src/UTextSnippetDoc.pas
@@ -46,13 +46,6 @@ TTextSnippetDoc = class(TSnippetDoc)
/// Initialises plain text document.
procedure InitialiseDoc; override;
-// /// Adds given heading (i.e. snippet name) to document. Can be
-// /// user defined or from main database.
-// /// Heading is output the same whether user defined or not, so
-// /// UserDefined parameter is ignored.
-// procedure RenderHeading(const Heading: string; const UserDefined: Boolean);
-// override;
-
/// Output given heading, i.e. snippet name for snippet from a
/// given collection.
/// Heading is output the same regardless of the snippet's
@@ -179,12 +172,6 @@ procedure TTextSnippetDoc.RenderHeading(const Heading: string;
fWriter.WriteLine(Heading);
end;
-//procedure TTextSnippetDoc.RenderHeading(const Heading: string;
-// const UserDefined: Boolean);
-//begin
-// fWriter.WriteLine(Heading);
-//end;
-
procedure TTextSnippetDoc.RenderNoCompilerInfo(const Heading,
NoCompileTests: string);
begin
diff --git a/Src/UUserDBMgr.pas b/Src/UUserDBMgr.pas
index 88fda6c5c..04f11cbb2 100644
--- a/Src/UUserDBMgr.pas
+++ b/Src/UUserDBMgr.pas
@@ -294,7 +294,6 @@ class function TUserDBMgr.CanEdit(ViewItem: IView): Boolean;
Assert(Assigned(ViewItem), ClassName + '.CanEdit: ViewItem is nil');
Result := Assigned(ViewItem)
and Supports(ViewItem, ISnippetView, SnippetView)
-// and SnippetView.Snippet.UserDefined;
and (SnippetView.Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID);
end;
@@ -363,7 +362,6 @@ class function TUserDBMgr.CreateUserCatList(
begin
Result := TCategoryList.Create;
for Cat in Database.Categories do
-// if Cat.UserDefined and
if (Cat.CollectionID <> TCollectionID.__TMP__MainDBCollectionID) and
(IncludeSpecial or not TReservedCategories.IsReserved(Cat)) then
Result.Add(Cat);
@@ -425,8 +423,6 @@ class procedure TUserDBMgr.DeleteSnippet(ViewItem: IView);
Assert(Supports(ViewItem, ISnippetView),
ClassName + '.Delete: Current view is not a snippet');
Snippet := (ViewItem as ISnippetView).Snippet;
-// Assert(Snippet.UserDefined,
-// ClassName + '.Delete: Snippet must be user defined');
Assert(Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID,
ClassName + '.Delete: Snippet must be user defined');
// Check if snippet has dependents: don't allow deletion if so
@@ -469,7 +465,6 @@ class procedure TUserDBMgr.EditSnippet(const SnippetName: string);
var
Snippet: TSnippet; // reference to snippet to be edited
begin
-// Snippet := Database.Snippets.Find(SnippetName, True);
Snippet := Database.Snippets.Find(SnippetName, TCollectionID.__TMP__UserDBCollectionID);
if not Assigned(Snippet) then
raise EBug.Create(ClassName + '.EditSnippet: Snippet not in user database');
diff --git a/Src/UView.pas b/Src/UView.pas
index db192a255..36e28553d 100644
--- a/Src/UView.pas
+++ b/Src/UView.pas
@@ -60,8 +60,6 @@ interface
/// without having have an instance of any object wrapped by the view.
///
function GetKey: IViewKey;
-// /// Checks if view is user-defined.
-// function IsUserDefined: Boolean;
/// Checks if view is a grouping.
/// A grouping is a view that groups views together.
///
@@ -234,9 +232,6 @@ TKey = class(TInterfacedObject, IViewKey)
/// Gets object containing view's unique key.
/// Method of IView.
function GetKey: IViewKey;
-// /// Checks if view is user-defined.
-// /// Method of IView.
-// function IsUserDefined: Boolean;
/// Checks if view is a grouping.
/// Method of IView.
function IsGrouping: Boolean;
@@ -324,8 +319,6 @@ TKey = class(TInterfacedObject, IViewKey)
/// Gets object containing view's unique key.
/// Method of IView.
function GetKey: IViewKey;
-// /// Checks if view is user-defined.
-// function IsUserDefined: Boolean;
/// Checks if view is a grouping.
/// Method of IView.
function IsGrouping: Boolean;
@@ -371,9 +364,6 @@ TKey = class(TInterfacedObject, IViewKey)
/// Gets object containing view's unique key.
/// Method of IView.
function GetKey: IViewKey;
-// /// Checks if view is user-defined.
-// /// Method of IView.
-// function IsUserDefined: Boolean;
/// Checks if view is a grouping.
/// Method of IView.
function IsGrouping: Boolean;
@@ -421,9 +411,6 @@ TKey = class(TInterfacedObject, IViewKey)
/// Gets object containing view's unique key.
/// Method of IView.
function GetKey: IViewKey;
-// /// Checks if view is user-defined.
-// /// Method of IView.
-// function IsUserDefined: Boolean;
/// Checks if view is a grouping.
/// Method of IView.
function IsGrouping: Boolean;
@@ -471,9 +458,6 @@ TKey = class(TInterfacedObject, IViewKey)
/// Gets object containing view's unique key.
/// Method of IView.
function GetKey: IViewKey;
-// /// Checks if view is user-defined.
-// /// Method of IView.
-// function IsUserDefined: Boolean;
/// Checks if view is a grouping.
/// Method of IView.
function IsGrouping: Boolean;
@@ -499,11 +483,6 @@ function TSimpleView.IsGrouping: Boolean;
Result := False;
end;
-//function TSimpleView.IsUserDefined: Boolean;
-//begin
-// Result := False;
-//end;
-
{ TSimpleView.TKey }
constructor TSimpleView.TKey.Create(OwnerClass: TClass);
@@ -590,11 +569,6 @@ function TSnippetView.IsGrouping: Boolean;
Result := False;
end;
-//function TSnippetView.IsUserDefined: Boolean;
-//begin
-// Result := GetSnippet.UserDefined;
-//end;
-
{ TSnippetView.TKey }
constructor TSnippetView.TKey.Create(const ID: TSnippetID);
@@ -649,11 +623,6 @@ function TCategoryView.IsGrouping: Boolean;
Result := True;
end;
-//function TCategoryView.IsUserDefined: Boolean;
-//begin
-// Result := GetCategory.UserDefined;
-//end;
-
{ TCategoryView.TKey }
constructor TCategoryView.TKey.Create(const ID: string);
@@ -706,11 +675,6 @@ function TSnippetKindView.IsGrouping: Boolean;
Result := True;
end;
-//function TSnippetKindView.IsUserDefined: Boolean;
-//begin
-// Result := False;
-//end;
-
{ TSnippetKindView.TKey }
constructor TSnippetKindView.TKey.Create(const ID: TSnippetKind);
@@ -763,11 +727,6 @@ function TInitialLetterView.IsGrouping: Boolean;
Result := True;
end;
-//function TInitialLetterView.IsUserDefined: Boolean;
-//begin
-// Result := False;
-//end;
-
{ TInitialLetterView.TKey }
constructor TInitialLetterView.TKey.Create(const ID: TInitialLetter);
diff --git a/Src/UWBExternal.pas b/Src/UWBExternal.pas
index e219ecb10..5e0b5ba08 100644
--- a/Src/UWBExternal.pas
+++ b/Src/UWBExternal.pas
@@ -57,17 +57,6 @@ TWBExternal = class(TAutoIntfObject, IWBExternal15, ISetNotifier)
/// Method of IWBExternal15.
procedure UpdateDbase; safecall;
-// /// Displays a named snippet.
-// /// WideString [in] Name of snippet to be
-// /// displayed.
-// /// WordBool [in] Whether the snippet is user
-// /// defined.
-// /// WordBool [in] Whether to display snippet in a new
-// /// tab.
-// /// Method of IWBExternal14.
-// procedure DisplaySnippet(const SnippetName: WideString;
-// UserDefined: WordBool; NewTab: WordBool); safecall;
-
/// Displays the Configure Compilers dialogue box.
/// Displays a named snippet.
/// WideString [in] Name of snippet to be
@@ -184,17 +173,6 @@ procedure TWBExternal.DisplaySnippet(const SnippetName,
end;
end;
-//procedure TWBExternal.DisplaySnippet(const SnippetName: WideString;
-// UserDefined: WordBool; NewTab: WordBool);
-//begin
-// try
-// if Assigned(fNotifier) then
-// fNotifier.DisplaySnippet(SnippetName, UserDefined, NewTab);
-// except
-// HandleException;
-// end;
-//end;
-
procedure TWBExternal.EditSnippet(const SnippetName: WideString);
begin
try
From 6e6d67a2d16a8cade5ccf7ba43536f7c93dcc096 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 4 Nov 2024 20:48:35 +0000
Subject: [PATCH 034/222] Revise dbase I/O to get data format from collection
Revised TDatabaseIOFactory to create loader/saver object based on the
data format associated with a collection.
Only applied to data formats for "main" and "user" collections. Did not
get database path / file information from collection, only format kind.
Revised TDatabase's .Load & .Save methods to get collection associated
with user and main databases and to use those to load / save the data.
Added placeholder for code that can write "main" database. This code
currently does nothing for compatibility with CodeSnip 4.
---
Src/DB.UDatabaseIO.pas | 104 ++++++++++++++++++++++++++---------------
Src/DB.UMain.pas | 78 ++++++++++++++++++++++++++++---
2 files changed, 137 insertions(+), 45 deletions(-)
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index b94509019..937172c8d 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -21,7 +21,12 @@ interface
uses
// Project
- DB.UCategory, DB.UMain, DB.USnippet, UBaseObjects, UExceptions;
+ DB.UCollections,
+ DB.UCategory,
+ DB.UMain,
+ DB.USnippet,
+ UBaseObjects,
+ UExceptions;
type
@@ -72,19 +77,17 @@ interface
}
TDatabaseIOFactory = class(TNoConstructObject)
public
- class function CreateMainDBLoader: IDatabaseLoader;
- {Creates an object to use to load the main database.
- @return Required object instance.
- }
- class function CreateUserDBLoader: IDatabaseLoader;
- {Creates an object to use to load the user database.
- @return Required object instance.
- }
- class function CreateWriter: IDatabaseWriter;
- {Create an object that can write user defined data from the Database
- object to storage.
- @return Required object instance.
- }
+ /// Creates and returns an object to be used to load the given
+ /// collection's data. Nil is return if no loader object is supported.
+ ///
+ class function CreateDBLoader(const Collection: TCollection):
+ IDatabaseLoader;
+
+ /// Creates and returns an object to be used to save the given
+ /// collection's data. Nil is return if no saver object is supported.
+ ///
+ class function CreateDBWriter(const Collection: TCollection):
+ IDatabaseWriter;
end;
{
@@ -101,9 +104,15 @@ implementation
// Delphi
SysUtils,
// Project
- DB.UCollections,
- DBIO.UFileIOIntf, DBIO.UIniDataReader, DBIO.UNulDataReader, DBIO.UXMLDataIO,
- UAppInfo, UConsts, UIStringList, UReservedCategories, USnippetIDs;
+ DBIO.UFileIOIntf,
+ DBIO.UIniDataReader,
+ DBIO.UNulDataReader,
+ DBIO.UXMLDataIO,
+ UAppInfo,
+ UConsts,
+ UIStringList,
+ UReservedCategories,
+ USnippetIDs;
type
@@ -125,6 +134,7 @@ TDatabaseLoader = class(TInterfacedObject, IDatabaseLoader)
fSnipList: TSnippetList; // Receives list of snippets
fCategories: TCategoryList; // Receives list of categories
fFactory: IDBDataItemFactory; // Object creates new categories and snippets
+ fCollection: TCollection; // Collection being loaded
procedure LoadSnippets(const Cat: TCategory);
{Loads all snippets in a category.
@param Cat [in] Category to be loaded.
@@ -183,7 +193,9 @@ TDatabaseLoader = class(TInterfacedObject, IDatabaseLoader)
}
property Categories: TCategoryList read fCategories;
{Reference to category list}
+ property Collection: TCollection read fCollection;
public
+ constructor Create(const ACollection: TCollection);
{ IDatabaseLoader method }
procedure Load(const SnipList: TSnippetList;
const Categories: TCategoryList;
@@ -274,6 +286,7 @@ TDatabaseWriter = class(TInterfacedObject,
fSnipList: TSnippetList; // List of snippets to be written
fCategories: TCategoryList; // List of categories to be written
fProvider: IDBDataProvider; // Object used to get data to be written
+ fCollection: TCollection; // Collection being written
function CreateWriter: IDataWriter;
{Creates object that can write data for user-defined database to storage.
@return Requied writer object.
@@ -285,6 +298,7 @@ TDatabaseWriter = class(TInterfacedObject,
{Writes information about all snippets to storage.
}
public
+ constructor Create(const ACollection: TCollection);
{ IDatabaseWriter method }
procedure Write(const SnipList: TSnippetList;
const Categories: TCategoryList;
@@ -301,33 +315,42 @@ TDatabaseWriter = class(TInterfacedObject,
{ TDatabaseIOFactory }
-class function TDatabaseIOFactory.CreateMainDBLoader: IDatabaseLoader;
- {Creates an object to use to load the main database.
- @return Required object instance.
- }
+class function TDatabaseIOFactory.CreateDBLoader(const Collection: TCollection):
+ IDatabaseLoader;
begin
- Result := TMainDatabaseLoader.Create;
+ {TODO -cCollections: Revise database loaders to get file path and other
+ info from collection instead of hard wiring it.}
+ case Collection.CollectionFormatKind of
+ TCollectionFormatKind.DCSC_v2:
+ Result := TMainDatabaseLoader.Create(Collection);
+ TCollectionFormatKind.Native_v4:
+ Result := TUserDatabaseLoader.Create(Collection);
+ else
+ Result := nil;
+ end;
end;
-class function TDatabaseIOFactory.CreateUserDBLoader: IDatabaseLoader;
- {Creates an object to use to load the user database.
- @return Required object instance.
- }
+class function TDatabaseIOFactory.CreateDBWriter(
+ const Collection: TCollection): IDatabaseWriter;
begin
- Result := TUserDatabaseLoader.Create;
+ case Collection.CollectionFormatKind of
+ TCollectionFormatKind.DCSC_v2:
+ Result := nil; {TODO -cVault: add writer object here}
+ TCollectionFormatKind.Native_v4:
+ Result := TDatabaseWriter.Create(Collection);
+ else
+ Result := nil;
+ end;
end;
-class function TDatabaseIOFactory.CreateWriter: IDatabaseWriter;
- {Create an object that can write user defined data from the Database object to
- storage.
- @return Required object instance.
- }
+{ TDatabaseLoader }
+
+constructor TDatabaseLoader.Create(const ACollection: TCollection);
begin
- Result := TDatabaseWriter.Create;
+ inherited Create;
+ fCollection := ACollection;
end;
-{ TDatabaseLoader }
-
procedure TDatabaseLoader.CreateCategory(const CatID: string;
const CatData: TCategoryData);
{Creates a new category and adds it to the categories list.
@@ -335,7 +358,6 @@ procedure TDatabaseLoader.CreateCategory(const CatID: string;
@param CatData [in] Properties of category.
}
begin
-// fCategories.Add(fFactory.CreateCategory(CatID, IsUserDatabase, CatData));
fCategories.Add(fFactory.CreateCategory(CatID, CollectionID, CatData));
end;
@@ -509,7 +531,7 @@ function TMainDatabaseLoader.CreateReader: IDataReader;
@return Reader object instance.
}
begin
- Result := TIniDataReader.Create(TAppInfo.AppDataDir);
+ Result := TIniDataReader.Create(Collection.Location.Directory);
if not Result.DatabaseExists then
Result := TNulDataReader.Create;
end;
@@ -549,7 +571,7 @@ function TUserDatabaseLoader.CreateReader: IDataReader;
@return Reader object instance.
}
begin
- Result := TXMLDataReader.Create(TAppInfo.UserDataDir);
+ Result := TXMLDataReader.Create(Collection.Location.Directory);
if not Result.DatabaseExists then
Result := TNulDataReader.Create;
end;
@@ -601,6 +623,12 @@ procedure TUserDatabaseLoader.LoadCategories;
{ TDatabaseWriter }
+constructor TDatabaseWriter.Create(const ACollection: TCollection);
+begin
+ inherited Create;
+ fCollection := ACollection;
+end;
+
function TDatabaseWriter.CreateWriter: IDataWriter;
{Creates object that can write data for user-defined items from Database to
storage.
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index f60ef54ae..f6fefca65 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -969,18 +969,47 @@ procedure TDatabase.Load;
}
var
Factory: IDBDataItemFactory; // object reader uses to create snippets objects
+ MainCollectionIdx, UserCollectionIdx: Integer;
+ Loader: IDatabaseLoader;
+ Collections: TCollections;
+ Collection: TCollection;
begin
Clear;
+
// Create factory that reader calls into to create category and snippet
// objects. This is done to keep updating of snippet and categories private
// to this unit
Factory := TDBDataItemFactory.Create;
+
+ Collections := TCollections.Instance;
+
+ {TODO: -cVault: The following code is a kludge to maintain compatibility with
+ CodeSnip 4. In CodeSnip Vault we should iterate over all collections
+ creating a loader for each one. }
+
try
- // Load main database: MUST do this first since user database can
- // reference objects in main database
- TDatabaseIOFactory.CreateMainDBLoader.Load(fSnippets, fCategories, Factory);
- // Load any user database
- TDatabaseIOFactory.CreateUserDBLoader.Load(fSnippets, fCategories, Factory);
+ MainCollectionIdx := TCollections.Instance.IndexOfID(
+ TCollectionID.__TMP__MainDBCollectionID
+ );
+ if MainCollectionIdx >= 0 then
+ begin
+ Collection := Collections[MainCollectionIdx];
+ Loader := TDatabaseIOFactory.CreateDBLoader(Collection);
+ if Assigned(Loader) then
+ Loader.Load(fSnippets, fCategories, Factory);
+ end;
+
+ UserCollectionIdx := TCollections.Instance.IndexOfID(
+ TCollectionID.__TMP__UserDBCollectionID
+ );
+ if UserCollectionIdx >= 0 then
+ begin
+ Collection := Collections[UserCollectionIdx];
+ Loader := TDatabaseIOFactory.CreateDBLoader(Collection);
+ if Assigned(Loader) then
+ Loader.Load(fSnippets, fCategories, Factory);
+ end;
+
fUpdated := False;
except
// If an exception occurs clear the database
@@ -1002,11 +1031,46 @@ procedure TDatabase.Save;
}
var
Provider: IDBDataProvider; // object that supplies info to writer
+ MainCollectionIdx, UserCollectionIdx: Integer;
+ Saver: IDatabaseWriter;
+ Collections: TCollections;
+ Collection: TCollection;
begin
// Create object that can provide required information about user database
Provider := TUserDataProvider.Create(fSnippets, fCategories);
- // Use a writer object to write out the database
- TDatabaseIOFactory.CreateWriter.Write(fSnippets, fCategories, Provider);
+
+ Collections := TCollections.Instance;
+
+ {TODO: -cVault: The following code is a kludge to maintain compatibility with
+ CodeSnip 4. In CodeSnip Vault we should iterate over all collections
+ creating a writer for each one. }
+
+ // *** The following code is a stub for later versions. For CodeSnip 4
+ // compatibility this code does nothing because there is no writer for
+ // the "main" collection. TDatabaseIOFactory.CreateDBWriter will return
+ // nil for this format, so Saver.Write will never be called.
+ MainCollectionIdx := TCollections.Instance.IndexOfID(
+ TCollectionID.__TMP__MainDBCollectionID
+ );
+ if MainCollectionIdx >= 0 then
+ begin
+ Collection := Collections[MainCollectionIdx];
+ Saver := TDatabaseIOFactory.CreateDBWriter(Collection);
+ if Assigned(Saver) then
+ Saver.Write(fSnippets, fCategories, Provider);
+ end;
+
+ UserCollectionIdx := TCollections.Instance.IndexOfID(
+ TCollectionID.__TMP__UserDBCollectionID
+ );
+ if UserCollectionIdx >= 0 then
+ begin
+ Collection := Collections[UserCollectionIdx];
+ Saver := TDatabaseIOFactory.CreateDBWriter(Collection);
+ if Assigned(Saver) then
+ Saver.Write(fSnippets, fCategories, Provider);
+ end;
+
fUpdated := False;
end;
From b8390e3b018f61d6ccec269a14327156c336886e Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 5 Nov 2024 11:19:37 +0000
Subject: [PATCH 035/222] Change method of recording user-defined db location
User defined database location was originally recorded in [Database]
settings section in the config file. Since collections were added it was
also stored in the user-defined collection's [Collection:X] settings
section, which was a source of a bug that meant that database moves were
not being recorded consistently.
Removed the [Database] section and revised all relevant code to both
get and set the loaction from/to the [Collection:X] section. This made
the [Database] section redundant.
Updated database moving code in UUserDBMove to read/write database
location using the singleton Collections object.
Modified TAppInfo to get the user database path from the singleton
Collections object instead of settings.
Removed support for redundant [Database] section from settings object.
---
Src/UAppInfo.pas | 40 ++++++++--------------------------------
Src/USettings.pas | 4 +---
Src/UUserDBMove.pas | 15 +++++++++++++--
3 files changed, 22 insertions(+), 37 deletions(-)
diff --git a/Src/UAppInfo.pas b/Src/UAppInfo.pas
index 7bc91fd6e..67f967565 100644
--- a/Src/UAppInfo.pas
+++ b/Src/UAppInfo.pas
@@ -63,13 +63,6 @@ TAppInfo = class(TNoConstructObject)
files.
@return Full path to required directory.
}
- class procedure ChangeUserDataDir(const NewDir: string);
- {Changes directory where CodeSnip stores the user's "database" files and
- records it in the user config file.
- Does nothing on portable edition since it does not permit the user
- database to be moved.
- @param NewDir [in] New directory.
- }
class function AppExeFilePath: string;
{Returns fully specified name of program's executable file.
@return Name of file.
@@ -115,6 +108,7 @@ implementation
// Delphi
SysUtils,
// Project
+ DB.UCollections,
USettings,
UStrUtils,
USystemInfo,
@@ -156,28 +150,6 @@ class function TAppInfo.AppExeFilePath: string;
Result := ParamStr(0);
end;
-class procedure TAppInfo.ChangeUserDataDir(const NewDir: string);
- {Changes directory where CodeSnip stores the user's "database" files and
- records it in the user config file.
- Does nothing on portable edition since it does not permit the user database
- to be moved.
- @param NewDir [in] New directory.
- }
-{$IFNDEF PORTABLE}
-var
- Section: ISettingsSection;
-{$ENDIF}
-begin
- {$IFNDEF PORTABLE}
- Section := Settings.ReadSection(ssDatabase);
- if StrSameText(ExcludeTrailingPathDelimiter(NewDir), DefaultUserDataDir) then
- Section.DeleteItem('UserDataDir')
- else
- Section.SetString('UserDataDir', NewDir);
- Section.Save;
- {$ENDIF}
-end;
-
class function TAppInfo.CommonAppDir: string;
{Gets the CodeSnip data directory stored within the common application data
directory.
@@ -276,12 +248,16 @@ class function TAppInfo.UserDataDir: string;
}
{$IFNDEF PORTABLE}
var
- Section: ISettingsSection; // persistent storage where code is recorded
+ Collections: TCollections;
+ Collection: TCollection;
{$ENDIF}
begin
{$IFNDEF PORTABLE}
- Section := Settings.ReadSection(ssDatabase);
- Result := Section.GetString('UserDataDir', DefaultUserDataDir);
+ Collections := TCollections.Instance;
+ Collection := Collections.GetCollection(TCollectionID.__TMP__UserDBCollectionID);
+ Result := Collection.Location.Directory;
+ if Result = '' then
+ Result := DefaultUserDataDir;
{$ELSE}
Result := DefaultUserDataDir;
{$ENDIF}
diff --git a/Src/USettings.pas b/Src/USettings.pas
index 3f1d26ee8..fe963bffc 100644
--- a/Src/USettings.pas
+++ b/Src/USettings.pas
@@ -177,7 +177,6 @@ interface
/// -ssFavourites - persistent settings from Favourites dlg
/// -ssWindowState - info about the size and state of various
/// windows
- /// -ssDatabase - database customisation info
/// -ssCompilers - info about all compilers
/// -ssCollections - info about all snippet collections
/// -ssCollection - info about a specific snippet collection
@@ -185,7 +184,7 @@ interface
TSettingsSectionId = (
ssFindText, ssFindCompiler, ssFindXRefs, ssCompilerInfo,
ssPreferences, ssUnits, ssDuplicateSnippet,
- ssFavourites, ssWindowState, ssDatabase, ssCompilers, ssCollections,
+ ssFavourites, ssWindowState, ssCompilers, ssCollections,
ssCollection
);
@@ -579,7 +578,6 @@ function TIniSettings.SectionName(const Id: TSettingsSectionId;
'DuplicateSnippet', // ssDuplicateSnippet
'Favourites', // ssFavourites
'WindowState', // ssWindowState
- 'Database', // ssDatabase
'Compilers', // ssCompilers
'Collections', // ssCollections
'Collection' // ssCollection
diff --git a/Src/UUserDBMove.pas b/Src/UUserDBMove.pas
index 2af3f4056..946062070 100644
--- a/Src/UUserDBMove.pas
+++ b/Src/UUserDBMove.pas
@@ -91,7 +91,9 @@ implementation
// Delphi
SysUtils, IOUtils,
// Project
- UAppInfo, UStrUtils;
+ DB.UCollections,
+ UAppInfo,
+ UStrUtils;
{ TUserDBMove }
@@ -134,9 +136,18 @@ procedure TUserDBMove.ReportDeleteProgress(Sender: TObject;
end;
procedure TUserDBMove.SetNewDBDirectory(Sender: TObject);
+var
+ Collection: TCollection;
+ Collections: TCollections;
begin
// record new location BEFORE deleting old directory
- TAppInfo.ChangeUserDataDir(fDestDir);
+ Collections := TCollections.Instance;
+ Collection := Collections.GetCollection(TCollectionID.__TMP__UserDBCollectionID);
+ Collection.Location.Directory := fDestDir;
+ Collections.Update(Collection);
+ // Persist collections immediately to save new directory ASAP to prevent
+ // directory change being lost following a program crash.
+ Collections.Save;
end;
procedure TUserDBMove.ValidateDirectories;
From 55cb8873334922fb33dec1d3496fa3bd58c4906a Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 5 Nov 2024 17:05:22 +0000
Subject: [PATCH 036/222] Rename DBIO.UIniDataReader unit as DBIO.UIniData
Renamed the unit since it is going to be used for writing the Code
Snippets Collection ini database format (known as the "main database" in
CodeSnip 4) in addition to the existing code used to read the
collection.
Modified the CodeSnip .dpr and .dproj project files re the name change.
Updated use clause in DB.UDatabaseIO re the name change.
---
Src/CodeSnip.dpr | 2 +-
Src/CodeSnip.dproj | 2 +-
Src/DB.UDatabaseIO.pas | 2 +-
Src/{DBIO.UIniDataReader.pas => DBIO.UIniData.pas} | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
rename Src/{DBIO.UIniDataReader.pas => DBIO.UIniData.pas} (99%)
diff --git a/Src/CodeSnip.dpr b/Src/CodeSnip.dpr
index c2c6be15d..98cb69a47 100644
--- a/Src/CodeSnip.dpr
+++ b/Src/CodeSnip.dpr
@@ -70,7 +70,7 @@ uses
DB.USnippet in 'DB.USnippet.pas',
DB.USnippetKind in 'DB.USnippetKind.pas',
DBIO.UFileIOIntf in 'DBIO.UFileIOIntf.pas',
- DBIO.UIniDataReader in 'DBIO.UIniDataReader.pas',
+ DBIO.UIniData in 'DBIO.UIniData.pas',
DBIO.UNulDataReader in 'DBIO.UNulDataReader.pas',
DBIO.UXMLDataIO in 'DBIO.UXMLDataIO.pas',
Favourites.UManager in 'Favourites.UManager.pas',
diff --git a/Src/CodeSnip.dproj b/Src/CodeSnip.dproj
index f0d0f83f1..1141453ca 100644
--- a/Src/CodeSnip.dproj
+++ b/Src/CodeSnip.dproj
@@ -73,7 +73,7 @@
-
+
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index 937172c8d..208a83146 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -105,7 +105,7 @@ implementation
SysUtils,
// Project
DBIO.UFileIOIntf,
- DBIO.UIniDataReader,
+ DBIO.UIniData,
DBIO.UNulDataReader,
DBIO.UXMLDataIO,
UAppInfo,
diff --git a/Src/DBIO.UIniDataReader.pas b/Src/DBIO.UIniData.pas
similarity index 99%
rename from Src/DBIO.UIniDataReader.pas
rename to Src/DBIO.UIniData.pas
index 90b0c9657..7e849979c 100644
--- a/Src/DBIO.UIniDataReader.pas
+++ b/Src/DBIO.UIniData.pas
@@ -10,7 +10,7 @@
}
-unit DBIO.UIniDataReader;
+unit DBIO.UIniData;
interface
From 86f63ff175a7f828998a06b7de8a15369b60556b Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 5 Nov 2024 19:59:20 +0000
Subject: [PATCH 037/222] Class/interface/method renamings in DB.UDatabaseIO
Renamed the following classes and interfaces in DB.UDatabaseIO unit:
IDatabaseLoader => IDataFormatLoader
IDatabaseWriter => IDataFormatSaver
TMainDatabaseLoader => TDCSCV2FormatLoader
TUserDatabaseLoader => TNativeV4FormatLoader
TDatabaseWriter => TNativeV4FormatSaver
Also renamed the following methods:
IDataFormatSaver .Write => .Save (& in implementing class)
TDatabaseIOFactory .CreateDBWriter => .CreateDBSaver
Updated affected code in DB.UMain unit.
Updated some comments to XMLDoc format.
---
Src/DB.UDatabaseIO.pas | 160 +++++++++++++++++++----------------------
Src/DB.UMain.pas | 12 ++--
2 files changed, 79 insertions(+), 93 deletions(-)
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index 208a83146..ba8f489bd 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -31,43 +31,37 @@ interface
type
- {
- IDatabaseLoader:
- Interface to object that can load data into the Database object from
- storage.
- }
- IDatabaseLoader = interface(IInterface)
+ /// Interface to objects that can load data into a collection within
+ /// the database from storage in a supported data format.
+ IDataFormatLoader = interface(IInterface)
['{C6AF94FC-F56F-44AE-9E79-3B0CD0BB21D4}']
+ /// Loads data from storage into a collection within the database.
+ ///
+ /// TSnippetList [in] Receives information
+ /// about each snippet in the collection.
+ /// TCategoryList [in] Receives information
+ /// about each category in the collection.
+ /// DBDataItemFactory [in] Object
+ /// used to create new categories and snippets.
procedure Load(const SnipList: TSnippetList;
const Categories: TCategoryList;
const DBDataItemFactory: IDBDataItemFactory);
- {Loads data from storage and updates database object.
- @param SnipList [in] Receives information about each snippet in the
- database.
- @param Categories [in] Receives information about each category in the
- database.
- @param DBDataItemFactory [in] Object used to create new categories and
- snippets.
- }
end;
- {
- IDatabaseWriter:
- Interface to object that can write data from the user-defined component of
- the Database object to storage.
- }
- IDatabaseWriter = interface(IInterface)
+ /// Interface to objects that can save data from a collection within
+ /// the database into storage in a supported data format.
+ IDataFormatSaver = interface(IInterface)
['{F46EE2E3-68A7-4877-9E04-192D15D29BB1}']
- procedure Write(const SnipList: TSnippetList;
+ /// Saves data from a collection within the database to storage.
+ ///
+ /// TSnippetList [in] Contains information
+ /// about each snippet in the collection.
+ /// TCategoryList [in] Contains information
+ /// about each category in the collection.
+ /// IDBDataProvider [in] Object used to
+ /// obtain details of the data to storage.
+ procedure Save(const SnipList: TSnippetList;
const Categories: TCategoryList; const Provider: IDBDataProvider);
- {Writes data from Database object to storage.
- @param SnipList [in] Contains information about each snippet in the
- database.
- @param Categories [in] Contains information about each category in the
- database.
- @param Privider [in] Object used to obtain details of the data to be
- written to the Database object
- }
end;
{
@@ -78,16 +72,16 @@ interface
TDatabaseIOFactory = class(TNoConstructObject)
public
/// Creates and returns an object to be used to load the given
- /// collection's data. Nil is return if no loader object is supported.
- ///
+ /// collection's data in the correct format. Nil is returned if no loader
+ /// object is supported.
class function CreateDBLoader(const Collection: TCollection):
- IDatabaseLoader;
+ IDataFormatLoader;
/// Creates and returns an object to be used to save the given
- /// collection's data. Nil is return if no saver object is supported.
- ///
- class function CreateDBWriter(const Collection: TCollection):
- IDatabaseWriter;
+ /// collection's data in the correct format. Nil is return if no saver
+ /// object is supported.
+ class function CreateDBSaver(const Collection: TCollection):
+ IDataFormatSaver;
end;
{
@@ -128,7 +122,7 @@ TDatabaseLoaderClass = class of TDatabaseLoader;
Abstract base class for objects that can load data into the Database object
from storage.
}
- TDatabaseLoader = class(TInterfacedObject, IDatabaseLoader)
+ TDatabaseLoader = class(TInterfacedObject, IDataFormatLoader)
strict private
fReader: IDataReader; // Object used to read data from storage
fSnipList: TSnippetList; // Receives list of snippets
@@ -196,7 +190,7 @@ TDatabaseLoader = class(TInterfacedObject, IDatabaseLoader)
property Collection: TCollection read fCollection;
public
constructor Create(const ACollection: TCollection);
- { IDatabaseLoader method }
+ { IDataFormatLoader method }
procedure Load(const SnipList: TSnippetList;
const Categories: TCategoryList;
const DBDataItemFactory: IDBDataItemFactory);
@@ -211,10 +205,10 @@ TDatabaseLoader = class(TInterfacedObject, IDatabaseLoader)
end;
{
- TMainDatabaseLoader:
+ TDCSCV2FormatLoader:
Class that updates Database object with data read from main database.
}
- TMainDatabaseLoader = class(TDatabaseLoader, IDatabaseLoader)
+ TDCSCV2FormatLoader = class(TDatabaseLoader, IDataFormatLoader)
strict protected
function CreateReader: IDataReader; override;
{Creates reader object. If main database doesn't exist a nul reader is
@@ -241,10 +235,10 @@ TMainDatabaseLoader = class(TDatabaseLoader, IDatabaseLoader)
end;
{
- TUserDatabaseLoader:
+ TNativeV4FormatLoader:
Class that updates Database object with data read from user database.
}
- TUserDatabaseLoader = class(TDatabaseLoader, IDatabaseLoader)
+ TNativeV4FormatLoader = class(TDatabaseLoader, IDataFormatLoader)
strict protected
function CreateReader: IDataReader; override;
{Creates reader object. If user database doesn't exist a nul reader is
@@ -275,11 +269,11 @@ TUserDatabaseLoader = class(TDatabaseLoader, IDatabaseLoader)
end;
{
- TDatabaseWriter:
- Object used to write data from user database to storage.
+ TNativeV4FormatWriter:
+ Object used to write data from the native snippets v4 to storage.
}
- TDatabaseWriter = class(TInterfacedObject,
- IDatabaseWriter
+ TNativeV4FormatSaver = class(TInterfacedObject,
+ IDataFormatSaver
)
strict private
fWriter: IDataWriter; // Object used to write to storage
@@ -299,45 +293,45 @@ TDatabaseWriter = class(TInterfacedObject,
}
public
constructor Create(const ACollection: TCollection);
- { IDatabaseWriter method }
- procedure Write(const SnipList: TSnippetList;
+ /// Saves data from a collection within the database to storage.
+ ///
+ /// TSnippetList [in] Contains information
+ /// about each snippet in the collection.
+ /// TCategoryList [in] Contains information
+ /// about each category in the collection.
+ /// IDBDataProvider [in] Object used to
+ /// obtain details of the data to storage.
+ /// Method of IDataFormatSaver.
+ procedure Save(const SnipList: TSnippetList;
const Categories: TCategoryList;
const Provider: IDBDataProvider);
- {Writes data from Database object to storage.
- @param SnipList [in] Contains information about each snippet in the
- database.
- @param Categories [in] Contains information about each category in the
- database.
- @param Provider [in] Object used to obtain details of the data to be
- written from the Database object
- }
end;
{ TDatabaseIOFactory }
class function TDatabaseIOFactory.CreateDBLoader(const Collection: TCollection):
- IDatabaseLoader;
+ IDataFormatLoader;
begin
{TODO -cCollections: Revise database loaders to get file path and other
info from collection instead of hard wiring it.}
case Collection.CollectionFormatKind of
TCollectionFormatKind.DCSC_v2:
- Result := TMainDatabaseLoader.Create(Collection);
+ Result := TDCSCV2FormatLoader.Create(Collection);
TCollectionFormatKind.Native_v4:
- Result := TUserDatabaseLoader.Create(Collection);
+ Result := TNativeV4FormatLoader.Create(Collection);
else
Result := nil;
end;
end;
-class function TDatabaseIOFactory.CreateDBWriter(
- const Collection: TCollection): IDatabaseWriter;
+class function TDatabaseIOFactory.CreateDBSaver(
+ const Collection: TCollection): IDataFormatSaver;
begin
case Collection.CollectionFormatKind of
TCollectionFormatKind.DCSC_v2:
Result := nil; {TODO -cVault: add writer object here}
TCollectionFormatKind.Native_v4:
- Result := TDatabaseWriter.Create(Collection);
+ Result := TNativeV4FormatSaver.Create(Collection);
else
Result := nil;
end;
@@ -518,14 +512,14 @@ procedure TDatabaseLoader.LoadSnippets(const Cat: TCategory);
end;
end;
-{ TMainDatabaseLoader }
+{ TDCSCV2FormatLoader }
-function TMainDatabaseLoader.CollectionID: TCollectionID;
+function TDCSCV2FormatLoader.CollectionID: TCollectionID;
begin
Result := TCollectionID.__TMP__MainDBCollectionID;
end;
-function TMainDatabaseLoader.CreateReader: IDataReader;
+function TDCSCV2FormatLoader.CreateReader: IDataReader;
{Creates reader object. If main database doesn't exist a nul reader is
created.
@return Reader object instance.
@@ -536,7 +530,7 @@ function TMainDatabaseLoader.CreateReader: IDataReader;
Result := TNulDataReader.Create;
end;
-function TMainDatabaseLoader.ErrorMessageHeading: string;
+function TDCSCV2FormatLoader.ErrorMessageHeading: string;
{Returns heading to use in error messages. Identifies main database.
@return Required heading.
}
@@ -546,7 +540,7 @@ function TMainDatabaseLoader.ErrorMessageHeading: string;
Result := sError;
end;
-function TMainDatabaseLoader.FindSnippet(const SnippetName: string;
+function TDCSCV2FormatLoader.FindSnippet(const SnippetName: string;
const SnipList: TSnippetList): TSnippet;
{Finds the snippet object with a specified name in the main database.
@param SnippetName [in] Name of required snippet.
@@ -558,14 +552,14 @@ function TMainDatabaseLoader.FindSnippet(const SnippetName: string;
Result := SnipList.Find(SnippetName, CollectionID);
end;
-{ TUserDatabaseLoader }
+{ TNativeV4FormatLoader }
-function TUserDatabaseLoader.CollectionID: TCollectionID;
+function TNativeV4FormatLoader.CollectionID: TCollectionID;
begin
Result := TCollectionID.__TMP__UserDBCollectionID;
end;
-function TUserDatabaseLoader.CreateReader: IDataReader;
+function TNativeV4FormatLoader.CreateReader: IDataReader;
{Creates reader object. If user database doesn't exist a nul reader is
created.
@return Reader object instance.
@@ -576,7 +570,7 @@ function TUserDatabaseLoader.CreateReader: IDataReader;
Result := TNulDataReader.Create;
end;
-function TUserDatabaseLoader.ErrorMessageHeading: string;
+function TNativeV4FormatLoader.ErrorMessageHeading: string;
{Returns heading to use in error messages. Identifies main database.
@return Required heading.
}
@@ -586,7 +580,7 @@ function TUserDatabaseLoader.ErrorMessageHeading: string;
Result := sError;
end;
-function TUserDatabaseLoader.FindSnippet(const SnippetName: string;
+function TNativeV4FormatLoader.FindSnippet(const SnippetName: string;
const SnipList: TSnippetList): TSnippet;
{Finds the snippet object with a specified name. If snippet is not in this
(user) database the main database is searched.
@@ -602,7 +596,7 @@ function TUserDatabaseLoader.FindSnippet(const SnippetName: string;
Result := SnipList.Find(SnippetName, TCollectionID.__TMP__MainDBCollectionID);
end;
-procedure TUserDatabaseLoader.LoadCategories;
+procedure TNativeV4FormatLoader.LoadCategories;
{Loads all categories from storage and adds user and imports categories if not
present.
}
@@ -621,15 +615,15 @@ procedure TUserDatabaseLoader.LoadCategories;
end;
end;
-{ TDatabaseWriter }
+{ TNativeV4FormatSaver }
-constructor TDatabaseWriter.Create(const ACollection: TCollection);
+constructor TNativeV4FormatSaver.Create(const ACollection: TCollection);
begin
inherited Create;
fCollection := ACollection;
end;
-function TDatabaseWriter.CreateWriter: IDataWriter;
+function TNativeV4FormatSaver.CreateWriter: IDataWriter;
{Creates object that can write data for user-defined items from Database to
storage.
@return Requied writer object.
@@ -638,16 +632,8 @@ function TDatabaseWriter.CreateWriter: IDataWriter;
Result := TXMLDataWriter.Create(TAppInfo.UserDataDir);
end;
-procedure TDatabaseWriter.Write(const SnipList: TSnippetList;
+procedure TNativeV4FormatSaver.Save(const SnipList: TSnippetList;
const Categories: TCategoryList; const Provider: IDBDataProvider);
- {Writes data from Database object to storage.
- @param SnipList [in] Contains information about each snippet in the
- database.
- @param Categories [in] Contains information about each category in the
- database.
- @param Provider [in] Object used to obtain details of the Database data to
- be written.
- }
begin
fSnipList := SnipList;
fCategories := Categories;
@@ -659,7 +645,7 @@ procedure TDatabaseWriter.Write(const SnipList: TSnippetList;
fWriter.Finalise;
end;
-procedure TDatabaseWriter.WriteCategories;
+procedure TNativeV4FormatSaver.WriteCategories;
{Writes information about categories to storage.
}
var
@@ -676,7 +662,7 @@ procedure TDatabaseWriter.WriteCategories;
end;
end;
-procedure TDatabaseWriter.WriteSnippets;
+procedure TNativeV4FormatSaver.WriteSnippets;
{Writes information about all snippets to storage.
}
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index f6fefca65..6ef02abbd 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -970,7 +970,7 @@ procedure TDatabase.Load;
var
Factory: IDBDataItemFactory; // object reader uses to create snippets objects
MainCollectionIdx, UserCollectionIdx: Integer;
- Loader: IDatabaseLoader;
+ Loader: IDataFormatLoader;
Collections: TCollections;
Collection: TCollection;
begin
@@ -1032,7 +1032,7 @@ procedure TDatabase.Save;
var
Provider: IDBDataProvider; // object that supplies info to writer
MainCollectionIdx, UserCollectionIdx: Integer;
- Saver: IDatabaseWriter;
+ Saver: IDataFormatSaver;
Collections: TCollections;
Collection: TCollection;
begin
@@ -1055,9 +1055,9 @@ procedure TDatabase.Save;
if MainCollectionIdx >= 0 then
begin
Collection := Collections[MainCollectionIdx];
- Saver := TDatabaseIOFactory.CreateDBWriter(Collection);
+ Saver := TDatabaseIOFactory.CreateDBSaver(Collection);
if Assigned(Saver) then
- Saver.Write(fSnippets, fCategories, Provider);
+ Saver.Save(fSnippets, fCategories, Provider);
end;
UserCollectionIdx := TCollections.Instance.IndexOfID(
@@ -1066,9 +1066,9 @@ procedure TDatabase.Save;
if UserCollectionIdx >= 0 then
begin
Collection := Collections[UserCollectionIdx];
- Saver := TDatabaseIOFactory.CreateDBWriter(Collection);
+ Saver := TDatabaseIOFactory.CreateDBSaver(Collection);
if Assigned(Saver) then
- Saver.Write(fSnippets, fCategories, Provider);
+ Saver.Save(fSnippets, fCategories, Provider);
end;
fUpdated := False;
From 3fab0d3f174e9a0d7ef68246e7c099bbf7154834 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 5 Nov 2024 20:59:19 +0000
Subject: [PATCH 038/222] Replace TUserDataProvider w/ TCollectionDataProvider
TUserDataProvider provided information about snippets & ctaegories from
the user database / collection. TCollectionDataProvider generalises
TUserDataProvider to provide information about snippets & categories
from any given collection.
TDatabase.Save was modified to use different TCollectionDataProvider
instances for saving both the "main" and "user" collections.
The previous reliance on the same TUserDataProvider instance for both
user and main collections was a bug which had only not materialised
because, as yet, the "main" collection does not have an associated
saver object and so nothing is saved.
---
Src/DB.UMain.pas | 191 ++++++++++++++++++++++++-----------------------
1 file changed, 96 insertions(+), 95 deletions(-)
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index 6ef02abbd..e732ddb2e 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -54,33 +54,39 @@ interface
evCategoryChanged // a category's properties have changed
);
- {
- IDBDataProvider:
- Interface supported by objects that provides data about the categories and
- snippets in the database.
- }
+ /// Interface supported by objects that provide information about
+ /// categories and snippets.
IDBDataProvider = interface(IInterface)
['{D2D57A0D-DB29-4012-891E-E817E0EED8C8}']
+
+ /// Retrieves all the properties of a category.
+ /// Category [in] Category for which properties
+ /// are requested.
+ /// TCategoryData. Record containing the property data.
+ ///
function GetCategoryProps(const Cat: TCategory): TCategoryData;
- {Retrieves all the properties of a category.
- @param Cat [in] Category for which data is requested.
- @return Record containing property data.
- }
+
+ /// Retrieves names of all snippets that belong to a category.
+ ///
+ /// Category [in] Category for which snippet names
+ /// are requested.
+ /// IStringList. List of snippet names.
function GetCategorySnippets(const Cat: TCategory): IStringList;
- {Retrieves names of all snippets that belong to a category.
- @param Cat [in] Category for which snippet names are requested.
- @return Required list of snippet names.
- }
+
+ /// Retrieves all the properties of a snippet.
+ /// TSnippet [in] Snippet for which properties
+ /// are requested.
+ /// TSnippetData. Record containing the property data.
+ ///
function GetSnippetProps(const Snippet: TSnippet): TSnippetData;
- {Retrieves all the properties of a snippet.
- @param Snippet [in] Snippet for which data is requested.
- @return Record containing property data.
- }
+
+ /// Retrieves information about all the references of a snippet.
+ ///
+ /// TSnippet [in] Snippet for which references
+ /// are requested.
+ /// TSnippetReferences. Record containing references.
+ ///
function GetSnippetRefs(const Snippet: TSnippet): TSnippetReferences;
- {Retrieves information about all the references of a snippet.
- @param Snippet [in] Snippet for which information is requested.
- @return Record containing references.
- }
end;
{
@@ -106,11 +112,8 @@ interface
depends on Kind. May be nil}
end;
- {
- IDataItemFactory:
- Interface to factory object that creates snippet and category objects. For
- use by database loader objects.
- }
+ /// Interface to factory object that creates snippet and category
+ /// objects use by collection loader objects.
IDBDataItemFactory = interface(IInterface)
['{C6DD85BD-E649-4A90-961C-4011D2714B3E}']
@@ -301,12 +304,10 @@ implementation
type
- {
- TDBDataItemFactory:
- Class that can create category and snippet objects.
- }
+ /// Class that can create category and snippet objects..
TDBDataItemFactory = class(TInterfacedObject, IDBDataItemFactory)
public
+
/// Creates a new category object.
/// string [in] ID of new category. Must be
/// unique.
@@ -540,44 +541,59 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
}
end;
- {
- TUserDataProvider:
- Class that provides data about the categories and snippets in the user-
- defined database.
- }
- TUserDataProvider = class(TInterfacedObject, IDBDataProvider)
+ /// Class that provides data about the categories and snippets in
+ /// a given collection.
+ TCollectionDataProvider = class(TInterfacedObject, IDBDataProvider)
strict private
- fSnippets: TSnippetList; // All snippets in the whole database
- fCategories: TCategoryList; // All categories in the whole database
+ var
+ fCollectionID: TCollectionID; // Collection on which to operate
+ fSnippets: TSnippetList; // All snippets in the whole database
+ fCategories: TCategoryList; // All categories in the whole database
public
- constructor Create(const SnipList: TSnippetList;
+ /// Object constructor. Sets up data provider.
+ /// TCollectionID [in] Collection for
+ /// which to provide data.
+ /// TSnippetList [in] List of all snippets
+ /// in the database.
+ /// TCategoryList [in] List of all
+ /// categories in the database.
+ constructor Create(const ACollectionID: TCollectionID;
+ const SnipList: TSnippetList;
const Categories: TCategoryList);
- {Constructor. Records list of all snippets and categories in both
- databases.
- @param SnipList [in] List of all snippets in whole database.
- @param Categories [in] List of all categories in whole database.
- }
- { IDBDataProvider methods }
+
+ /// Retrieves all the properties of a category.
+ /// Category [in] Category for which properties
+ /// are requested.
+ /// TCategoryData. Record containing the property data.
+ ///
+ /// Method of IDBDataProvider
function GetCategoryProps(const Cat: TCategory): TCategoryData;
- {Retrieves all the properties of a category.
- @param Cat [in] Category for which data is requested.
- @return Record containing property data.
- }
+
+ /// Retrieves names of all snippets from the collection that
+ /// belong to a category.
+ /// Category [in] Category for which snippet names
+ /// are requested.
+ /// IStringList. List of snippet names.
+ /// Method of IDBDataProvider
function GetCategorySnippets(const Cat: TCategory): IStringList;
- {Retrieves names of all user-defined snippets that belong to a category.
- @param Cat [in] Category for which snippet names are requested.
- @return Required list of snippet names.
- }
+
+ /// Retrieves all the properties of a snippet.
+ /// TSnippet [in] Snippet for which properties
+ /// are requested.
+ /// TSnippetData. Record containing the property data.
+ ///
+ /// Method of IDBDataProvider
function GetSnippetProps(const Snippet: TSnippet): TSnippetData;
- {Retrieves all the properties of a snippet.
- @param Snippet [in] Snippet for which data is requested.
- @return Record containing property data.
- }
+
+ /// Retrieves information about all the references of a snippet.
+ ///
+ /// TSnippet [in] Snippet for which references
+ /// are requested.
+ /// TSnippetReferences. Record containing references.
+ ///
+ /// Method of IDBDataProvider
function GetSnippetRefs(const Snippet: TSnippet): TSnippetReferences;
- {Retrieves information about all the references of a snippet.
- @param Snippet [in] Snippet for which information is requested.
- @return Record containing references.
- }
+
end;
function Database: IDatabase;
@@ -1030,15 +1046,12 @@ procedure TDatabase.Save;
{Saves user defined snippets and all categories to user database.
}
var
- Provider: IDBDataProvider; // object that supplies info to writer
+ MainProvider, UserProvider: IDBDataProvider; // object that supplies info to writer
MainCollectionIdx, UserCollectionIdx: Integer;
Saver: IDataFormatSaver;
Collections: TCollections;
Collection: TCollection;
begin
- // Create object that can provide required information about user database
- Provider := TUserDataProvider.Create(fSnippets, fCategories);
-
Collections := TCollections.Instance;
{TODO: -cVault: The following code is a kludge to maintain compatibility with
@@ -1055,9 +1068,12 @@ procedure TDatabase.Save;
if MainCollectionIdx >= 0 then
begin
Collection := Collections[MainCollectionIdx];
+ MainProvider := TCollectionDataProvider.Create(
+ TCollectionID.__TMP__MainDBCollectionID, fSnippets, fCategories
+ );
Saver := TDatabaseIOFactory.CreateDBSaver(Collection);
if Assigned(Saver) then
- Saver.Save(fSnippets, fCategories, Provider);
+ Saver.Save(fSnippets, fCategories, MainProvider);
end;
UserCollectionIdx := TCollections.Instance.IndexOfID(
@@ -1066,9 +1082,12 @@ procedure TDatabase.Save;
if UserCollectionIdx >= 0 then
begin
Collection := Collections[UserCollectionIdx];
+ UserProvider := TCollectionDataProvider.Create(
+ TCollectionID.__TMP__UserDBCollectionID, fSnippets, fCategories
+ );
Saver := TDatabaseIOFactory.CreateDBSaver(Collection);
if Assigned(Saver) then
- Saver.Save(fSnippets, fCategories, Provider);
+ Saver.Save(fSnippets, fCategories, UserProvider);
end;
fUpdated := False;
@@ -1243,65 +1262,47 @@ function TDBDataItemFactory.CreateSnippet(const Name: string;
Result := TSnippetEx.Create(Name, ACollectionID, Props);
end;
-{ TUserDataProvider }
+{ TCollectionDataProvider }
-constructor TUserDataProvider.Create(const SnipList: TSnippetList;
- const Categories: TCategoryList);
- {Constructor. Records list of all snippets and categories in both databases.
- @param SnipList [in] List of all snippets in whole database.
- @param Categories [in] List of all categories in whole database.
- }
+constructor TCollectionDataProvider.Create(const ACollectionID: TCollectionID;
+ const SnipList: TSnippetList; const Categories: TCategoryList);
begin
inherited Create;
+ fCollectionID := ACollectionID;
fSnippets := SnipList;
fCategories := Categories;
end;
-function TUserDataProvider.GetCategoryProps(
+function TCollectionDataProvider.GetCategoryProps(
const Cat: TCategory): TCategoryData;
- {Retrieves all the properties of a category.
- @param Cat [in] Category for which data is requested.
- @return Record containing property data.
- }
begin
Result.Desc := Cat.Description;
end;
-function TUserDataProvider.GetCategorySnippets(
+function TCollectionDataProvider.GetCategorySnippets(
const Cat: TCategory): IStringList;
- {Retrieves names of all user-defined snippets that belong to a category.
- @param Cat [in] Category for which snippet names are requested.
- @return Required list of snippet names.
- }
var
Snippet: TSnippet; // references each snippet in category
begin
Result := TIStringList.Create;
for Snippet in Cat.Snippets do
- if Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
+ if Snippet.CollectionID = fCollectionID then
Result.Add(Snippet.Name);
end;
-function TUserDataProvider.GetSnippetProps(
+function TCollectionDataProvider.GetSnippetProps(
const Snippet: TSnippet): TSnippetData;
- {Retrieves all the properties of a snippet.
- @param Snippet [in] Snippet for which data is requested.
- @return Record containing property data.
- }
begin
Result := (Snippet as TSnippetEx).GetProps;
end;
-function TUserDataProvider.GetSnippetRefs(
+function TCollectionDataProvider.GetSnippetRefs(
const Snippet: TSnippet): TSnippetReferences;
- {Retrieves information about all the references of a snippet.
- @param Snippet [in] Snippet for which information is requested.
- @return Record containing references.
- }
begin
Result := (Snippet as TSnippetEx).GetReferences;
end;
+
initialization
From a7959cfb4f67efbf4eebf1fe623cc5f9c8fd4254 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Wed, 6 Nov 2024 16:07:37 +0000
Subject: [PATCH 039/222] Add option to TREMLWriter to render one-line REML
Added optional "Formatted" paramter to TREMLWriter.Render method to
given option to render REML all on one line with no indentation suitable
for inclusion in .ini files. Default behaviour remains to render multi-
line, indented REML.
Some private methods received similar new parameters and changes.
---
Src/UREMLDataIO.pas | 111 +++++++++++++++++++++++++-------------------
1 file changed, 62 insertions(+), 49 deletions(-)
diff --git a/Src/UREMLDataIO.pas b/Src/UREMLDataIO.pas
index 76974afc8..a6d73004e 100644
--- a/Src/UREMLDataIO.pas
+++ b/Src/UREMLDataIO.pas
@@ -132,28 +132,45 @@ TREMLWriter = class(TNoPublicConstructObject)
@param Text [in] Plain text to be converted.
@return Converted text.
}
- function RenderTag(const TagElem: IActiveTextActionElem): string;
- {Renders an active text action element as a REML tag.
- @param TagElem [in] Active text action element to be rendered.
- @return Required REML tag.
- }
- function RenderText(const TextElem: IActiveTextTextElem): string;
- {Renders an active text text element. Illegal characters are converted to
- REML character entities.
- @param TextElem [in] Active text text element.
- @return REML-safe text containing necessary character entities.
- }
+ /// Renders an active text action element as a REML tag.
+ /// IActiveTextActionElem [in] Active text
+ /// action element to be rendered.
+ /// Boolean [in] Optional flag that
+ /// determines if tag is to be rendered formatted as multiple, indented
+ /// lines of REML code (True) or with no formatting (False).
+ /// string. Required REML tag.
+ function RenderTag(const TagElem: IActiveTextActionElem;
+ const Formatted: Boolean): string;
+
+ /// Renders an active text text element. Illegal characters are
+ /// converted to REML character entities.
+ /// IActiveTextTextElem [in] Active text text
+ /// element to be rendered.
+ /// Boolean [in] Optional flag that
+ /// determines if text is to be rendered indented (True) or not (False).
+ ///
+ /// string. REML-safe text containing necessary character
+ /// entities.
+ function RenderText(const TextElem: IActiveTextTextElem;
+ const Indented: Boolean): string;
+
strict protected
constructor InternalCreate;
- {Internal class constructor. Sets up object to render active text document
+ {Internal constructor. Sets up object to render active text document
as REML.
}
public
- class function Render(const ActiveText: IActiveText): string;
- {Renders REML representation of an active text object.
- @param ActiveText [in] Active text to be rendered.
- @return String containing REML markup.
- }
+ /// Renders REML representation of an active text object.
+ ///
+ /// IActiveText [in] Active text to be
+ /// rendered.
+ /// Boolean [in] Optional flag that
+ /// determines if REML is to be rendered formatted as multiple lines of
+ /// indented text (True: the default) or as a single line of text with no
+ /// formatting (False).
+ /// string containing REML markup.
+ class function Render(const ActiveText: IActiveText;
+ const Formatted: Boolean = True): string;
end;
@@ -719,11 +736,8 @@ constructor TREMLWriter.InternalCreate;
inherited InternalCreate;
end;
-class function TREMLWriter.Render(const ActiveText: IActiveText): string;
- {Renders REML representation of an active text object.
- @param ActiveText [in] Active text to be rendered.
- @return String containing REML markup.
- }
+class function TREMLWriter.Render(const ActiveText: IActiveText;
+ const Formatted: Boolean): string;
var
Elem: IActiveTextElem; // each element in active text object
TextElem: IActiveTextTextElem; // an active text text element
@@ -744,30 +758,31 @@ class function TREMLWriter.Render(const ActiveText: IActiveText): string;
for Elem in ActiveText do
begin
if Supports(Elem, IActiveTextTextElem, TextElem) then
- Text := Text + RW.RenderText(TextElem)
+ Text := Text + RW.RenderText(TextElem, Formatted)
else if Supports(Elem, IActiveTextActionElem, TagElem) then
- Text := Text + RW.RenderTag(TagElem);
+ Text := Text + RW.RenderTag(TagElem, Formatted);
end;
- SrcLines := TIStringList.Create(Text, EOL, False);
- DestLines := TIStringList.Create;
- for SrcLine in SrcLines do
+ if Formatted then
begin
- DestLine := StrTrimRight(SrcLine);
- if not StrIsEmpty(DestLine) then
- DestLines.Add(DestLine);
- end;
- Result := DestLines.GetText(EOL, False);
+ SrcLines := TIStringList.Create(Text, EOL, False);
+ DestLines := TIStringList.Create;
+ for SrcLine in SrcLines do
+ begin
+ DestLine := StrTrimRight(SrcLine);
+ if not StrIsEmpty(DestLine) then
+ DestLines.Add(DestLine);
+ end;
+ Result := DestLines.GetText(EOL, False);
+ end
+ else
+ Result := StrTrim(Text);
finally
RW.Free;
end;
end;
-function TREMLWriter.RenderTag(
- const TagElem: IActiveTextActionElem): string;
- {Renders an active text action element as a REML tag.
- @param TagElem [in] Active text action element to be rendered.
- @return Required REML tag.
- }
+function TREMLWriter.RenderTag(const TagElem: IActiveTextActionElem;
+ const Formatted: Boolean): string;
var
TagName: string; // name of tag
ParamName: string; // name of any parameter
@@ -785,7 +800,8 @@ function TREMLWriter.RenderTag(
if TActiveTextElemCaps.DisplayStyleOf(TagElem.Kind) = dsBlock then
begin
Dec(fLevel);
- Result := EOL + StrOfSpaces(IndentMult * fLevel) + Result + EOL;
+ if Formatted then
+ Result := EOL + StrOfSpaces(IndentMult * fLevel) + Result + EOL;
fIsStartOfTextLine := True;
end;
end
@@ -815,7 +831,8 @@ function TREMLWriter.RenderTag(
);
if TActiveTextElemCaps.DisplayStyleOf(TagElem.Kind) = dsBlock then
begin
- Result := EOL + StrOfSpaces(IndentMult * fLevel) + Result + EOL;
+ if Formatted then
+ Result := EOL + StrOfSpaces(IndentMult * fLevel) + Result + EOL;
Inc(fLevel);
fIsStartOfTextLine := True;
end
@@ -823,7 +840,8 @@ function TREMLWriter.RenderTag(
begin
if fIsStartOfTextLine then
begin
- Result := StrOfSpaces(IndentMult * fLevel) + Result;
+ if Formatted then
+ Result := StrOfSpaces(IndentMult * fLevel) + Result;
fIsStartOfTextLine := False;
end;
end;
@@ -839,15 +857,10 @@ function TREMLWriter.RenderTag(
end;
end;
-function TREMLWriter.RenderText(
- const TextElem: IActiveTextTextElem): string;
- {Renders an active text text element. Illegal characters are converted to
- REML character entities.
- @param TextElem [in] Active text text element.
- @return REML-safe text containing necessary character entities.
- }
+function TREMLWriter.RenderText(const TextElem: IActiveTextTextElem;
+ const Indented: Boolean): string;
begin
- if fIsStartOfTextLine then
+ if fIsStartOfTextLine and Indented then
begin
Result := StrOfSpaces(IndentMult * fLevel);
fIsStartOfTextLine := False;
From 60574fd812f749a85e70c4c64f942f1c43f8d42b Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Thu, 7 Nov 2024 01:41:05 +0000
Subject: [PATCH 040/222] Fix TCollectionLocation.IsValid
This method was checking whether the location directory and any meta
data files exist. This was causing exceptions at program startup if
the directories didn't exist. Such checks are actually made in the
collection loading code, which fail gracefully when the checks fail.
---
Src/DB.UCollections.pas | 4 ----
1 file changed, 4 deletions(-)
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
index 3793168f0..3e321aa42 100644
--- a/Src/DB.UCollections.pas
+++ b/Src/DB.UCollections.pas
@@ -267,14 +267,10 @@ function TCollectionLocation.IsValid: Boolean;
Exit(False);
if not TPath.HasValidPathChars(fDirectory, False) then
Exit(False);
- if not TDirectory.Exists(fDirectory) then
- Exit(False);
if (fMetaDataFile <> '') then
begin
if not TPath.IsRelativePath(fMetaDataFile) then
Exit(False);
- if not TFile.Exists(TPath.Combine(fDirectory, fMetaDataFile)) then
- Exit(False);
end;
end;
From 6e2c26cf37d453ccb9a5019bc023f0fa298791c5 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Thu, 7 Nov 2024 02:03:38 +0000
Subject: [PATCH 041/222] Add facility to save "main" collection
A new TDCSCV2FormatSaver class to save "main" collection in
DelphiDabbler Code Snippets Collection v2 format. The format version is
actually v2.1.x at present, which could loose extended testing
information.
Updated other code necessary to create and use TDCSCV2FormatSaver where
necessary.
---
Src/DB.UDatabaseIO.pas | 201 +++++++++++++++--
Src/DBIO.UIniData.pas | 480 ++++++++++++++++++++++++++++++++++++++++-
2 files changed, 663 insertions(+), 18 deletions(-)
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index ba8f489bd..d2ae7d542 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -52,14 +52,14 @@ interface
/// the database into storage in a supported data format.
IDataFormatSaver = interface(IInterface)
['{F46EE2E3-68A7-4877-9E04-192D15D29BB1}']
- /// Saves data from a collection within the database to storage.
- ///
+ /// Saves data to storage.
/// TSnippetList [in] Contains information
- /// about each snippet in the collection.
+ /// about each snippet to be saved.
/// TCategoryList [in] Contains information
- /// about each category in the collection.
+ /// about each category to be saved.
/// IDBDataProvider [in] Object used to
- /// obtain details of the data to storage.
+ /// obtain details of the data to be stored.
+ /// Method of IDataFormatSaver.
procedure Save(const SnipList: TSnippetList;
const Categories: TCategoryList; const Provider: IDBDataProvider);
end;
@@ -97,6 +97,7 @@ implementation
uses
// Delphi
SysUtils,
+ IOUtils,
// Project
DBIO.UFileIOIntf,
DBIO.UIniData,
@@ -104,6 +105,7 @@ implementation
DBIO.UXMLDataIO,
UAppInfo,
UConsts,
+ UFolderBackup,
UIStringList,
UReservedCategories,
USnippetIDs;
@@ -268,10 +270,56 @@ TNativeV4FormatLoader = class(TDatabaseLoader, IDataFormatLoader)
}
end;
- {
- TNativeV4FormatWriter:
- Object used to write data from the native snippets v4 to storage.
- }
+ {TODO -cVault: Extract common code in TNativeV4FormatSaver and
+ TDCSCV2FormatSaver into a common base class. }
+
+ /// Class used to write data from a collection to storage in the
+ /// DelphiDabbler Code Snippets v2 data format.
+ TDCSCV2FormatSaver = class(TInterfacedObject,
+ IDataFormatSaver
+ )
+ strict private
+ const
+ BakFileID = SmallInt($DC52);
+ var
+ fWriter: IDataWriter; // Object used to write to storage
+ fSnipList: TSnippetList; // List of snippets to be written
+ fCategories: TCategoryList; // List of categories to be written
+ fProvider: IDBDataProvider; // Object used to get data to be written
+ fCollection: TCollection; // Collection being written
+ fBakFile: string; // Backup file used in case of failure
+ function CreateWriter: IDataWriter;
+ {Creates object that can write data for user-defined database to storage.
+ @return Requied writer object.
+ }
+ procedure WriteCategories;
+ {Writes information about categories to storage.
+ }
+ procedure WriteSnippets;
+ {Writes information about all snippets to storage.
+ }
+ /// Backup current data.
+ procedure Backup;
+ /// Restore current data.
+ procedure Restore;
+ public
+ constructor Create(const ACollection: TCollection);
+
+ /// Saves data to storage.
+ /// TSnippetList [in] Contains information
+ /// about each snippet to be saved.
+ /// TCategoryList [in] Contains information
+ /// about each category to be saved.
+ /// IDBDataProvider [in] Object used to
+ /// obtain details of the data to be stored.
+ /// Method of IDataFormatSaver.
+ procedure Save(const SnipList: TSnippetList;
+ const Categories: TCategoryList;
+ const Provider: IDBDataProvider);
+ end;
+
+ /// Class used to write data from a collection to storage in
+ /// CodeSnip's native v4 data format.
TNativeV4FormatSaver = class(TInterfacedObject,
IDataFormatSaver
)
@@ -293,8 +341,7 @@ TNativeV4FormatSaver = class(TInterfacedObject,
}
public
constructor Create(const ACollection: TCollection);
- /// Saves data from a collection within the database to storage.
- ///
+ /// Saves data to storage.
/// TSnippetList [in] Contains information
/// about each snippet in the collection.
/// TCategoryList [in] Contains information
@@ -312,7 +359,7 @@ TNativeV4FormatSaver = class(TInterfacedObject,
class function TDatabaseIOFactory.CreateDBLoader(const Collection: TCollection):
IDataFormatLoader;
begin
- {TODO -cCollections: Revise database loaders to get file path and other
+ {TODO -cUDatabaseIO: Revise database loaders to get file path and other
info from collection instead of hard wiring it.}
case Collection.CollectionFormatKind of
TCollectionFormatKind.DCSC_v2:
@@ -329,7 +376,7 @@ class function TDatabaseIOFactory.CreateDBSaver(
begin
case Collection.CollectionFormatKind of
TCollectionFormatKind.DCSC_v2:
- Result := nil; {TODO -cVault: add writer object here}
+ Result := TDCSCV2FormatSaver.Create(Collection);
TCollectionFormatKind.Native_v4:
Result := TNativeV4FormatSaver.Create(Collection);
else
@@ -588,6 +635,8 @@ function TNativeV4FormatLoader.FindSnippet(const SnippetName: string;
@param SnipList [in] List of snippets to search.
@return Reference to required snippet object or nil if snippet is not found.
}
+
+
begin
// Search in user database
Result := SnipList.Find(SnippetName, CollectionID);
@@ -615,6 +664,129 @@ procedure TNativeV4FormatLoader.LoadCategories;
end;
end;
+{ TDCSCV2FormatSaver }
+
+procedure TDCSCV2FormatSaver.Backup;
+var
+ FB: TFolderBackup;
+begin
+ FB := TFolderBackup.Create(
+ fCollection.Location.Directory, fBakFile, BakFileID
+ );
+ try
+ FB.Backup;
+ finally
+ FB.Free;
+ end;
+end;
+
+constructor TDCSCV2FormatSaver.Create(const ACollection: TCollection);
+begin
+ inherited Create;
+ fCollection := ACollection;
+ // Find an used temp file name in system temp directory
+ repeat
+ fBakFile := TPath.Combine(
+ TPath.GetTempPath, '~codesnip-' + TPath.GetGUIDFileName
+ );
+ until not TFile.Exists(fBakFile);
+end;
+
+function TDCSCV2FormatSaver.CreateWriter: IDataWriter;
+begin
+ Result := TIniDataWriter.Create(fCollection.Location.Directory);
+end;
+
+procedure TDCSCV2FormatSaver.Restore;
+var
+ FB: TFolderBackup;
+begin
+ FB := TFolderBackup.Create(
+ fCollection.Location.Directory, fBakFile, BakFileID
+ );
+ try
+ FB.Restore;
+ finally
+ FB.Free;
+ end;
+end;
+
+procedure TDCSCV2FormatSaver.Save(const SnipList: TSnippetList;
+ const Categories: TCategoryList; const Provider: IDBDataProvider);
+begin
+ Backup;
+ try
+ try
+ fSnipList := SnipList;
+ fCategories := Categories;
+ fProvider := Provider;
+ fWriter := CreateWriter;
+ fWriter.Initialise;
+ WriteCategories;
+ WriteSnippets;
+ fWriter.Finalise;
+ except
+ Restore;
+ raise ExceptObject;
+ end;
+ finally
+ TFile.Delete(fBakFile);
+ end;
+end;
+
+procedure TDCSCV2FormatSaver.WriteCategories;
+var
+ Cat: TCategory; // loops through each category
+ Props: TCategoryData; // category properties
+ SnipList: IStringList; // list of names of snippets in a category
+begin
+ for Cat in fCategories do
+ begin
+ SnipList := fProvider.GetCategorySnippets(Cat);
+ if SnipList.Count > 0 then
+ begin
+ // Only write categories containing snippets
+ Props := fProvider.GetCategoryProps(Cat);
+ fWriter.WriteCatProps(Cat.ID, Props);
+ fWriter.WriteCatSnippets(Cat.ID, SnipList);
+ end;
+ end;
+end;
+
+procedure TDCSCV2FormatSaver.WriteSnippets;
+
+ // Adds names of snippets from IDList to a string list
+ function IDListToStrings(const IDList: ISnippetIDList): IStringList;
+ var
+ ID: TSnippetID; // each id in snippet id list
+ begin
+ Result := TIStringList.Create;
+ for ID in IDList do
+ Result.Add(ID.Name);
+ end;
+
+var
+ Snippet: TSnippet; // loops through each snippet in list
+ Props: TSnippetData; // snippet properties
+ Refs: TSnippetReferences; // snippet references
+begin
+ for Snippet in fSnipList do
+ begin
+ // Only write user-defined snippets
+ if Snippet.CollectionID = fCollection.UID then
+ begin
+ // Get and write a snippet's properties
+ Props := fProvider.GetSnippetProps(Snippet);
+ fWriter.WriteSnippetProps(Snippet.Name, Props);
+ // Get and write a snippet's references
+ Refs := fProvider.GetSnippetRefs(Snippet);
+ fWriter.WriteSnippetUnits(Snippet.Name, Refs.Units);
+ fWriter.WriteSnippetDepends(Snippet.Name, IDListToStrings(Refs.Depends));
+ fWriter.WriteSnippetXRefs(Snippet.Name, IDListToStrings(Refs.XRef));
+ end;
+ end;
+end;
+
{ TNativeV4FormatSaver }
constructor TNativeV4FormatSaver.Create(const ACollection: TCollection);
@@ -629,6 +801,7 @@ function TNativeV4FormatSaver.CreateWriter: IDataWriter;
@return Requied writer object.
}
begin
+ {TODO -cUDatabaseIO: Use Collection.Location.Directory instead}
Result := TXMLDataWriter.Create(TAppInfo.UserDataDir);
end;
@@ -689,7 +862,7 @@ procedure TNativeV4FormatSaver.WriteSnippets;
for Snippet in fSnipList do
begin
// Only write user-defined snippets
- if Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
+ if Snippet.CollectionID = fCollection.UID then
begin
// Get and write a snippet's properties
Props := fProvider.GetSnippetProps(Snippet);
diff --git a/Src/DBIO.UIniData.pas b/Src/DBIO.UIniData.pas
index 7e849979c..04ab602a8 100644
--- a/Src/DBIO.UIniData.pas
+++ b/Src/DBIO.UIniData.pas
@@ -9,6 +9,8 @@
* files.
}
+{TODO -cVault: rename INI term to DCSCv2 - this isn't a general .ini data
+ IO unit, the .ini format only part of a wider collection format.}
unit DBIO.UIniData;
@@ -18,9 +20,17 @@ interface
uses
// Delphi
- Classes, Generics.Collections, IniFiles,
+ Classes,
+ Generics.Collections,
+ Generics.Defaults,
+ IniFiles,
// Project
- DB.UCategory, DB.USnippet, DBIO.UFileIOIntf, UIStringList, UMainDBFileReader;
+ ActiveText.UMain,
+ DB.UCategory,
+ DB.USnippet,
+ DBIO.UFileIOIntf,
+ UIStringList,
+ UMainDBFileReader;
type
@@ -196,6 +206,182 @@ TIniFileCache = class(TObject)
function GetSnippetUnits(const Snippet: string): IStringList;
end;
+ /// Write a collection to disk in the DelphiDabbler Code Snippets
+ /// collection format.
+ TIniDataWriter = class sealed(TInterfacedObject, IDataWriter)
+ strict private
+ type
+
+ /// Encapsulates an INI file stored in UTF8 format.
+ TUTF8IniFile = class(TMemIniFile)
+ public
+ /// Saves the ini data to a file in UTF8 format.
+ procedure Save;
+ end;
+
+ /// Implements a cache of UTF8 format ini file objects, indexed
+ /// by ini file name.
+ TUTF8IniFileCache = class(TObject)
+ strict private
+ type
+ /// Maps ini file names to related ini file objects.
+ ///
+ TIniFileMap = TObjectDictionary;
+ var
+ /// Maps file names to related ini file objects.
+ fCache: TIniFileMap;
+
+ /// Adds an ini file to the cache and returns it.
+ /// Performs no checks on whether the ini file is already in
+ /// the cache.
+ /// string [in] Fully specified path
+ /// to ini file.
+ /// TUTF8IniFile instance.
+ function InternalAddIniFile(const APathToFile: string): TUTF8IniFile;
+
+ public
+
+ /// Object constructor. Sets up empty cache.
+ constructor Create;
+
+ /// Object destructor. Frees cache.
+ destructor Destroy; override;
+
+ /// Gets reference to ini file object. Creates it if i
+ /// doesn't extist.
+ /// string [in] Fully specified path
+ /// to ini file.
+ /// TUTF8IniFile instance.
+ /// Caller must not free the returned TCustomIniFile
+ /// instance.
+ function GetIniFile(const APathToFile: string): TUTF8IniFile;
+
+ /// Creates and adds an ini file object to the cache if not
+ /// already present.
+ /// string [in] Fully specified path
+ /// to ini file.
+ procedure AddIniFile(const APathToFile: string);
+
+ /// Enumerator for cached ini files.
+ function GetEnumerator:
+ TObjectDictionary.TPairEnumerator;
+ end;
+
+ var
+ /// Cache of ini files.
+ fCache: TUTF8IniFileCache;
+ /// Output directory.
+ fOutDir: string;
+ /// Path to master ini file.
+ fMasterIniPath: string;
+ /// Ini file containing currently processed category.
+ fCurrentCatIni: TUTF8IniFile;
+ /// Number of next available unused data file.
+ fFileNumber: Integer;
+
+ /// Handles exceptions raised by converting expected exceptions
+ /// into ECodeSnip derived exceptions.
+ /// TObject [in] Reference to exception to be
+ /// handled.
+ /// Always raise an exception.
+ /// Unexpected exceptions are re-raised as is.
+ procedure HandleException(const EObj: TObject);
+
+ /// Returns full path to AFileName rooted at
+ /// fOutDir.
+ function MakePath(const AFileName: string): string;
+
+ /// Returns the name of the ini file associated with
+ /// ACatID.
+ function MakeCatIniName(const ACatID: string): string;
+
+ /// Returns the full path to the ini file associated with
+ /// ACatID rooted at fOutDir.
+ function MakeCatIniPath(const ACatID: string): string;
+
+ /// Converts the given active text AActiveText to an
+ /// unformatted, single line, REML string.
+ function ActiveTextToREML(AActiveText: IActiveText): string;
+
+ public
+
+ /// Object constructor.
+ /// string [in] Directory containing the
+ /// output.
+ constructor Create(const AOutDir: string);
+
+ /// Object destructor.
+ destructor Destroy; override;
+
+ /// Initialise the output. Always called before any other methods.
+ ///
+ /// Method of IDataWriter.
+ procedure Initialise;
+
+ /// Write the properties of a category. Always called before
+ /// WriteCatSnippets for a given category, so can be used to perform
+ /// any per-category initialisation.
+ /// string [in] ID of category.
+ /// TCategoryData [in] Properties of category.
+ ///
+ /// Method of IDataWriter.
+ procedure WriteCatProps(const CatID: string; const Props: TCategoryData);
+
+ /// Write the list of snippets belonging to a category. Always
+ /// called after WriteCatProps for any given category.
+ /// string [in] ID of category.
+ /// IStringList [in] List of names of
+ /// snippets.
+ /// Method of IDataWriter.
+ procedure WriteCatSnippets(const CatID: string;
+ const SnipList: IStringList);
+
+ /// Write the properties of a snippet. Always called after all
+ /// categories are written and before WriteSnippetUnits, so can be
+ /// used to perform any per-snippet intialisation.
+ /// string [in] Name of snippet.
+ /// TSnippetData [in] Properties of snippet.
+ ///
+ ///
+ /// NOTE: This method conforms to DelphiDabbler Code Snippets
+ /// collection format v2.1.x.
+ /// Method of IDataWriter.
+ ///
+ procedure WriteSnippetProps(const SnippetName: string;
+ const Props: TSnippetData);
+
+ /// Write the list of units required by a snippet.
+ /// string [in] Name of snippet.
+ /// IStringList [in] List of names of required
+ /// units.
+ /// Method of IDataWriter.
+ procedure WriteSnippetUnits(const SnippetName: string;
+ const Units: IStringList);
+
+ /// Write the list of snippets on which a snippet depends.
+ ///
+ /// string [in] Name of snippet.
+ /// IStringList [in] List of snippet names.
+ ///
+ /// Method of IDataWriter.
+ procedure WriteSnippetDepends(const SnippetName: string;
+ const Depends: IStringList);
+
+ /// Write the list of snippets that a snippet cross-references.
+ ///
+ /// string [in] Name of snippet.
+ /// IStringList [in] List of snippet names.
+ ///
+ /// Method of IDataWriter.
+ procedure WriteSnippetXRefs(const SnippetName: string;
+ const XRefs: IStringList);
+
+ /// Finalises the output. Always called after all other methods.
+ ///
+ /// Method of IDataWriter.
+ procedure Finalise;
+
+ end;
implementation
@@ -203,9 +389,20 @@ implementation
uses
// Delphi
SysUtils,
+ IOUtils,
// Project
- ActiveText.UMain, Compilers.UGlobals, DB.USnippetKind, UComparers, UConsts,
- UIniDataLoader, USnippetExtraHelper, UStrUtils, UUtils;
+ Compilers.UGlobals,
+ DB.USnippetKind,
+ UComparers,
+ UConsts,
+ UExceptions,
+ UIniDataLoader,
+ UIOUtils,
+ UREMLDataIO,
+ USnippetExtraHelper,
+ USystemInfo,
+ UStrUtils,
+ UUtils;
const
@@ -614,5 +811,280 @@ function TIniDataReader.TIniFileCache.GetIniFile(
Result := fCache[PathToFile];
end;
+{ TIniDataWriter }
+
+function TIniDataWriter.ActiveTextToREML(AActiveText: IActiveText): string;
+begin
+ Result := TREMLWriter.Render(AActiveText, False);
+end;
+
+constructor TIniDataWriter.Create(const AOutDir: string);
+begin
+ inherited Create;
+ fOutDir := AOutDir;
+ fCache := TUTF8IniFileCache.Create;
+end;
+
+destructor TIniDataWriter.Destroy;
+begin
+ fCache.Free; // frees owned ini file objects
+ inherited;
+end;
+
+procedure TIniDataWriter.Finalise;
+var
+ IniInfo: TPair;
+begin
+ try
+ for IniInfo in fCache do
+ IniInfo.Value.Save;
+ except
+ HandleException(ExceptObject);
+ end;
+end;
+
+procedure TIniDataWriter.HandleException(const EObj: TObject);
+begin
+ if (EObj is EFileStreamError) or (EObj is ECodeSnip)
+ or (EObj is EDirectoryNotFoundException) then
+ raise EDataIO.Create(EObj as Exception);
+ raise EObj;
+end;
+
+procedure TIniDataWriter.Initialise;
+begin
+ try
+ // Make sure database folder exists
+ TDirectory.CreateDirectory(fOutDir);
+
+ // Delete current ini and data files
+ // (don't delete special files: CONTRIBUTORS, LICENSE, LICENSE-INFO,
+ // TESTERS, VERSION).
+ DeleteFiles(fOutDir, '*.dat');
+ DeleteFiles(fOutDir, '*.ini');
+
+ // Initialise file count
+ fFileNumber := 0;
+
+ // Record path to master meta data file.
+ fMasterIniPath := MakePath(cMasterFileName);
+
+ except
+ HandleException(ExceptObject);
+ end;
+end;
+
+function TIniDataWriter.MakeCatIniName(const ACatID: string): string;
+begin
+ Result := ACatID + '.ini';
+end;
+
+function TIniDataWriter.MakeCatIniPath(const ACatID: string): string;
+begin
+ Result := MakePath(MakeCatIniName(ACatID));
+end;
+
+function TIniDataWriter.MakePath(const AFileName: string): string;
+begin
+ Result := TPath.Combine(fOutDir, AFileName);
+end;
+
+procedure TIniDataWriter.WriteCatProps(const CatID: string;
+ const Props: TCategoryData);
+var
+ Master: TUTF8IniFile;
+begin
+ // Add entry to master ini file
+ Master := fCache.GetIniFile(fMasterIniPath);
+ Master.WriteString(CatId, cMasterDescName, Props.Desc);
+ Master.WriteString(CatId, cMasterIniName, MakeCatIniName(CatID));
+end;
+
+procedure TIniDataWriter.WriteCatSnippets(const CatID: string;
+ const SnipList: IStringList);
+begin
+ // Do nothing
+end;
+
+procedure TIniDataWriter.WriteSnippetDepends(const SnippetName: string;
+ const Depends: IStringList);
+begin
+ fCurrentCatIni.WriteString(
+ SnippetName, cDependsName, Depends.GetText(',', False)
+ );
+end;
+
+procedure TIniDataWriter.WriteSnippetProps(const SnippetName: string;
+ const Props: TSnippetData);
+const
+ Kinds: array[TSnippetKind] of string = (
+ 'freeform', // skFreeform
+ 'routine', // skRoutine
+ 'const', // skConstant
+ 'type', // skTypeDef
+ 'unit', // skUnit
+ 'class' // skClass
+ );
+ CompileResults: array[TCompileResult] of Char = (
+ 'Y', // crSuccess
+ 'Y', // crWarning
+ 'N', // crError
+ 'Q' // crQuery
+ );
+ TestInfo: array[TSnippetTestInfo] of string = (
+ 'none', // stiNone
+ 'basic', // stiBasic
+ 'advanced' // stiAdvanced
+ );
+var
+ SourceFileName: string;
+ SourceFilePath: string;
+ CompilerID: TCompilerID;
+ CompileResult: Char;
+begin
+
+ fCurrentCatIni := fCache.GetIniFile(MakeCatIniPath(Props.Cat));
+
+ try
+ // Write source code file
+ Inc(fFileNumber);
+ SourceFileName := IntToStr(fFileNumber) + '.dat';
+ SourceFilePath := MakePath(SourceFileName);
+ TFileIO.WriteAllText(SourceFilePath, Props.SourceCode, TEncoding.UTF8, True);
+
+ // snippet kind
+ fCurrentCatIni.WriteString(SnippetName, cKindName, Kinds[Props.Kind]);
+
+ // display name, if set
+ if (Props.DisplayName <> '') then
+ {TODO -cVault: strictly, for v2 format, this name must be <=64 chars}
+ fCurrentCatIni.WriteString(SnippetName, cDisplayName, Props.DisplayName);
+
+ // description (must be set for v2)
+ fCurrentCatIni.WriteString(
+ SnippetName,
+ cDescExName,
+ DOUBLEQUOTE + ActiveTextToREML(Props.Desc) + DOUBLEQUOTE
+ );
+
+ // extra info, if set
+ if Props.Extra.HasContent then
+ fCurrentCatIni.WriteString(
+ SnippetName,
+ cExtraName,
+ DOUBLEQUOTE + ActiveTextToREML(Props.Extra) + DOUBLEQUOTE
+ );
+
+ // snippet file reference
+ fCurrentCatIni.WriteString(SnippetName, cSnipFileName, SourceFileName);
+
+ // compiler info
+ for CompilerID := Low(TCompilerID) to High(TCompilerID) do
+ begin
+ CompileResult := CompileResults[Props.CompilerResults[CompilerID]];
+ if CompileResult <> 'Q' then
+ fCurrentCatIni.WriteString(
+ SnippetName, cCompilerIDNames[CompilerID], CompileResult
+ );
+ end;
+
+ // test info: only write if not basic
+ {TODO -cVault: Add support for AdvancedTest .Level & .URL}
+ if Props.TestInfo <> stiBasic then
+ fCurrentCatIni.WriteString(SnippetName, cTestInfoName, TestInfo[Props.TestInfo]);
+
+ except
+
+ HandleException(ExceptObject);
+
+ end;
+ // NOTE:
+ // The following deprecated keys are not written: alternatives are always
+ // used:
+ // * StandardFormat - Kind is used instead
+ // * Credits - Extra is used instead
+ // * Credits_URL - Extra is used instead
+ // * Comments - Extra is used instead
+ // * Desc - DescEx is used instead
+
+end;
+
+procedure TIniDataWriter.WriteSnippetUnits(const SnippetName: string;
+ const Units: IStringList);
+begin
+ fCurrentCatIni.WriteString(
+ SnippetName, cUnitsName, Units.GetText(',', False)
+ );
+end;
+
+procedure TIniDataWriter.WriteSnippetXRefs(const SnippetName: string;
+ const XRefs: IStringList);
+begin
+ fCurrentCatIni.WriteString(
+ SnippetName, cXRefName, XRefs.GetText(',', False)
+ );
+end;
+
+{ TIniDataWriter.TUTF8IniFile }
+
+procedure TIniDataWriter.TUTF8IniFile.Save;
+var
+ Data: TStringList;
+begin
+ Data := TStringList.Create;
+ try
+ GetStrings(Data);
+ TFileIO.WriteAllLines(FileName, Data.ToStringArray, Encoding, True);
+ finally
+ Data.Free;
+ end;
+end;
+
+{ TIniDataWriter.TUTF8IniFileCache }
+
+procedure TIniDataWriter.TUTF8IniFileCache.AddIniFile(
+ const APathToFile: string);
+begin
+ if not fCache.ContainsKey(APathToFile) then
+ InternalAddIniFile(APathToFile);
+end;
+
+constructor TIniDataWriter.TUTF8IniFileCache.Create;
+begin
+ inherited Create;
+ // fCache owns and frees the ini file objects
+ fCache := TIniFileMap.Create(
+ [doOwnsValues], TTextEqualityComparer.Create
+ );
+end;
+
+destructor TIniDataWriter.TUTF8IniFileCache.Destroy;
+begin
+ fCache.Free; // frees all owned ini file objects in .Values[]
+ inherited;
+end;
+
+function TIniDataWriter.TUTF8IniFileCache.GetEnumerator:
+ TObjectDictionary.TPairEnumerator;
+begin
+ Result := fCache.GetEnumerator;
+end;
+
+function TIniDataWriter.TUTF8IniFileCache.GetIniFile(
+ const APathToFile: string): TUTF8IniFile;
+begin
+ if not fCache.ContainsKey(APathToFile) then
+ Result := InternalAddIniFile(APathToFile)
+ else
+ Result := fCache[APathToFile];
+end;
+
+function TIniDataWriter.TUTF8IniFileCache.InternalAddIniFile(
+ const APathToFile: string): TUTF8IniFile;
+begin
+ Result := TUTF8IniFile.Create(APathToFile, TEncoding.UTF8);
+ fCache.Add(APathToFile, Result);
+end;
+
end.
From d71df6629896967f3c92296f7bdfbd6dda6ebbff Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Thu, 7 Nov 2024 02:22:35 +0000
Subject: [PATCH 042/222] Refactor DB.UDatabaseIO unit
Removed the unused TDatabaseLoader.IsUserDatabase method.
Changed explicit references to __TMP__ TCollectionID methods to get the
collection ID in TDatabaseLoader and descendant classes with references
to the UID of the collection passed to the class' constructors.
Removed TDatabaseLoader.CollectionID method: replaced calls to it with
references to TDatabaseLoader.Collection.UID property.
Created TFormatSaver as abstract base class for saver classes and
refactored TDCSCV2FormatSaver and TNativeV4FormatSaver as sub classes
of TFormatSaver.
Changed TNativeV4FormatSaver.CreateWriter to get storage location from
Collection.Location.Directory instead of TAppInfo.UserDataDir.
---
Src/DB.UDatabaseIO.pas | 429 ++++++++++++++++++++---------------------
1 file changed, 210 insertions(+), 219 deletions(-)
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index d2ae7d542..6baf3193b 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -165,15 +165,6 @@ TDatabaseLoader = class(TInterfacedObject, IDataFormatLoader)
@param Snippet [in] Snippet to test.
@return True if snippet is native, False if not.
}
- function IsUserDatabase: Boolean; virtual;
- {Checks if the database is the user database.
- @return True if the database is the user database, False if not.
- }
-
- /// Returns the ID of the collection being loaded into the
- /// database.
- function CollectionID: TCollectionID; virtual; abstract;
-
function ErrorMessageHeading: string; virtual; abstract;
{Returns heading to use in error messages. Should identify the database.
@return Required heading.
@@ -226,10 +217,6 @@ TDCSCV2FormatLoader = class(TDatabaseLoader, IDataFormatLoader)
found.
}
- /// Returns the ID of the collection being loaded into the
- /// database.
- function CollectionID: TCollectionID; override;
-
function ErrorMessageHeading: string; override;
{Returns heading to use in error messages. Identifies main database.
@return Required heading.
@@ -257,10 +244,6 @@ TNativeV4FormatLoader = class(TDatabaseLoader, IDataFormatLoader)
found.
}
- /// Returns the ID of the collection being loaded into the
- /// database.
- function CollectionID: TCollectionID; override;
-
function ErrorMessageHeading: string; override;
{Returns heading to use in error messages. Identifies main database.
@return Required heading.
@@ -270,88 +253,162 @@ TNativeV4FormatLoader = class(TDatabaseLoader, IDataFormatLoader)
}
end;
- {TODO -cVault: Extract common code in TNativeV4FormatSaver and
- TDCSCV2FormatSaver into a common base class. }
-
- /// Class used to write data from a collection to storage in the
- /// DelphiDabbler Code Snippets v2 data format.
- TDCSCV2FormatSaver = class(TInterfacedObject,
+ /// Base for classes that save a collection to storage.
+ TFormatSaver = class abstract (TInterfacedObject,
IDataFormatSaver
)
strict private
- const
- BakFileID = SmallInt($DC52);
var
fWriter: IDataWriter; // Object used to write to storage
fSnipList: TSnippetList; // List of snippets to be written
fCategories: TCategoryList; // List of categories to be written
fProvider: IDBDataProvider; // Object used to get data to be written
fCollection: TCollection; // Collection being written
- fBakFile: string; // Backup file used in case of failure
- function CreateWriter: IDataWriter;
- {Creates object that can write data for user-defined database to storage.
- @return Requied writer object.
- }
- procedure WriteCategories;
- {Writes information about categories to storage.
- }
+
+ /// Writes information about all snippets belonging to the
+ /// collection.
procedure WriteSnippets;
- {Writes information about all snippets to storage.
- }
+
+ /// Writes information about categories relevant to the
+ /// collection.
+ procedure WriteCategories;
+
+ strict protected
+
+ /// Saves collection to storage.
+ /// TSnippetList [in] List of all snippets
+ /// in the database.
+ /// TCategoryList [in] List of all
+ /// categories in the database.
+ /// IDBDataProvider [in] Object used to
+ /// obtain details of the data to be stored.
+ procedure DoSave(const SnipList: TSnippetList;
+ const Categories: TCategoryList;
+ const Provider: IDBDataProvider
+ );
+
+ /// Creates an object that can write data to storage in the
+ /// required format.
+ /// IDataWriter. Required writer object.
+ function CreateWriter: IDataWriter; virtual; abstract;
+
+ /// Checks if a category can be written to storage.
+ /// TCategory [in] The category being
+ /// queried.
+ /// IStringList [in] List of the
+ /// names of all snippets in the category.
+ /// Boolean. True if category can be written, False
+ /// otherwise.
+ function CanWriteCategory(const ACategory: TCategory;
+ const ASnippetsInCategory: IStringList): Boolean; virtual; abstract;
+
+ /// Collection being saved.
+ property Collection: TCollection read fCollection;
+
+ public
+ /// Creates object that can save the given collection.
+ constructor Create(const ACollection: TCollection);
+
+ /// Saves data to storage.
+ /// TSnippetList [in] List of all snippets
+ /// in the database.
+ /// TCategoryList [in] List of all
+ /// categories in the database.
+ /// IDBDataProvider [in] Object used to
+ /// obtain details of the data to be stored.
+ /// Method of IDataFormatSaver.
+ procedure Save(const SnipList: TSnippetList;
+ const Categories: TCategoryList;
+ const Provider: IDBDataProvider); virtual; abstract;
+ end;
+
+ /// Class used to write data from a collection to storage in the
+ /// DelphiDabbler Code Snippets v2 data format.
+ TDCSCV2FormatSaver = class(TFormatSaver,
+ IDataFormatSaver
+ )
+ strict private
+ const
+ BakFileID = SmallInt($DC52);
+ var
+ fBakFile: string; // Backup file used in case of failure
+
/// Backup current data.
procedure Backup;
+
/// Restore current data.
procedure Restore;
+
+ strict protected
+
+ /// Creates an object that can write data to storage in
+ /// DelphiDabbler Code Snippets v2 data format.
+ /// IDataWriter. Required writer object.
+ function CreateWriter: IDataWriter; override;
+
+ /// Checks if a category can be written to storage.
+ /// TCategory [in] The category being
+ /// queried.
+ /// IStringList [in] List of the
+ /// names of all snippets in the category.
+ /// Boolean. True if category contains snippets, False
+ /// otherwise.
+ function CanWriteCategory(const ACategory: TCategory;
+ const ASnippetsInCategory: IStringList): Boolean; override;
+
public
+
+ /// Creates object that can save the given collection.
constructor Create(const ACollection: TCollection);
/// Saves data to storage.
- /// TSnippetList [in] Contains information
- /// about each snippet to be saved.
- /// TCategoryList [in] Contains information
- /// about each category to be saved.
+ /// TSnippetList [in] List of all snippets
+ /// in the database.
+ /// TCategoryList [in] List of all
+ /// categories in the database.
/// IDBDataProvider [in] Object used to
/// obtain details of the data to be stored.
/// Method of IDataFormatSaver.
procedure Save(const SnipList: TSnippetList;
const Categories: TCategoryList;
- const Provider: IDBDataProvider);
+ const Provider: IDBDataProvider); override;
end;
/// Class used to write data from a collection to storage in
/// CodeSnip's native v4 data format.
- TNativeV4FormatSaver = class(TInterfacedObject,
+ TNativeV4FormatSaver = class(TFormatSaver,
IDataFormatSaver
)
- strict private
- fWriter: IDataWriter; // Object used to write to storage
- fSnipList: TSnippetList; // List of snippets to be written
- fCategories: TCategoryList; // List of categories to be written
- fProvider: IDBDataProvider; // Object used to get data to be written
- fCollection: TCollection; // Collection being written
- function CreateWriter: IDataWriter;
- {Creates object that can write data for user-defined database to storage.
- @return Requied writer object.
- }
- procedure WriteCategories;
- {Writes information about categories to storage.
- }
- procedure WriteSnippets;
- {Writes information about all snippets to storage.
- }
+ strict protected
+
+ /// Creates an object that can write data to storage in
+ /// CodeSnip's native v4 data format.
+ /// IDataWriter. Required writer object.
+ function CreateWriter: IDataWriter; override;
+
+ /// Checks if a category can be written to storage.
+ /// TCategory [in] The category being
+ /// queried.
+ /// IStringList [in] List of the
+ /// names of all snippets in the category.
+ /// Boolean. Always True: all categories are written.
+ ///
+ function CanWriteCategory(const ACategory: TCategory;
+ const ASnippetsInCategory: IStringList): Boolean; override;
+
public
- constructor Create(const ACollection: TCollection);
+
/// Saves data to storage.
- /// TSnippetList [in] Contains information
- /// about each snippet in the collection.
- /// TCategoryList [in] Contains information
- /// about each category in the collection.
+ /// TSnippetList [in] List of all snippets
+ /// in the database.
+ /// TCategoryList [in] List of all
+ /// categories in the database.
/// IDBDataProvider [in] Object used to
- /// obtain details of the data to storage.
+ /// obtain details of the data to be stored.
/// Method of IDataFormatSaver.
procedure Save(const SnipList: TSnippetList;
const Categories: TCategoryList;
- const Provider: IDBDataProvider);
+ const Provider: IDBDataProvider); override;
end;
{ TDatabaseIOFactory }
@@ -399,7 +456,7 @@ procedure TDatabaseLoader.CreateCategory(const CatID: string;
@param CatData [in] Properties of category.
}
begin
- fCategories.Add(fFactory.CreateCategory(CatID, CollectionID, CatData));
+ fCategories.Add(fFactory.CreateCategory(CatID, Collection.UID, CatData));
end;
procedure TDatabaseLoader.HandleException(const E: Exception);
@@ -418,12 +475,7 @@ procedure TDatabaseLoader.HandleException(const E: Exception);
function TDatabaseLoader.IsNativeSnippet(const Snippet: TSnippet): Boolean;
begin
- Result := Snippet.CollectionID = CollectionID;
-end;
-
-function TDatabaseLoader.IsUserDatabase: Boolean;
-begin
- Result := CollectionID <> TCollectionID.__TMP__MainDBCollectionID;
+ Result := Snippet.CollectionID = Collection.UID;
end;
procedure TDatabaseLoader.Load(const SnipList: TSnippetList;
@@ -544,12 +596,12 @@ procedure TDatabaseLoader.LoadSnippets(const Cat: TCategory);
for SnippetName in SnippetNames do
begin
// Check if snippet exists in current database and add it to list if not
- Snippet := fSnipList.Find(SnippetName, CollectionID);
+ Snippet := fSnipList.Find(SnippetName, Collection.UID);
if not Assigned(Snippet) then
begin
fReader.GetSnippetProps(SnippetName, SnippetProps);
Snippet := fFactory.CreateSnippet(
- SnippetName, CollectionID, SnippetProps
+ SnippetName, Collection.UID, SnippetProps
);
fSnipList.Add(Snippet);
end;
@@ -561,11 +613,6 @@ procedure TDatabaseLoader.LoadSnippets(const Cat: TCategory);
{ TDCSCV2FormatLoader }
-function TDCSCV2FormatLoader.CollectionID: TCollectionID;
-begin
- Result := TCollectionID.__TMP__MainDBCollectionID;
-end;
-
function TDCSCV2FormatLoader.CreateReader: IDataReader;
{Creates reader object. If main database doesn't exist a nul reader is
created.
@@ -596,16 +643,11 @@ function TDCSCV2FormatLoader.FindSnippet(const SnippetName: string;
}
begin
// We only search main database
- Result := SnipList.Find(SnippetName, CollectionID);
+ Result := SnipList.Find(SnippetName, Collection.UID);
end;
{ TNativeV4FormatLoader }
-function TNativeV4FormatLoader.CollectionID: TCollectionID;
-begin
- Result := TCollectionID.__TMP__UserDBCollectionID;
-end;
-
function TNativeV4FormatLoader.CreateReader: IDataReader;
{Creates reader object. If user database doesn't exist a nul reader is
created.
@@ -639,7 +681,9 @@ function TNativeV4FormatLoader.FindSnippet(const SnippetName: string;
begin
// Search in user database
- Result := SnipList.Find(SnippetName, CollectionID);
+ Result := SnipList.Find(SnippetName, Collection.UID);
+ {TODO -cVault: Delete the following - only allow references in same collection
+ }
if not Assigned(Result) then
// Not in user database: try main database
Result := SnipList.Find(SnippetName, TCollectionID.__TMP__MainDBCollectionID);
@@ -664,77 +708,28 @@ procedure TNativeV4FormatLoader.LoadCategories;
end;
end;
-{ TDCSCV2FormatSaver }
+{ TFormatSaver }
-procedure TDCSCV2FormatSaver.Backup;
-var
- FB: TFolderBackup;
-begin
- FB := TFolderBackup.Create(
- fCollection.Location.Directory, fBakFile, BakFileID
- );
- try
- FB.Backup;
- finally
- FB.Free;
- end;
-end;
-
-constructor TDCSCV2FormatSaver.Create(const ACollection: TCollection);
+constructor TFormatSaver.Create(const ACollection: TCollection);
begin
inherited Create;
fCollection := ACollection;
- // Find an used temp file name in system temp directory
- repeat
- fBakFile := TPath.Combine(
- TPath.GetTempPath, '~codesnip-' + TPath.GetGUIDFileName
- );
- until not TFile.Exists(fBakFile);
-end;
-
-function TDCSCV2FormatSaver.CreateWriter: IDataWriter;
-begin
- Result := TIniDataWriter.Create(fCollection.Location.Directory);
end;
-procedure TDCSCV2FormatSaver.Restore;
-var
- FB: TFolderBackup;
-begin
- FB := TFolderBackup.Create(
- fCollection.Location.Directory, fBakFile, BakFileID
- );
- try
- FB.Restore;
- finally
- FB.Free;
- end;
-end;
-
-procedure TDCSCV2FormatSaver.Save(const SnipList: TSnippetList;
+procedure TFormatSaver.DoSave(const SnipList: TSnippetList;
const Categories: TCategoryList; const Provider: IDBDataProvider);
begin
- Backup;
- try
- try
- fSnipList := SnipList;
- fCategories := Categories;
- fProvider := Provider;
- fWriter := CreateWriter;
- fWriter.Initialise;
- WriteCategories;
- WriteSnippets;
- fWriter.Finalise;
- except
- Restore;
- raise ExceptObject;
- end;
- finally
- TFile.Delete(fBakFile);
- end;
+ fSnipList := SnipList;
+ fCategories := Categories;
+ fProvider := Provider;
+ fWriter := CreateWriter;
+ fWriter.Initialise;
+ WriteCategories;
+ WriteSnippets;
+ fWriter.Finalise;
end;
-procedure TDCSCV2FormatSaver.WriteCategories;
+procedure TFormatSaver.WriteCategories;
var
Cat: TCategory; // loops through each category
Props: TCategoryData; // category properties
@@ -743,9 +738,8 @@ procedure TDCSCV2FormatSaver.WriteCategories;
for Cat in fCategories do
begin
SnipList := fProvider.GetCategorySnippets(Cat);
- if SnipList.Count > 0 then
+ if CanWriteCategory(Cat, SnipList) then
begin
- // Only write categories containing snippets
Props := fProvider.GetCategoryProps(Cat);
fWriter.WriteCatProps(Cat.ID, Props);
fWriter.WriteCatSnippets(Cat.ID, SnipList);
@@ -753,7 +747,7 @@ procedure TDCSCV2FormatSaver.WriteCategories;
end;
end;
-procedure TDCSCV2FormatSaver.WriteSnippets;
+procedure TFormatSaver.WriteSnippets;
// Adds names of snippets from IDList to a string list
function IDListToStrings(const IDList: ISnippetIDList): IStringList;
@@ -772,7 +766,6 @@ procedure TDCSCV2FormatSaver.WriteSnippets;
begin
for Snippet in fSnipList do
begin
- // Only write user-defined snippets
if Snippet.CollectionID = fCollection.UID then
begin
// Get and write a snippet's properties
@@ -787,94 +780,92 @@ procedure TDCSCV2FormatSaver.WriteSnippets;
end;
end;
-{ TNativeV4FormatSaver }
+{ TDCSCV2FormatSaver }
-constructor TNativeV4FormatSaver.Create(const ACollection: TCollection);
+procedure TDCSCV2FormatSaver.Backup;
+var
+ FB: TFolderBackup;
begin
- inherited Create;
- fCollection := ACollection;
+ FB := TFolderBackup.Create(
+ Collection.Location.Directory, fBakFile, BakFileID
+ );
+ try
+ FB.Backup;
+ finally
+ FB.Free;
+ end;
end;
-function TNativeV4FormatSaver.CreateWriter: IDataWriter;
- {Creates object that can write data for user-defined items from Database to
- storage.
- @return Requied writer object.
- }
+function TDCSCV2FormatSaver.CanWriteCategory(const ACategory: TCategory;
+ const ASnippetsInCategory: IStringList): Boolean;
begin
- {TODO -cUDatabaseIO: Use Collection.Location.Directory instead}
- Result := TXMLDataWriter.Create(TAppInfo.UserDataDir);
+ Result := ASnippetsInCategory.Count > 0
end;
-procedure TNativeV4FormatSaver.Save(const SnipList: TSnippetList;
- const Categories: TCategoryList; const Provider: IDBDataProvider);
+constructor TDCSCV2FormatSaver.Create(const ACollection: TCollection);
begin
- fSnipList := SnipList;
- fCategories := Categories;
- fProvider := Provider;
- fWriter := CreateWriter;
- fWriter.Initialise;
- WriteCategories;
- WriteSnippets;
- fWriter.Finalise;
+ inherited Create(ACollection);
+ // Find a temp file name in system temp directory that doesn't yet exist
+ repeat
+ fBakFile := TPath.Combine(
+ TPath.GetTempPath, '~codesnip-' + TPath.GetGUIDFileName
+ );
+ until not TFile.Exists(fBakFile);
end;
-procedure TNativeV4FormatSaver.WriteCategories;
- {Writes information about categories to storage.
- }
-var
- Cat: TCategory; // loops through each category
- Props: TCategoryData; // category properties
- SnipList: IStringList; // list of names of snippets in a category
+function TDCSCV2FormatSaver.CreateWriter: IDataWriter;
begin
- for Cat in fCategories do
- begin
- Props := fProvider.GetCategoryProps(Cat);
- fWriter.WriteCatProps(Cat.ID, Props);
- SnipList := fProvider.GetCategorySnippets(Cat);
- fWriter.WriteCatSnippets(Cat.ID, SnipList);
- end;
+ Result := TIniDataWriter.Create(Collection.Location.Directory);
end;
-procedure TNativeV4FormatSaver.WriteSnippets;
- {Writes information about all snippets to storage.
- }
-
- // ---------------------------------------------------------------------------
- function IDListToStrings(const IDList: ISnippetIDList): IStringList;
- {Copies snippet names from a snippet ID list to a string list.
- @param IDList [in] Snippet ID List to be copied.
- @return String list containing names.
- }
- var
- ID: TSnippetID; // each id in snippet id list
- begin
- Result := TIStringList.Create;
- for ID in IDList do
- Result.Add(ID.Name);
+procedure TDCSCV2FormatSaver.Restore;
+var
+ FB: TFolderBackup;
+begin
+ FB := TFolderBackup.Create(
+ Collection.Location.Directory, fBakFile, BakFileID
+ );
+ try
+ FB.Restore;
+ finally
+ FB.Free;
end;
- // ---------------------------------------------------------------------------
+end;
-var
- Snippet: TSnippet; // loops through each snippet in list
- Props: TSnippetData; // snippet properties
- Refs: TSnippetReferences; // snippet references
+procedure TDCSCV2FormatSaver.Save(const SnipList: TSnippetList;
+ const Categories: TCategoryList; const Provider: IDBDataProvider);
begin
- for Snippet in fSnipList do
- begin
- // Only write user-defined snippets
- if Snippet.CollectionID = fCollection.UID then
- begin
- // Get and write a snippet's properties
- Props := fProvider.GetSnippetProps(Snippet);
- fWriter.WriteSnippetProps(Snippet.Name, Props);
- // Get and write a snippet's references
- Refs := fProvider.GetSnippetRefs(Snippet);
- fWriter.WriteSnippetUnits(Snippet.Name, Refs.Units);
- fWriter.WriteSnippetDepends(Snippet.Name, IDListToStrings(Refs.Depends));
- fWriter.WriteSnippetXRefs(Snippet.Name, IDListToStrings(Refs.XRef));
+ Backup;
+ try
+ try
+ DoSave(SnipList, Categories, Provider);
+ except
+ Restore;
+ raise ExceptObject;
end;
+ finally
+ TFile.Delete(fBakFile);
end;
end;
+{ TNativeV4FormatSaver }
+
+function TNativeV4FormatSaver.CanWriteCategory(const ACategory: TCategory;
+ const ASnippetsInCategory: IStringList): Boolean;
+begin
+ Result := True;
+end;
+
+function TNativeV4FormatSaver.CreateWriter: IDataWriter;
+begin
+ Result := TXMLDataWriter.Create(Collection.Location.Directory);
+end;
+
+procedure TNativeV4FormatSaver.Save(const SnipList: TSnippetList;
+ const Categories: TCategoryList; const Provider: IDBDataProvider);
+begin
+ DoSave(SnipList, Categories, Provider);
+end;
+
end.
From 3bf7361ce068ccd286c325119268e947230ee089 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Thu, 7 Nov 2024 08:58:04 +0000
Subject: [PATCH 043/222] Rename TSnippetID & TSnippet Name props as Key
Also renamed methods and parameters of TSnippetID and TSnippet that
refer to "Name" to refer to "Key".
Made minimal changes to calling code needed to compile.
---
Src/DB.UDatabaseIO.pas | 18 ++++++++---------
Src/DB.UMain.pas | 14 ++++++-------
Src/DB.USnippet.pas | 35 +++++++++++++++------------------
Src/Favourites.UPersist.pas | 2 +-
Src/FmDependenciesDlg.pas | 4 ++--
Src/FmDuplicateSnippetDlg.pas | 6 +++---
Src/FmFavouritesDlg.pas | 4 ++--
Src/FmMain.pas | 2 +-
Src/FmSnippetsEditorDlg.pas | 10 +++++-----
Src/UCodeImportExport.pas | 10 +++++-----
Src/UCodeImportMgr.pas | 6 +++---
Src/UDetailPageHTML.pas | 2 +-
Src/USnippetHTML.pas | 4 ++--
Src/USnippetIDListIOHandler.pas | 2 +-
Src/USnippetIDs.pas | 34 ++++++++++++++++----------------
Src/USnippetValidator.pas | 10 +++++-----
Src/UTestUnit.pas | 5 +++--
17 files changed, 83 insertions(+), 85 deletions(-)
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index 6baf3193b..29d6315f9 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -571,12 +571,12 @@ procedure TDatabaseLoader.LoadReferences(const Snippet: TSnippet);
begin
LoadSnippetReferences(
- Snippet.Depends, fReader.GetSnippetDepends(Snippet.Name)
+ Snippet.Depends, fReader.GetSnippetDepends(Snippet.Key)
);
LoadSnippetReferences(
- Snippet.XRef, fReader.GetSnippetXRefs(Snippet.Name)
+ Snippet.XRef, fReader.GetSnippetXRefs(Snippet.Key)
);
- fReader.GetSnippetUnits(Snippet.Name).CopyTo(Snippet.Units);
+ fReader.GetSnippetUnits(Snippet.Key).CopyTo(Snippet.Units);
end;
procedure TDatabaseLoader.LoadSnippets(const Cat: TCategory);
@@ -749,14 +749,14 @@ procedure TFormatSaver.WriteCategories;
procedure TFormatSaver.WriteSnippets;
- // Adds names of snippets from IDList to a string list
+ // Adds snippet keys from IDList to a string list
function IDListToStrings(const IDList: ISnippetIDList): IStringList;
var
ID: TSnippetID; // each id in snippet id list
begin
Result := TIStringList.Create;
for ID in IDList do
- Result.Add(ID.Name);
+ Result.Add(ID.Key);
end;
var
@@ -770,12 +770,12 @@ procedure TFormatSaver.WriteSnippets;
begin
// Get and write a snippet's properties
Props := fProvider.GetSnippetProps(Snippet);
- fWriter.WriteSnippetProps(Snippet.Name, Props);
+ fWriter.WriteSnippetProps(Snippet.Key, Props);
// Get and write a snippet's references
Refs := fProvider.GetSnippetRefs(Snippet);
- fWriter.WriteSnippetUnits(Snippet.Name, Refs.Units);
- fWriter.WriteSnippetDepends(Snippet.Name, IDListToStrings(Refs.Depends));
- fWriter.WriteSnippetXRefs(Snippet.Name, IDListToStrings(Refs.XRef));
+ fWriter.WriteSnippetUnits(Snippet.Key, Refs.Units);
+ fWriter.WriteSnippetDepends(Snippet.Key, IDListToStrings(Refs.Depends));
+ fWriter.WriteSnippetXRefs(Snippet.Key, IDListToStrings(Refs.XRef));
end;
end;
end;
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index e732ddb2e..301da2d70 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -702,7 +702,7 @@ function TDatabase.CreateTempSnippet(const Snippet: TSnippet): TSnippet;
ClassName + '.CreateTempSnippet: Snippet is a TSnippetEx');
Data := (Snippet as TSnippetEx).GetEditData;
Result := TTempSnippet.Create(
- Snippet.Name, Snippet.CollectionID, (Snippet as TSnippetEx).GetProps);
+ Snippet.Key, Snippet.CollectionID, (Snippet as TSnippetEx).GetProps);
(Result as TTempSnippet).UpdateRefs(
(Snippet as TSnippetEx).GetReferences, fSnippets
);
@@ -952,7 +952,7 @@ function TDatabase.InternalAddSnippet(const SnippetName: string;
(Result as TSnippetEx).UpdateRefs(Data.Refs, fSnippets);
Cat := fCategories.Find(Result.Category);
if not Assigned(Cat) then
- raise ECodeSnip.CreateFmt(sCatNotFound, [Result.Category, Result.Name]);
+ raise ECodeSnip.CreateFmt(sCatNotFound, [Result.Category, Result.Key]);
Cat.Snippets.Add(Result);
fSnippets.Add(Result);
end;
@@ -1182,11 +1182,11 @@ function TDatabase.UpdateSnippet(const Snippet: TSnippet;
if NewName <> '' then
SnippetName := NewName
else
- SnippetName := Snippet.Name;
- // If name has changed then new name musn't exist in user database
- if not StrSameText(SnippetName, Snippet.Name) then
+ SnippetName := Snippet.Key;
+ // If key has changed then new key musn't exist in user database
+ if not StrSameText(SnippetName, Snippet.Key) then
if fSnippets.Find(SnippetName, TCollectionID.__TMP__UserDBCollectionID) <> nil then
- raise ECodeSnip.CreateFmt(sCantRename, [Snippet.Name, SnippetName]);
+ raise ECodeSnip.CreateFmt(sCantRename, [Snippet.Key, SnippetName]);
// We update by deleting old snippet and inserting new one
// get lists of snippets that cross reference or depend on this snippet
Dependents := TSnippetList.Create;
@@ -1287,7 +1287,7 @@ function TCollectionDataProvider.GetCategorySnippets(
Result := TIStringList.Create;
for Snippet in Cat.Snippets do
if Snippet.CollectionID = fCollectionID then
- Result.Add(Snippet.Name);
+ Result.Add(Snippet.Key);
end;
function TCollectionDataProvider.GetSnippetProps(
diff --git a/Src/DB.USnippet.pas b/Src/DB.USnippet.pas
index 7032f436d..fcfe0ef00 100644
--- a/Src/DB.USnippet.pas
+++ b/Src/DB.USnippet.pas
@@ -118,8 +118,8 @@ type TDisplayNameComparer = class(TComparer)
fKind: TSnippetKind; // Kind of snippet this is
fCategory: string; // Name of snippet's category
fDescription: IActiveText; // Description of snippet
- fSourceCode: string; // Snippet's source code
- fName: string; // Name of snippet
+ fSourceCode: string; // Snippet source code
+ fKey: string; // Snippet key: unique in collection
fDisplayName: string; // Display name of snippet
fUnits: TStringList; // List of required units
fDepends: TSnippetList; // List of required snippets
@@ -138,9 +138,9 @@ type TDisplayNameComparer = class(TComparer)
@return Required display name.
}
strict protected
- procedure SetName(const Name: string);
- {Sets Name property.
- @param Name [in] New name.
+ procedure SetKey(const AKey: string);
+ {Sets Key property.
+ @param AKey [in] New key.
}
procedure SetProps(const Data: TSnippetData);
{Sets snippet's properties.
@@ -154,12 +154,12 @@ type TDisplayNameComparer = class(TComparer)
/// Object constructor. Sets up snippet object with given property
/// values belonging to a specified collection.
- /// string [in] Name of snippet.
+ /// string [in] Snippet's key.
/// TCollectionID [in] ID of collection
/// to which the snippet belongs. ID must not be null.
/// TSnippetData [in] Values of snippet
/// properties.
- constructor Create(const Name: string; const ACollectionID: TCollectionID;
+ constructor Create(const AKey: string; const ACollectionID: TCollectionID;
const Props: TSnippetData);
destructor Destroy; override;
@@ -179,8 +179,8 @@ type TDisplayNameComparer = class(TComparer)
{Kind of snippet represented by this object}
property ID: TSnippetID read GetID;
{Snippet's unique ID}
- property Name: string read fName;
- {Name of snippet}
+ property Key: string read fKey;
+ {Snippet key}
property DisplayName: string read GetDisplayName;
{Displat name of snippet}
property Category: string read fCategory;
@@ -414,7 +414,7 @@ function TSnippet.CanCompile: Boolean;
Result := Kind <> skFreeform;
end;
-constructor TSnippet.Create(const Name: string;
+constructor TSnippet.Create(const AKey: string;
const ACollectionID: TCollectionID; const Props: TSnippetData);
begin
Assert(ClassType <> TSnippet,
@@ -423,7 +423,7 @@ constructor TSnippet.Create(const Name: string;
ClassName + '.Create: ACollectionID is null');
inherited Create;
// Record simple property values
- SetName(Name);
+ SetKey(AKey);
SetProps(Props);
// Create string list to store required units
fUnits := TStringList.Create;
@@ -451,7 +451,7 @@ function TSnippet.GetDisplayName: string;
if GetDisplayNameValue <> '' then
Result := GetDisplayNameValue
else
- Result := fName;
+ Result := fKey;
end;
function TSnippet.GetDisplayNameValue: string;
@@ -464,7 +464,7 @@ function TSnippet.GetID: TSnippetID;
@return Required ID.
}
begin
- Result := TSnippetID.Create(fName, fCollectionID);
+ Result := TSnippetID.Create(fKey, fCollectionID);
end;
function TSnippet.IsEqual(const Snippet: TSnippet): Boolean;
@@ -477,12 +477,9 @@ function TSnippet.IsEqual(const Snippet: TSnippet): Boolean;
Result := Snippet.ID = Self.ID;
end;
-procedure TSnippet.SetName(const Name: string);
- {Sets Name property.
- @param Name [in] New name.
- }
+procedure TSnippet.SetKey(const AKey: string);
begin
- fName := Name;
+ fKey := AKey;
end;
procedure TSnippet.SetProps(const Data: TSnippetData);
@@ -740,7 +737,7 @@ function TSnippetList.Find(const SnippetID: TSnippetID): TSnippet;
@return Reference to required snippet or nil if not found.
}
begin
- Result := Find(SnippetID.Name, SnippetID.CollectionID);
+ Result := Find(SnippetID.Key, SnippetID.CollectionID);
end;
function TSnippetList.GetEnumerator: TEnumerator;
diff --git a/Src/Favourites.UPersist.pas b/Src/Favourites.UPersist.pas
index 9fb4937dc..4d914bf08 100644
--- a/Src/Favourites.UPersist.pas
+++ b/Src/Favourites.UPersist.pas
@@ -134,7 +134,7 @@ class procedure TFavouritesPersist.Save(Favourites: TFavourites);
SB.AppendLine(Watermark);
for Fav in Favourites do
begin
- SB.Append(Fav.SnippetID.Name);
+ SB.Append(Fav.SnippetID.Key);
SB.Append(TAB);
SB.Append(BoolToStr(Fav.SnippetID.CollectionID <> TCollectionID.__TMP__MainDBCollectionID, True));
SB.Append(TAB);
diff --git a/Src/FmDependenciesDlg.pas b/Src/FmDependenciesDlg.pas
index 00742823a..5a7c32bb4 100644
--- a/Src/FmDependenciesDlg.pas
+++ b/Src/FmDependenciesDlg.pas
@@ -399,8 +399,8 @@ function TDependenciesDlg.GetDisplayName: string;
begin
if fDisplayName <> '' then
Exit(fDisplayName);
- if fSnippetID.Name <> '' then
- Exit(fSnippetID.Name);
+ if fSnippetID.Key <> '' then
+ Exit(fSnippetID.Key);
Result := sUntitled;
end;
diff --git a/Src/FmDuplicateSnippetDlg.pas b/Src/FmDuplicateSnippetDlg.pas
index f3a9831e3..48e1bfdbf 100644
--- a/Src/FmDuplicateSnippetDlg.pas
+++ b/Src/FmDuplicateSnippetDlg.pas
@@ -133,7 +133,7 @@ function TDuplicateSnippetDlg.DisallowedNames: IStringList;
Result.CaseSensitive := False;
for Snippet in Database.Snippets do
if Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
- Result.Add(Snippet.Name);
+ Result.Add(Snippet.Key);
end;
class function TDuplicateSnippetDlg.Execute(const AOwner: TComponent;
@@ -179,9 +179,9 @@ procedure TDuplicateSnippetDlg.InitForm;
SnippetCat: TCategory;
begin
inherited;
- edUniqueName.Text := UniqueSnippetName(fSnippet.Name);
+ edUniqueName.Text := UniqueSnippetName(fSnippet.Key);
edDisplayName.Text := StrIf(
- StrSameStr(fSnippet.Name, fSnippet.DisplayName), '', fSnippet.DisplayName
+ StrSameStr(fSnippet.Key, fSnippet.DisplayName), '', fSnippet.DisplayName
);
fCatList.ToStrings(cbCategory.Items);
SnippetCat := Database.Categories.Find(fSnippet.Category);
diff --git a/Src/FmFavouritesDlg.pas b/Src/FmFavouritesDlg.pas
index 02fca4a25..06f92d52f 100644
--- a/Src/FmFavouritesDlg.pas
+++ b/Src/FmFavouritesDlg.pas
@@ -344,7 +344,7 @@ procedure TFavouritesDlg.actDisplayExecute(Sender: TObject);
LI := fLVFavs.Selected as TFavouriteListItem;
SelectedSnippet := LI.Favourite.SnippetID;
fNotifier.DisplaySnippet(
- SelectedSnippet.Name,
+ SelectedSnippet.Key,
SelectedSnippet.CollectionID,
chkNewTab.Checked
);
@@ -367,7 +367,7 @@ procedure TFavouritesDlg.AddLVItem(const Favourite: TFavourite);
if Assigned(Snippet) then
LI.Caption := Snippet.DisplayName
else
- LI.Caption := Favourite.SnippetID.Name;
+ LI.Caption := Favourite.SnippetID.Key;
if IsToday(Favourite.LastAccessed) then
LI.SubItems.Add(TimeToStr(Favourite.LastAccessed))
else
diff --git a/Src/FmMain.pas b/Src/FmMain.pas
index 5b06ad27a..6b04f8107 100644
--- a/Src/FmMain.pas
+++ b/Src/FmMain.pas
@@ -770,7 +770,7 @@ procedure TMainForm.actEditSnippetExecute(Sender: TObject);
Assert(TUserDBMgr.CanEdit(fMainDisplayMgr.CurrentView),
ClassName + '.actEditSnippetExecute: Can''t edit current view item');
fNotifier.EditSnippet(
- (fMainDisplayMgr.CurrentView as ISnippetView).Snippet.Name
+ (fMainDisplayMgr.CurrentView as ISnippetView).Snippet.Key
);
// display of updated snippet is handled by snippets change event handler
end;
diff --git a/Src/FmSnippetsEditorDlg.pas b/Src/FmSnippetsEditorDlg.pas
index 6e1c15192..be21eced6 100644
--- a/Src/FmSnippetsEditorDlg.pas
+++ b/Src/FmSnippetsEditorDlg.pas
@@ -822,8 +822,8 @@ procedure TSnippetsEditorDlg.InitControls;
chkUseHiliter.Checked := fSnippet.HiliteSource;
frmDescription.DefaultEditMode := emAuto;
frmDescription.ActiveText := fSnippet.Description;
- edName.Text := fSnippet.Name;
- if fSnippet.Name <> fSnippet.DisplayName then
+ edName.Text := fSnippet.Key;
+ if fSnippet.Key <> fSnippet.DisplayName then
edDisplayName.Text := fSnippet.DisplayName
else
edDisplayName.Text := '';
@@ -876,7 +876,7 @@ procedure TSnippetsEditorDlg.InitForm;
fEditData := (Database as IDatabaseEdit).GetEditableSnippetInfo(fSnippet);
// Record snippet's original name, if any
if Assigned(fSnippet) then
- fOrigName := fSnippet.Name
+ fOrigName := fSnippet.Key
else
fOrigName := '';
// Populate controls with dynamic data
@@ -985,11 +985,11 @@ procedure TSnippetsEditorDlg.UpdateReferences;
for Snippet in Database.Snippets do
begin
// We ignore snippet being edited and main database snippets if there is
- // a user-defined one with same name
+ // a user-defined one with same key
if (Snippet.ID <> EditSnippetID) and
(
(Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID) or
- not Assigned(Database.Snippets.Find(Snippet.Name, TCollectionID.__TMP__UserDBCollectionID))
+ not Assigned(Database.Snippets.Find(Snippet.Key, TCollectionID.__TMP__UserDBCollectionID))
) then
begin
// Decide if snippet can be added to depends list: must be correct kind
diff --git a/Src/UCodeImportExport.pas b/Src/UCodeImportExport.pas
index d190fc852..600e47990 100644
--- a/Src/UCodeImportExport.pas
+++ b/Src/UCodeImportExport.pas
@@ -256,7 +256,7 @@ function TCodeExporter.SnippetNames(
begin
Result := TIStringList.Create;
for Snippet in SnipList do
- Result.Add(Snippet.Name);
+ Result.Add(Snippet.Key);
end;
procedure TCodeExporter.WriteProgInfo(const ParentNode: IXMLNode);
@@ -283,9 +283,9 @@ procedure TCodeExporter.WriteSnippet(const ParentNode: IXMLNode;
var
SnippetNode: IXMLNode; // new snippet node
begin
- // Create snippet node with attribute that specifies snippet name
+ // Create snippet node with attribute that specifies snippet key
SnippetNode := fXMLDoc.CreateElement(ParentNode, cSnippetNode);
- SnippetNode.Attributes[cSnippetNameAttr] := Snippet.Name;
+ SnippetNode.Attributes[cSnippetNameAttr] := Snippet.Key;
// Add nodes for properties: (ignore category and xrefs)
// description node is written even if empty (which it shouldn't be)
fXMLDoc.CreateElement(
@@ -293,8 +293,8 @@ procedure TCodeExporter.WriteSnippet(const ParentNode: IXMLNode;
cDescriptionNode,
TSnippetExtraHelper.BuildREMLMarkup(Snippet.Description)
);
- // Snippet's display name is only written if different to Snippet's name
- if Snippet.Name <> Snippet.DisplayName then
+ // Snippet's display name is only written if different to Snippet's key
+ if Snippet.Key <> Snippet.DisplayName then
fXMLDoc.CreateElement(SnippetNode, cDisplayNameNode, Snippet.DisplayName);
// source code is stored directly in XML, not in external file
fXMLDoc.CreateElement(SnippetNode, cSourceCodeTextNode, Snippet.SourceCode);
diff --git a/Src/UCodeImportMgr.pas b/Src/UCodeImportMgr.pas
index a347b21d3..f2ae236d2 100644
--- a/Src/UCodeImportMgr.pas
+++ b/Src/UCodeImportMgr.pas
@@ -186,7 +186,7 @@ function TCodeImportMgr.DisallowedNames(const ExcludedName: string):
Result.CaseSensitive := False;
for Snippet in Database.Snippets do
if Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
- Result.Add(Snippet.Name);
+ Result.Add(Snippet.Key);
for SnippetInfo in fSnippetInfoList do
if not StrSameText(SnippetInfo.Name, ExcludedName) then
Result.Add(SnippetInfo.Name);
@@ -257,7 +257,7 @@ procedure TCodeImportMgr.UpdateDatabase;
begin
SnippetID := Depends[Idx];
CollectionID := TCollectionID.__TMP__UserDBCollectionID;
- if Database.Snippets.Find(SnippetID.Name, CollectionID) = nil then
+ if Database.Snippets.Find(SnippetID.Key, CollectionID) = nil then
CollectionID := TCollectionID.__TMP__MainDBCollectionID;
SnippetID.CollectionID := CollectionID;
Depends[Idx] := SnippetID;
@@ -308,7 +308,7 @@ constructor TImportInfo.Create(const AOrigName, AImportAsName: string;
function TImportInfoComparer.Compare(const Left, Right: TImportInfo): Integer;
begin
- Result := TSnippetID.CompareNames(Left.OrigName, Right.OrigName);
+ Result := TSnippetID.CompareKeys(Left.OrigName, Right.OrigName);
end;
{ TImportInfoList }
diff --git a/Src/UDetailPageHTML.pas b/Src/UDetailPageHTML.pas
index d34ec1f5b..e231822f6 100644
--- a/Src/UDetailPageHTML.pas
+++ b/Src/UDetailPageHTML.pas
@@ -538,7 +538,7 @@ procedure TSnippetInfoPageHTML.ResolvePlaceholders(const Tplt: THTMLTemplate);
);
Tplt.ResolvePlaceholderText(
'EditEventHandler',
- TJavaScript.LiteralFunc('editSnippet', [GetSnippet.Name])
+ TJavaScript.LiteralFunc('editSnippet', [GetSnippet.Key])
);
SnippetHTML := TSnippetHTML.Create(GetSnippet);
try
diff --git a/Src/USnippetHTML.pas b/Src/USnippetHTML.pas
index caaca05a7..3d4a6fbc5 100644
--- a/Src/USnippetHTML.pas
+++ b/Src/USnippetHTML.pas
@@ -204,10 +204,10 @@ function TSnippetHTML.SnippetName: string;
class function TSnippetHTML.SnippetALink(const Snippet: TSnippet): string;
begin
- // Create javascript link enclosing snippet name
+ // Create javascript link enclosing snippet key
Result := JSALink(
TJavaScript.LiteralFunc(
- 'displaySnippet', [Snippet.Name, Snippet.CollectionID.ToHexString]
+ 'displaySnippet', [Snippet.Key, Snippet.CollectionID.ToHexString]
),
'snippet-link',
Snippet.DisplayName
diff --git a/Src/USnippetIDListIOHandler.pas b/Src/USnippetIDListIOHandler.pas
index a67a37b67..64c47eeb9 100644
--- a/Src/USnippetIDListIOHandler.pas
+++ b/Src/USnippetIDListIOHandler.pas
@@ -162,7 +162,7 @@ procedure TSnippetIDListFileWriter.CreateContent(
fBuilder.AppendLine(fWatermark);
for SnippetID in SnippetIDs do
begin
- fBuilder.Append(SnippetID.Name);
+ fBuilder.Append(SnippetID.Key);
fBuilder.Append(TAB);
fBuilder.Append(Ord(SnippetID.CollectionID <> TCollectionID.__TMP__MainDBCollectionID));
fBuilder.AppendLine;
diff --git a/Src/USnippetIDs.pas b/Src/USnippetIDs.pas
index 81b5c7bc7..8b4ee35dd 100644
--- a/Src/USnippetIDs.pas
+++ b/Src/USnippetIDs.pas
@@ -26,18 +26,18 @@ interface
type
- /// Record that uniquely identifies a code snippet. Specifies name
- /// and flag indicating whether snippet is user-defined.
+ /// Record that uniquely identifies a code snippet.
+ /// Comprises the snippet's key and collection.
TSnippetID = record
strict private
var
- /// Value of Name property.
- fName: string;
+ /// Value of Key property.
+ fKey: string;
fCollectionID: TCollectionID;
procedure SetCollectionID(const AValue: TCollectionID);
public
- /// Name of snippet.
- property Name: string read fName write fName;
+ /// Snippet's key.
+ property Key: string read fKey write fKey;
/// ID of the collection to which a snippet with this ID belongs.
///
@@ -47,7 +47,7 @@ TSnippetID = record
/// Creates a record with given property values.
/// ACollectionID must not be null.
- constructor Create(const AName: string; const ACollectionID: TCollectionID);
+ constructor Create(const AKey: string; const ACollectionID: TCollectionID);
/// Creates copy of given snippet ID
constructor Clone(const Src: TSnippetID);
@@ -58,12 +58,12 @@ TSnippetID = record
/// SID or +ve if this record greater than SID.
function CompareTo(const SID: TSnippetID): Integer;
- /// Compares two snippet names.
- /// string [in] First name.
- /// string [in] Second name.
- /// Integer. 0 if names are same, -ve if Left is less than Right or
+ /// Compares two snippet keys.
+ /// string [in] First key.
+ /// string [in] Second key.
+ /// Integer. 0 if keys are same, -ve if Left is less than Right or
/// +ve Left is greater than Right.
- class function CompareNames(const Left, Right: string): Integer; static;
+ class function CompareKeys(const Left, Right: string): Integer; static;
/// Overload of equality operator for two TSnippetIDs.
class operator Equal(const SID1, SID2: TSnippetID): Boolean;
@@ -162,26 +162,26 @@ implementation
constructor TSnippetID.Clone(const Src: TSnippetID);
begin
- Create(Src.Name, Src.CollectionID);
+ Create(Src.Key, Src.CollectionID);
end;
-class function TSnippetID.CompareNames(const Left, Right: string): Integer;
+class function TSnippetID.CompareKeys(const Left, Right: string): Integer;
begin
Result := StrCompareText(Left, Right);
end;
function TSnippetID.CompareTo(const SID: TSnippetID): Integer;
begin
- Result := CompareNames(Name, SID.Name);
+ Result := CompareKeys(Key, SID.Key);
if Result = 0 then
// TODO -cNote: New comparison changes ordering (no problem tho!)
Result := TCollectionID.Compare(CollectionID, SID.CollectionID);
end;
-constructor TSnippetID.Create(const AName: string;
+constructor TSnippetID.Create(const AKey: string;
const ACollectionID: TCollectionID);
begin
- fName := AName;
+ fKey := AKey;
SetCollectionID(ACollectionID);
end;
diff --git a/Src/USnippetValidator.pas b/Src/USnippetValidator.pas
index 0fc8ef764..1e8988921 100644
--- a/Src/USnippetValidator.pas
+++ b/Src/USnippetValidator.pas
@@ -172,7 +172,7 @@ class function TSnippetValidator.Validate(const Snippet: TSnippet;
@return True if snippet valid or False if not.
}
begin
- Result := ValidateName(Snippet.Name, False, ErrorMsg, ErrorSel)
+ Result := ValidateName(Snippet.Key, False, ErrorMsg, ErrorSel)
and ValidateDescription(Snippet.Description.ToString, ErrorMsg, ErrorSel)
and ValidateSourceCode(Snippet.SourceCode, ErrorMsg, ErrorSel)
and ValidateDependsList(Snippet, ErrorMsg)
@@ -241,8 +241,8 @@ class function TSnippetValidator.ValidateDependsList(const Snippet: TSnippet;
resourcestring
// Error messages
sInvalidKind = 'Invalid snippet kind "%0:s" in depends list for snippet '
- + 'named "%1:s"';
- sCircular = '%0:s Snippet named "%1:s" cannot depend on itself.';
+ + 'with key "%1:s"';
+ sCircular = '%0:s snippet with key "%1:s" cannot depend on itself.';
var
DeniedDepends: TSnippetKinds; // snippet kinds that can't be in depends list
begin
@@ -255,7 +255,7 @@ class function TSnippetValidator.ValidateDependsList(const Snippet: TSnippet;
ErrorMsg := Format(
sCircular, [
TSnippetKindInfoList.Items[Snippet.Kind].DisplayName,
- Snippet.Name
+ Snippet.Key
]
);
Exit;
@@ -270,7 +270,7 @@ class function TSnippetValidator.ValidateDependsList(const Snippet: TSnippet;
sInvalidKind,
[
TSnippetKindInfoList.Items[Snippet.Kind].DisplayName,
- Snippet.Name
+ Snippet.Key
]
);
end;
diff --git a/Src/UTestUnit.pas b/Src/UTestUnit.pas
index eef7d44c5..d0b3f7a92 100644
--- a/Src/UTestUnit.pas
+++ b/Src/UTestUnit.pas
@@ -136,8 +136,9 @@ function TTestUnit.UnitName: string;
begin
if fSnippet.Kind = skUnit then
Exit(TUnitAnalyser.UnitName(fSnippet.SourceCode));
- // Unit name is same as Snippet being tested, but with prefix to make unique
- Result := cUnitPrefix + fSnippet.Name;
+ // Unit name is same as key of Snippet being tested, but with prefix to make
+ // unique
+ Result := cUnitPrefix + fSnippet.Key;
// We ensure only ASCII characters are used in unit name. Any unsuitable
// characters are replaced by underscore.
// This is done because unit name is also used as unit file name. If we took
From 4a59735c1819c823c0b56940ea7cd7379b2ddb74 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Thu, 7 Nov 2024 10:27:41 +0000
Subject: [PATCH 044/222] Rename params & vars to refer to snippet keys
Several method parameter and local variable names that refer to snippet
or snippet ID "names" were renamed to refer to keys.
External object type library had similar renaming & Pascal code that
interfaces with was changed accordingly.
Some error messages were changed to refer to keys instead of snippet
names.
No method signatures (i.e. method names and / or parameter types) were
changed.
---
Src/DB.UDatabaseIO.pas | 78 +++++++++---------
Src/DB.UMain.pas | 122 +++++++++++++--------------
Src/DB.USnippet.pas | 29 +++----
Src/DBIO.UFileIOIntf.pas | 48 +++++------
Src/DBIO.UIniData.pas | 158 +++++++++++++++++------------------
Src/DBIO.UNulDataReader.pas | 54 ++++++------
Src/DBIO.UXMLDataIO.pas | 159 ++++++++++++++++++------------------
Src/ExternalObj.ridl | 12 +--
Src/IntfNotifier.pas | 10 ++-
Src/UNotifier.pas | 16 ++--
Src/USnippetValidator.pas | 98 +++++++++++-----------
Src/UUserDBMgr.pas | 16 ++--
Src/UWBExternal.pas | 37 ++++-----
13 files changed, 423 insertions(+), 414 deletions(-)
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index 29d6315f9..16a02c42c 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -151,10 +151,10 @@ TDatabaseLoader = class(TInterfacedObject, IDataFormatLoader)
reader must be created.
@return Reader object instance.
}
- function FindSnippet(const SnippetName: string;
+ function FindSnippet(const SnippetKey: string;
const SnipList: TSnippetList): TSnippet; virtual; abstract;
- {Finds the snippet object with a specified name.
- @param SnippetName [in] Name of required snippet.
+ {Finds the snippet object with a specified key.
+ @param SnippetKey [in] Key of required snippet.
@param SnipList [in] List of snippets to search.
@return Reference to required snippet object or nil if snippet is not
found.
@@ -208,10 +208,10 @@ TDCSCV2FormatLoader = class(TDatabaseLoader, IDataFormatLoader)
created.
@return Reader object instance.
}
- function FindSnippet(const SnippetName: string;
+ function FindSnippet(const SnippetKey: string;
const SnipList: TSnippetList): TSnippet; override;
- {Finds the snippet object with a specified name in the main database.
- @param SnippetName [in] Name of required snippet.
+ {Finds the snippet object with a specified key in the main database.
+ @param SnippetKey [in] Key of required snippet.
@param SnipList [in] List of snippets to search.
@return Reference to required snippet object or nil if snippet is not
found.
@@ -234,11 +234,11 @@ TNativeV4FormatLoader = class(TDatabaseLoader, IDataFormatLoader)
created.
@return Reader object instance.
}
- function FindSnippet(const SnippetName: string;
+ function FindSnippet(const SnippetKey: string;
const SnipList: TSnippetList): TSnippet; override;
- {Finds the snippet object with a specified name. If snippet is not in this
+ {Finds the snippet object with a specified key. If snippet is not in this
(user) database the main database is searched.
- @param SnippetName [in] Name of required snippet.
+ @param SnippetKey [in] Key of required snippet.
@param SnipList [in] List of snippets to search.
@return Reference to required snippet object or nil if snippet is not
found.
@@ -296,7 +296,7 @@ TFormatSaver = class abstract (TInterfacedObject,
/// TCategory [in] The category being
/// queried.
/// IStringList [in] List of the
- /// names of all snippets in the category.
+ /// keys of all snippets in the category.
/// Boolean. True if category can be written, False
/// otherwise.
function CanWriteCategory(const ACategory: TCategory;
@@ -350,7 +350,7 @@ TDCSCV2FormatSaver = class(TFormatSaver,
/// TCategory [in] The category being
/// queried.
/// IStringList [in] List of the
- /// names of all snippets in the category.
+ /// keys of all snippets in the category.
/// Boolean. True if category contains snippets, False
/// otherwise.
function CanWriteCategory(const ACategory: TCategory;
@@ -390,7 +390,7 @@ TNativeV4FormatSaver = class(TFormatSaver,
/// TCategory [in] The category being
/// queried.
/// IStringList [in] List of the
- /// names of all snippets in the category.
+ /// keys of all snippets in the category.
/// Boolean. Always True: all categories are written.
///
function CanWriteCategory(const ACategory: TCategory;
@@ -549,20 +549,20 @@ procedure TDatabaseLoader.LoadReferences(const Snippet: TSnippet);
// ---------------------------------------------------------------------------
procedure LoadSnippetReferences(const RefList: TSnippetList;
- const RefNames: IStringList);
- {Creates a snippet list from names of snippets in a string list. If no
- snippet with a given name is found no matching entry is added to snippet
+ const RefKeys: IStringList);
+ {Creates a snippet list from keys of snippets in a string list. If no
+ snippet with a given key is found no matching entry is added to snippet
list.
@param RefList [in] List to receive referenced snippets.
- @param RefNames [in] List of snippet names.
+ @param RefKeys [in] List of snippet keys.
}
var
- RefName: string; // referenced snippet name
+ RefKey: string; // referenced snippet key
Reference: TSnippet; // referenced snippet object
begin
- for RefName in RefNames do
+ for RefKey in RefKeys do
begin
- Reference := FindSnippet(RefName, fSnipList);
+ Reference := FindSnippet(RefKey, fSnipList);
if Assigned(Reference) then
RefList.Add(Reference);
end;
@@ -584,24 +584,24 @@ procedure TDatabaseLoader.LoadSnippets(const Cat: TCategory);
@param Cat [in] Category to be loaded.
}
var
- SnippetNames: IStringList; // list of names of snippets in category
+ SnippetKeys: IStringList; // list of keys of snippets in category
SnippetProps: TSnippetData; // properties of a snippet
- SnippetName: string; // each name in name list
+ SnippetKey: string; // each key in key list
Snippet: TSnippet; // references a snippet object
begin
FillChar(SnippetProps, SizeOf(SnippetProps), 0);
- // Get names of all snippets in category
- SnippetNames := fReader.GetCatSnippets(Cat.ID);
- // Process each snippet name in list
- for SnippetName in SnippetNames do
+ // Get keys of all snippets in category
+ SnippetKeys := fReader.GetCatSnippets(Cat.ID);
+ // Process each snippet key in list
+ for SnippetKey in SnippetKeys do
begin
// Check if snippet exists in current database and add it to list if not
- Snippet := fSnipList.Find(SnippetName, Collection.UID);
+ Snippet := fSnipList.Find(SnippetKey, Collection.UID);
if not Assigned(Snippet) then
begin
- fReader.GetSnippetProps(SnippetName, SnippetProps);
+ fReader.GetSnippetProps(SnippetKey, SnippetProps);
Snippet := fFactory.CreateSnippet(
- SnippetName, Collection.UID, SnippetProps
+ SnippetKey, Collection.UID, SnippetProps
);
fSnipList.Add(Snippet);
end;
@@ -634,16 +634,16 @@ function TDCSCV2FormatLoader.ErrorMessageHeading: string;
Result := sError;
end;
-function TDCSCV2FormatLoader.FindSnippet(const SnippetName: string;
+function TDCSCV2FormatLoader.FindSnippet(const SnippetKey: string;
const SnipList: TSnippetList): TSnippet;
- {Finds the snippet object with a specified name in the main database.
- @param SnippetName [in] Name of required snippet.
+ {Finds the snippet object with a specified key in the main database.
+ @param SnippetKey [in] Key of required snippet.
@param SnipList [in] List of snippets to search.
@return Reference to required snippet object or nil if snippet is not found.
}
begin
// We only search main database
- Result := SnipList.Find(SnippetName, Collection.UID);
+ Result := SnipList.Find(SnippetKey, Collection.UID);
end;
{ TNativeV4FormatLoader }
@@ -669,24 +669,22 @@ function TNativeV4FormatLoader.ErrorMessageHeading: string;
Result := sError;
end;
-function TNativeV4FormatLoader.FindSnippet(const SnippetName: string;
+function TNativeV4FormatLoader.FindSnippet(const SnippetKey: string;
const SnipList: TSnippetList): TSnippet;
- {Finds the snippet object with a specified name. If snippet is not in this
+ {Finds the snippet object with a specified key. If snippet is not in this
(user) database the main database is searched.
- @param SnippetName [in] Name of required snippet.
+ @param SnippetKey [in] Key of required snippet.
@param SnipList [in] List of snippets to search.
@return Reference to required snippet object or nil if snippet is not found.
}
-
-
begin
// Search in user database
- Result := SnipList.Find(SnippetName, Collection.UID);
+ Result := SnipList.Find(SnippetKey, Collection.UID);
{TODO -cVault: Delete the following - only allow references in same collection
}
if not Assigned(Result) then
// Not in user database: try main database
- Result := SnipList.Find(SnippetName, TCollectionID.__TMP__MainDBCollectionID);
+ Result := SnipList.Find(SnippetKey, TCollectionID.__TMP__MainDBCollectionID);
end;
procedure TNativeV4FormatLoader.LoadCategories;
@@ -733,7 +731,7 @@ procedure TFormatSaver.WriteCategories;
var
Cat: TCategory; // loops through each category
Props: TCategoryData; // category properties
- SnipList: IStringList; // list of names of snippets in a category
+ SnipList: IStringList; // list of keys of snippets in a category
begin
for Cat in fCategories do
begin
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index 301da2d70..f37e8dbdb 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -66,11 +66,11 @@ interface
///
function GetCategoryProps(const Cat: TCategory): TCategoryData;
- /// Retrieves names of all snippets that belong to a category.
+ /// Retrieves keys of all snippets that belong to a category.
///
- /// Category [in] Category for which snippet names
+ /// Category [in] Category for which snippet keys
/// are requested.
- /// IStringList. List of snippet names.
+ /// IStringList. List of snippet keys.
function GetCategorySnippets(const Cat: TCategory): IStringList;
/// Retrieves all the properties of a snippet.
@@ -129,14 +129,14 @@ interface
const ACollectionID: TCollectionID; const Data: TCategoryData): TCategory;
/// Creates a new snippet object.
- /// string [in] Name of new snippet. Must not
+ /// string [in] New snippet's key. Must not
/// exist in database
/// TCollectionID [in] Collection
/// containing the snippet.
/// TSnippetData [in] Record describing
/// snippet's properties.
/// Instance of new snippet with no references.
- function CreateSnippet(const Name: string;
+ function CreateSnippet(const Key: string;
const ACollectionID: TCollectionID; const Props: TSnippetData): TSnippet;
end;
@@ -202,30 +202,30 @@ interface
@return List of IDs of referring snippets.
}
function UpdateSnippet(const Snippet: TSnippet;
- const Data: TSnippetEditData; const NewName: string = ''): TSnippet;
+ const Data: TSnippetEditData; const NewKey: string = ''): TSnippet;
{Updates a user defined snippet's properties and references using provided
data.
@param Snippet [in] Snippet to be updated. Must be user-defined.
@param Data [in] Record containing revised data.
- @param NewName [in] New name of snippet. Set to '' or Snippet.Name if
- name is not to change.
+ @param NewKey [in] New snippet's key. Set to '' or Snippet.Key if
+ key is not to change.
@return Reference to updated snippet. Will have changed.
}
- function AddSnippet(const SnippetName: string;
+ function AddSnippet(const SnippetKey: string;
const Data: TSnippetEditData): TSnippet;
{Adds a new snippet to the user database.
- @param SnippetName [in] Name of new snippet.
+ @param SnippetKey [in] New snippet's key.
@param Data [in] Record storing new snippet's properties and references.
@return Reference to new snippet.
}
function DuplicateSnippet(const Snippet: TSnippet;
- const UniqueName, DisplayName: string; const CatID: string): TSnippet;
- function CreateTempSnippet(const SnippetName: string;
+ const UniqueKey, DisplayName: string; const CatID: string): TSnippet;
+ function CreateTempSnippet(const SnippetKey: string;
const Data: TSnippetEditData): TSnippet; overload;
{Creates a new temporary snippet without adding it to the Snippets
object's snippets list. The new instance may not be added to the
Snippets object.
- @param SnippetName [in] Name of new snippet.
+ @param SnippetKey [in] New snippet's key.
@param Data [in] Record storing new snippet's properties and references.
@return Reference to new snippet.
}
@@ -320,14 +320,14 @@ TDBDataItemFactory = class(TInterfacedObject, IDBDataItemFactory)
const ACollectionID: TCollectionID; const Data: TCategoryData): TCategory;
/// Creates a new snippet object.
- /// string [in] Name of new snippet. Must not
+ /// string [in] New snippet's key. Must not
/// exist in database
/// TCollectionID [in] Collection
/// containing the snippet.
/// TSnippetData [in] Record describing
/// snippet's properties.
/// Instance of new snippet with no references.
- function CreateSnippet(const Name: string;
+ function CreateSnippet(const Key: string;
const ACollectionID: TCollectionID; const Props: TSnippetData): TSnippet;
end;
@@ -381,11 +381,11 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
@param Info [in] Reference to any further information for event. May be
nil.
}
- function InternalAddSnippet(const SnippetName: string;
+ function InternalAddSnippet(const SnippetKey: string;
const Data: TSnippetEditData): TSnippet;
{Adds a new snippet to the user database. Assumes snippet not already in
user database.
- @param SnippetName [in] Name of new snippet.
+ @param SnippetKey [in] New snippet's key.
@param Data [in] Properties and references of new snippet.
@return Reference to new snippet object.
@except Exception raised if snippet's category does not exist.
@@ -469,30 +469,30 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
@return List of IDs of referring snippets.
}
function UpdateSnippet(const Snippet: TSnippet;
- const Data: TSnippetEditData; const NewName: string = ''): TSnippet;
+ const Data: TSnippetEditData; const NewKey: string = ''): TSnippet;
{Updates a user defined snippet's properties and references using provided
data.
@param Snippet [in] Snippet to be updated. Must be user-defined.
@param Data [in] Record containing revised data.
- @param NewName [in] New name of snippet. Set to '' or Snippet.Name if
- name is not to change.
+ @param NewKey [in] New snippet's key. Set to '' or Snippet.Key if
+ key is not to change.
@return Reference to updated snippet. Will have changed.
}
- function AddSnippet(const SnippetName: string;
+ function AddSnippet(const SnippetKey: string;
const Data: TSnippetEditData): TSnippet;
{Adds a new snippet to the user database.
- @param SnippetName [in] Name of new snippet.
+ @param SnippetKey [in] New snippet's key.
@param Data [in] Record storing new snippet's properties and references.
@return Reference to new snippet.
}
function DuplicateSnippet(const Snippet: TSnippet;
- const UniqueName, DisplayName: string; const CatID: string): TSnippet;
- function CreateTempSnippet(const SnippetName: string;
+ const UniqueKey, DisplayName: string; const CatID: string): TSnippet;
+ function CreateTempSnippet(const SnippetKey: string;
const Data: TSnippetEditData): TSnippet; overload;
{Creates a new temporary user defined snippet without adding it to the
Snippets object's snippets list. The new instance may not be added to the
Snippets object.
- @param SnippetName [in] Name of new snippet.
+ @param SnippetKey [in] New snippet's key.
@param Data [in] Record storing new snippet's properties and references.
@return Reference to new snippet.
}
@@ -569,11 +569,11 @@ TCollectionDataProvider = class(TInterfacedObject, IDBDataProvider)
/// Method of IDBDataProvider
function GetCategoryProps(const Cat: TCategory): TCategoryData;
- /// Retrieves names of all snippets from the collection that
- /// belong to a category.
- /// Category [in] Category for which snippet names
+ /// Retrieves keys of all snippets from the collection that belong
+ /// to a category.
+ /// Category [in] Category for which snippet keys
/// are requested.
- /// IStringList. List of snippet names.
+ /// IStringList. List of snippet keys.
/// Method of IDBDataProvider
function GetCategorySnippets(const Cat: TCategory): IStringList;
@@ -643,24 +643,24 @@ procedure TDatabase.AddChangeEventHandler(const Handler: TNotifyEventInfo);
fChangeEvents.AddHandler(Handler);
end;
-function TDatabase.AddSnippet(const SnippetName: string;
+function TDatabase.AddSnippet(const SnippetKey: string;
const Data: TSnippetEditData): TSnippet;
{Adds a new snippet to the user database.
- @param SnippetName [in] Name of new snippet.
+ @param SnippetKey [in] New snippet's key.
@param Data [in] Record storing new snippet's properties and references.
@return Reference to new snippet.
}
resourcestring
// Error message
- sNameExists = 'Snippet "%s" already exists in user database';
+ sKeyExists = 'Snippet with key "%s" already exists in user database';
begin
Result := nil; // keeps compiler happy
TriggerEvent(evChangeBegin);
try
- // Check if snippet with same name exists in user database: error if so
- if fSnippets.Find(SnippetName, TCollectionID.__TMP__UserDBCollectionID) <> nil then
- raise ECodeSnip.CreateFmt(sNameExists, [SnippetName]);
- Result := InternalAddSnippet(SnippetName, Data);
+ // Check if snippet with same key exists in user database: error if so
+ if fSnippets.Find(SnippetKey, TCollectionID.__TMP__UserDBCollectionID) <> nil then
+ raise ECodeSnip.CreateFmt(sKeyExists, [SnippetKey]);
+ Result := InternalAddSnippet(SnippetKey, Data);
Query.Update;
TriggerEvent(evSnippetAdded, Result);
finally
@@ -708,17 +708,17 @@ function TDatabase.CreateTempSnippet(const Snippet: TSnippet): TSnippet;
);
end;
-function TDatabase.CreateTempSnippet(const SnippetName: string;
+function TDatabase.CreateTempSnippet(const SnippetKey: string;
const Data: TSnippetEditData): TSnippet;
{Creates a new temporary user defined snippet without adding it to the
Snippets object's snippets list. The new instance may not be added to the
Snippets object.
- @param SnippetName [in] Name of new snippet.
+ @param SnippetKey [in] New snippet's key.
@param Data [in] Record storing new snippet's properties and references.
@return Reference to new snippet.
}
begin
- Result := TTempSnippet.Create(SnippetName, TCollectionID.__TMP__UserDBCollectionID, Data.Props);
+ Result := TTempSnippet.Create(SnippetKey, TCollectionID.__TMP__UserDBCollectionID, Data.Props);
(Result as TTempSnippet).UpdateRefs(Data.Refs, fSnippets);
end;
@@ -795,14 +795,14 @@ destructor TDatabase.Destroy;
end;
function TDatabase.DuplicateSnippet(const Snippet: TSnippet;
- const UniqueName, DisplayName: string; const CatID: string): TSnippet;
+ const UniqueKey, DisplayName: string; const CatID: string): TSnippet;
var
Data: TSnippetEditData;
begin
Data := (Snippet as TSnippetEx).GetEditData;
Data.Props.Cat := CatID;
Data.Props.DisplayName := DisplayName;
- Result := AddSnippet(UniqueName, Data);
+ Result := AddSnippet(UniqueKey, Data);
end;
function TDatabase.GetCategories: TCategoryList;
@@ -932,11 +932,11 @@ function TDatabase.InternalAddCategory(const CatID: string;
fCategories.Add(Result);
end;
-function TDatabase.InternalAddSnippet(const SnippetName: string;
+function TDatabase.InternalAddSnippet(const SnippetKey: string;
const Data: TSnippetEditData): TSnippet;
{Adds a new snippet to the user database. Assumes snippet not already in user
database.
- @param SnippetName [in] Name of new snippet.
+ @param SnippetKey [in] New snippet's key.
@param Data [in] Properties and references of new snippet.
@return Reference to new snippet object.
@except Exception raised if snippet's category does not exist.
@@ -945,10 +945,10 @@ function TDatabase.InternalAddSnippet(const SnippetName: string;
Cat: TCategory; // category object containing new snippet
resourcestring
// Error message
- sCatNotFound = 'Category "%0:s" referenced by new snippet named "%1:s" does '
- + 'not exist';
+ sCatNotFound = 'Category "%0:s" referenced by new snippet with key "%1:s" '
+ + 'does not exist';
begin
- Result := TSnippetEx.Create(SnippetName, TCollectionID.__TMP__UserDBCollectionID, Data.Props);
+ Result := TSnippetEx.Create(SnippetKey, TCollectionID.__TMP__UserDBCollectionID, Data.Props);
(Result as TSnippetEx).UpdateRefs(Data.Refs, fSnippets);
Cat := fCategories.Find(Result.Category);
if not Assigned(Cat) then
@@ -1150,25 +1150,25 @@ function TDatabase.Updated: Boolean;
end;
function TDatabase.UpdateSnippet(const Snippet: TSnippet;
- const Data: TSnippetEditData; const NewName: string): TSnippet;
+ const Data: TSnippetEditData; const NewKey: string): TSnippet;
{Updates a user defined snippet's properties and references using provided
data.
@param Snippet [in] Snippet to be updated. Must be user-defined.
@param Data [in] Record containing revised data.
- @param NewName [in] New name of snippet. Set to '' or Snippet.Name if name
+ @param NewKey [in] New snippet's key. Set to '' or Snippet.Key if key
is not to change.
@return Reference to updated snippet. Will have changed.
}
var
- SnippetName: string; // name of snippet
+ SnippetKey: string; // snippet key
Dependent: TSnippet; // loops thru each snippetthat depends on Snippet
Dependents: TSnippetList; // list of dependent snippets
Referrer: TSnippet; // loops thru snippets that cross references Snippet
Referrers: TSnippetList; // list of referencing snippets
resourcestring
// Error message
- sCantRename = 'Can''t rename snippet named %0:s to %1:s: Snippet with name '
- + '%1:s already exists in user database';
+ sCantChangeKey = 'Can''t change key of snippet with key %0:s to %1:s: '
+ + 'Snippet with key %1:s already exists in user database';
begin
Result := Snippet; // keeps compiler happy
Assert(Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID,
@@ -1178,15 +1178,15 @@ function TDatabase.UpdateSnippet(const Snippet: TSnippet;
TriggerEvent(evChangeBegin);
TriggerEvent(evBeforeSnippetChange, Snippet);
try
- // Calculate new name
- if NewName <> '' then
- SnippetName := NewName
+ // Calculate new key
+ if NewKey <> '' then
+ SnippetKey := NewKey
else
- SnippetName := Snippet.Key;
+ SnippetKey := Snippet.Key;
// If key has changed then new key musn't exist in user database
- if not StrSameText(SnippetName, Snippet.Key) then
- if fSnippets.Find(SnippetName, TCollectionID.__TMP__UserDBCollectionID) <> nil then
- raise ECodeSnip.CreateFmt(sCantRename, [Snippet.Key, SnippetName]);
+ if not StrSameText(SnippetKey, Snippet.Key) then
+ if fSnippets.Find(SnippetKey, TCollectionID.__TMP__UserDBCollectionID) <> nil then
+ raise ECodeSnip.CreateFmt(sCantChangeKey, [Snippet.Key, SnippetKey]);
// We update by deleting old snippet and inserting new one
// get lists of snippets that cross reference or depend on this snippet
Dependents := TSnippetList.Create;
@@ -1201,7 +1201,7 @@ function TDatabase.UpdateSnippet(const Snippet: TSnippet;
// delete the snippet
InternalDeleteSnippet(Snippet);
// add new snippet
- Result := InternalAddSnippet(SnippetName, Data);
+ Result := InternalAddSnippet(SnippetKey, Data);
// add new snippet to referrer list of referring snippets
for Referrer in Referrers do
Referrer.XRef.Add(Result);
@@ -1256,10 +1256,10 @@ function TDBDataItemFactory.CreateCategory(const CatID: string;
Result := TCategoryEx.Create(CatID, ACollectionID, Data);
end;
-function TDBDataItemFactory.CreateSnippet(const Name: string;
+function TDBDataItemFactory.CreateSnippet(const Key: string;
const ACollectionID: TCollectionID; const Props: TSnippetData): TSnippet;
begin
- Result := TSnippetEx.Create(Name, ACollectionID, Props);
+ Result := TSnippetEx.Create(Key, ACollectionID, Props);
end;
{ TCollectionDataProvider }
diff --git a/Src/DB.USnippet.pas b/Src/DB.USnippet.pas
index fcfe0ef00..483ffe928 100644
--- a/Src/DB.USnippet.pas
+++ b/Src/DB.USnippet.pas
@@ -167,7 +167,8 @@ type TDisplayNameComparer = class(TComparer)
}
function IsEqual(const Snippet: TSnippet): Boolean;
{Checks if this snippet is same as another snippet. Snippets are
- considered equal if they have the same name and come from same database.
+ considered equal if they have the same key and come from the same
+ collection.
@param Snippet [in] Snippet being compared.
@return True if snippets are equal, False if not.
}
@@ -261,16 +262,16 @@ TSnippetList = class(TObject)
@return Snippet at specified index in list.
}
- /// Finds a snippet in the list with whose name and collection ID
+ /// Finds a snippet in the list with whose key and collection ID
/// match.
- /// string [in] Name of snippet.
+ /// string [in] Snippet's key.
/// TCollectionID [in] ID of collection
/// to which the snippet belongs.
/// Integer. [out] Set to the index of the
/// required snippet in the list. Valid only if the snippet was found.
///
/// Boolean. True if snippet found, False if not.
- function Find(const SnippetName: string; const ACollectionID: TCollectionID;
+ function Find(const SnippetKey: string; const ACollectionID: TCollectionID;
out Index: Integer): Boolean; overload;
strict protected
@@ -306,14 +307,14 @@ TSnippetList = class(TObject)
@return Reference to required snippet or nil if not found.
}
- /// Finds a snippet in the list with whose name and collection ID
+ /// Finds a snippet in the list with whose key and collection ID
/// match.
- /// string [in] Name of snippet.
+ /// string [in] Snippet's key.
/// TCollectionID [in] ID of collection
/// to which the snippet belongs.
/// TSnippet. Reference to the required snippet or nil if
/// not found.
- function Find(const SnippetName: string;
+ function Find(const SnippetKey: string;
const ACollectionID: TCollectionID): TSnippet; overload;
function Contains(const Snippet: TSnippet): Boolean;
@@ -469,7 +470,7 @@ function TSnippet.GetID: TSnippetID;
function TSnippet.IsEqual(const Snippet: TSnippet): Boolean;
{Checks if this snippet is same as another snippet. Snippets are considered
- equal if they have the same name and come from same database.
+ equal if they have the same key and come from the same collection.
@param Snippet [in] Snippet being compared.
@return True if snippets are equal, False if not.
}
@@ -703,7 +704,7 @@ destructor TSnippetList.Destroy;
inherited;
end;
-function TSnippetList.Find(const SnippetName: string;
+function TSnippetList.Find(const SnippetKey: string;
const ACollectionID: TCollectionID; out Index: Integer): Boolean;
var
TempSnippet: TSnippet; // temp snippet used to perform search
@@ -712,7 +713,7 @@ function TSnippetList.Find(const SnippetName: string;
// We need a temporary snippet object in order to perform binary search using
// object list's built in search
NullData.Init;
- TempSnippet := TTempSnippet.Create(SnippetName, ACollectionID, NullData);
+ TempSnippet := TTempSnippet.Create(SnippetKey, ACollectionID, NullData);
try
Result := fList.Find(TempSnippet, Index);
finally
@@ -720,12 +721,12 @@ function TSnippetList.Find(const SnippetName: string;
end;
end;
-function TSnippetList.Find(const SnippetName: string;
+function TSnippetList.Find(const SnippetKey: string;
const ACollectionID: TCollectionID): TSnippet;
var
- Idx: Integer; // index of snippet name in list
+ Idx: Integer; // index of snippet key in list
begin
- if Find(SnippetName, ACollectionID, Idx) then
+ if Find(SnippetKey, ACollectionID, Idx) then
Result := Items[Idx]
else
Result := nil;
@@ -782,7 +783,7 @@ function TSnippetList.IsEqual(const AList: TSnippetList): Boolean;
Result := Assigned(AList) and (Self.Count = AList.Count);
if Result then
begin
- // Same number of snippets: scan list checking snippet names same. We can
+ // Same number of snippets: scan list checking snippet keys are same. We can
// rely on items being in same order since lists are sorted
for Idx := 0 to Pred(Self.Count) do
begin
diff --git a/Src/DBIO.UFileIOIntf.pas b/Src/DBIO.UFileIOIntf.pas
index f9c88923e..d032816b5 100644
--- a/Src/DBIO.UFileIOIntf.pas
+++ b/Src/DBIO.UFileIOIntf.pas
@@ -38,7 +38,7 @@ interface
@return True if database exists, False if not.
}
function GetAllCatIDs: IStringList;
- {Get names of all categories in database.
+ {Get ids of all categories in database.
@return List of category ids.
}
procedure GetCatProps(const CatID: string; var Props: TCategoryData);
@@ -48,30 +48,30 @@ interface
values of category properties by implementor.
}
function GetCatSnippets(const CatID: string): IStringList;
- {Get names of all snippets in a category.
+ {Get keys of all snippets in a category.
@param CatID [in] Id of category containing snippets.
- @return List of snippet names.
+ @return List of snippet IDs.
}
- procedure GetSnippetProps(const Snippet: string; var Props: TSnippetData);
+ procedure GetSnippetProps(const SnippetKey: string; var Props: TSnippetData);
{Get properties of a snippet. These are the fields of the snippet's
record in the snippets "table".
- @param Snippet [in] Name of snippet.
+ @param SnippetKey [in] Snippet's key.
@param Props [in/out] Empty properties passed in. Record fields set to
values of snippet's properties by implementor.
}
- function GetSnippetXRefs(const Snippet: string): IStringList;
+ function GetSnippetXRefs(const SnippetKey: string): IStringList;
{Get list of all snippets that are cross referenced by a snippet.
- @param Snippet [in] Name of snippet we need cross references for.
- @return List of snippet names.
+ @param SnippetKey [in] Keyof snippet we need cross references for.
+ @return List of snippet keys.
}
- function GetSnippetDepends(const Snippet: string): IStringList;
+ function GetSnippetDepends(const SnippetKey: string): IStringList;
{Get list of all snippet on which a given snippet depends.
- @param Snippet [in] Name of snippet.
- @return List of snippet names.
+ @param SnippetKey [in] Snippet's key.
+ @return List of snippet keys.
}
- function GetSnippetUnits(const Snippet: string): IStringList;
+ function GetSnippetUnits(const SnippetKey: string): IStringList;
{Get list of all units referenced by a snippet.
- @param Snippet [in] Name of snippet.
+ @param SnippetKey [in] Snippet's key.
@return List of unit names.
}
end;
@@ -100,33 +100,33 @@ interface
{Write the list of snippets belonging to a category. Always called after
WriteCatProps for any given category.
@param CatID [in] ID of category.
- @param SnipList [in] List of names of snippets.
+ @param SnipList [in] List of IDs of snippets.
}
- procedure WriteSnippetProps(const SnippetName: string;
+ procedure WriteSnippetProps(const SnippetKey: string;
const Props: TSnippetData);
{Write the properties of a snippet. Always called after all categories are
written and before WriteSnippetUnits, so can be used to perform any per-
snippet intialisation.
- @param SnippetName [in] Name of snippet.
+ @param SnippetKey [in] Snippet's key.
@param Props [in] Properties of snippet.
}
- procedure WriteSnippetUnits(const SnippetName: string;
+ procedure WriteSnippetUnits(const SnippetKey: string;
const Units: IStringList);
{Write the list of units required by a snippet.
- @param SnippetName [in] Name of snippet.
+ @param SnippetKey [in] Snippet's key.
@param Units [in] List of names of required units.
}
- procedure WriteSnippetDepends(const SnippetName: string;
+ procedure WriteSnippetDepends(const SnippetKey: string;
const Depends: IStringList);
{Write the list of snippets on which a snippet depends.
- @param SnippetName [in] Name of snippet.
- @param Depends [in] List of snippet names.
+ @param SnippetKey [in] Snippet's key.
+ @param Depends [in] List of snippet keys.
}
- procedure WriteSnippetXRefs(const SnippetName: string;
+ procedure WriteSnippetXRefs(const SnippetKey: string;
const XRefs: IStringList);
{Write the list of snippets that a snippet cross-references.
- @param SnippetName [in] Name of snippet.
- @param XRefs [in] List of snippet names.
+ @param SnippetKey [in] Snippet's key.
+ @param XRefs [in] List of snippet keys.
}
procedure Finalise;
{Finalises the database. Always called after all other methods.
diff --git a/Src/DBIO.UIniData.pas b/Src/DBIO.UIniData.pas
index 04ab602a8..d314f8a61 100644
--- a/Src/DBIO.UIniData.pas
+++ b/Src/DBIO.UIniData.pas
@@ -95,14 +95,14 @@ TIniFileCache = class(TObject)
///
/// Returns ID of category associated with a snippet.
///
- /// string [in] Name of snippet.
+ /// string [in] Snippet's key.
/// string containing category ID
- function SnippetToCat(const Snippet: string): string;
+ function SnippetToCat(const SnippetKey: string): string;
///
/// Returns name of ini file containing details of a category.
///
/// string [in] Id of category.
- /// string containing bame of category's ini file
+ /// string containing name of category's ini file
function CatToCatIni(const CatID: string): string;
///
/// Loads indices of all names of categories and snippets in database.
@@ -129,11 +129,11 @@ TIniFileCache = class(TObject)
/// Gets a list from ini file of all of items of a specified kind that are
/// referenced by a snippet.
///
- /// string [in] Name of snippet.
- /// string [in] Name of a key in ini file storing
+ /// string [in] Snippet's key.
+ /// string [in] Name of a key in ini file storing
/// comma separated list of references.
/// IStringList containing names of referenced items.
- function GetSnippetReferences(const Snippet, RefName: string): IStringList;
+ function GetSnippetReferences(const SnippetKey, KeyName: string): IStringList;
strict protected
///
/// Extracts comma delimited text fields into a string list.
@@ -173,37 +173,38 @@ TIniFileCache = class(TObject)
/// record and updates relevant property fields.
procedure GetCatProps(const CatID: string; var Props: TCategoryData);
///
- /// Gets names of all snippets in a category.
+ /// Gets keys of all snippets in a category.
///
/// string [in] Id of category.
- /// IStringList containing names of snippets.
+ /// IStringList containing keys of snippets.
function GetCatSnippets(const CatID: string): IStringList;
///
/// Gets properties of a snippet.
///
- /// string [in] Name of snippet.
+ /// string [in] Snippet's key.
/// TSnippetData [in/out] Receives empty property
/// record and updates relevant property fields.
- procedure GetSnippetProps(const Snippet: string; var Props: TSnippetData);
+ procedure GetSnippetProps(const SnippetKey: string;
+ var Props: TSnippetData);
///
/// Gets list of all snippets that are cross referenced by a specified
/// snippet.
///
- /// string [in] Name of snippet.
- /// IStringList containing snippet names.
- function GetSnippetXRefs(const Snippet: string): IStringList;
+ /// string [in] Snippet's key.
+ /// IStringList containing snippet keys.
+ function GetSnippetXRefs(const SnippetKey: string): IStringList;
///
/// Gets list of all snippets on which a specified snippet depends.
///
- /// string [in] Name of snippet.
- /// IStringList containing snippet names.
- function GetSnippetDepends(const Snippet: string): IStringList;
+ /// string [in] Snippet's key.
+ /// IStringList containing snippet keys.
+ function GetSnippetDepends(const SnippetKey: string): IStringList;
///
/// Gets list of all units referenced by a snippet.
///
- /// string [in] Name of snippet.
+ /// string [in] Snippet's key.
/// IStringList containing unit names.
- function GetSnippetUnits(const Snippet: string): IStringList;
+ function GetSnippetUnits(const SnippetKey: string): IStringList;
end;
/// Write a collection to disk in the DelphiDabbler Code Snippets
@@ -327,11 +328,11 @@ TUTF8IniFileCache = class(TObject)
/// Method of IDataWriter.
procedure WriteCatProps(const CatID: string; const Props: TCategoryData);
- /// Write the list of snippets belonging to a category. Always
+ /// Write the list of snippet keys belonging to a category. Always
/// called after WriteCatProps for any given category.
/// string [in] ID of category.
- /// IStringList [in] List of names of
- /// snippets.
+ /// IStringList [in] List of snippet keys.
+ ///
/// Method of IDataWriter.
procedure WriteCatSnippets(const CatID: string;
const SnipList: IStringList);
@@ -339,7 +340,7 @@ TUTF8IniFileCache = class(TObject)
/// Write the properties of a snippet. Always called after all
/// categories are written and before WriteSnippetUnits, so can be
/// used to perform any per-snippet intialisation.
- /// string [in] Name of snippet.
+ /// string [in] Snippet's key.
/// TSnippetData [in] Properties of snippet.
///
///
@@ -347,33 +348,33 @@ TUTF8IniFileCache = class(TObject)
/// collection format v2.1.x.
/// Method of IDataWriter.
///
- procedure WriteSnippetProps(const SnippetName: string;
+ procedure WriteSnippetProps(const SnippetKey: string;
const Props: TSnippetData);
/// Write the list of units required by a snippet.
- /// string [in] Name of snippet.
+ /// string [in] Snippet's key.
/// IStringList [in] List of names of required
/// units.
/// Method of IDataWriter.
- procedure WriteSnippetUnits(const SnippetName: string;
+ procedure WriteSnippetUnits(const SnippetKey: string;
const Units: IStringList);
/// Write the list of snippets on which a snippet depends.
///
- /// string [in] Name of snippet.
- /// IStringList [in] List of snippet names.
+ /// string [in] Snippet's key.
+ /// IStringList [in] List of snippet keys.
///
/// Method of IDataWriter.
- procedure WriteSnippetDepends(const SnippetName: string;
+ procedure WriteSnippetDepends(const SnippetKey: string;
const Depends: IStringList);
/// Write the list of snippets that a snippet cross-references.
///
- /// string [in] Name of snippet.
- /// IStringList [in] List of snippet names.
+ /// string [in] Snippet's keys.
+ /// IStringList [in] List of snippet keys.
///
/// Method of IDataWriter.
- procedure WriteSnippetXRefs(const SnippetName: string;
+ procedure WriteSnippetXRefs(const SnippetKey: string;
const XRefs: IStringList);
/// Finalises the output. Always called after all other methods.
@@ -401,7 +402,7 @@ implementation
UREMLDataIO,
USnippetExtraHelper,
USystemInfo,
- UStrUtils,
+ UStrUtils,
UUtils;
@@ -531,12 +532,13 @@ function TIniDataReader.GetCatSnippets(const CatID: string): IStringList;
end;
end;
-function TIniDataReader.GetSnippetDepends(const Snippet: string): IStringList;
+function TIniDataReader.GetSnippetDepends(const SnippetKey: string):
+ IStringList;
begin
- Result := GetSnippetReferences(Snippet, cDependsName);
+ Result := GetSnippetReferences(SnippetKey, cDependsName);
end;
-procedure TIniDataReader.GetSnippetProps(const Snippet: string;
+procedure TIniDataReader.GetSnippetProps(const SnippetKey: string;
var Props: TSnippetData);
var
CatIni: TCustomIniFile; // .ini file associated with snippet's category
@@ -546,7 +548,7 @@ procedure TIniDataReader.GetSnippetProps(const Snippet: string;
/// Reads "StandardFormat" value from ini file.
function GetStdFormatProperty: Boolean;
begin
- Result := CatIni.ReadBool(Snippet, cStdFormatName, True);
+ Result := CatIni.ReadBool(SnippetKey, cStdFormatName, True);
end;
/// Reads "Kind" value from ini file.
@@ -554,7 +556,7 @@ procedure TIniDataReader.GetSnippetProps(const Snippet: string;
var
KindStr: string; // string value read from ini file
begin
- KindStr := CatIni.ReadString(Snippet, cKindName, '');
+ KindStr := CatIni.ReadString(SnippetKey, cKindName, '');
if StrSameText(KindStr, 'freeform') then
Result := skFreeform
else if StrSameText(KindStr, 'routine') then
@@ -581,7 +583,7 @@ procedure TIniDataReader.GetSnippetProps(const Snippet: string;
Extra: string; // extra value from ini file if present
begin
try
- Extra := CatIni.ReadString(Snippet, cExtraName, '');
+ Extra := CatIni.ReadString(SnippetKey, cExtraName, '');
if Extra <> '' then
// There is an "extra" value: use it to set Extra property. We ignore
// any credits, credits url and comments values in this case
@@ -590,9 +592,9 @@ procedure TIniDataReader.GetSnippetProps(const Snippet: string;
// There is no "extra" value: use any comments, credits and credits URL
// values to set Extra property
Result := TSnippetExtraHelper.BuildActiveText(
- CatIni.ReadString(Snippet, cCommentsName, ''),
- CatIni.ReadString(Snippet, cCreditsName, ''),
- CatIni.ReadString(Snippet, cCreditsURLName, '')
+ CatIni.ReadString(SnippetKey, cCommentsName, ''),
+ CatIni.ReadString(SnippetKey, cCreditsName, ''),
+ CatIni.ReadString(SnippetKey, cCreditsURLName, '')
);
except
// There was an error: use an empty property value
@@ -606,7 +608,7 @@ procedure TIniDataReader.GetSnippetProps(const Snippet: string;
var
SnipFileName: string; // name of file containing source code
begin
- SnipFileName := CatIni.ReadString(Snippet, cSnipFileName, '');
+ SnipFileName := CatIni.ReadString(SnippetKey, cSnipFileName, '');
try
Result := fFileReader.ReadAllText(DataFile(SnipFileName));
except
@@ -627,7 +629,7 @@ procedure TIniDataReader.GetSnippetProps(const Snippet: string;
begin
for CompID := Low(TCompilerID) to High(TCompilerID) do
begin
- CompRes := CatIni.ReadString(Snippet, cCompilerIDNames[CompID], '?');
+ CompRes := CatIni.ReadString(SnippetKey, cCompilerIDNames[CompID], '?');
if CompRes = '' then
CompRes := '?';
case CompRes[1] of
@@ -648,12 +650,12 @@ procedure TIniDataReader.GetSnippetProps(const Snippet: string;
REML: string; // REML code from DescEx field
PlainText: string; // plain text from Desc field
begin
- REML := CatIni.ReadString(Snippet, cDescExName, '');
+ REML := CatIni.ReadString(SnippetKey, cDescExName, '');
if REML <> '' then
Result := TSnippetExtraHelper.BuildActiveText(REML)
else
begin
- PlainText := CatIni.ReadString(Snippet, cDescName, '');
+ PlainText := CatIni.ReadString(SnippetKey, cDescName, '');
if PlainText <> '' then
Result := TSnippetExtraHelper.PlainTextToActiveText(PlainText)
else
@@ -664,7 +666,7 @@ procedure TIniDataReader.GetSnippetProps(const Snippet: string;
/// Gets snippet's display name from ini file.
function GetDisplayNameProperty: string;
begin
- Result := CatIni.ReadString(Snippet, cDisplayName, '');
+ Result := CatIni.ReadString(SnippetKey, cDisplayName, '');
end;
/// Get's snippet's test info from ini file.
@@ -672,7 +674,7 @@ procedure TIniDataReader.GetSnippetProps(const Snippet: string;
var
Str: string; // string value read from ini file
begin
- Str := CatIni.ReadString(Snippet, cTestInfoName, 'basic');
+ Str := CatIni.ReadString(SnippetKey, cTestInfoName, 'basic');
if StrSameText(Str, 'basic') then
Result := stiBasic
else if StrSameText(Str, 'advanced') then
@@ -685,7 +687,7 @@ procedure TIniDataReader.GetSnippetProps(const Snippet: string;
begin
try
// Get name of category associated with this snippet
- CatID := SnippetToCat(Snippet);
+ CatID := SnippetToCat(SnippetKey);
// Get snippet properties from values listed under snippet's section in
// category's .ini file
CatIni := fIniCache.GetIniFile(CatToCatIni(CatID));
@@ -705,29 +707,29 @@ procedure TIniDataReader.GetSnippetProps(const Snippet: string;
end;
end;
-function TIniDataReader.GetSnippetReferences(const Snippet,
- RefName: string): IStringList;
+function TIniDataReader.GetSnippetReferences(const SnippetKey,
+ KeyName: string): IStringList;
var
CatIni: TCustomIniFile; // accesses snippet's category's .ini
begin
try
// References are contained in comma separated value in category's ini file
// under snippet's section
- CatIni := fIniCache.GetIniFile(CatToCatIni(SnippetToCat(Snippet)));
- Result := CommaStrToStrings(CatIni.ReadString(Snippet, RefName, ''));
+ CatIni := fIniCache.GetIniFile(CatToCatIni(SnippetToCat(SnippetKey)));
+ Result := CommaStrToStrings(CatIni.ReadString(SnippetKey, KeyName, ''));
except
HandleCorruptDatabase(ExceptObject);
end;
end;
-function TIniDataReader.GetSnippetUnits(const Snippet: string): IStringList;
+function TIniDataReader.GetSnippetUnits(const SnippetKey: string): IStringList;
begin
- Result := GetSnippetReferences(Snippet, cUnitsName);
+ Result := GetSnippetReferences(SnippetKey, cUnitsName);
end;
-function TIniDataReader.GetSnippetXRefs(const Snippet: string): IStringList;
+function TIniDataReader.GetSnippetXRefs(const SnippetKey: string): IStringList;
begin
- Result := GetSnippetReferences(Snippet, cXRefName);
+ Result := GetSnippetReferences(SnippetKey, cXRefName);
end;
procedure TIniDataReader.HandleCorruptDatabase(const EObj: TObject);
@@ -748,7 +750,7 @@ procedure TIniDataReader.HandleCorruptDatabase(const EObj: TObject);
procedure TIniDataReader.LoadIndices;
var
- SnippetName: string; // each snippet name in a category
+ SnippetKey: string; // key of each snippet in a category
CatIdx: Integer; // loops thru all categories
CatSnippets: IStringList; // list of snippets in a single category
begin
@@ -761,8 +763,8 @@ procedure TIniDataReader.LoadIndices;
begin
// Get list of snippets in category ...
CatSnippets := GetCatSnippets(fCatIDs[CatIdx]);
- for SnippetName in CatSnippets do
- fSnippetCatMap.Add(SnippetName, CatIdx);
+ for SnippetKey in CatSnippets do
+ fSnippetCatMap.Add(SnippetKey, CatIdx);
end;
end;
@@ -771,16 +773,16 @@ function TIniDataReader.MasterFileName: string;
Result := DataFile(cMasterFileName);
end;
-function TIniDataReader.SnippetToCat(const Snippet: string): string;
+function TIniDataReader.SnippetToCat(const SnippetKey: string): string;
var
CatIdx: Integer; // index of category in category list for this snippet
resourcestring
// Error message
- sMissingSnippet = 'Snippet "%s" not found in database.';
+ sMissingSnippet = 'Snippet key "%s" not found in database.';
begin
- if not fSnippetCatMap.ContainsKey(Snippet) then
- raise EDataIO.CreateFmt(sMissingSnippet, [Snippet]);
- CatIdx := fSnippetCatMap[Snippet];
+ if not fSnippetCatMap.ContainsKey(SnippetKey) then
+ raise EDataIO.CreateFmt(sMissingSnippet, [SnippetKey]);
+ CatIdx := fSnippetCatMap[SnippetKey];
Result := fCatIDs[CatIdx];
end;
@@ -906,15 +908,15 @@ procedure TIniDataWriter.WriteCatSnippets(const CatID: string;
// Do nothing
end;
-procedure TIniDataWriter.WriteSnippetDepends(const SnippetName: string;
+procedure TIniDataWriter.WriteSnippetDepends(const SnippetKey: string;
const Depends: IStringList);
begin
fCurrentCatIni.WriteString(
- SnippetName, cDependsName, Depends.GetText(',', False)
+ SnippetKey, cDependsName, Depends.GetText(',', False)
);
end;
-procedure TIniDataWriter.WriteSnippetProps(const SnippetName: string;
+procedure TIniDataWriter.WriteSnippetProps(const SnippetKey: string;
const Props: TSnippetData);
const
Kinds: array[TSnippetKind] of string = (
@@ -953,16 +955,16 @@ procedure TIniDataWriter.WriteSnippetProps(const SnippetName: string;
TFileIO.WriteAllText(SourceFilePath, Props.SourceCode, TEncoding.UTF8, True);
// snippet kind
- fCurrentCatIni.WriteString(SnippetName, cKindName, Kinds[Props.Kind]);
+ fCurrentCatIni.WriteString(SnippetKey, cKindName, Kinds[Props.Kind]);
// display name, if set
if (Props.DisplayName <> '') then
{TODO -cVault: strictly, for v2 format, this name must be <=64 chars}
- fCurrentCatIni.WriteString(SnippetName, cDisplayName, Props.DisplayName);
+ fCurrentCatIni.WriteString(SnippetKey, cDisplayName, Props.DisplayName);
// description (must be set for v2)
fCurrentCatIni.WriteString(
- SnippetName,
+ SnippetKey,
cDescExName,
DOUBLEQUOTE + ActiveTextToREML(Props.Desc) + DOUBLEQUOTE
);
@@ -970,13 +972,13 @@ procedure TIniDataWriter.WriteSnippetProps(const SnippetName: string;
// extra info, if set
if Props.Extra.HasContent then
fCurrentCatIni.WriteString(
- SnippetName,
+ SnippetKey,
cExtraName,
DOUBLEQUOTE + ActiveTextToREML(Props.Extra) + DOUBLEQUOTE
);
// snippet file reference
- fCurrentCatIni.WriteString(SnippetName, cSnipFileName, SourceFileName);
+ fCurrentCatIni.WriteString(SnippetKey, cSnipFileName, SourceFileName);
// compiler info
for CompilerID := Low(TCompilerID) to High(TCompilerID) do
@@ -984,14 +986,14 @@ procedure TIniDataWriter.WriteSnippetProps(const SnippetName: string;
CompileResult := CompileResults[Props.CompilerResults[CompilerID]];
if CompileResult <> 'Q' then
fCurrentCatIni.WriteString(
- SnippetName, cCompilerIDNames[CompilerID], CompileResult
+ SnippetKey, cCompilerIDNames[CompilerID], CompileResult
);
end;
// test info: only write if not basic
{TODO -cVault: Add support for AdvancedTest .Level & .URL}
if Props.TestInfo <> stiBasic then
- fCurrentCatIni.WriteString(SnippetName, cTestInfoName, TestInfo[Props.TestInfo]);
+ fCurrentCatIni.WriteString(SnippetKey, cTestInfoName, TestInfo[Props.TestInfo]);
except
@@ -1009,19 +1011,19 @@ procedure TIniDataWriter.WriteSnippetProps(const SnippetName: string;
end;
-procedure TIniDataWriter.WriteSnippetUnits(const SnippetName: string;
+procedure TIniDataWriter.WriteSnippetUnits(const SnippetKey: string;
const Units: IStringList);
begin
fCurrentCatIni.WriteString(
- SnippetName, cUnitsName, Units.GetText(',', False)
+ SnippetKey, cUnitsName, Units.GetText(',', False)
);
end;
-procedure TIniDataWriter.WriteSnippetXRefs(const SnippetName: string;
+procedure TIniDataWriter.WriteSnippetXRefs(const SnippetKey: string;
const XRefs: IStringList);
begin
fCurrentCatIni.WriteString(
- SnippetName, cXRefName, XRefs.GetText(',', False)
+ SnippetKey, cXRefName, XRefs.GetText(',', False)
);
end;
diff --git a/Src/DBIO.UNulDataReader.pas b/Src/DBIO.UNulDataReader.pas
index ab6e8ecf2..fff3aedf5 100644
--- a/Src/DBIO.UNulDataReader.pas
+++ b/Src/DBIO.UNulDataReader.pas
@@ -46,30 +46,31 @@ TNulDataReader = class(TInterfacedObject,
@param Props [in/out] Empty properties passed in. Unchanged.
}
function GetCatSnippets(const CatID: string): IStringList;
- {Gets names of all snippets in a category.
+ {Gets keys of all snippets in a category.
@param CatID [in] Id of category containing snippets.
- @return Empty list.
+ @return Empty snippet key list.
}
- procedure GetSnippetProps(const Snippet: string; var Props: TSnippetData);
+ procedure GetSnippetProps(const SnippetKey: string;
+ var Props: TSnippetData);
{Gets properties of a snippet. These are the fields of the snippet's
record in the snippets "table".
- @param Snippet [in] Name of required snippet.
+ @param SnippetKey [in] Keys of required snippet.
@param Props [in/out] Empty properties passed in. Unchanged.
}
- function GetSnippetXRefs(const Snippet: string): IStringList;
+ function GetSnippetXRefs(const SnippetKey: string): IStringList;
{Gets list of all snippets that are cross referenced by a snippet.
- @param Snippet [in] Name of snippet we need cross references for.
- @return Empty list.
+ @param SnippetKey [in] Key of snippet we need cross references for.
+ @return Empty snippet key list.
}
- function GetSnippetDepends(const Snippet: string): IStringList;
+ function GetSnippetDepends(const SnippetKey: string): IStringList;
{Gets list of all snippets on which a given snippet depends.
- @param Snippet [in] Name of required snippet.
- @return Empty list.
+ @param SnippetKey [in] Key of required snippet.
+ @return Empty snippet key list.
}
- function GetSnippetUnits(const Snippet: string): IStringList;
+ function GetSnippetUnits(const SnippetKey: string): IStringList;
{Gets list of all units referenced by a snippet.
- @param Snippet [in] Name of required snippet.
- @return Empty list.
+ @param SnippetKey [in] Key of required snippet.
+ @return Empty unit name list.
}
end;
@@ -107,47 +108,48 @@ procedure TNulDataReader.GetCatProps(const CatID: string;
end;
function TNulDataReader.GetCatSnippets(const CatID: string): IStringList;
- {Gets names of all snippets in a category.
+ {Gets keys of all snippets in a category.
@param CatID [in] Id of category containing snippets.
- @return Empty list.
+ @return Empty snippey key list.
}
begin
Result := TIStringList.Create;
end;
-function TNulDataReader.GetSnippetDepends(const Snippet: string): IStringList;
+function TNulDataReader.GetSnippetDepends(const SnippetKey: string):
+ IStringList;
{Gets list of all snippets on which a given snippet depends.
- @param Snippet [in] Name of required snippet.
- @return Empty list.
+ @param SnippetKey [in] Key of required snippet.
+ @return Empty snippet key list.
}
begin
Result := TIStringList.Create;
end;
-procedure TNulDataReader.GetSnippetProps(const Snippet: string;
+procedure TNulDataReader.GetSnippetProps(const SnippetKey: string;
var Props: TSnippetData);
{Gets properties of a snippet. These are the fields of the snippet's record in
the snippets "table".
- @param Snippet [in] Name of required snippet.
+ @param SnippetKey [in] Key of required snippet.
@param Props [in/out] Empty properties passed in. Unchanged.
}
begin
// Do nothing
end;
-function TNulDataReader.GetSnippetUnits(const Snippet: string): IStringList;
+function TNulDataReader.GetSnippetUnits(const SnippetKey: string): IStringList;
{Gets list of all units referenced by a snippet.
- @param Snippet [in] Name of required snippet.
- @return Empty list.
+ @param SnippetKey [in] Key of required snippet.
+ @return Empty unit name list.
}
begin
Result := TIStringList.Create;
end;
-function TNulDataReader.GetSnippetXRefs(const Snippet: string): IStringList;
+function TNulDataReader.GetSnippetXRefs(const SnippetKey: string): IStringList;
{Gets list of all snippets that are cross referenced by a snippet.
- @param Snippet [in] Name of snippet we need cross references for.
- @return Empty list.
+ @param SnippetKey [in] Key of snippet we need cross references for.
+ @return Empty snippet key list.
}
begin
Result := TIStringList.Create;
diff --git a/Src/DBIO.UXMLDataIO.pas b/Src/DBIO.UXMLDataIO.pas
index 0d1c0c0fc..eb0ec1db5 100644
--- a/Src/DBIO.UXMLDataIO.pas
+++ b/Src/DBIO.UXMLDataIO.pas
@@ -56,9 +56,9 @@ TXMLDataIO = class(TInterfacedObject)
@param CatID [in] Id of required category.
@return Required node or nil if node doesn't exist.
}
- function FindSnippetNode(const SnippetName: string): IXMLNode;
+ function FindSnippetNode(const SnippetKey: string): IXMLNode;
{Finds a specified snippet node for a snippet in the file.
- @param SnippetName [in] Name of required snippet.
+ @param SnippetKey [in] Key of required snippet.
@return Required node or nil if node doesn't exist.
}
public
@@ -94,11 +94,12 @@ TXMLDataReader = class(TXMLDataIO,
called.
@except Exception always raised.
}
- function GetSnippetReferences(const Snippet, RefName: string): IStringList;
+ function GetSnippetReferences(const SnippetKey, RefName: string):
+ IStringList;
{Get list of all specified references made by a snippet.
- @param Snippet [in] Name of required snippet.
+ @param SnippetKey [in] Key of required snippet.
@param RefName [in] Name of node containing snippet's references.
- @return List of names of references.
+ @return List of references.
}
public
constructor Create(const DBDir: string);
@@ -123,29 +124,30 @@ TXMLDataReader = class(TXMLDataIO,
values of category properties by implementor.
}
function GetCatSnippets(const CatID: string): IStringList;
- {Get names of all snippets in a category.
+ {Get keys of all snippets in a category.
@param CatID [in] Id of category containing snippets.
- @return List of snippet names.
+ @return List of snippet keys.
}
- procedure GetSnippetProps(const Snippet: string; var Props: TSnippetData);
+ procedure GetSnippetProps(const SnippetKey: string;
+ var Props: TSnippetData);
{Get properties of a snippet.
- @param Snippet [in] Name of required snippet.
+ @param SnippetKey [in] Key of required snippet.
@param Props [in/out] Empty properties passed in. Record fields set to
values of snippet properties.
}
- function GetSnippetXRefs(const Snippet: string): IStringList;
+ function GetSnippetXRefs(const SnippetKey: string): IStringList;
{Get list of all snippets that are cross referenced by a snippet.
- @param Snippet [in] Name of snippet we need cross references for.
- @return List of snippet names.
+ @param SnippetKey [in] Key of snippet we need cross references for.
+ @return List of snippet keys.
}
- function GetSnippetDepends(const Snippet: string): IStringList;
+ function GetSnippetDepends(const SnippetKey: string): IStringList;
{Get list of all snippets on which a given snippet depends.
- @param Snippet [in] Name of required snippet.
- @return List of snippet names.
+ @param SnippetKey [in] Key of required snippet.
+ @return List of snippet keys.
}
- function GetSnippetUnits(const Snippet: string): IStringList;
+ function GetSnippetUnits(const SnippetKey: string): IStringList;
{Get list of all units referenced by a snippet.
- @param Snippet [in] Name of required snippet.
+ @param SnippetKey [in] Key of required snippet.
@return List of unit names.
}
end;
@@ -170,10 +172,10 @@ TXMLDataWriter = class(TXMLDataIO,
@param ItemName [in] Name of each list item tag.
@param Items [in] List of names in list. One ItemName node per name.
}
- procedure WriteReferenceList(const SnippetName, ListName: string;
+ procedure WriteReferenceList(const SnippetKey, ListName: string;
const Items: IStringList);
{Writes a snippet's reference list to XML.
- @param SnippetName [in] Name of snippet whose reference list is to be
+ @param SnippetKey [in] Key of snippet whose reference list is to be
written.
@param ListName [in] Name of tag that encloses list entry.
@param Items [in] List of items in reference list.
@@ -198,36 +200,36 @@ TXMLDataWriter = class(TXMLDataIO,
}
procedure WriteCatSnippets(const CatID: string;
const SnipList: IStringList);
- {Write the list of snippets belonging to a category. Always called after
- WriteCatProps for any given category.
+ {Write the list of snippets keys belonging to a category. Always called
+ after WriteCatProps for any given category.
@param CatID [in] ID of category.
- @param SnipList [in] List of names of snippets.
+ @param SnipList [in] List of snippet keys.
}
- procedure WriteSnippetProps(const SnippetName: string;
+ procedure WriteSnippetProps(const SnippetKey: string;
const Props: TSnippetData);
{Write the properties of a snippet. Always called after all categories are
written and before WriteSnippetUnits, so can be used to perform any per-
snippet intialisation.
- @param SnippetName [in] Name of snippet.
+ @param SnippetKey [in] Snippet's key.
@param Props [in] Properties of snippet.
}
- procedure WriteSnippetUnits(const SnippetName: string;
+ procedure WriteSnippetUnits(const SnippetKey: string;
const Units: IStringList);
{Write the list of units required by a snippet.
- @param SnippetName [in] Name of snippet.
+ @param SnippetKey [in] Snippet's key.
@param Units [in] List of names of required units.
}
- procedure WriteSnippetDepends(const SnippetName: string;
+ procedure WriteSnippetDepends(const SnippetKey: string;
const Depends: IStringList);
{Write the list of snippets on which a snippet depends.
- @param SnippetName [in] Name of snippet.
- @param Depends [in] List of snippet names.
+ @param SnippetKey [in] Snippet's key.
+ @param Depends [in] List of snippet keys.
}
- procedure WriteSnippetXRefs(const SnippetName: string;
+ procedure WriteSnippetXRefs(const SnippetKey: string;
const XRefs: IStringList);
{Write the list of snippets that a snippet cross-references.
- @param SnippetName [in] Name of snippet.
- @param XRefs [in] List of cross references snippets.
+ @param SnippetKey [in] Snippet's key.
+ @param XRefs [in] List of snippet keys.
}
procedure Finalise;
{Finalises the database. Always called after all other methods.
@@ -345,9 +347,9 @@ function TXMLDataIO.FindCategoryNode(const CatID: string): IXMLNode;
)
end;
-function TXMLDataIO.FindSnippetNode(const SnippetName: string): IXMLNode;
+function TXMLDataIO.FindSnippetNode(const SnippetKey: string): IXMLNode;
{Finds a specified snippet node for a snippet in the file.
- @param SnippetName [in] Name of required snippet.
+ @param SnippetKey [in] Key of required snippet.
@return Required node or nil if node doesn't exist.
}
var
@@ -360,7 +362,7 @@ function TXMLDataIO.FindSnippetNode(const SnippetName: string): IXMLNode;
Error(sMissingNode, [cSnippetsNode]);
// Find required snippet node
Result := fXMLDoc.FindFirstChildNode(
- SnippetListNode, cSnippetNode, cSnippetNameAttr, SnippetName
+ SnippetListNode, cSnippetNode, cSnippetNameAttr, SnippetKey
);
end;
@@ -379,7 +381,7 @@ function TXMLDataIO.PathToXMLFile: string;
// Error messages
sNoCategoriesNode = 'No categories node in XML file';
sCatNotFound = 'Can''t find reference to category "%s" in XML file';
- sSnippetNotFound = 'Can''t find reference to snippet "%s" in XML file';
+ sSnippetNotFound = 'Can''t find reference to snippet key "%s" in XML file';
sMissingSource = 'Source code file name missing for snippet "%s"';
sDBError = 'The database is corrupt and had been deleted.' + EOL2 + '%s';
@@ -472,9 +474,9 @@ procedure TXMLDataReader.GetCatProps(const CatID: string;
end;
function TXMLDataReader.GetCatSnippets(const CatID: string): IStringList;
- {Get names of all snippets in a category.
+ {Get keys of all snippets in a category.
@param CatID [in] Id of category containing snippets.
- @return List of snippet names.
+ @return List of snippet keys.
}
var
CatNode: IXMLNode; // reference to required category node
@@ -494,19 +496,20 @@ function TXMLDataReader.GetCatSnippets(const CatID: string): IStringList;
end;
end;
-function TXMLDataReader.GetSnippetDepends(const Snippet: string): IStringList;
+function TXMLDataReader.GetSnippetDepends(const SnippetKey: string):
+ IStringList;
{Get list of all snippets on which a given snippet depends.
- @param Snippet [in] Name of required snippet.
- @return List of snippet names.
+ @param SnippetKey [in] Key of required snippet.
+ @return List of snippet keys.
}
begin
- Result := GetSnippetReferences(Snippet, cDependsNode);
+ Result := GetSnippetReferences(SnippetKey, cDependsNode);
end;
-procedure TXMLDataReader.GetSnippetProps(const Snippet: string;
+procedure TXMLDataReader.GetSnippetProps(const SnippetKey: string;
var Props: TSnippetData);
{Get properties of a snippet.
- @param Snippet [in] Name of required snippet.
+ @param SnippetKey [in] Key of required snippet.
@param Props [in/out] Empty properties passed in. Record fields set to
values of snippet's properties.
}
@@ -532,7 +535,7 @@ procedure TXMLDataReader.GetSnippetProps(const Snippet: string;
begin
DataFileName := GetPropertyText(cSourceCodeFileNode);
if DataFileName = '' then
- Error(sMissingSource, [Snippet]);
+ Error(sMissingSource, [SnippetKey]);
try
// load the file: before file v5 files used default encoding, from v5
// UTF-8 with no BOM was used
@@ -628,9 +631,9 @@ procedure TXMLDataReader.GetSnippetProps(const Snippet: string;
begin
try
// Find snippet node
- SnippetNode := FindSnippetNode(Snippet);
+ SnippetNode := FindSnippetNode(SnippetKey);
if not Assigned(SnippetNode) then
- Error(sSnippetNotFound, [Snippet]);
+ Error(sSnippetNotFound, [SnippetKey]);
// Snippet found: read properties
Props.Cat := GetPropertyText(cCatIdNode);
Props.DisplayName := GetPropertyText(cDisplayNameNode);
@@ -649,21 +652,21 @@ procedure TXMLDataReader.GetSnippetProps(const Snippet: string;
end;
end;
-function TXMLDataReader.GetSnippetReferences(const Snippet,
- RefName: string): IStringList;
+function TXMLDataReader.GetSnippetReferences(const SnippetKey, RefName: string):
+ IStringList;
{Get list of all specified references made by a snippet.
- @param Snippet [in] Name of required snippet.
+ @param SnippetKey [in] Key of required snippet.
@param RefName [in] Name of node containing snippet's references.
- @return List of names of references.
+ @return List of references.
}
var
SnippetNode: IXMLNode; // node for required snippet
begin
try
Result := TIStringList.Create;
- SnippetNode := FindSnippetNode(Snippet);
+ SnippetNode := FindSnippetNode(SnippetKey);
if not Assigned(SnippetNode) then
- Error(sSnippetNotFound, [Snippet]);
+ Error(sSnippetNotFound, [SnippetKey]);
// References are contained in a list of contained nodes
TXMLDocHelper.GetPascalNameList(
fXMLDoc, fXMLDoc.FindFirstChildNode(SnippetNode, RefName), Result
@@ -673,22 +676,22 @@ function TXMLDataReader.GetSnippetReferences(const Snippet,
end;
end;
-function TXMLDataReader.GetSnippetUnits(const Snippet: string): IStringList;
+function TXMLDataReader.GetSnippetUnits(const SnippetKey: string): IStringList;
{Get list of all units referenced by a snippet.
- @param Snippet [in] Name of required snippet.
- @return List of unit names.
+ @param SnippetKey [in] Key of required snippet.
+ @return List of unit keys.
}
begin
- Result := GetSnippetReferences(Snippet, cUnitsNode);
+ Result := GetSnippetReferences(SnippetKey, cUnitsNode);
end;
-function TXMLDataReader.GetSnippetXRefs(const Snippet: string): IStringList;
+function TXMLDataReader.GetSnippetXRefs(const SnippetKey: string): IStringList;
{Get list of all snippets that are cross referenced by a snippet.
- @param Snippet [in] Name of snippet we need cross references for.
- @return List of snippet names.
+ @param SnippetKey [in] Key of snippet we need cross references for.
+ @return List of snippet keys.
}
begin
- Result := GetSnippetReferences(Snippet, cXRefNode);
+ Result := GetSnippetReferences(SnippetKey, cXRefNode);
end;
procedure TXMLDataReader.HandleCorruptDatabase(const EObj: TObject);
@@ -835,7 +838,7 @@ procedure TXMLDataWriter.WriteCatSnippets(const CatID: string;
{Write the list of snippets belonging to a category. Always called after
WriteCatProps for any given category.
@param CatID [in] ID of category.
- @param SnipList [in] List of names of snippets.
+ @param SnipList [in] List of snippet keyss.
}
var
CatNode: IXMLNode; // reference to required category node
@@ -872,10 +875,10 @@ procedure TXMLDataWriter.WriteNameList(const Parent: IXMLNode; const ListName,
fXMLDoc.CreateElement(ListNode, ItemName, Item);
end;
-procedure TXMLDataWriter.WriteReferenceList(const SnippetName, ListName: string;
+procedure TXMLDataWriter.WriteReferenceList(const SnippetKey, ListName: string;
const Items: IStringList);
{Writes a snippet's reference list to XML.
- @param SnippetName [in] Name of snippet whose reference list is to be
+ @param SnippetKey [in] Key of snippet whose reference list is to be
written.
@param ListName [in] Name of tag that encloses list entry.
@param Items [in] List of items in reference list.
@@ -888,7 +891,7 @@ procedure TXMLDataWriter.WriteReferenceList(const SnippetName, ListName: string;
if Items.Count = 0 then
Exit;
// Find snippet node
- SnippetNode := FindSnippetNode(SnippetName);
+ SnippetNode := FindSnippetNode(SnippetKey);
Assert(Assigned(SnippetNode),
ClassName + '.WriteReferenceList: Can''t find snippet node');
// Write the list
@@ -900,22 +903,22 @@ procedure TXMLDataWriter.WriteReferenceList(const SnippetName, ListName: string;
end;
end;
-procedure TXMLDataWriter.WriteSnippetDepends(const SnippetName: string;
+procedure TXMLDataWriter.WriteSnippetDepends(const SnippetKey: string;
const Depends: IStringList);
{Write the list of snippets on which a snippet depends.
- @param SnippetName [in] Name of snippet.
- @param Depends [in] List of snippet names.
+ @param SnippetKey [in] Snippet's key.
+ @param Depends [in] List of snippet keys.
}
begin
- WriteReferenceList(SnippetName, cDependsNode, Depends);
+ WriteReferenceList(SnippetKey, cDependsNode, Depends);
end;
-procedure TXMLDataWriter.WriteSnippetProps(const SnippetName: string;
+procedure TXMLDataWriter.WriteSnippetProps(const SnippetKey: string;
const Props: TSnippetData);
{Write the properties of a snippet. Always called after all categories are
written and before WriteSnippetsUnits, so can be used to perform any per-
snippet intialisation.
- @param SnippetName [in] Name of snippet.
+ @param SnippetKey [in] Snippet's key.
@param Props [in] Properties of snippet.
}
var
@@ -928,7 +931,7 @@ procedure TXMLDataWriter.WriteSnippetProps(const SnippetName: string;
try
// Create snippet node
SnippetNode := fXMLDoc.CreateElement(fSnippetsNode, cSnippetNode);
- SnippetNode.Attributes[cSnippetNameAttr] := SnippetName;
+ SnippetNode.Attributes[cSnippetNameAttr] := SnippetKey;
// Add properties
fXMLDoc.CreateElement(SnippetNode, cCatIdNode, Props.Cat);
// description node is written even if empty (which it shouldn't be)
@@ -968,24 +971,24 @@ procedure TXMLDataWriter.WriteSnippetProps(const SnippetName: string;
end;
end;
-procedure TXMLDataWriter.WriteSnippetUnits(const SnippetName: string;
+procedure TXMLDataWriter.WriteSnippetUnits(const SnippetKey: string;
const Units: IStringList);
{Write the list of units required by a snippet.
- @param SnippetName [in] Name of snippet.
+ @param SnippetKey [in] Snippet's key.
@param Units [in] List of names of required units.
}
begin
- WriteReferenceList(SnippetName, cUnitsNode, Units);
+ WriteReferenceList(SnippetKey, cUnitsNode, Units);
end;
-procedure TXMLDataWriter.WriteSnippetXRefs(const SnippetName: string;
+procedure TXMLDataWriter.WriteSnippetXRefs(const SnippetKey: string;
const XRefs: IStringList);
{Write the list of snippets that a snippet cross-references.
- @param SnippetName [in] Name of snippet.
+ @param SnippetKey [in] Snippet's key.
@param XRefs [in] List of cross references snippets.
}
begin
- WriteReferenceList(SnippetName, cXRefNode, XRefs);
+ WriteReferenceList(SnippetKey, cXRefNode, XRefs);
end;
end.
diff --git a/Src/ExternalObj.ridl b/Src/ExternalObj.ridl
index 47a60868b..22c549d50 100644
--- a/Src/ExternalObj.ridl
+++ b/Src/ExternalObj.ridl
@@ -45,13 +45,13 @@ library ExternalObj
HRESULT _stdcall UpdateDbase(void);
/*
- * Display named snippet.
- * @param SnippetName [in] Name of snippet to display.
+ * Display snippet identified by key and collection ID.
+ * @param Key [in] Snippet's key.
* @param CollectionIDAsHex [in] Hex representation of snippet's
* collection ID.
*/
[id(0x00000080)]
- HRESULT _stdcall DisplaySnippet([in] BSTR SnippetName,
+ HRESULT _stdcall DisplaySnippet([in] BSTR Key,
[in] BSTR CollectionIDAsHex, [in] VARIANT_BOOL NewTab);
/*
@@ -61,11 +61,11 @@ library ExternalObj
HRESULT _stdcall ConfigCompilers(void);
/*
- * Edits the named snippet.
- * @param SnippetName [in] Name of snippet to edit. Must be user defined.
+ * Edits the snippet identified by its key.
+ * @param Key [in] Key of snippet to edit. Must be user defined.
*/
[id(0x0000006C)]
- HRESULT _stdcall EditSnippet([in] BSTR SnippetName);
+ HRESULT _stdcall EditSnippet([in] BSTR Key);
/*
* Display identified category.
diff --git a/Src/IntfNotifier.pas b/Src/IntfNotifier.pas
index 40141c9bd..5269ef3a2 100644
--- a/Src/IntfNotifier.pas
+++ b/Src/IntfNotifier.pas
@@ -34,13 +34,13 @@ interface
procedure UpdateDbase;
/// Displays a snippet.
- /// WideString [in] Name of required snippet.
+ /// WideString [in] Required snippet's key.
///
/// TCollectionID [in] ID of the snippet's
/// collection.
/// WordBool [in] Whether to display snippet in a new
/// detail pane tab.
- procedure DisplaySnippet(const SnippetName: WideString;
+ procedure DisplaySnippet(const Key: WideString;
ACollectionID: TCollectionID; NewTab: WordBool);
/// Displays a category.
@@ -68,9 +68,11 @@ interface
procedure ChangeDetailPane(const Pane: Integer);
/// Edits a snippet in Snippets Editor.
- /// WideString [in] Name of snippet.
+ /// WideString [in] Snippet's key.
/// Snippet must be user defined.
- procedure EditSnippet(const SnippetName: WideString);
+ procedure EditSnippet(const Key: WideString);
+ {TODO -cVault: lift restriction on being user-defined. Provide 2nd param
+ containing snippet's collection ID?}
/// Opens Snippets Editor ready to create a new snippet.
procedure NewSnippet;
diff --git a/Src/UNotifier.pas b/Src/UNotifier.pas
index 310c570e2..34df201cf 100644
--- a/Src/UNotifier.pas
+++ b/Src/UNotifier.pas
@@ -74,13 +74,13 @@ TNotifier = class(TInterfacedObject, INotifier, ISetActions)
procedure UpdateDbase;
/// Displays a snippet.
- /// WideString [in] Name of required snippet.
+ /// WideString [in] Required snippet's key.
///
/// TCollectionID [in] ID of the snippet's
/// collection.
/// WordBool [in] Whether to display snippet in a new
/// detail pane tab.
- procedure DisplaySnippet(const SnippetName: WideString;
+ procedure DisplaySnippet(const Key: WideString;
ACollectionID: TCollectionID; NewTab: WordBool);
/// Displays a category.
@@ -115,12 +115,12 @@ TNotifier = class(TInterfacedObject, INotifier, ISetActions)
procedure ChangeDetailPane(const Pane: Integer);
/// Edits a snippet in Snippets Editor.
- /// WideString [in] Name of snippet.
+ /// WideString [in] Snippet's key.
///
/// Snippet must be user defined.
/// Methods of INotifier.
///
- procedure EditSnippet(const SnippetName: WideString);
+ procedure EditSnippet(const Key: WideString);
/// Opens Snippets Editor ready to create a new snippet.
/// Methods of INotifier.
@@ -254,23 +254,23 @@ procedure TNotifier.DisplayCategory(const CatID: WideString; NewTab: WordBool);
end;
end;
-procedure TNotifier.DisplaySnippet(const SnippetName: WideString;
+procedure TNotifier.DisplaySnippet(const Key: WideString;
ACollectionID: TCollectionID; NewTab: WordBool);
begin
if Assigned(fDisplaySnippetAction) then
begin
- (fDisplaySnippetAction as TSnippetAction).SnippetName := SnippetName;
+ (fDisplaySnippetAction as TSnippetAction).SnippetName := Key;
(fDisplaySnippetAction as TSnippetAction).CollectionID := ACollectionID;
(fDisplaySnippetAction as TSnippetAction).NewTab := NewTab;
fDisplaySnippetAction.Execute;
end;
end;
-procedure TNotifier.EditSnippet(const SnippetName: WideString);
+procedure TNotifier.EditSnippet(const Key: WideString);
begin
if Assigned(fEditSnippetAction) then
begin
- (fEditSnippetAction as TEditSnippetAction).SnippetName := SnippetName;
+ (fEditSnippetAction as TEditSnippetAction).SnippetName := Key;
fEditSnippetAction.Execute;
end;
end;
diff --git a/Src/USnippetValidator.pas b/Src/USnippetValidator.pas
index 1e8988921..d02e4e956 100644
--- a/Src/USnippetValidator.pas
+++ b/Src/USnippetValidator.pas
@@ -39,10 +39,10 @@ TSnippetValidator = class(TNoConstructObject)
returned.
@return True if dependency list is valid or False if not.
}
- class function ValidateDependsList(const SnippetName: string;
+ class function ValidateDependsList(const SnippetKey: string;
const Data: TSnippetEditData; out ErrorMsg: string): Boolean; overload;
{Recursively checks dependency list of a snippet for validity.
- @param SnippetName [in] Name of snippet for which dependencies are to be
+ @param SnippetKey [in] Key of snippet for which dependencies are to be
checked.
@param Data [in] Data describing properties and references of snippet
for which dependencies are to be checked.
@@ -68,36 +68,36 @@ TSnippetValidator = class(TNoConstructObject)
@param ErrorSel [out] Selection that can be used to highlight error.
@return True if description is valid or False if not.
}
- class function ValidateName(const Name: string;
+ class function ValidateName(const Key: string;
const CheckForUniqueness: Boolean): Boolean; overload;
- {Validates a snippet's name.
- @param Name [in] Snippet name to be checked.
+ {Validates a snippet's key.
+ @param Key [in] Snippet key to be checked.
@param CheckForUniqueness [in] Flag indicating whether a check should
- be made to see if snippet name is already in user database.
- @return True if name is valid or False if not.
+ be made to see if snippet key is already in user database.
+ @return True if key is valid or False if not.
}
- class function ValidateName(const Name: string;
+ class function ValidateName(const Key: string;
const CheckForUniqueness: Boolean; out ErrorMsg: string): Boolean;
overload;
- {Validates a snippet's name.
- @param Name [in] Snippet name to be checked.
+ {Validates a snippet's key.
+ @param Key [in] Snippet key to be checked.
@param CheckForUniqueness [in] Flag indicating whether a check should
- be made to see if snippet name is already in user database.
+ be made to see if snippet key is already in user database.
@param ErrorMsg [out] Message that describes error. Undefined if True
returned.
- @return True if name is valid or False if not.
+ @return True if key is valid or False if not.
}
- class function ValidateName(const Name: string;
+ class function ValidateName(const Key: string;
const CheckForUniqueness: Boolean; out ErrorMsg: string;
out ErrorSel: TSelection): Boolean; overload;
- {Validates a snippet's name.
- @param Name [in] Snippet name to be checked.
+ {Validates a snippet's key.
+ @param Key [in] Snippet key to be checked.
@param CheckForUniqueness [in] Flag indicating whether a check should
- be made to see if snippet name is already in user database.
+ be made to see if snippet key is already in user database.
@param ErrorMsg [out] Message that describes error. Undefined if True
returned.
@param ErrorSel [out] Selection that can be used to highlight error.
- @return True if name is valid or False if not.
+ @return True if key is valid or False if not.
}
class function ValidateExtra(const Extra: IActiveText;
out ErrorMsg: string): Boolean;
@@ -275,10 +275,10 @@ class function TSnippetValidator.ValidateDependsList(const Snippet: TSnippet;
);
end;
-class function TSnippetValidator.ValidateDependsList(const SnippetName: string;
+class function TSnippetValidator.ValidateDependsList(const SnippetKey: string;
const Data: TSnippetEditData; out ErrorMsg: string): Boolean;
{Recursively checks dependency list of a snippet for validity.
- @param SnippetName [in] Name of snippet for which dependencies are to be
+ @param SnippetKey [in] Key of snippet for which dependencies are to be
checked.
@param Data [in] Data describing properties and references of snippet for
which dependencies are to be checked.
@@ -290,7 +290,7 @@ class function TSnippetValidator.ValidateDependsList(const SnippetName: string;
TempSnippet: TSnippet; // temporary snippet that is checked for dependencies
begin
TempSnippet := (Database as IDatabaseEdit).CreateTempSnippet(
- SnippetName, Data
+ SnippetKey, Data
);
try
Result := ValidateDependsList(TempSnippet, ErrorMsg);
@@ -348,67 +348,67 @@ class function TSnippetValidator.ValidateExtra(const Extra: IActiveText;
ErrorMsg := ErrorInfo.Description;
end;
-class function TSnippetValidator.ValidateName(const Name: string;
+class function TSnippetValidator.ValidateName(const Key: string;
const CheckForUniqueness: Boolean; out ErrorMsg: string): Boolean;
- {Validates a snippet's name.
- @param Name [in] Snippet name to be checked.
+ {Validates a snippet's key.
+ @param Key [in] Snippet key to be checked.
@param CheckForUniqueness [in] Flag indicating whether a check should be
- made to see if snippet name is already in user database.
+ made to see if snippet key is already in user database.
@param ErrorMsg [out] Message that describes error. Undefined if True
returned.
- @return True if name is valid or False if not.
+ @return True if key is valid or False if not.
}
resourcestring
// Error messages
- sErrNoName = 'A name must be provided';
- sErrDupName = '"%s" is already in the database. Please choose another name';
- sErrBadName = '"%s" is not a valid Pascal identifier';
+ sErrNoKey = 'A key must be provided';
+ sErrDupKey = 'Key "%s" is already in the database. Please choose another key';
+ sErrBadKey = '"%s" is not a valid Pascal identifier';
var
- TrimmedName: string; // Name param trimmed of leading trailing spaces
+ TrimmedKey: string; // Key param trimmed of leading trailing spaces
begin
Result := False;
- TrimmedName := StrTrim(Name);
- if TrimmedName = '' then
- ErrorMsg := sErrNoName
- else if not IsValidIdent(TrimmedName) then
- ErrorMsg := Format(sErrBadName, [TrimmedName])
+ TrimmedKey := StrTrim(Key);
+ if TrimmedKey = '' then
+ ErrorMsg := sErrNoKey
+ else if not IsValidIdent(TrimmedKey) then
+ ErrorMsg := Format(sErrBadKey, [TrimmedKey])
else if CheckForUniqueness and
- (Database.Snippets.Find(TrimmedName, TCollectionID.__TMP__UserDBCollectionID) <> nil) then
- ErrorMsg := Format(sErrDupName, [TrimmedName])
+ (Database.Snippets.Find(TrimmedKey, TCollectionID.__TMP__UserDBCollectionID) <> nil) then
+ ErrorMsg := Format(sErrDupKey, [TrimmedKey])
else
Result := True;
end;
-class function TSnippetValidator.ValidateName(const Name: string;
+class function TSnippetValidator.ValidateName(const Key: string;
const CheckForUniqueness: Boolean; out ErrorMsg: string;
out ErrorSel: TSelection): Boolean;
- {Validates a snippet's name.
- @param Name [in] Snippet name to be checked.
+ {Validates a snippet's key.
+ @param Key [in] Snippet key to be checked.
@param CheckForUniqueness [in] Flag indicating whether a check should be
- made to see if snippet name is already in user database.
+ made to see if snippet key is already in user database.
@param ErrorMsg [out] Message that describes error. Undefined if True
returned.
@param ErrorSel [out] Selection that can be used to highlight error.
- @return True if name is valid or False if not.
+ @return True if key is valid or False if not.
}
begin
- Result := ValidateName(Name, CheckForUniqueness, ErrorMsg);
+ Result := ValidateName(Key, CheckForUniqueness, ErrorMsg);
if not Result then
- ErrorSel := TSelection.Create(0, Length(Name));
+ ErrorSel := TSelection.Create(0, Length(Key));
end;
-class function TSnippetValidator.ValidateName(const Name: string;
+class function TSnippetValidator.ValidateName(const Key: string;
const CheckForUniqueness: Boolean): Boolean;
- {Validates a snippet's name.
- @param Name [in] Snippet name to be checked.
+ {Validates a snippet's key.
+ @param Key [in] Snippet key to be checked.
@param CheckForUniqueness [in] Flag indicating whether a check should be
- made to see if snippet name is already in user database.
- @return True if name is valid or False if not.
+ made to see if snippet key is already in user database.
+ @return True if key is valid or False if not.
}
var
DummyErrMsg: string;
begin
- Result := ValidateName(Name, CheckForUniqueness, DummyErrMsg);
+ Result := ValidateName(Key, CheckForUniqueness, DummyErrMsg);
end;
class function TSnippetValidator.ValidateSourceCode(const Source: string;
diff --git a/Src/UUserDBMgr.pas b/Src/UUserDBMgr.pas
index 04f11cbb2..04b8d51b4 100644
--- a/Src/UUserDBMgr.pas
+++ b/Src/UUserDBMgr.pas
@@ -53,10 +53,10 @@ TUserDBMgr = class(TNoConstructObject)
/// Enables user to adds a new user defined snippet to the
/// database using the snippets editor.
class procedure AddSnippet;
- /// Enables user to edit the snippet with the given name using the
+ /// Enables user to edit the snippet with the given key using the
/// snippets editor.
- /// The named snippet must be user defined.
- class procedure EditSnippet(const SnippetName: string);
+ /// The snippet must be user defined.
+ class procedure EditSnippet(const SnippetKey: string);
/// Duplicates the snippet specified by the given view as a user
/// defined snippet with name specified by user.
class procedure DuplicateSnippet(ViewItem: IView);
@@ -392,7 +392,9 @@ class function TUserDBMgr.DeleteDatabase: Boolean;
class procedure TUserDBMgr.DeleteSnippet(ViewItem: IView);
- // Builds a list of snippet names from a given snippet ID list.
+ {TODO -cVault: rename following inner method to SnippetDisplayNames for
+ clarity}
+ // Builds a list of snippet display names from a given snippet ID list.
function SnippetNames(const IDList: ISnippetIDList): IStringList;
var
ID: TSnippetID; // loops through all IDs in list
@@ -461,11 +463,13 @@ class procedure TUserDBMgr.DuplicateSnippet(ViewItem: IView);
TDuplicateSnippetDlg.Execute(nil, (ViewItem as ISnippetView).Snippet);
end;
-class procedure TUserDBMgr.EditSnippet(const SnippetName: string);
+class procedure TUserDBMgr.EditSnippet(const SnippetKey: string);
+ {TODO -cVault: lift restriction on being user defined. Change to take a
+ collection ID as 2nd param?}
var
Snippet: TSnippet; // reference to snippet to be edited
begin
- Snippet := Database.Snippets.Find(SnippetName, TCollectionID.__TMP__UserDBCollectionID);
+ Snippet := Database.Snippets.Find(SnippetKey, TCollectionID.__TMP__UserDBCollectionID);
if not Assigned(Snippet) then
raise EBug.Create(ClassName + '.EditSnippet: Snippet not in user database');
TSnippetsEditorDlg.EditSnippet(nil, Snippet);
diff --git a/Src/UWBExternal.pas b/Src/UWBExternal.pas
index 5e0b5ba08..a8f82be92 100644
--- a/Src/UWBExternal.pas
+++ b/Src/UWBExternal.pas
@@ -57,30 +57,27 @@ TWBExternal = class(TAutoIntfObject, IWBExternal15, ISetNotifier)
/// Method of IWBExternal15.
procedure UpdateDbase; safecall;
- /// Displays the Configure Compilers dialogue box.
- /// Displays a named snippet.
- /// WideString [in] Name of snippet to be
- /// displayed.
- /// WideString [in] Hex string
- /// representation of the ID of the collection to which the snippet
- /// belongs.
+ /// Display snippet identified by key and collection ID.
+ /// WideString [in] Snippet's key.
+ /// WideString [in] Hex representation of
+ /// snippet's collection ID.
/// WordBool [in] Whether to display snippet in a new
/// tab.
/// Method of IWBExternal15.
- procedure DisplaySnippet(const SnippetName: WideString;
+ procedure DisplaySnippet(const Key: WideString;
const CollectionIDAsHex: WideString; NewTab: WordBool); safecall;
+ /// Displays the Configure Compilers dialogue box.
/// Method of IWBExternal15.
procedure ConfigCompilers; safecall;
- /// Edits a named snippet.
- /// WideString [in] Name of snippet to be edited.
- ///
+ /// Edits the snippet identified by its key.
+ /// WideString [in] Key of snippet to edit.
///
- /// The named snippet must be user defined.
+ /// The snippet must be user defined.
/// Method of IWBExternal15.
///
- procedure EditSnippet(const SnippetName: WideString); safecall;
+ procedure EditSnippet(const Key: WideString); safecall;
/// Displays a named category.
/// WideString [in] ID of category to be displayed.
@@ -158,26 +155,26 @@ procedure TWBExternal.DisplayCategory(const CatID: WideString;
end;
end;
-procedure TWBExternal.DisplaySnippet(const SnippetName,
- CollectionIDAsHex: WideString; NewTab: WordBool);
+procedure TWBExternal.DisplaySnippet(const Key, CollectionIDAsHex: WideString;
+ NewTab: WordBool);
begin
try
if Assigned(fNotifier) then
fNotifier.DisplaySnippet(
- SnippetName,
- TCollectionID.CreateFromHexString(CollectionIDAsHex),
- NewTab
+ Key, TCollectionID.CreateFromHexString(CollectionIDAsHex), NewTab
);
except
HandleException;
end;
end;
-procedure TWBExternal.EditSnippet(const SnippetName: WideString);
+procedure TWBExternal.EditSnippet(const Key: WideString);
+ {TODO -cVault: change to take a collection ID as hex string as 2nd param &
+ lift restriction on having to be user defined.}
begin
try
if Assigned(fNotifier) then
- fNotifier.EditSnippet(SnippetName);
+ fNotifier.EditSnippet(Key);
except
HandleException;
end;
From 0272cab93c517a127fe9ee8a1f80eedb846eac17 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Thu, 7 Nov 2024 13:37:03 +0000
Subject: [PATCH 045/222] Rewrite TUniqueID & add new GenerateAlpha method
TUniqueID was completely rewritten as an advanced record instead of a
TNoConstructObject class.
The existing Generate method was totally rewritten and code shared
between it and the new GenerateAlpha method was extract into a private
method.
---
Src/UUniqueID.pas | 93 +++++++++++++++++++++++++++++++----------------
1 file changed, 62 insertions(+), 31 deletions(-)
diff --git a/Src/UUniqueID.pas b/Src/UUniqueID.pas
index cf18f058a..90bd9ef94 100644
--- a/Src/UUniqueID.pas
+++ b/Src/UUniqueID.pas
@@ -5,7 +5,7 @@
*
* Copyright (C) 2009-2021, Peter Johnson (gravatar.com/delphidabbler).
*
- * Implements a static class that generates globally unique id strings.
+ * Implements a generator of globally unique ids.
}
@@ -16,22 +16,36 @@ interface
uses
- // Project
- UBaseObjects;
+ // Delphi
+ SysUtils;
type
- {
- TUniqueID:
- Static class that generates globally unique id strings.
- }
- TUniqueID = class(TNoConstructObject)
+ /// Generator of globally unique ids.
+ TUniqueID = record
+ strict private
+
+ /// Generates a new GUID and returns it as an array of bytes.
+ ///
+ class function NewUID: TBytes; static;
+
public
- class function Generate: string;
- {Generates a 32 digit globally unique id string of hex characters.
- @return Required unique id.
- }
+
+ /// Generates a globally unique string of 32 hexadecimal
+ /// characters.
+ class function Generate: string; static;
+ {TODO -cClarity: Rename above method as GenerateHex}
+
+ /// Generates a globally unique string of 32 alphabetical
+ /// characters.
+ ///
+ /// The returned string comprises the letters 'A' to 'S', omitting
+ /// 'I' and 'O'.
+ /// The string is a valid Pascal identifier.
+ ///
+ class function GenerateAlpha: string; static;
+
end;
@@ -39,34 +53,51 @@ implementation
uses
- // Delphi
- SysUtils;
+ // Project
+ UUtils;
{ TUniqueID }
class function TUniqueID.Generate: string;
- {Generates a 32 digit globally unique id string of hex characters.
- @return Required unique id.
- }
+var
+ Bytes: TBytes;
+ B: Byte;
+begin
+ Bytes := NewUID;
+ Result := '';
+ for B in Bytes do
+ Result := Result + IntToHex(B, 2);
+end;
+
+class function TUniqueID.GenerateAlpha: string;
type
- TGUIDFragment = LongWord; // part of a TGUID
- TGUIDFragments = // array of TGUID parts - assume same size as TGUID
- array[1..SizeOf(TGUID) div SizeOf(TGUIDFragment)] of TGUIDFragment;
+ TNybble = 0..15;
+const
+ AlphaMap: array[TNybble] of Char = (
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'J', 'K', 'L', 'M', 'P', 'Q', 'R', 'S'
+ );
var
- GUID: TGUID; // generated GUID
- Idx: Integer; // loops through parts of GUID as an array
+ Bytes: TBytes;
+ B: Byte;
begin
- Assert(SizeOf(TGUID) = SizeOf(TGUIDFragments),
- ClassName + '.Generate: Size of TGUID <> size of TGUIDFragments');
- // get a GUID
- CreateGUID(GUID);
+ Bytes := NewUID;
Result := '';
- // crack GUID into parts and build result from hex representation of the parts
- for Idx := Low(TGUIDFragments) to High(TGUIDFragments) do
- Result := Result + IntToHex(
- TGUIDFragments(GUID)[Idx], 2 * SizeOf(TGUIDFragment)
- );
+ for B in Bytes do
+ begin
+ Result := Result
+ + AlphaMap[TNybble(B shr 4)]
+ + AlphaMap[TNybble(B and $0F)];
+ end;
+end;
+
+class function TUniqueID.NewUID: TBytes;
+var
+ GUID: TGUID;
+begin
+ CreateGUID(GUID);
+ Result := GUIDToBytes(GUID);
end;
end.
From f284f32febec6759d9e298272278fb8befd773c7 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Thu, 7 Nov 2024 15:08:28 +0000
Subject: [PATCH 046/222] Add new TDatabase.GetUniqueSnippetKey method
This method was added to IDatabaseEdit and implemented in TDatabase.
It returns a 32 character alphabetical value that is unique within a
given snippet collection.
Its purpose to for use in new snippet keys.
The key is also a valid Pascal identifier, so can be used as a unit name
for test compiling.
---
Src/DB.UMain.pas | 44 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 43 insertions(+), 1 deletion(-)
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index f37e8dbdb..6e5844c1e 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -182,6 +182,14 @@ interface
}
IDatabaseEdit = interface(IInterface)
['{CBF6FBB0-4C18-481F-A378-84BB09E5ECF4}']
+
+ /// Creates a new snippet key that is unique within the given
+ /// collection.
+ /// TCollectionID ID of collection that
+ /// the new key must be unique within.
+ /// string containing the key.
+ function GetUniqueSnippetKey(const ACollectionID: TCollectionID): string;
+
function GetEditableSnippetInfo(const Snippet: TSnippet = nil):
TSnippetEditData;
{Provides details of all a snippet's data (properties and references) that
@@ -294,7 +302,8 @@ implementation
IntfCommon,
UExceptions,
UQuery,
- UStrUtils;
+ UStrUtils,
+ UUniqueID;
var
@@ -448,7 +457,17 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
{Removes a change event handler from list of listeners.
@param Handler [in] Handler to remove from list.
}
+
{ IDatabaseEdit methods }
+
+ /// Creates a new snippet key that is unique within the given
+ /// collection.
+ /// TCollectionID ID of collection that
+ /// the new key must be unique within.
+ /// string containing the key.
+ /// Method of IDatabaseEdit.
+ function GetUniqueSnippetKey(const ACollectionID: TCollectionID): string;
+
function GetEditableSnippetInfo(const Snippet: TSnippet = nil):
TSnippetEditData;
{Provides details of all a snippet's data (properties and references) that
@@ -919,6 +938,29 @@ function TDatabase.GetSnippets: TSnippetList;
Result := fSnippets;
end;
+function TDatabase.GetUniqueSnippetKey(
+ const ACollectionID: TCollectionID): string;
+var
+ SnippetsInCollection: TSnippetList;
+ Snippet: TSnippet;
+begin
+ // NOTE: It is probable that TUniqueID will always generate a key that is
+ // unique across the whole database, let alone within the collection. But it's
+ // safer to check and regenerate if necessary.
+ SnippetsInCollection := TSnippetList.Create;
+ try
+ // Build list of all snippets in collection
+ for Snippet in fSnippets do
+ if Snippet.CollectionID = ACollectionID then
+ SnippetsInCollection.Add(Snippet);
+ repeat
+ Result := TUniqueID.GenerateAlpha;
+ until SnippetsInCollection.Find(Result, ACollectionID) = nil;
+ finally
+ SnippetsInCollection.Free;
+ end;
+end;
+
function TDatabase.InternalAddCategory(const CatID: string;
const Data: TCategoryData): TCategory;
{Adds a new category to the user database. Assumes category not already in
From a1b5e576d38e36a7b7bc4b1a45167ecdf1e762d2 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Thu, 7 Nov 2024 15:47:44 +0000
Subject: [PATCH 047/222] Auto-generate snippet key in duplicate snippets dlg
Removed the ability for the user to specify the snippet key (formerly
the snippet name) in the Duplicate snippet dialogue box. The new snippet
key is now automatically generated and is certain to be unique within
the snippet's collection.
It is now compulsory to enter a display name (because the key that is
used for the display name by default is now a pseudo random sequence of
characters & makes no sense as a name).
Hard wired the "user" snippets collection. Later this should be chosen
by the user.
Put snippet display name in dialogue box caption in double quotes.
---
Src/FmDuplicateSnippetDlg.dfm | 37 +++++-------------
Src/FmDuplicateSnippetDlg.pas | 74 ++++++++++-------------------------
2 files changed, 30 insertions(+), 81 deletions(-)
diff --git a/Src/FmDuplicateSnippetDlg.dfm b/Src/FmDuplicateSnippetDlg.dfm
index 567120d7e..001fc6109 100644
--- a/Src/FmDuplicateSnippetDlg.dfm
+++ b/Src/FmDuplicateSnippetDlg.dfm
@@ -1,7 +1,7 @@
inherited DuplicateSnippetDlg: TDuplicateSnippetDlg
Caption = 'DuplicateSnippetDlg'
ExplicitWidth = 474
- ExplicitHeight = 356
+ ExplicitHeight = 375
PixelsPerInch = 96
TextHeight = 13
inherited pnlBody: TPanel
@@ -9,17 +9,9 @@ inherited DuplicateSnippetDlg: TDuplicateSnippetDlg
Height = 185
ExplicitWidth = 222
ExplicitHeight = 185
- object lblUniqueName: TLabel
- Left = 0
- Top = 0
- Width = 173
- Height = 13
- Caption = '&Unique name for duplicated snippet:'
- FocusControl = edUniqueName
- end
object lblCategory: TLabel
Left = 0
- Top = 104
+ Top = 58
Width = 49
Height = 13
Caption = '&Category:'
@@ -27,48 +19,37 @@ inherited DuplicateSnippetDlg: TDuplicateSnippetDlg
end
object lblDisplayName: TLabel
Left = 0
- Top = 48
+ Top = 2
Width = 67
Height = 13
Caption = '&Display name:'
FocusControl = edDisplayName
end
- object edUniqueName: TEdit
- Left = 0
- Top = 19
- Width = 222
- Height = 21
- Anchors = [akLeft, akTop, akRight]
- TabOrder = 0
- ExplicitWidth = 200
- end
object cbCategory: TComboBox
Left = 0
- Top = 123
+ Top = 77
Width = 222
Height = 21
Style = csDropDownList
Anchors = [akLeft, akTop, akRight]
- TabOrder = 2
+ TabOrder = 1
end
object edDisplayName: TEdit
Left = 0
- Top = 67
+ Top = 21
Width = 222
Height = 21
Anchors = [akLeft, akTop, akRight]
- TabOrder = 1
- ExplicitWidth = 200
+ TabOrder = 0
end
object chkEdit: TCheckBox
Left = 0
- Top = 160
+ Top = 114
Width = 222
Height = 17
Anchors = [akLeft, akTop, akRight]
Caption = '&Edit in Snippets Editor'
- TabOrder = 3
- ExplicitWidth = 200
+ TabOrder = 2
end
end
inherited btnHelp: TButton
diff --git a/Src/FmDuplicateSnippetDlg.pas b/Src/FmDuplicateSnippetDlg.pas
index 48e1bfdbf..1910b83dd 100644
--- a/Src/FmDuplicateSnippetDlg.pas
+++ b/Src/FmDuplicateSnippetDlg.pas
@@ -19,6 +19,7 @@ interface
// Delphi
SysUtils, Controls, StdCtrls, ExtCtrls, Classes,
// Project
+ DB.UCollections,
DB.USnippet, FmGenericOKDlg, UBaseObjects, UCategoryListAdapter,
UIStringList;
@@ -28,10 +29,8 @@ TDuplicateSnippetDlg = class(TGenericOKDlg, INoPublicConstruct)
cbCategory: TComboBox;
chkEdit: TCheckBox;
edDisplayName: TEdit;
- edUniqueName: TEdit;
lblCategory: TLabel;
lblDisplayName: TLabel;
- lblUniqueName: TLabel;
procedure btnOKClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
@@ -52,8 +51,9 @@ TPersistentOptions = class(TObject)
fSnippet: TSnippet;
fCatList: TCategoryListAdapter;
fOptions: TPersistentOptions;
- function DisallowedNames: IStringList;
- function UniqueSnippetName(const BaseName: string): string;
+ fSnippetKey: string;
+ /// ID of collection to receive the duplicated snippet.
+ function SelectedCollectionID: TCollectionID;
procedure ValidateData;
procedure HandleException(const E: Exception);
procedure UpdateDatabase;
@@ -77,7 +77,6 @@ implementation
// Delphi
Math,
// Project
- DB.UCollections,
DB.UCategory, DB.UMain, UCtrlArranger, UExceptions, UMessageBox, USettings,
USnippetValidator, UStructs, UStrUtils, UUserDBMgr;
@@ -90,16 +89,11 @@ procedure TDuplicateSnippetDlg.ArrangeForm;
TCtrlArranger.SetLabelHeights(Self);
TCtrlArranger.AlignLefts(
- [
- lblUniqueName, lblDisplayName, lblCategory, edUniqueName, edDisplayName,
- cbCategory, chkEdit
- ],
+ [lblDisplayName, lblCategory, edDisplayName, cbCategory, chkEdit],
0
);
- lblUniqueName.Top := 0;
- TCtrlArranger.MoveBelow(lblUniqueName, edUniqueName, 4);
- TCtrlArranger.MoveBelow(edUniqueName, lblDisplayName, 8);
+ lblDisplayName.Top := 0;
TCtrlArranger.MoveBelow(lblDisplayName, edDisplayName, 4);
TCtrlArranger.MoveBelow(edDisplayName, lblCategory, 8);
TCtrlArranger.MoveBelow(lblCategory, cbCategory, 4);
@@ -117,6 +111,9 @@ procedure TDuplicateSnippetDlg.ArrangeForm;
procedure TDuplicateSnippetDlg.btnOKClick(Sender: TObject);
begin
try
+ fSnippetKey := (Database as IDatabaseEdit).GetUniqueSnippetKey(
+ SelectedCollectionID
+ );
ValidateData;
UpdateDatabase;
except
@@ -125,23 +122,12 @@ procedure TDuplicateSnippetDlg.btnOKClick(Sender: TObject);
end;
end;
-function TDuplicateSnippetDlg.DisallowedNames: IStringList;
-var
- Snippet: TSnippet;
-begin
- Result := TIStringList.Create;
- Result.CaseSensitive := False;
- for Snippet in Database.Snippets do
- if Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
- Result.Add(Snippet.Key);
-end;
-
class function TDuplicateSnippetDlg.Execute(const AOwner: TComponent;
const ASnippet: TSnippet): Boolean;
var
Dlg: TDuplicateSnippetDlg;
resourcestring
- sCaption = 'Duplicate %s'; // dialog box caption
+ sCaption = 'Duplicate "%s"'; // dialogue box caption
begin
Assert(Assigned(ASnippet), ClassName + '.Execute: ASnippet is nil');
Dlg := InternalCreate(AOwner);
@@ -179,10 +165,7 @@ procedure TDuplicateSnippetDlg.InitForm;
SnippetCat: TCategory;
begin
inherited;
- edUniqueName.Text := UniqueSnippetName(fSnippet.Key);
- edDisplayName.Text := StrIf(
- StrSameStr(fSnippet.Key, fSnippet.DisplayName), '', fSnippet.DisplayName
- );
+ edDisplayName.Text := fSnippet.DisplayName;
fCatList.ToStrings(cbCategory.Items);
SnippetCat := Database.Categories.Find(fSnippet.Category);
if Assigned(SnippetCat) then
@@ -192,48 +175,33 @@ procedure TDuplicateSnippetDlg.InitForm;
chkEdit.Checked := fOptions.EditSnippetOnClose;
end;
-function TDuplicateSnippetDlg.UniqueSnippetName(const BaseName: string): string;
-var
- ExistingNames: IStringList;
- Postfix: Cardinal;
+function TDuplicateSnippetDlg.SelectedCollectionID: TCollectionID;
begin
- ExistingNames := DisallowedNames;
- if not ExistingNames.Contains(BaseName) then
- Exit(BaseName);
- // BaseName exists: find number to append to it to make name unique
- Postfix := 1;
- repeat
- Inc(PostFix);
- Result := BaseName + IntToStr(PostFix);
- until not ExistingNames.Contains(Result);
+ {TODO -cCollections: change the following to return the ID of a collection
+ chosen by the user.}
+ Result := TCollectionID.__TMP__UserDBCollectionID;
end;
procedure TDuplicateSnippetDlg.UpdateDatabase;
var
- UniqueName: string;
DisplayName: string;
begin
- UniqueName := StrTrim(edUniqueName.Text);
DisplayName := StrTrim(edDisplayName.Text);
(Database as IDatabaseEdit).DuplicateSnippet(
fSnippet,
- UniqueName,
- StrIf(StrSameStr(UniqueName, DisplayName), '', DisplayName),
+ fSnippetKey,
+ DisplayName,
fCatList.CatID(cbCategory.ItemIndex)
);
end;
procedure TDuplicateSnippetDlg.ValidateData;
-var
- ErrMsg: string;
- ErrSel: TSelection;
resourcestring
sNoCategory = 'You must choose a category';
+ sNoDisplayName = 'You must provide a display name';
begin
- if not TSnippetValidator.ValidateName(
- StrTrim(edUniqueName.Text), True, ErrMsg, ErrSel
- ) then
- raise EDataEntry.Create(ErrMsg, edUniqueName, ErrSel);
+ if StrTrim(edDisplayName.Text) = '' then
+ raise EDataEntry.Create(sNoDisplayName, edDisplayName);
if cbCategory.ItemIndex = -1 then
raise EDataEntry.Create(sNoCategory, cbCategory);
end;
@@ -248,7 +216,7 @@ procedure TDuplicateSnippetDlg.FormCreate(Sender: TObject);
procedure TDuplicateSnippetDlg.FormDestroy(Sender: TObject);
begin
if (ModalResult = mrOK) and chkEdit.Checked then
- TUserDBMgr.EditSnippet(StrTrim(edUniqueName.Text));
+ TUserDBMgr.EditSnippet(fSnippetKey);
fOptions.EditSnippetOnClose := chkEdit.Checked;
inherited;
fOptions.Free;
From d56e17274d11b77bd8cab3094bdfa6d9aca8d5c0 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Thu, 7 Nov 2024 16:44:20 +0000
Subject: [PATCH 048/222] Add precondition to TSnippet & TSnippetID Key props
Changed TSnippet and TSnippetID so that attempting to pass an empty or
all whitespace key string to their constructors will result in an
assertion failure.
Also changed TSnippetID's Key property setter to support the same
precondition check.
Key strings are now trimmed before assigning to the properties.
---
Src/DB.USnippet.pas | 3 ++-
Src/USnippetIDs.pas | 11 +++++++++--
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/Src/DB.USnippet.pas b/Src/DB.USnippet.pas
index 483ffe928..573955009 100644
--- a/Src/DB.USnippet.pas
+++ b/Src/DB.USnippet.pas
@@ -480,7 +480,8 @@ function TSnippet.IsEqual(const Snippet: TSnippet): Boolean;
procedure TSnippet.SetKey(const AKey: string);
begin
- fKey := AKey;
+ fKey := StrTrim(AKey);
+ Assert(fKey <> '', ClassName + '.SetKey: AKey is whitespace or empty');
end;
procedure TSnippet.SetProps(const Data: TSnippetData);
diff --git a/Src/USnippetIDs.pas b/Src/USnippetIDs.pas
index 8b4ee35dd..0cad2c12b 100644
--- a/Src/USnippetIDs.pas
+++ b/Src/USnippetIDs.pas
@@ -34,10 +34,11 @@ TSnippetID = record
/// Value of Key property.
fKey: string;
fCollectionID: TCollectionID;
+ procedure SetKey(const AValue: string);
procedure SetCollectionID(const AValue: TCollectionID);
public
/// Snippet's key.
- property Key: string read fKey write fKey;
+ property Key: string read fKey write SetKey;
/// ID of the collection to which a snippet with this ID belongs.
///
@@ -181,7 +182,7 @@ function TSnippetID.CompareTo(const SID: TSnippetID): Integer;
constructor TSnippetID.Create(const AKey: string;
const ACollectionID: TCollectionID);
begin
- fKey := AKey;
+ SetKey(AKey);
SetCollectionID(ACollectionID);
end;
@@ -201,6 +202,12 @@ procedure TSnippetID.SetCollectionID(const AValue: TCollectionID);
fCollectionID := AValue.Clone;
end;
+procedure TSnippetID.SetKey(const AValue: string);
+begin
+ fKey := StrTrim(AValue);
+ Assert(fKey <> '', 'TSnippetID.SetKey: Value is whitespace or empty');
+end;
+
{ TSnippetIDList }
function TSnippetIDList.Add(const SnippetID: TSnippetID): Integer;
From 65f5b7e50f1a6698df6b29ae094816f5cfd2ee99 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Thu, 7 Nov 2024 19:10:02 +0000
Subject: [PATCH 049/222] Add TSnippetValidator.ValidateDisplayName method
Added new TSnippetValidator method to validate display names, which must
be non-empty when trimmed of white space.
---
Src/USnippetValidator.pas | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/Src/USnippetValidator.pas b/Src/USnippetValidator.pas
index d02e4e956..d3452ea15 100644
--- a/Src/USnippetValidator.pas
+++ b/Src/USnippetValidator.pas
@@ -31,6 +31,17 @@ TSnippetValidator = class(TNoConstructObject)
cAllSnippetKinds: TSnippetKinds = // Set of all possible snippet kinds
[skFreeform, skRoutine, skConstant, skTypeDef, skUnit, skClass];
public
+
+ /// Validate a snippet display name.
+ /// string [in] Display name to be
+ /// checked.
+ /// string [out] Message that describes
+ /// error. Undefined if True returned.
+ /// Boolean. True if source code is valid or
+ /// False if not.
+ class function ValidateDisplayName(const DisplayName: string;
+ out ErrorMsg: string): Boolean;
+
class function ValidateDependsList(const Snippet: TSnippet;
out ErrorMsg: string): Boolean; overload;
{Recursively checks dependency list of a snippet for validity.
@@ -332,6 +343,19 @@ class function TSnippetValidator.ValidateDescription(const Desc: string;
Result := True;
end;
+class function TSnippetValidator.ValidateDisplayName(const DisplayName: string;
+ out ErrorMsg: string): Boolean;
+var
+ TrimmedDisplayName: string;
+resourcestring
+ sErrEmpty = 'A display name must be provided';
+begin
+ TrimmedDisplayName := StrTrim(DisplayName);
+ Result := TrimmedDisplayName <> '';
+ if not Result then
+ ErrorMsg := sErrEmpty;
+end;
+
class function TSnippetValidator.ValidateExtra(const Extra: IActiveText;
out ErrorMsg: string): Boolean;
{Validates a extra information from a snippet.
From 3a978b034aadc97a050e70b4b7a142f8488522c0 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Thu, 7 Nov 2024 19:50:49 +0000
Subject: [PATCH 050/222] Remove editing of snippet key from Snippets Editor
Removed the ability for the user to specify the snippet key (formerly
the snippet name) in the Snippets Editor dialogue box. When creating new
snippets, the new snippet key is now automatically generated and is
certain to be unique within the snippet's collection. When editing
existing snippets the original snippet ID is preserved.
It is now compulsory to enter a display name, for two reasons:
1. because the key that is used for the display name by default is now a
pseudo random sequence of characters & makes no sense as a name.
2. because the key can no longer be edited.
Hard wired the "user" snippets collection for new snippets. Later this
should be chosen by the user. Existing snippets being edited can't be
moved from their original collection.
Put snippet display name in dialogue box caption in double quotes.
---
Src/FmSnippetsEditorDlg.dfm | 30 +++--------
Src/FmSnippetsEditorDlg.pas | 99 +++++++++++++++++++++----------------
2 files changed, 64 insertions(+), 65 deletions(-)
diff --git a/Src/FmSnippetsEditorDlg.dfm b/Src/FmSnippetsEditorDlg.dfm
index 365274c63..bbb544308 100644
--- a/Src/FmSnippetsEditorDlg.dfm
+++ b/Src/FmSnippetsEditorDlg.dfm
@@ -42,14 +42,6 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
Caption = '&Source code:'
FocusControl = edSourceCode
end
- object lblName: TLabel
- Left = 3
- Top = 11
- Width = 31
- Height = 13
- Caption = '&Name:'
- FocusControl = edName
- end
object lblCategories: TLabel
Left = 0
Top = 183
@@ -111,15 +103,7 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
ParentFont = False
PopupMenu = mnuEditCtrls
ScrollBars = ssBoth
- TabOrder = 6
- end
- object edName: TEdit
- Left = 93
- Top = 7
- Width = 209
- Height = 21
- PopupMenu = mnuEditCtrls
- TabOrder = 0
+ TabOrder = 5
end
object cbCategories: TComboBox
Left = 93
@@ -127,7 +111,7 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
Width = 209
Height = 21
Style = csDropDownList
- TabOrder = 5
+ TabOrder = 4
end
object cbKind: TComboBox
Left = 93
@@ -135,7 +119,7 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
Width = 209
Height = 21
Style = csDropDownList
- TabOrder = 4
+ TabOrder = 3
OnChange = cbKindChange
end
inline frmDescription: TSnippetsActiveTextEdFrame
@@ -146,7 +130,7 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
Color = clWindow
ParentBackground = False
ParentColor = False
- TabOrder = 2
+ TabOrder = 1
ExplicitLeft = 93
ExplicitTop = 67
ExplicitWidth = 462
@@ -171,7 +155,7 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
Height = 25
Action = actViewDescription
Caption = 'Previe&w...'
- TabOrder = 3
+ TabOrder = 2
end
object edDisplayName: TEdit
Left = 93
@@ -179,7 +163,7 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
Width = 298
Height = 21
PopupMenu = mnuEditCtrls
- TabOrder = 1
+ TabOrder = 0
end
object chkUseHiliter: TCheckBox
Left = 3
@@ -187,7 +171,7 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
Width = 478
Height = 17
Caption = 'Synta&x highlight this snippet as Pascal code'
- TabOrder = 7
+ TabOrder = 6
end
end
object tsReferences: TTabSheet
diff --git a/Src/FmSnippetsEditorDlg.pas b/Src/FmSnippetsEditorDlg.pas
index be21eced6..4b3f8ec64 100644
--- a/Src/FmSnippetsEditorDlg.pas
+++ b/Src/FmSnippetsEditorDlg.pas
@@ -21,7 +21,8 @@ interface
SysUtils, Classes, ActnList, Buttons, StdCtrls, Forms, Controls, CheckLst,
ComCtrls, ExtCtrls, StdActns, Menus, ImgList,
// Project
- ActiveText.UMain, Compilers.UGlobals, DB.USnippet, FmGenericOKDlg,
+ ActiveText.UMain, Compilers.UGlobals,
+ DB.UCollections, DB.USnippet, FmGenericOKDlg,
FrBrowserBase, FrFixedHTMLDlg, FrHTMLDlg, UBaseObjects, UCategoryListAdapter,
UCompileMgr, UCompileResultsLBMgr, UCSSBuilder, UMemoCaretPosDisplayMgr,
UMemoHelper, USnipKindListAdapter, USnippetsChkListMgr, UUnitsChkListMgr,
@@ -61,7 +62,6 @@ TSnippetsEditorDlg = class(TGenericOKDlg, INoPublicConstruct)
clbDepends: TCheckListBox;
clbUnits: TCheckListBox;
clbXRefs: TCheckListBox;
- edName: TEdit;
edSourceCode: TMemo;
edUnit: TEdit;
lbCompilers: TListBox;
@@ -73,7 +73,6 @@ TSnippetsEditorDlg = class(TGenericOKDlg, INoPublicConstruct)
lblDescription: TLabel;
lblExtra: TLabel;
lblExtraCaretPos: TLabel;
- lblName: TLabel;
lblKind: TLabel;
lblSourceCaretPos: TLabel;
lblSourceCode: TLabel;
@@ -160,7 +159,6 @@ TSnippetsEditorDlg = class(TGenericOKDlg, INoPublicConstruct)
fCatList: TCategoryListAdapter; // Accesses sorted list of categories
fSnipKindList:
TSnipKindListAdapter; // Accesses sorted list of snippet kinds
- fOrigName: string; // Original name of snippet ('' for new)
fEditData: TSnippetEditData; // Record storing a snippet's editable data
fCompileMgr: TCompileMgr; // Manages compilation and results display
fDependsCLBMgr:
@@ -173,6 +171,24 @@ TSnippetsEditorDlg = class(TGenericOKDlg, INoPublicConstruct)
fSourceMemoHelper: TMemoHelper; // Helper for working with source code memo
fMemoCaretPosDisplayMgr: TMemoCaretPosDisplayMgr;
// Manages display of memo caret positions
+
+ /// Returns the ID of the collection that applies to a new or
+ /// existing snippet.
+ /// TCollectionID. The required collection ID.
+ /// For a new snippet the return value is the collection to be
+ /// applied to the snippet. For an existing snippet this is collection to
+ /// which the snippet already belongs.
+ function SelectedCollectionID: TCollectionID;
+
+ /// Returns a snippet key that is unique with the current
+ /// snippet collection.
+ /// string. The required key.
+ /// For a new snippet this key will change depending each time the
+ /// method is called, and will always be unique within the selected
+ /// collection. For an existing snippet the key is always that of the
+ /// snippet and never changes across method calls.
+ function UniqueSnippetKey: string;
+
procedure PopulateControls;
{Populates controls with dynamic data.
}
@@ -254,7 +270,6 @@ implementation
// Delphi
Windows {for inlining}, Graphics,
// Project
- DB.UCollections,
DB.UMain, DB.USnippetKind, FmDependenciesDlg, IntfCommon, UColours, UConsts,
UCSSUtils, UCtrlArranger, UExceptions, UFontHelper, UIStringList,
UReservedCategories, USnippetExtraHelper, USnippetValidator, UMessageBox,
@@ -425,7 +440,7 @@ procedure TSnippetsEditorDlg.actViewDependenciesExecute(Sender: TObject);
fDependsCLBMgr.GetCheckedSnippets(DependsList);
TDependenciesDlg.Execute(
Self,
- TSnippetID.Create(StrTrim(edName.Text), TCollectionID.__TMP__UserDBCollectionID),
+ TSnippetID.Create(UniqueSnippetKey, TCollectionID.__TMP__UserDBCollectionID),
StrTrim(edDisplayName.Text),
DependsList,
[tiDependsUpon],
@@ -555,7 +570,7 @@ procedure TSnippetsEditorDlg.ArrangeForm;
edSourceCode.Width := tsCode.ClientWidth - 8;
TCtrlArranger.AlignLefts(
[
- lblName, lblDisplayName, lblDescription, lblKind, lblCategories,
+ lblDisplayName, lblDescription, lblKind, lblCategories,
lblSourceCode, edSourceCode
],
3
@@ -564,10 +579,7 @@ procedure TSnippetsEditorDlg.ArrangeForm;
[edSourceCode, lblSourceCaretPos, btnViewDescription]
);
frmDescription.Width := btnViewDescription.Left - frmDescription.Left - 8;
- TCtrlArranger.AlignVCentres(3, [lblName, edName]);
- TCtrlArranger.AlignVCentres(
- TCtrlArranger.BottomOf([lblName, edName], 8),
- [lblDisplayName, edDisplayName]
+ TCtrlArranger.AlignVCentres(3, [lblDisplayName, edDisplayName]
);
TCtrlArranger.AlignTops(
[lblDescription, frmDescription, btnViewDescription],
@@ -622,24 +634,21 @@ procedure TSnippetsEditorDlg.btnOKClick(Sender: TObject);
snippet if all is well.
@param Sender [in] Not used.
}
-var
- SnippetName: string; // name of snippet being edited / added
begin
inherited;
try
// Validate and record entered data
ValidateData;
fEditData.Assign(UpdateData);
- SnippetName := StrTrim(edName.Text);
// Add or update snippet
if Assigned(fSnippet) then
- fSnippet := (Database as IDatabaseEdit).UpdateSnippet(
- fSnippet, fEditData, SnippetName
+ (Database as IDatabaseEdit).UpdateSnippet(
+ fSnippet, fEditData, UniqueSnippetKey
)
else
begin
- fSnippet := (Database as IDatabaseEdit).AddSnippet(
- SnippetName, fEditData
+ (Database as IDatabaseEdit).AddSnippet(
+ UniqueSnippetKey, fEditData
)
end;
except
@@ -685,7 +694,7 @@ function TSnippetsEditorDlg.CreateTempSnippet: TSnippet;
// Create snippet object from entered data
EditData.Assign(UpdateData);
Result := (Database as IDatabaseEdit).CreateTempSnippet(
- StrTrim(edName.Text), EditData
+ UniqueSnippetKey, EditData
);
end;
@@ -718,6 +727,7 @@ class function TSnippetsEditorDlg.EditSnippet(AOwner: TComponent;
resourcestring
sCaption = 'Edit Snippet'; // dialogue box caption
begin
+ Assert(Assigned(Snippet), ClassName + '.EditSnippet: Snippet is nil');
Instance := InternalCreate(AOwner);
try
Instance.Caption := sCaption;
@@ -822,11 +832,7 @@ procedure TSnippetsEditorDlg.InitControls;
chkUseHiliter.Checked := fSnippet.HiliteSource;
frmDescription.DefaultEditMode := emAuto;
frmDescription.ActiveText := fSnippet.Description;
- edName.Text := fSnippet.Key;
- if fSnippet.Key <> fSnippet.DisplayName then
- edDisplayName.Text := fSnippet.DisplayName
- else
- edDisplayName.Text := '';
+ edDisplayName.Text := fSnippet.DisplayName;
cbCategories.ItemIndex := fCatList.IndexOf(fSnippet.Category);
frmExtra.DefaultEditMode := emAuto;
frmExtra.ActiveText := fSnippet.Extra;
@@ -845,7 +851,6 @@ procedure TSnippetsEditorDlg.InitControls;
chkUseHiliter.Checked := True;
frmDescription.DefaultEditMode := emPlainText;
frmDescription.Clear;
- edName.Clear;
edDisplayName.Clear;
cbCategories.ItemIndex := fCatList.IndexOf(TReservedCategories.UserCatID);
if cbCategories.ItemIndex = -1 then
@@ -874,11 +879,6 @@ procedure TSnippetsEditorDlg.InitForm;
// Get data associated with snippet, or blank / default data if adding a new
// snippet
fEditData := (Database as IDatabaseEdit).GetEditableSnippetInfo(fSnippet);
- // Record snippet's original name, if any
- if Assigned(fSnippet) then
- fOrigName := fSnippet.Key
- else
- fOrigName := '';
// Populate controls with dynamic data
PopulateControls;
// Initialise controls to default values
@@ -934,6 +934,17 @@ procedure TSnippetsEditorDlg.PopulateControls;
fCatList.ToStrings(cbCategories.Items);
end;
+function TSnippetsEditorDlg.SelectedCollectionID: TCollectionID;
+begin
+ if Assigned(fSnippet) then
+ Result := fSnippet.CollectionID
+ else
+ {TODO -cCollections: Replace the following __TMP__ method with collection ID
+ selected by user from a combo box. DO NOT permit this choice when
+ editing an existing snippet.}
+ Result := TCollectionID.__TMP__UserDBCollectionID;
+end;
+
procedure TSnippetsEditorDlg.SetAllCompilerResults(
const CompRes: TCompileResult);
{Sets all compiler results to same value.
@@ -943,16 +954,23 @@ procedure TSnippetsEditorDlg.SetAllCompilerResults(
fCompilersLBMgr.SetCompileResults(CompRes);
end;
+function TSnippetsEditorDlg.UniqueSnippetKey: string;
+begin
+ if Assigned(fSnippet) then
+ Result := fSnippet.Key
+ else
+ Result := (Database as IDatabaseEdit).GetUniqueSnippetKey(
+ SelectedCollectionID
+ );
+end;
+
function TSnippetsEditorDlg.UpdateData: TSnippetEditData;
{Updates snippet's data from user entries. Assumes data has been validated.
@return Record containing snippet's data.
}
begin
Result.Init;
- if StrTrim(edName.Text) <> StrTrim(edDisplayName.Text) then
- Result.Props.DisplayName := StrTrim(edDisplayName.Text)
- else
- Result.Props.DisplayName := '';
+ Result.Props.DisplayName := StrTrim(edDisplayName.Text);
Result.Props.Cat := fCatList.CatID(cbCategories.ItemIndex);
Result.Props.Kind := fSnipKindList.SnippetKind(cbKind.ItemIndex);
(Result.Props.Desc as IAssignable).Assign(frmDescription.ActiveText);
@@ -980,7 +998,7 @@ procedure TSnippetsEditorDlg.UpdateReferences;
fXRefsCLBMgr.Save;
fXRefsCLBMgr.Clear;
- EditSnippetID := TSnippetID.Create(fOrigName, TCollectionID.__TMP__UserDBCollectionID);
+ EditSnippetID := TSnippetID.Create(UniqueSnippetKey, SelectedCollectionID);
EditSnippetKind := fSnipKindList.SnippetKind(cbKind.ItemIndex);
for Snippet in Database.Snippets do
begin
@@ -1019,13 +1037,10 @@ procedure TSnippetsEditorDlg.ValidateData;
ErrorMessage: string; // receives validation error messages
ErrorSelection: TSelection; // receives selection containing errors
begin
- if not TSnippetValidator.ValidateName(
- edName.Text,
- not StrSameText(StrTrim(edName.Text), fOrigName),
- ErrorMessage,
- ErrorSelection
+ if not TSnippetValidator.ValidateDisplayName(
+ edDisplayName.Text, ErrorMessage
) then
- raise EDataEntry.Create(ErrorMessage, edName, ErrorSelection);
+ raise EDataEntry.Create(ErrorMessage, edDisplayName);
frmDescription.Validate;
if not TSnippetValidator.ValidateSourceCode(
edSourceCode.Text, ErrorMessage, ErrorSelection
@@ -1033,7 +1048,7 @@ procedure TSnippetsEditorDlg.ValidateData;
raise EDataEntry.Create(ErrorMessage, edSourceCode, ErrorSelection);
frmExtra.Validate;
if not TSnippetValidator.ValidateDependsList(
- StrTrim(edName.Text), UpdateData, ErrorMessage
+ UniqueSnippetKey, UpdateData, ErrorMessage
) then
raise EDataEntry.Create( // selection not applicable to list boxes
StrMakeSentence(ErrorMessage) + EOL2 + sDependencyPrompt, clbDepends
From 93169ceed93d4843c09754887d3192221381146d Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Fri, 8 Nov 2024 09:55:18 +0000
Subject: [PATCH 051/222] Rename "Name" to "Key" in snippet import units
Updated UCodeImportMgr & UCodeImportExport units to refer to snippet
keys by the correct terminology in fields, parameters and method names.
Updated all other units affected by this refactoring.
---
Src/FmCodeImportDlg.dfm | 16 +++++++++++
Src/FmCodeImportDlg.pas | 8 +++---
Src/UCodeImportExport.pas | 10 +++----
Src/UCodeImportMgr.pas | 58 +++++++++++++++++++--------------------
4 files changed, 54 insertions(+), 38 deletions(-)
diff --git a/Src/FmCodeImportDlg.dfm b/Src/FmCodeImportDlg.dfm
index f3cc01a43..6b516057b 100644
--- a/Src/FmCodeImportDlg.dfm
+++ b/Src/FmCodeImportDlg.dfm
@@ -14,6 +14,10 @@ inherited CodeImportDlg: TCodeImportDlg
object tsInfo: TTabSheet
Caption = 'tsInfo'
TabVisible = False
+ ExplicitLeft = 0
+ ExplicitTop = 0
+ ExplicitWidth = 0
+ ExplicitHeight = 0
object lblIntro: TLabel
Left = 0
Top = 8
@@ -30,6 +34,10 @@ inherited CodeImportDlg: TCodeImportDlg
Caption = 'tsFile'
ImageIndex = 1
TabVisible = False
+ ExplicitLeft = 0
+ ExplicitTop = 0
+ ExplicitWidth = 0
+ ExplicitHeight = 0
object lblFile: TLabel
Left = 0
Top = 8
@@ -71,6 +79,10 @@ inherited CodeImportDlg: TCodeImportDlg
Caption = 'tsUpdate'
ImageIndex = 3
TabVisible = False
+ ExplicitLeft = 0
+ ExplicitTop = 0
+ ExplicitWidth = 0
+ ExplicitHeight = 0
object lblImportList: TLabel
Left = 0
Top = 53
@@ -149,6 +161,10 @@ inherited CodeImportDlg: TCodeImportDlg
Caption = 'tsFinish'
ImageIndex = 5
TabVisible = False
+ ExplicitLeft = 0
+ ExplicitTop = 0
+ ExplicitWidth = 0
+ ExplicitHeight = 0
object lblFinish: TLabel
Left = 0
Top = 8
diff --git a/Src/FmCodeImportDlg.pas b/Src/FmCodeImportDlg.pas
index 7315b29e8..7dfb4956e 100644
--- a/Src/FmCodeImportDlg.pas
+++ b/Src/FmCodeImportDlg.pas
@@ -346,8 +346,8 @@ procedure TCodeImportDlg.InitImportInfo;
LI := lvImports.Items.Add;
LI.SubItems.Add('');
LI.SubItems.Add('');
- LI.Caption := Info.OrigName;
- SetImportNameInLV(LI, Info.ImportAsName);
+ LI.Caption := Info.OrigKey;
+ SetImportNameInLV(LI, Info.ImportAsKey);
LI.Checked := not Info.Skip;
UpdateActionDisplay(LI);
end;
@@ -440,7 +440,7 @@ procedure TCodeImportDlg.PresentResults;
begin
if DataItem.Skip then
Continue;
- AddLabel(LblTop, DataItem.ImportAsName);
+ AddLabel(LblTop, DataItem.ImportAsKey);
end;
end;
@@ -511,7 +511,7 @@ procedure TCodeImportDlg.UpdateImportData(const Item: TListItem);
begin
if not Assigned(Item) then
Exit;
- Idx := fImportMgr.ImportInfo.IndexOfName(Item.Caption);
+ Idx := fImportMgr.ImportInfo.IndexOfKey(Item.Caption);
if Idx = -1 then
raise EBug.Create(
ClassName + '.UpdateImportData: Can''t find import data item.'
diff --git a/Src/UCodeImportExport.pas b/Src/UCodeImportExport.pas
index 600e47990..902edc10b 100644
--- a/Src/UCodeImportExport.pas
+++ b/Src/UCodeImportExport.pas
@@ -34,8 +34,8 @@ interface
/// Encapsulates data that describes a snippet that has been read
/// from an import file.
TSnippetInfo = record
- /// Snippet name.
- Name: string;
+ /// Snippet key.
+ Key: string;
/// Description of snippet.
Data: TSnippetEditData;
/// Copies given TSnippetInfo record to this one.
@@ -419,7 +419,7 @@ procedure TCodeImporter.Execute(const Data: TBytes);
begin
// Read a snippet node
SnippetNode := SnippetNodes[Idx];
- fSnippetInfo[Idx].Name := SnippetNode.Attributes[cSnippetNameAttr];
+ fSnippetInfo[Idx].Key := SnippetNode.Attributes[cSnippetNameAttr];
fSnippetInfo[Idx].Data :=
(Database as IDatabaseEdit).GetEditableSnippetInfo;
fSnippetInfo[Idx].Data.Props.Cat := TReservedCategories.ImportsCatID;
@@ -545,13 +545,13 @@ function TCodeImporter.ValidateDoc: Integer;
procedure TSnippetInfo.Assign(const Src: TSnippetInfo);
begin
- Name := Src.Name;
+ Key := Src.Key;
Data.Assign(Src.Data);
end;
procedure TSnippetInfo.Init;
begin
- Name := '';
+ Key := '';
Data.Init;
end;
diff --git a/Src/UCodeImportMgr.pas b/Src/UCodeImportMgr.pas
index f2ae236d2..2410bfc27 100644
--- a/Src/UCodeImportMgr.pas
+++ b/Src/UCodeImportMgr.pas
@@ -30,18 +30,18 @@ interface
TImportInfo = record
strict private
// Property values
- fOrigName: string;
- fImportAsName: string;
+ fOrigKey: string;
+ fImportAsKey: string;
fSkip: Boolean;
public
/// Initialises properties to given values.
- constructor Create(const AOrigName, AImportAsName: string;
+ constructor Create(const AOrigKey, AImportAsKey: string;
const ASkip: Boolean = False);
- /// Name of snippet per import file.
- property OrigName: string read fOrigName;
- /// Name of snippet to be used when updating database.
+ /// Snippet key per import file.
+ property OrigKey: string read fOrigKey;
+ /// Key of snippet to be used when updating database.
/// Can be changed by user.
- property ImportAsName: string read fImportAsName write fImportAsName;
+ property ImportAsKey: string read fImportAsKey write fImportAsKey;
/// Flag indicating if snippet is to be skipped (ignored) when
/// updating database.
property Skip: Boolean read fSkip write fSkip;
@@ -68,16 +68,16 @@ TImportInfoList = class(TList)
public
/// Constructs list with appropriate comparer.
constructor Create;
- /// Finds a record based on its OrigName field value.
- /// string [in] Name to be found.
+ /// Finds a record based on its OrigKey field value.
+ /// string [in] Key to be found.
/// TImportInfo [out] Found record. Undefined if
/// Name not found.
- /// Boolean: True if Name found, False if not.
- function FindByName(const Name: string; out ImportInfo: TImportInfo):
+ /// Boolean: True if Key found, False if not.
+ function FindByKey(const Key: string; out ImportInfo: TImportInfo):
Boolean;
- /// Returns index of record in list whose OrigName field matches
+ /// Returns index of record in list whose OrigKey field matches
/// given name or -1 if name not found.
- function IndexOfName(const Name: string): Integer;
+ function IndexOfKey(const Key: string): Integer;
end;
type
@@ -188,8 +188,8 @@ function TCodeImportMgr.DisallowedNames(const ExcludedName: string):
if Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
Result.Add(Snippet.Key);
for SnippetInfo in fSnippetInfoList do
- if not StrSameText(SnippetInfo.Name, ExcludedName) then
- Result.Add(SnippetInfo.Name);
+ if not StrSameText(SnippetInfo.Key, ExcludedName) then
+ Result.Add(SnippetInfo.Key);
end;
function TCodeImportMgr.GetUniqueSnippetName(
@@ -234,7 +234,7 @@ procedure TCodeImportMgr.InitImportInfoList;
begin
fImportInfoList.Add(
TImportInfo.Create(
- SnippetInfo.Name, GetUniqueSnippetName(SnippetInfo.Name)
+ SnippetInfo.Key, GetUniqueSnippetName(SnippetInfo.Key)
)
);
end;
@@ -271,36 +271,36 @@ procedure TCodeImportMgr.UpdateDatabase;
ImportInfo: TImportInfo; // info about how / whether to import a snippet
resourcestring
// Error message
- sBadNameError = 'Can''t find snippet "%s" in import data';
+ sBadNameError = 'Can''t find snippet with key "%s" in import data';
begin
Editor := Database as IDatabaseEdit;
for SnippetInfo in fSnippetInfoList do
begin
- if not fImportInfoList.FindByName(SnippetInfo.Name, ImportInfo) then
- raise EBug.CreateFmt(sBadNameError, [SnippetInfo.Name]);
+ if not fImportInfoList.FindByKey(SnippetInfo.Key, ImportInfo) then
+ raise EBug.CreateFmt(sBadNameError, [SnippetInfo.Key]);
if ImportInfo.Skip then
Continue;
AdjustDependsList(SnippetInfo.Data.Refs.Depends);
- Snippet := Database.Snippets.Find(ImportInfo.ImportAsName, TCollectionID.__TMP__UserDBCollectionID);
+ Snippet := Database.Snippets.Find(ImportInfo.ImportAsKey, TCollectionID.__TMP__UserDBCollectionID);
if Assigned(Snippet) then
// snippet already exists: overwrite it
Editor.UpdateSnippet(Snippet, SnippetInfo.Data)
else
// snippet is new: add to database
- Editor.AddSnippet(ImportInfo.ImportAsName, SnippetInfo.Data);
+ Editor.AddSnippet(ImportInfo.ImportAsKey, SnippetInfo.Data);
end;
end;
{ TImportInfo }
-constructor TImportInfo.Create(const AOrigName, AImportAsName: string;
+constructor TImportInfo.Create(const AOrigKey, AImportAsKey: string;
const ASkip: Boolean);
begin
- fOrigName := AOrigName;
- fImportAsName := AImportAsName;
+ fOrigKey := AOrigKey;
+ fImportAsKey := AImportAsKey;
fSkip := ASkip;
end;
@@ -308,7 +308,7 @@ constructor TImportInfo.Create(const AOrigName, AImportAsName: string;
function TImportInfoComparer.Compare(const Left, Right: TImportInfo): Integer;
begin
- Result := TSnippetID.CompareKeys(Left.OrigName, Right.OrigName);
+ Result := TSnippetID.CompareKeys(Left.OrigKey, Right.OrigKey);
end;
{ TImportInfoList }
@@ -318,21 +318,21 @@ constructor TImportInfoList.Create;
inherited Create(TImportInfoComparer.Create);
end;
-function TImportInfoList.FindByName(const Name: string;
+function TImportInfoList.FindByKey(const Key: string;
out ImportInfo: TImportInfo): Boolean;
var
Idx: Integer; // index of named snippet in list
begin
- Idx := IndexOf(TImportInfo.Create(Name, ''));
+ Idx := IndexOf(TImportInfo.Create(Key, ''));
if Idx = -1 then
Exit(False);
ImportInfo := Items[Idx];
Result := True;
end;
-function TImportInfoList.IndexOfName(const Name: string): Integer;
+function TImportInfoList.IndexOfKey(const Key: string): Integer;
begin
- Result := IndexOf(TImportInfo.Create(Name, ''));
+ Result := IndexOf(TImportInfo.Create(Key, ''));
end;
end.
From 3e2c492c49667bba1bfe3559c8e046fd0be96770 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Fri, 8 Nov 2024 15:58:42 +0000
Subject: [PATCH 052/222] Prevent editing of snippet keys in snippet imports
Revised tsUpdate page of snippet import wizard in FmCodeImportDlg.dfm /
.pas:
* Removed edit box and related button, action and label where snippet
keys were renamed.
* Changed list view to display snippet's display name instead of key and
removed column that displayed optionally renamed keys.
Overhauled supporting code in FmCodeImportDlg.pas:
* Removed code that supported editing snippet keys
* Added placeholder code for getting collection into which imported
snippets are to be added.
Changed UCodeImportExport unit to ensure display name snippet property
is always set.
Updated UCodeImportMgr:
* Removed support for changing snippet IDs
* Removed support for updating existing snippets with data from imported
snippet when both snippets have the same ID.
* Added a callback to permit user to specify the collection into which
the imported snippets will be added.
* Replaced custom code for finding a unique snippet ID with a call to
IDatabaseEdit.GetUniqueSnippetKey.
---
Src/FmCodeImportDlg.dfm | 60 ++-------------
Src/FmCodeImportDlg.pas | 151 ++++++++++----------------------------
Src/UCodeImportExport.pas | 2 +
Src/UCodeImportMgr.pas | 139 ++++++++++++++++++-----------------
4 files changed, 117 insertions(+), 235 deletions(-)
diff --git a/Src/FmCodeImportDlg.dfm b/Src/FmCodeImportDlg.dfm
index 6b516057b..5182ac866 100644
--- a/Src/FmCodeImportDlg.dfm
+++ b/Src/FmCodeImportDlg.dfm
@@ -14,10 +14,6 @@ inherited CodeImportDlg: TCodeImportDlg
object tsInfo: TTabSheet
Caption = 'tsInfo'
TabVisible = False
- ExplicitLeft = 0
- ExplicitTop = 0
- ExplicitWidth = 0
- ExplicitHeight = 0
object lblIntro: TLabel
Left = 0
Top = 8
@@ -34,10 +30,6 @@ inherited CodeImportDlg: TCodeImportDlg
Caption = 'tsFile'
ImageIndex = 1
TabVisible = False
- ExplicitLeft = 0
- ExplicitTop = 0
- ExplicitWidth = 0
- ExplicitHeight = 0
object lblFile: TLabel
Left = 0
Top = 8
@@ -79,10 +71,6 @@ inherited CodeImportDlg: TCodeImportDlg
Caption = 'tsUpdate'
ImageIndex = 3
TabVisible = False
- ExplicitLeft = 0
- ExplicitTop = 0
- ExplicitWidth = 0
- ExplicitHeight = 0
object lblImportList: TLabel
Left = 0
Top = 53
@@ -91,14 +79,6 @@ inherited CodeImportDlg: TCodeImportDlg
Caption = 'Imported &snippets:'
FocusControl = lvImports
end
- object lblSelectedSnippet: TLabel
- Left = 0
- Top = 217
- Width = 83
- Height = 13
- Caption = 'S&elected snippet:'
- FocusControl = edRename
- end
object lblModifyInstructions: TLabel
Left = 0
Top = 8
@@ -106,9 +86,10 @@ inherited CodeImportDlg: TCodeImportDlg
Height = 40
AutoSize = False
Caption =
- 'The functions to be imported are listed below. Select, deselect ' +
- 'and rename as required then click the "Update" button to update ' +
- 'the database. Use "Cancel" to abandon the import.'
+ 'The functions to be imported are listed below. Clear the check b' +
+ 'oxes next to any snippets you don'#39't want to import then click th' +
+ 'e "Update" button to update the database. Use "Cancel" to abando' +
+ 'n the import.'
WordWrap = True
end
object lvImports: TListView
@@ -119,12 +100,8 @@ inherited CodeImportDlg: TCodeImportDlg
Checkboxes = True
Columns = <
item
- Caption = 'Snippet Name'
- Width = 140
- end
- item
- Caption = 'Import Using Name'
- Width = 140
+ Caption = 'Snippet'
+ Width = 280
end
item
Caption = 'Action'
@@ -138,33 +115,13 @@ inherited CodeImportDlg: TCodeImportDlg
SortType = stText
TabOrder = 0
ViewStyle = vsReport
- OnSelectItem = lvImportsSelectItem
OnItemChecked = lvImportsItemChecked
end
- object btnRename: TButton
- Left = 161
- Top = 236
- Width = 75
- Height = 25
- Action = actRename
- TabOrder = 1
- end
- object edRename: TEdit
- Left = 0
- Top = 238
- Width = 155
- Height = 21
- TabOrder = 2
- end
end
object tsFinish: TTabSheet
Caption = 'tsFinish'
ImageIndex = 5
TabVisible = False
- ExplicitLeft = 0
- ExplicitTop = 0
- ExplicitWidth = 0
- ExplicitHeight = 0
object lblFinish: TLabel
Left = 0
Top = 8
@@ -190,11 +147,6 @@ inherited CodeImportDlg: TCodeImportDlg
object alMain: TActionList
Left = 448
Top = 208
- object actRename: TAction
- Caption = '&Rename...'
- OnExecute = actRenameExecute
- OnUpdate = actRenameUpdate
- end
object actBrowse: TAction
Caption = '...'
Hint = 'Browse for import file'
diff --git a/Src/FmCodeImportDlg.pas b/Src/FmCodeImportDlg.pas
index 7dfb4956e..4bdd74688 100644
--- a/Src/FmCodeImportDlg.pas
+++ b/Src/FmCodeImportDlg.pas
@@ -25,6 +25,7 @@ interface
ExtCtrls,
Forms,
// Project
+ DB.UCollections,
FmWizardDlg,
UBaseObjects,
UCodeImportMgr;
@@ -47,38 +48,32 @@ TCodeImportDlg = class(TWizardDlg, INoPublicConstruct)
lvImports: TListView;
lblImportList: TLabel;
lblLoadFile: TLabel;
- btnRename: TButton;
- edRename: TEdit;
- lblSelectedSnippet: TLabel;
alMain: TActionList;
- actRename: TAction;
actBrowse: TAction;
lblModifyInstructions: TLabel;
lblFinish: TLabel;
sbFinish: TScrollBox;
/// Handles clicks on list view check boxes.
procedure lvImportsItemChecked(Sender: TObject; Item: TListItem);
- /// Handles selection changes events in list view.
- procedure lvImportsSelectItem(Sender: TObject; Item: TListItem;
- Selected: Boolean);
- /// Updates enabled state of rename action and associated
- /// controls.
- procedure actRenameUpdate(Sender: TObject);
- /// Handles event that requests renaming of a snippet.
- procedure actRenameExecute(Sender: TObject);
/// Handles request to display open file dialog box to get import
/// file name.
procedure actBrowseExecute(Sender: TObject);
+ /// Frees objects stored in list view items' Data properties.
+ ///
+ procedure FormDestroy(Sender: TObject);
strict private
const
+ {TODO -cCollections: Insert a new page to get collection to receive
+ imports from user after cFilePage and before cUpdatePage. That way
+ we can be sure that the collection won't change after selecting
+ snippets.}
// Indices of wizard pages
cIntroPage = 0;
cFilePage = 1;
cUpdatePage = 2;
cFinishPage = 3;
// Index of subitems in list view
- cLVActionIdx = 1;
- cLVImportName = 0;
+ cLVActionIdx = 0;
var
/// Reference to import manager object used to perform import
/// operations.
@@ -86,11 +81,6 @@ TCodeImportDlg = class(TWizardDlg, INoPublicConstruct)
/// Validates entries on wizard pages indetified by the page
/// index.
procedure ValidatePage(const PageIdx: Integer);
- /// Checks validity of a given snippet name that is to be used
- /// to replace the name in a given list item. Passes any error message
- /// back via parameter list.
- function ValidateSnippetName(const Name: string; const Item: TListItem;
- out ErrMsg: string): Boolean;
/// Reads input file from disk.
procedure ReadImportFile;
/// Retrieves import file name from edit control where it is
@@ -106,12 +96,6 @@ TCodeImportDlg = class(TWizardDlg, INoPublicConstruct)
/// Counts snippets that will be / have been added to database.
/// Excludes any snippets skipped by user.
function CountImportSnippets: Integer;
- /// Retrieves the name that will be used to add an imported
- /// snippet to the database from the given list item.
- function GetImportAsNameFromLV(const Item: TListItem): string;
- /// Updates given list item with new imported snippet name.
- ///
- procedure SetImportNameInLV(const Item: TListItem; const Value: string);
/// Updates given list item with description of current import
/// action for the associated snippet.
procedure SetActionInLV(const Item: TListItem; const Value: string);
@@ -126,6 +110,9 @@ TCodeImportDlg = class(TWizardDlg, INoPublicConstruct)
procedure UpdateDatabase;
/// Displays names of imported snippets on finish page.
procedure PresentResults;
+ /// Gets the ID of the collection into which all snippets are to
+ /// be imported.
+ function GetCollectionID: TCollectionID;
strict protected
/// Protected constructor that sets up object to use given import
/// manager object.
@@ -168,6 +155,7 @@ implementation
SysUtils,
Dialogs,
// Project
+ UBox,
UCtrlArranger,
UExceptions,
UMessageBox,
@@ -187,7 +175,7 @@ procedure TCodeImportDlg.actBrowseExecute(Sender: TObject);
resourcestring
sFilter = 'CodeSnip export files (*.csexp)|*.csexp|' // file filter
+ 'All files (*.*)|*.*';
- sTitle = 'Import File'; // dialog box title
+ sTitle = 'Import File'; // dialogue box title
begin
OpenDlg := TOpenDialogEx.Create(nil);
try
@@ -208,23 +196,6 @@ procedure TCodeImportDlg.actBrowseExecute(Sender: TObject);
end;
end;
-procedure TCodeImportDlg.actRenameExecute(Sender: TObject);
-var
- ErrMsg: string; // any error message returned from snippets validator
-begin
- if not ValidateSnippetName(edRename.Text, lvImports.Selected, ErrMsg) then
- raise EDataEntry.Create(ErrMsg, edRename);
- SetImportNameInLV(lvImports.Selected, edRename.Text);
- lvImports.Selected.MakeVisible(False);
- UpdateImportData(lvImports.Selected);
-end;
-
-procedure TCodeImportDlg.actRenameUpdate(Sender: TObject);
-begin
- actRename.Enabled := Assigned(lvImports.Selected);
- edRename.Enabled := Assigned(lvImports.Selected);
-end;
-
procedure TCodeImportDlg.ArrangeForm;
begin
TCtrlArranger.SetLabelHeights(Self);
@@ -243,10 +214,6 @@ procedure TCodeImportDlg.ArrangeForm;
// tsUpdate
lblImportList.Top := TCtrlArranger.BottomOf(lblModifyInstructions, 8);
lvImports.Top := TCtrlArranger.BottomOf(lblImportList, 6);
- lblSelectedSnippet.Top := TCtrlArranger.BottomOf(lvImports, 8);
- TCtrlArranger.AlignVCentres(
- TCtrlArranger.BottomOf(lblSelectedSnippet, 6), [edRename, btnRename]
- );
// tsFinish
sbFinish.Top := TCtrlArranger.BottomOf(lblFinish, 6);
@@ -307,16 +274,28 @@ class function TCodeImportDlg.Execute(AOwner: TComponent;
end;
end;
-function TCodeImportDlg.GetFileNameFromEditCtrl: string;
+procedure TCodeImportDlg.FormDestroy(Sender: TObject);
+var
+ Idx: Integer;
begin
- Result := StrTrim(edFile.Text);
+ inherited;
+ // Free the TBox<> objects stored in list item data pointer
+ for Idx := Pred(lvImports.Items.Count) downto 0 do
+ TObject(lvImports.Items[Idx].Data).Free;
+end;
+
+function TCodeImportDlg.GetCollectionID: TCollectionID;
+begin
+ {TODO -cCollections: Add code to get user's choice of collection into which
+ snippets are to be imported. Will need a drop down list of available
+ collections. At present, only the "user" collection is permitted.
+ }
+ Result := TCollectionID.__TMP__UserDBCollectionID;
end;
-function TCodeImportDlg.GetImportAsNameFromLV(const Item: TListItem): string;
+function TCodeImportDlg.GetFileNameFromEditCtrl: string;
begin
- if Item.SubItems.Count <= cLVImportName then
- Exit('');
- Result := Item.SubItems[cLVImportName];
+ Result := StrTrim(edFile.Text);
end;
function TCodeImportDlg.HeadingText(const PageIdx: Integer): string;
@@ -337,7 +316,6 @@ function TCodeImportDlg.HeadingText(const PageIdx: Integer): string;
procedure TCodeImportDlg.InitImportInfo;
- // ---------------------------------------------------------------------------
/// Creates a new list view items containing given information.
procedure AddListItem(const Info: TImportInfo);
var
@@ -345,13 +323,11 @@ procedure TCodeImportDlg.InitImportInfo;
begin
LI := lvImports.Items.Add;
LI.SubItems.Add('');
- LI.SubItems.Add('');
- LI.Caption := Info.OrigKey;
- SetImportNameInLV(LI, Info.ImportAsKey);
+ LI.Caption := Info.DisplayName;
LI.Checked := not Info.Skip;
+ LI.Data := TBox.Create(Info);
UpdateActionDisplay(LI);
end;
- // ---------------------------------------------------------------------------
var
InfoItem: TImportInfo; // import info item describing an imported snippet
@@ -375,6 +351,7 @@ constructor TCodeImportDlg.InternalCreate(AOwner: TComponent;
begin
inherited InternalCreate(AOwner);
fImportMgr := ImportMgr;
+ fImportMgr.RequestCollectionCallback := GetCollectionID;
end;
procedure TCodeImportDlg.lvImportsItemChecked(Sender: TObject; Item: TListItem);
@@ -383,13 +360,6 @@ procedure TCodeImportDlg.lvImportsItemChecked(Sender: TObject; Item: TListItem);
UpdateImportData(Item);
end;
-procedure TCodeImportDlg.lvImportsSelectItem(Sender: TObject; Item: TListItem;
- Selected: Boolean);
-begin
- if Assigned(Item) then
- edRename.Text := GetImportAsNameFromLV(Item);
-end;
-
procedure TCodeImportDlg.MoveForward(const PageIdx: Integer;
var CanMove: Boolean);
begin
@@ -415,7 +385,6 @@ procedure TCodeImportDlg.MoveForward(const PageIdx: Integer;
procedure TCodeImportDlg.PresentResults;
- // ---------------------------------------------------------------------------
/// Creates a label containing name of an imported snippet and adds it to
/// scroll box with top at given position.
procedure AddLabel(var Top: Integer; const SnippetName: string);
@@ -429,7 +398,6 @@ procedure TCodeImportDlg.PresentResults;
Lbl.Caption := '� ' + SnippetName;
Top := TCtrlArranger.BottomOf(Lbl, 2);
end;
- // ---------------------------------------------------------------------------
var
DataItem: TImportInfo; // description of each snippet from import file
@@ -440,7 +408,7 @@ procedure TCodeImportDlg.PresentResults;
begin
if DataItem.Skip then
Continue;
- AddLabel(LblTop, DataItem.ImportAsKey);
+ AddLabel(LblTop, DataItem.DisplayName);
end;
end;
@@ -457,14 +425,6 @@ procedure TCodeImportDlg.SetActionInLV(const Item: TListItem;
Item.SubItems[cLVActionIdx] := Value;
end;
-procedure TCodeImportDlg.SetImportNameInLV(const Item: TListItem;
- const Value: string);
-begin
- if Item.SubItems.Count <= cLVImportName then
- Exit;
- Item.SubItems[cLVImportName] := Value;
-end;
-
procedure TCodeImportDlg.UpdateActionDisplay(const Item: TListItem);
resourcestring
// description of actions
@@ -505,21 +465,13 @@ procedure TCodeImportDlg.UpdateDatabase;
end;
procedure TCodeImportDlg.UpdateImportData(const Item: TListItem);
-var
- DataItem: TImportInfo; // description of each snippet from import file
- Idx: Integer; // index of selected snippet name in import info list
begin
if not Assigned(Item) then
Exit;
- Idx := fImportMgr.ImportInfo.IndexOfKey(Item.Caption);
- if Idx = -1 then
- raise EBug.Create(
- ClassName + '.UpdateImportData: Can''t find import data item.'
- );
- DataItem := TImportInfo.Create(
- Item.Caption, GetImportAsNameFromLV(Item), not Item.Checked
+ fImportMgr.ImportInfo.SetSkip(
+ TBox(Item.Data).Value.OrigKey,
+ not Item.Checked
);
- fImportMgr.ImportInfo.Items[Idx] := DataItem;
end;
procedure TCodeImportDlg.ValidatePage(const PageIdx: Integer);
@@ -548,29 +500,4 @@ procedure TCodeImportDlg.ValidatePage(const PageIdx: Integer);
end;
end;
-function TCodeImportDlg.ValidateSnippetName(const Name: string;
- const Item: TListItem; out ErrMsg: string): Boolean;
-resourcestring
- // Error message
- sDuplicateName = '"%s" duplicates a name in the import list.';
-var
- LI: TListItem; // each list item in list view
-begin
- // Checks snippet name for being well formed and not already in user database
- Result := TSnippetValidator.ValidateName(Name, True, ErrMsg);
- if not Result then
- Exit;
- // Checks name not already used for other imported snippets
- for LI in lvImports.Items do
- begin
- if LI = Item then
- Continue; // this is item we're about to change: ignore its name
- if StrSameText(Name, GetImportAsNameFromLV(LI)) then
- begin
- ErrMsg := Format(sDuplicateName, [Name]);
- Exit(False);
- end;
- end;
-end;
-
end.
diff --git a/Src/UCodeImportExport.pas b/Src/UCodeImportExport.pas
index 902edc10b..6940a699d 100644
--- a/Src/UCodeImportExport.pas
+++ b/Src/UCodeImportExport.pas
@@ -427,6 +427,8 @@ procedure TCodeImporter.Execute(const Data: TBytes);
fSnippetInfo[Idx].Data.Props.DisplayName := TXMLDocHelper.GetSubTagText(
fXMLDoc, SnippetNode, cDisplayNameNode
);
+ if fSnippetInfo[Idx].Data.Props.DisplayName = '' then
+ fSnippetInfo[Idx].Data.Props.DisplayName := fSnippetInfo[Idx].Key;
fSnippetInfo[Idx].Data.Props.SourceCode := TXMLDocHelper.GetSubTagText(
fXMLDoc, SnippetNode, cSourceCodeTextNode
);
diff --git a/Src/UCodeImportMgr.pas b/Src/UCodeImportMgr.pas
index 2410bfc27..b1e71dec2 100644
--- a/Src/UCodeImportMgr.pas
+++ b/Src/UCodeImportMgr.pas
@@ -18,9 +18,14 @@ interface
uses
// Delphi
- Generics.Collections, Generics.Defaults,
+ SysUtils,
+ Generics.Collections,
+ Generics.Defaults,
// Project
- UCodeImportExport, UExceptions, UIStringList;
+ DB.UCollections,
+ UCodeImportExport,
+ UExceptions,
+ UIStringList;
type
@@ -31,17 +36,16 @@ TImportInfo = record
strict private
// Property values
fOrigKey: string;
- fImportAsKey: string;
+ fDisplayName: string;
fSkip: Boolean;
public
/// Initialises properties to given values.
- constructor Create(const AOrigKey, AImportAsKey: string;
+ constructor Create(const AOrigKey, ADisplayName: string;
const ASkip: Boolean = False);
/// Snippet key per import file.
property OrigKey: string read fOrigKey;
- /// Key of snippet to be used when updating database.
- /// Can be changed by user.
- property ImportAsKey: string read fImportAsKey write fImportAsKey;
+ /// Snippet's display name.
+ property DisplayName: string read fDisplayName;
/// Flag indicating if snippet is to be skipped (ignored) when
/// updating database.
property Skip: Boolean read fSkip write fSkip;
@@ -78,6 +82,12 @@ TImportInfoList = class(TList)
/// Returns index of record in list whose OrigKey field matches
/// given name or -1 if name not found.
function IndexOfKey(const Key: string): Integer;
+ /// Updates Skip property of a given list item.
+ /// string [in] Key that identifies list item to
+ /// be updated.
+ /// Boolean [in] Value to be stored in the given
+ /// list item's Skip property.
+ procedure SetSkip(const AKey: string; const AFlag: Boolean);
end;
type
@@ -94,27 +104,11 @@ TCodeImportMgr = class sealed(TObject)
fSnippetInfoList: TSnippetInfoList;
/// Value of ImportInfo property.
fImportInfoList: TImportInfoList;
+ /// Value of RequestCollectionCallback property.
+ fRequestCollectionCallback: TFunc;
/// Initialises import information list with details of snippets
/// read from import file.
procedure InitImportInfoList;
- /// Returns list of names that can't be used to rename an imported
- /// snippet.
- /// string [in] Name of snippet to be excluded
- /// from import list.
- /// IStringList: List of disallowed snippet names.
- /// List is made up of all names of snippets in user database plus
- /// names of all imported snippets except for ExcludedName. ExcludedName
- /// should be the name of a snippet being renamed.
- function DisallowedNames(const ExcludedName: string): IStringList;
- /// Returns a name for snippet SnippetName that does not already
- /// exist in user database or imported snippet list.
- ///
- /// If SnippetName is not in user database then it is returned
- /// unchanged.
- /// If SnippetName is in user database then numbers are appended
- /// sequentially until a unique name is found.
- ///
- function GetUniqueSnippetName(const SnippetName: string): string;
public
/// Constructor. Sets up object.
constructor Create;
@@ -133,6 +127,12 @@ TCodeImportMgr = class sealed(TObject)
/// List of information describing if and how to import snippets
/// in import file. Permits customisation of import.
property ImportInfo: TImportInfoList read fImportInfoList;
+ /// Callback that gets the ID of the collection that will receive
+ /// the imported snippets.
+ /// Defaults to the "user" collection ID if not assigned.
+ ///
+ property RequestCollectionCallback: TFunc
+ read fRequestCollectionCallback write fRequestCollectionCallback;
end;
type
@@ -148,11 +148,9 @@ implementation
uses
// Delphi
- SysUtils,
Classes,
// Project
ActiveText.UMain,
- DB.UCollections,
DB.UMain,
DB.USnippet,
UIOUtils,
@@ -167,6 +165,13 @@ constructor TCodeImportMgr.Create;
inherited Create;
SetLength(fSnippetInfoList, 0);
fImportInfoList := TImportInfoList.Create;
+ // set default event handler
+ fRequestCollectionCallback := function: TCollectionID
+ begin
+ {TODO -cCollections: Require a TCollections.DefaultCollection method or
+ similar to replace the following __TMP__ method call.}
+ Result := TCollectionID.__TMP__UserDBCollectionID;
+ end;
end;
destructor TCodeImportMgr.Destroy;
@@ -176,38 +181,6 @@ destructor TCodeImportMgr.Destroy;
inherited;
end;
-function TCodeImportMgr.DisallowedNames(const ExcludedName: string):
- IStringList;
-var
- Snippet: TSnippet; // each snippet in user database
- SnippetInfo: TSnippetInfo; // info about each imported snippet
-begin
- Result := TIStringList.Create;
- Result.CaseSensitive := False;
- for Snippet in Database.Snippets do
- if Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
- Result.Add(Snippet.Key);
- for SnippetInfo in fSnippetInfoList do
- if not StrSameText(SnippetInfo.Key, ExcludedName) then
- Result.Add(SnippetInfo.Key);
-end;
-
-function TCodeImportMgr.GetUniqueSnippetName(
- const SnippetName: string): string;
-var
- UsedNames: IStringList; // list of snippet names in use
- Postfix: Cardinal; // number to be appended to name to make unique
-begin
- UsedNames := DisallowedNames(SnippetName);
- if not UsedNames.Contains(SnippetName) then
- Exit(SnippetName);
- Postfix := 1;
- repeat
- Inc(PostFix);
- Result := SnippetName + IntToStr(PostFix);
- until not UsedNames.Contains(Result);
-end;
-
procedure TCodeImportMgr.Import(const FileName: string);
var
Data: TBytes; // content of import file as bytes
@@ -228,13 +201,19 @@ procedure TCodeImportMgr.Import(const FileName: string);
procedure TCodeImportMgr.InitImportInfoList;
var
SnippetInfo: TSnippetInfo; // info about each snippet in import file
+
begin
fImportInfoList.Clear;
for SnippetInfo in fSnippetInfoList do
begin
fImportInfoList.Add(
TImportInfo.Create(
- SnippetInfo.Key, GetUniqueSnippetName(SnippetInfo.Key)
+ SnippetInfo.Key,
+ StrIf(
+ SnippetInfo.Data.Props.DisplayName = '',
+ SnippetInfo.Key,
+ SnippetInfo.Data.Props.DisplayName
+ )
)
);
end;
@@ -269,11 +248,14 @@ procedure TCodeImportMgr.UpdateDatabase;
Snippet: TSnippet; // reference any existing snippet to overwrite
SnippetInfo: TSnippetInfo; // info about each snippet from import file
ImportInfo: TImportInfo; // info about how / whether to import a snippet
+ CollectionID: TCollectionID;
+ SnippetKey: string;
resourcestring
// Error message
sBadNameError = 'Can''t find snippet with key "%s" in import data';
begin
Editor := Database as IDatabaseEdit;
+ CollectionID := RequestCollectionCallback();
for SnippetInfo in fSnippetInfoList do
begin
if not fImportInfoList.FindByKey(SnippetInfo.Key, ImportInfo) then
@@ -284,24 +266,27 @@ procedure TCodeImportMgr.UpdateDatabase;
AdjustDependsList(SnippetInfo.Data.Refs.Depends);
- Snippet := Database.Snippets.Find(ImportInfo.ImportAsKey, TCollectionID.__TMP__UserDBCollectionID);
+ Snippet := Database.Snippets.Find(ImportInfo.OrigKey, CollectionID);
if Assigned(Snippet) then
- // snippet already exists: overwrite it
- Editor.UpdateSnippet(Snippet, SnippetInfo.Data)
+ SnippetKey := (Database as IDatabaseEdit).GetUniqueSnippetKey(
+ CollectionID
+ )
else
- // snippet is new: add to database
- Editor.AddSnippet(ImportInfo.ImportAsKey, SnippetInfo.Data);
+ SnippetKey := ImportInfo.OrigKey;
+ Editor.AddSnippet(SnippetKey, SnippetInfo.Data);
+ {TODO -cVault: Reintroduce the option to overwrite a snippet with matching
+ ID, but allow user to select whether this can happen.}
end;
end;
{ TImportInfo }
-constructor TImportInfo.Create(const AOrigKey, AImportAsKey: string;
- const ASkip: Boolean);
+constructor TImportInfo.Create(const AOrigKey, ADisplayName: string;
+ const ASkip: Boolean = False);
begin
fOrigKey := AOrigKey;
- fImportAsKey := AImportAsKey;
fSkip := ASkip;
+ fDisplayName := ADisplayName;
end;
{ TImportInfoComparer }
@@ -323,7 +308,7 @@ function TImportInfoList.FindByKey(const Key: string;
var
Idx: Integer; // index of named snippet in list
begin
- Idx := IndexOf(TImportInfo.Create(Key, ''));
+ Idx := IndexOfKey(Key);
if Idx = -1 then
Exit(False);
ImportInfo := Items[Idx];
@@ -335,5 +320,21 @@ function TImportInfoList.IndexOfKey(const Key: string): Integer;
Result := IndexOf(TImportInfo.Create(Key, ''));
end;
+procedure TImportInfoList.SetSkip(const AKey: string; const AFlag: Boolean);
+const
+ // Do not localise
+ sKeyNotFound = 'Snippet key "%s" not found while setting import skip flag';
+var
+ ImportInfo: TImportInfo;
+ Idx: Integer;
+begin
+ Idx := IndexOfKey(AKey);
+ if Idx < 0 then
+ raise EBug.CreateFmt(sKeyNotFound, [AKey]);
+ ImportInfo := Items[Idx];
+ ImportInfo.Skip := AFlag;
+ Items[Idx] := ImportInfo;
+end;
+
end.
From eb51720c1d3cf6a28a3ace4801ef5b58f4086e24 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Fri, 8 Nov 2024 17:35:28 +0000
Subject: [PATCH 053/222] Change how SWAG import handles snippet keys
The snippet key under which a SWAG snippet is to be created has been
changed. It was previously created from concatenating "SWAG" with the
SWAG ID number of the snippet. It is now generated by calling
IDatabaseEdit.GetUniqueSnippetKey, which brings it into line with how
other parts of CodeSnip create new keys. As part of this change, the ID
of the collection receiving the snippets was required.
A method was added to TSWAGImportDlg to get the ID of the collection in
which to add imported SWAG snippets. This method is a stub that always
returns the "user" collection ID. In later updates it will be changed to
get the required collection from the user.
The SWAG import wizard no longer displays the key to be used for
imported snippets.
---
Src/FmSWAGImportDlg.dfm | 15 +++++---------
Src/FmSWAGImportDlg.pas | 21 ++++++++++++++++++--
Src/SWAG.UImporter.pas | 43 +++++++++++++----------------------------
3 files changed, 37 insertions(+), 42 deletions(-)
diff --git a/Src/FmSWAGImportDlg.dfm b/Src/FmSWAGImportDlg.dfm
index e93311a78..534e58ae8 100644
--- a/Src/FmSWAGImportDlg.dfm
+++ b/Src/FmSWAGImportDlg.dfm
@@ -192,11 +192,10 @@ inherited SWAGImportDlg: TSWAGImportDlg
AutoSize = False
Caption =
'You have chosen to import the following SWAG packets as CodeSnip' +
- ' snippets. They will be imported with the given Display Names an' +
- 'd Packet IDs. You can change these if you wish using the Snippet' +
- 's Editor. To make changes go back to the previous page. When you' +
- ' are ready to import the packets click "Import". This step can'#39't' +
- ' be undone.'
+ ' snippets with the given Display Names. You can change these nam' +
+ 'es later, if you wish, using the Snippets Editor. To modify your' +
+ ' selection go back to the previous page. When you are ready to i' +
+ 'mport the packets click "Import". This step can'#39't be undone.'
WordWrap = True
end
object lvImports: TListView
@@ -207,11 +206,7 @@ inherited SWAGImportDlg: TSWAGImportDlg
Columns = <
item
Caption = 'Packet Title '#8594' Snippet Display Name'
- Width = 400
- end
- item
- Caption = 'Snippet Name from SWAG ID'
- Width = 200
+ Width = 600
end>
ColumnClick = False
GridLines = True
diff --git a/Src/FmSWAGImportDlg.pas b/Src/FmSWAGImportDlg.pas
index ffe252edc..a6e3db4eb 100644
--- a/Src/FmSWAGImportDlg.pas
+++ b/Src/FmSWAGImportDlg.pas
@@ -24,9 +24,11 @@ interface
StdCtrls,
Forms,
ExtCtrls,
+ ActnList,
Classes,
Generics.Collections,
// Project
+ DB.UCollections,
FmWizardDlg,
FrBrowserBase,
FrFixedHTMLDlg,
@@ -37,7 +39,7 @@ interface
UCSSBuilder,
SWAG.UCommon,
SWAG.UImporter,
- SWAG.UReader, ActnList;
+ SWAG.UReader;
type
@@ -106,6 +108,9 @@ TSWAGImportDlg = class(TWizardDlg, INoPublicConstruct)
procedure actDisplayPacketUpdate(Sender: TObject);
strict private
const
+ {TODO -cCollections: Add combo box to select collection into which to add
+ imported snippets. Either add combo box to update page, or add a
+ new page for it before finish page or before update page.}
/// Index of introductory page in wizard.
cIntroPage = 0;
/// Index of SWAG database folder selection page in wizard.
@@ -140,6 +145,10 @@ TSWAGImportDlg = class(TWizardDlg, INoPublicConstruct)
/// Retrieves import directory name from edit control where it is
/// entered.
function GetDirNameFromEditCtrl: string;
+ /// Retrieves collection specified by user that applies to
+ /// imported snippets.
+ /// TCollectionID. The required collection ID.
+ function SelectedCollectionID: TCollectionID;
/// Validates entries on the wizard page identified by the given
/// page index.
procedure ValidatePage(const PageIdx: Integer);
@@ -771,7 +780,6 @@ procedure TSWAGImportDlg.PopulateImportsLV;
begin
LI := lvImports.Items.Add;
LI.Caption := Packet.Title;
- LI.SubItems.Add(TSWAGImporter.MakeValidSnippetName(Packet.ID));
end;
finally
lvImports.Items.EndUpdate;
@@ -823,6 +831,14 @@ procedure TSWAGImportDlg.PreviewSelectedPacket;
);
end;
+function TSWAGImportDlg.SelectedCollectionID: TCollectionID;
+begin
+ {TODO -cCollections: Replace the following __TMP__ method with collection ID
+ selected by user from a combo box. DO NOT permit this choice when
+ editing an existing snippet.}
+ Result := TCollectionID.__TMP__UserDBCollectionID;
+end;
+
procedure TSWAGImportDlg.UpdateButtons(const PageIdx: Integer);
resourcestring
// button caption for update page
@@ -856,6 +872,7 @@ procedure TSWAGImportDlg.UpdateDatabase;
procedure
begin
fImporter.Import(
+ SelectedCollectionID,
procedure (const Packet: TSWAGPacket)
begin
Application.ProcessMessages;
diff --git a/Src/SWAG.UImporter.pas b/Src/SWAG.UImporter.pas
index ab193dd22..131d565da 100644
--- a/Src/SWAG.UImporter.pas
+++ b/Src/SWAG.UImporter.pas
@@ -21,6 +21,7 @@ interface
Generics.Collections,
// Project
ActiveText.UMain,
+ DB.UCollections,
DB.USnippet,
SWAG.UCommon;
@@ -57,7 +58,8 @@ TSWAGImporter = class(TObject)
TSnippetEditData;
/// Imports (i.e. adds) the given SWAG packet into the user
/// database as a CodeSnip format snippet.
- procedure ImportPacketAsSnippet(const SWAGPacket: TSWAGPacket);
+ procedure ImportPacketAsSnippet(const ACollectionID: TCollectionID;
+ const SWAGPacket: TSWAGPacket);
public
/// Constructs new object instance.
constructor Create;
@@ -76,11 +78,8 @@ TSWAGImporter = class(TObject)
/// called after each SWAG packet is imported.
/// The packets that are imported are those that have been
/// recorded by calling IncludePacket.
- procedure Import(const Callback: TProgressCallback = nil);
- /// Creates and returns a valid CodeSnip snippet name, based on
- /// the given SWAG packet ID, that is unique in the user database.
- ///
- class function MakeValidSnippetName(SWAGPacketID: Cardinal): string;
+ procedure Import(const ACollectionID: TCollectionID;
+ const Callback: TProgressCallback = nil);
/// Description of the category in the user database used for all
/// imported SWAG packets.
class function SWAGCategoryDesc: string;
@@ -234,7 +233,8 @@ function TSWAGImporter.ExtraBoilerplate: IActiveText;
Result := fExtraBoilerplate;
end;
-procedure TSWAGImporter.Import(const Callback: TProgressCallback);
+procedure TSWAGImporter.Import(const ACollectionID: TCollectionID;
+ const Callback: TProgressCallback);
var
SWAGPacket: TSWAGPacket;
begin
@@ -242,18 +242,19 @@ procedure TSWAGImporter.Import(const Callback: TProgressCallback);
begin
if Assigned(Callback) then
Callback(SWAGPacket);
- ImportPacketAsSnippet(SWAGPacket);
+ ImportPacketAsSnippet(ACollectionID, SWAGPacket);
end;
end;
-procedure TSWAGImporter.ImportPacketAsSnippet(const SWAGPacket: TSWAGPacket);
+procedure TSWAGImporter.ImportPacketAsSnippet(
+ const ACollectionID: TCollectionID; const SWAGPacket: TSWAGPacket);
var
- SnippetName: string; // unique name of new snippet
+ SnippetKey: string; // unique ID of new snippet
SnippetDetails: TSnippetEditData; // data describing new snippet
begin
- SnippetName := MakeValidSnippetName(SWAGPacket.ID);
+ SnippetKey := (Database as IDatabaseEdit).GetUniqueSnippetKey(ACollectionID);
SnippetDetails := BuildSnippetInfo(SWAGPacket);
- (Database as IDatabaseEdit).AddSnippet(SnippetName, SnippetDetails);
+ (Database as IDatabaseEdit).AddSnippet(SnippetKey, SnippetDetails);
end;
procedure TSWAGImporter.IncludePacket(const SWAGPacket: TSWAGPacket);
@@ -261,24 +262,6 @@ procedure TSWAGImporter.IncludePacket(const SWAGPacket: TSWAGPacket);
fImportList.Add(SWAGPacket);
end;
-class function TSWAGImporter.MakeValidSnippetName(SWAGPacketID: Cardinal):
- string;
-var
- Appendix: Integer;
- RootName: string;
-begin
- RootName := 'SWAG_' + IntToStr(SWAGPacketID);
- Assert(IsValidIdent(RootName, False), ClassName
- + '.MakeValidSnippetName: RootName is not a valid snippet identifier');
- Result := RootName;
- Appendix := 0;
- while not TSnippetValidator.ValidateName(Result, True) do
- begin
- Inc(Appendix);
- Result := RootName + '_' + IntToStr(Appendix);
- end;
-end;
-
procedure TSWAGImporter.Reset;
begin
fImportList.Clear;
From 667a3bafc7dcd51fa882be5473376e231b5a20d4 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Fri, 8 Nov 2024 18:03:15 +0000
Subject: [PATCH 054/222] Removed all TSnippetValidator.ValidateName overloads
The TSnippetValidator.ValidateName overloads are no longer required or
called now that snippet keys are not user-editable: program generated
keys are guaranteed to be valid.
Also removed call to TSnippetValidator.ValidateName from TSnippetValidator.Validate that validates an entire snippet, because snippets cannot now be created with invalid keys.
---
Src/USnippetValidator.pas | 99 ++-------------------------------------
1 file changed, 3 insertions(+), 96 deletions(-)
diff --git a/Src/USnippetValidator.pas b/Src/USnippetValidator.pas
index d3452ea15..0cbcdd7c9 100644
--- a/Src/USnippetValidator.pas
+++ b/Src/USnippetValidator.pas
@@ -79,37 +79,6 @@ TSnippetValidator = class(TNoConstructObject)
@param ErrorSel [out] Selection that can be used to highlight error.
@return True if description is valid or False if not.
}
- class function ValidateName(const Key: string;
- const CheckForUniqueness: Boolean): Boolean; overload;
- {Validates a snippet's key.
- @param Key [in] Snippet key to be checked.
- @param CheckForUniqueness [in] Flag indicating whether a check should
- be made to see if snippet key is already in user database.
- @return True if key is valid or False if not.
- }
- class function ValidateName(const Key: string;
- const CheckForUniqueness: Boolean; out ErrorMsg: string): Boolean;
- overload;
- {Validates a snippet's key.
- @param Key [in] Snippet key to be checked.
- @param CheckForUniqueness [in] Flag indicating whether a check should
- be made to see if snippet key is already in user database.
- @param ErrorMsg [out] Message that describes error. Undefined if True
- returned.
- @return True if key is valid or False if not.
- }
- class function ValidateName(const Key: string;
- const CheckForUniqueness: Boolean; out ErrorMsg: string;
- out ErrorSel: TSelection): Boolean; overload;
- {Validates a snippet's key.
- @param Key [in] Snippet key to be checked.
- @param CheckForUniqueness [in] Flag indicating whether a check should
- be made to see if snippet key is already in user database.
- @param ErrorMsg [out] Message that describes error. Undefined if True
- returned.
- @param ErrorSel [out] Selection that can be used to highlight error.
- @return True if key is valid or False if not.
- }
class function ValidateExtra(const Extra: IActiveText;
out ErrorMsg: string): Boolean;
{Validates a extra information from a snippet.
@@ -183,8 +152,9 @@ class function TSnippetValidator.Validate(const Snippet: TSnippet;
@return True if snippet valid or False if not.
}
begin
- Result := ValidateName(Snippet.Key, False, ErrorMsg, ErrorSel)
- and ValidateDescription(Snippet.Description.ToString, ErrorMsg, ErrorSel)
+ Result :=
+ {TODO -cVault: Add validation of display name here}
+ ValidateDescription(Snippet.Description.ToString, ErrorMsg, ErrorSel)
and ValidateSourceCode(Snippet.SourceCode, ErrorMsg, ErrorSel)
and ValidateDependsList(Snippet, ErrorMsg)
and ValidateExtra(Snippet.Extra, ErrorMsg);
@@ -372,69 +342,6 @@ class function TSnippetValidator.ValidateExtra(const Extra: IActiveText;
ErrorMsg := ErrorInfo.Description;
end;
-class function TSnippetValidator.ValidateName(const Key: string;
- const CheckForUniqueness: Boolean; out ErrorMsg: string): Boolean;
- {Validates a snippet's key.
- @param Key [in] Snippet key to be checked.
- @param CheckForUniqueness [in] Flag indicating whether a check should be
- made to see if snippet key is already in user database.
- @param ErrorMsg [out] Message that describes error. Undefined if True
- returned.
- @return True if key is valid or False if not.
- }
-resourcestring
- // Error messages
- sErrNoKey = 'A key must be provided';
- sErrDupKey = 'Key "%s" is already in the database. Please choose another key';
- sErrBadKey = '"%s" is not a valid Pascal identifier';
-var
- TrimmedKey: string; // Key param trimmed of leading trailing spaces
-begin
- Result := False;
- TrimmedKey := StrTrim(Key);
- if TrimmedKey = '' then
- ErrorMsg := sErrNoKey
- else if not IsValidIdent(TrimmedKey) then
- ErrorMsg := Format(sErrBadKey, [TrimmedKey])
- else if CheckForUniqueness and
- (Database.Snippets.Find(TrimmedKey, TCollectionID.__TMP__UserDBCollectionID) <> nil) then
- ErrorMsg := Format(sErrDupKey, [TrimmedKey])
- else
- Result := True;
-end;
-
-class function TSnippetValidator.ValidateName(const Key: string;
- const CheckForUniqueness: Boolean; out ErrorMsg: string;
- out ErrorSel: TSelection): Boolean;
- {Validates a snippet's key.
- @param Key [in] Snippet key to be checked.
- @param CheckForUniqueness [in] Flag indicating whether a check should be
- made to see if snippet key is already in user database.
- @param ErrorMsg [out] Message that describes error. Undefined if True
- returned.
- @param ErrorSel [out] Selection that can be used to highlight error.
- @return True if key is valid or False if not.
- }
-begin
- Result := ValidateName(Key, CheckForUniqueness, ErrorMsg);
- if not Result then
- ErrorSel := TSelection.Create(0, Length(Key));
-end;
-
-class function TSnippetValidator.ValidateName(const Key: string;
- const CheckForUniqueness: Boolean): Boolean;
- {Validates a snippet's key.
- @param Key [in] Snippet key to be checked.
- @param CheckForUniqueness [in] Flag indicating whether a check should be
- made to see if snippet key is already in user database.
- @return True if key is valid or False if not.
- }
-var
- DummyErrMsg: string;
-begin
- Result := ValidateName(Key, CheckForUniqueness, DummyErrMsg);
-end;
-
class function TSnippetValidator.ValidateSourceCode(const Source: string;
out ErrorMsg: string; out ErrorSel: TSelection): Boolean;
{Validates a source code from a snippet.
From a909774993b7046f2e3ed3a9faac0409bc4b9121 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 9 Nov 2024 00:40:29 +0000
Subject: [PATCH 055/222] Change property names in snippet related actions
Renamed `SnippetName` property to `Key` in both TSnippetAction and
TEditSnippetAction.
Updated calling code re the renaming.
---
Src/FmMain.pas | 2 +-
Src/UEditSnippetAction.pas | 16 +++++++++-------
Src/UNotifier.pas | 4 ++--
Src/USnippetAction.pas | 26 +++++++++++++++-----------
4 files changed, 27 insertions(+), 21 deletions(-)
diff --git a/Src/FmMain.pas b/Src/FmMain.pas
index 6b04f8107..606a035a1 100644
--- a/Src/FmMain.pas
+++ b/Src/FmMain.pas
@@ -762,7 +762,7 @@ procedure TMainForm.ActEditDeleteSnippetUpdate(Sender: TObject);
procedure TMainForm.ActEditSnippetByNameExecute(Sender: TObject);
begin
- TUserDBMgr.EditSnippet((Sender as TEditSnippetAction).SnippetName);
+ TUserDBMgr.EditSnippet((Sender as TEditSnippetAction).Key);
end;
procedure TMainForm.actEditSnippetExecute(Sender: TObject);
diff --git a/Src/UEditSnippetAction.pas b/Src/UEditSnippetAction.pas
index 4b33cc385..8763da475 100644
--- a/Src/UEditSnippetAction.pas
+++ b/Src/UEditSnippetAction.pas
@@ -5,7 +5,7 @@
*
* Copyright (C) 2008-2021, Peter Johnson (gravatar.com/delphidabbler).
*
- * Custom action used to request editing of a named user-defined snippet.
+ * Custom action used to request editing of a user-defined snippet.
}
@@ -20,19 +20,21 @@ interface
Classes;
+{TODO -cCollections: Add a collection ID property, or change Key property to ID of
+ type TSnippetID.}
+
type
///
- /// Custom action used to request that a named user defined snippet is
- /// edited.
+ /// Custom action used to request that a user defined snippet is edited.
///
TEditSnippetAction = class(TBasicAction)
strict private
var
- /// Value of SnippetName property.
- fSnippetName: string;
+ /// Value of Key property.
+ fKey: string;
public
- /// Name of snippet to be edited.
- property SnippetName: string read fSnippetName write fSnippetName;
+ /// Key of snippet to be edited.
+ property Key: string read fKey write fKey;
end;
diff --git a/Src/UNotifier.pas b/Src/UNotifier.pas
index 34df201cf..e4fc727b1 100644
--- a/Src/UNotifier.pas
+++ b/Src/UNotifier.pas
@@ -259,7 +259,7 @@ procedure TNotifier.DisplaySnippet(const Key: WideString;
begin
if Assigned(fDisplaySnippetAction) then
begin
- (fDisplaySnippetAction as TSnippetAction).SnippetName := Key;
+ (fDisplaySnippetAction as TSnippetAction).Key := Key;
(fDisplaySnippetAction as TSnippetAction).CollectionID := ACollectionID;
(fDisplaySnippetAction as TSnippetAction).NewTab := NewTab;
fDisplaySnippetAction.Execute;
@@ -270,7 +270,7 @@ procedure TNotifier.EditSnippet(const Key: WideString);
begin
if Assigned(fEditSnippetAction) then
begin
- (fEditSnippetAction as TEditSnippetAction).SnippetName := Key;
+ (fEditSnippetAction as TEditSnippetAction).Key := Key;
fEditSnippetAction.Execute;
end;
end;
diff --git a/Src/USnippetAction.pas b/Src/USnippetAction.pas
index 6f801e5bc..5d17d1fcc 100644
--- a/Src/USnippetAction.pas
+++ b/Src/USnippetAction.pas
@@ -5,7 +5,7 @@
*
* Copyright (C) 2005-2021, Peter Johnson (gravatar.com/delphidabbler).
*
- * Custom action used to request display of a snippet by name.
+ * Custom action used to request display of a snippet by key and collection ID.
}
@@ -23,20 +23,22 @@ interface
IntfNotifier;
+{TODO -cVault: Combine the two TSnippetAction properties into a single
+ TSnippetID property.}
+
type
///
/// Custom action used to request display of a snippet.
///
///
- /// Required snippet is uniquely identified by its name and whether it is
- /// user defined or not.
+ /// Required snippet is uniquely identified by its key and collection ID.
///
TSnippetAction = class(TBasicAction, ISetNotifier)
strict private
var
- /// Value of SnippetName property.
- fSnippetName: string;
+ /// Value of Key property.
+ fKey: string;
/// Value of CollectionID property.
fCollectionID: TCollectionID;
/// Value of NewTab property.
@@ -57,12 +59,12 @@ TSnippetAction = class(TBasicAction, ISetNotifier)
/// Stores reference to given notifier object.
/// Implements ISetNotifier.SetNotifier
procedure SetNotifier(const Notifier: INotifier);
- /// Name of snippet to be displayed.
- property SnippetName: string read fSnippetName write fSnippetName;
+ /// Key of snippet to be displayed.
+ property Key: string read fKey write fKey;
/// ID of the collection containing the snippet to be displayed.
///
property CollectionID: TCollectionID read fCollectionID write fCollectionID;
- /// Flag indicating if snippet is to be displayed in new detail
+ /// Flag indicating if snippet is to be displayed in a new detail
/// pane tab.
property NewTab: Boolean read fNewTab write fNewTab;
end;
@@ -85,9 +87,11 @@ function TSnippetAction.Execute: Boolean;
Snippet: TSnippet; // snippet to be displayed
begin
Assert(Assigned(fNotifier), ClassName + '.Execute: Notifier not set');
- Assert(SnippetName <> '', ClassName + '.Execute: SnippetName not provided');
- Snippet := Database.Snippets.Find(SnippetName, fCollectionID);
- Assert(Assigned(Snippet), ClassName + '.Execute: SnippetName not valid');
+ Assert(Key <> '', ClassName + '.Execute: Key not provided');
+
+ Snippet := Database.Snippets.Find(Key, fCollectionID);
+ Assert(Assigned(Snippet), ClassName + '.Execute: Key not valid');
+
// Create a view item for snippet and get notifier to display it
fNotifier.ShowViewItem(TViewFactory.CreateSnippetView(Snippet), NewTab);
Result := False;
From aae1699aa649336ffdae03a6931df019780d10fa Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 9 Nov 2024 02:30:53 +0000
Subject: [PATCH 056/222] Add collection ID param to TDatabase.Add method
Also added collection ID parameter to TDatabase.InternalAdd.
Calling code and internal TDatabase code was updated re this change.
---
Src/DB.UMain.pas | 98 +++++++++++++++++++++----------------
Src/FmSnippetsEditorDlg.pas | 2 +-
Src/SWAG.UImporter.pas | 4 +-
Src/UCodeImportMgr.pas | 2 +-
4 files changed, 61 insertions(+), 45 deletions(-)
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index 6e5844c1e..59d089cfb 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -219,13 +219,17 @@ interface
key is not to change.
@return Reference to updated snippet. Will have changed.
}
- function AddSnippet(const SnippetKey: string;
- const Data: TSnippetEditData): TSnippet;
- {Adds a new snippet to the user database.
- @param SnippetKey [in] New snippet's key.
- @param Data [in] Record storing new snippet's properties and references.
- @return Reference to new snippet.
- }
+
+ /// Adds a new snippet to the database.
+ /// string [in] New snippet's key.
+ /// TCollectionID [in] ID of collection
+ /// that the new snippet will belong to.
+ /// TSnippetEditData [in] Record storing the new
+ /// snippet's properties and references.
+ /// TSnippet. Reference to the new snippet.
+ function AddSnippet(const AKey: string; const ACollectionID: TCollectionID;
+ const AData: TSnippetEditData): TSnippet;
+
function DuplicateSnippet(const Snippet: TSnippet;
const UniqueKey, DisplayName: string; const CatID: string): TSnippet;
function CreateTempSnippet(const SnippetKey: string;
@@ -390,14 +394,26 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
@param Info [in] Reference to any further information for event. May be
nil.
}
- function InternalAddSnippet(const SnippetKey: string;
- const Data: TSnippetEditData): TSnippet;
+
+ /// Adds a new snippet to the database. Assumes the snippet is
+ /// not already in the database.
+ /// string [in] New snippet's key.
+ /// TCollectionID [in] ID of collection
+ /// that the new snippet will belong to.
+ /// TSnippetEditData [in] Record storing the new
+ /// snippet's properties and references.
+ /// TSnippet. Reference to the new snippet.
+ /// ECodeSnip raised if the snippet's category does not
+ /// exist.
+ function InternalAddSnippet(const AKey: string;
+ const ACollectionID: TCollectionID; const AData: TSnippetEditData):
+ TSnippet;
{Adds a new snippet to the user database. Assumes snippet not already in
user database.
@param SnippetKey [in] New snippet's key.
@param Data [in] Properties and references of new snippet.
@return Reference to new snippet object.
- @except Exception raised if snippet's category does not exist.
+ @except Exception raised if
}
procedure InternalDeleteSnippet(const Snippet: TSnippet);
{Deletes a snippet from the user database.
@@ -497,13 +513,18 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
key is not to change.
@return Reference to updated snippet. Will have changed.
}
- function AddSnippet(const SnippetKey: string;
- const Data: TSnippetEditData): TSnippet;
- {Adds a new snippet to the user database.
- @param SnippetKey [in] New snippet's key.
- @param Data [in] Record storing new snippet's properties and references.
- @return Reference to new snippet.
- }
+
+ /// Adds a new snippet to the database.
+ /// string [in] New snippet's key.
+ /// TCollectionID [in] ID of collection
+ /// that the new snippet will belong to.
+ /// TSnippetEditData [in] Record storing the new
+ /// snippet's properties and references.
+ /// TSnippet. Reference to the new snippet.
+ /// Method of IDatabaseEdit.
+ function AddSnippet(const AKey: string; const ACollectionID: TCollectionID;
+ const AData: TSnippetEditData): TSnippet;
+
function DuplicateSnippet(const Snippet: TSnippet;
const UniqueKey, DisplayName: string; const CatID: string): TSnippet;
function CreateTempSnippet(const SnippetKey: string;
@@ -662,24 +683,19 @@ procedure TDatabase.AddChangeEventHandler(const Handler: TNotifyEventInfo);
fChangeEvents.AddHandler(Handler);
end;
-function TDatabase.AddSnippet(const SnippetKey: string;
- const Data: TSnippetEditData): TSnippet;
- {Adds a new snippet to the user database.
- @param SnippetKey [in] New snippet's key.
- @param Data [in] Record storing new snippet's properties and references.
- @return Reference to new snippet.
- }
+function TDatabase.AddSnippet(const AKey: string;
+ const ACollectionID: TCollectionID; const AData: TSnippetEditData): TSnippet;
resourcestring
// Error message
- sKeyExists = 'Snippet with key "%s" already exists in user database';
+ sKeyExists = 'Snippet with key "%s" already exists in collection';
begin
Result := nil; // keeps compiler happy
TriggerEvent(evChangeBegin);
try
// Check if snippet with same key exists in user database: error if so
- if fSnippets.Find(SnippetKey, TCollectionID.__TMP__UserDBCollectionID) <> nil then
- raise ECodeSnip.CreateFmt(sKeyExists, [SnippetKey]);
- Result := InternalAddSnippet(SnippetKey, Data);
+ if fSnippets.Find(AKey, ACollectionID) <> nil then
+ raise ECodeSnip.CreateFmt(sKeyExists, [AKey]);
+ Result := InternalAddSnippet(AKey, ACollectionID, AData);
Query.Update;
TriggerEvent(evSnippetAdded, Result);
finally
@@ -815,13 +831,14 @@ destructor TDatabase.Destroy;
function TDatabase.DuplicateSnippet(const Snippet: TSnippet;
const UniqueKey, DisplayName: string; const CatID: string): TSnippet;
+ {TODO -cCollections: Add collection ID parameter}
var
Data: TSnippetEditData;
begin
Data := (Snippet as TSnippetEx).GetEditData;
Data.Props.Cat := CatID;
Data.Props.DisplayName := DisplayName;
- Result := AddSnippet(UniqueKey, Data);
+ Result := AddSnippet(UniqueKey, TCollectionID.__TMP__UserDBCollectionID, Data);
end;
function TDatabase.GetCategories: TCategoryList;
@@ -974,15 +991,8 @@ function TDatabase.InternalAddCategory(const CatID: string;
fCategories.Add(Result);
end;
-function TDatabase.InternalAddSnippet(const SnippetKey: string;
- const Data: TSnippetEditData): TSnippet;
- {Adds a new snippet to the user database. Assumes snippet not already in user
- database.
- @param SnippetKey [in] New snippet's key.
- @param Data [in] Properties and references of new snippet.
- @return Reference to new snippet object.
- @except Exception raised if snippet's category does not exist.
- }
+function TDatabase.InternalAddSnippet(const AKey: string;
+ const ACollectionID: TCollectionID; const AData: TSnippetEditData): TSnippet;
var
Cat: TCategory; // category object containing new snippet
resourcestring
@@ -990,8 +1000,8 @@ function TDatabase.InternalAddSnippet(const SnippetKey: string;
sCatNotFound = 'Category "%0:s" referenced by new snippet with key "%1:s" '
+ 'does not exist';
begin
- Result := TSnippetEx.Create(SnippetKey, TCollectionID.__TMP__UserDBCollectionID, Data.Props);
- (Result as TSnippetEx).UpdateRefs(Data.Refs, fSnippets);
+ Result := TSnippetEx.Create(AKey, ACollectionID, AData.Props);
+ (Result as TSnippetEx).UpdateRefs(AData.Refs, fSnippets);
Cat := fCategories.Find(Result.Category);
if not Assigned(Cat) then
raise ECodeSnip.CreateFmt(sCatNotFound, [Result.Category, Result.Key]);
@@ -1193,6 +1203,10 @@ function TDatabase.Updated: Boolean;
function TDatabase.UpdateSnippet(const Snippet: TSnippet;
const Data: TSnippetEditData; const NewKey: string): TSnippet;
+ {TODO -cCollections: Don't need NewKey parameter: key never changes. Also
+ don't pass a collection ID, since that can never change either,
+ because to do so would (1) invalidate the key because key is only
+ guaranteed unique in collection and (2) would change the snippet ID}
{Updates a user defined snippet's properties and references using provided
data.
@param Snippet [in] Snippet to be updated. Must be user-defined.
@@ -1202,7 +1216,7 @@ function TDatabase.UpdateSnippet(const Snippet: TSnippet;
@return Reference to updated snippet. Will have changed.
}
var
- SnippetKey: string; // snippet key
+ SnippetKey: string; // snippet key
Dependent: TSnippet; // loops thru each snippetthat depends on Snippet
Dependents: TSnippetList; // list of dependent snippets
Referrer: TSnippet; // loops thru snippets that cross references Snippet
@@ -1243,7 +1257,7 @@ function TDatabase.UpdateSnippet(const Snippet: TSnippet;
// delete the snippet
InternalDeleteSnippet(Snippet);
// add new snippet
- Result := InternalAddSnippet(SnippetKey, Data);
+ Result := InternalAddSnippet(SnippetKey, TCollectionID.__TMP__UserDBCollectionID, Data);
// add new snippet to referrer list of referring snippets
for Referrer in Referrers do
Referrer.XRef.Add(Result);
diff --git a/Src/FmSnippetsEditorDlg.pas b/Src/FmSnippetsEditorDlg.pas
index 4b3f8ec64..a93d070cd 100644
--- a/Src/FmSnippetsEditorDlg.pas
+++ b/Src/FmSnippetsEditorDlg.pas
@@ -648,7 +648,7 @@ procedure TSnippetsEditorDlg.btnOKClick(Sender: TObject);
else
begin
(Database as IDatabaseEdit).AddSnippet(
- UniqueSnippetKey, fEditData
+ UniqueSnippetKey, SelectedCollectionID, fEditData
)
end;
except
diff --git a/Src/SWAG.UImporter.pas b/Src/SWAG.UImporter.pas
index 131d565da..23f359efb 100644
--- a/Src/SWAG.UImporter.pas
+++ b/Src/SWAG.UImporter.pas
@@ -254,7 +254,9 @@ procedure TSWAGImporter.ImportPacketAsSnippet(
begin
SnippetKey := (Database as IDatabaseEdit).GetUniqueSnippetKey(ACollectionID);
SnippetDetails := BuildSnippetInfo(SWAGPacket);
- (Database as IDatabaseEdit).AddSnippet(SnippetKey, SnippetDetails);
+ (Database as IDatabaseEdit).AddSnippet(
+ SnippetKey, ACollectionID, SnippetDetails
+ );
end;
procedure TSWAGImporter.IncludePacket(const SWAGPacket: TSWAGPacket);
diff --git a/Src/UCodeImportMgr.pas b/Src/UCodeImportMgr.pas
index b1e71dec2..8a91a2560 100644
--- a/Src/UCodeImportMgr.pas
+++ b/Src/UCodeImportMgr.pas
@@ -273,7 +273,7 @@ procedure TCodeImportMgr.UpdateDatabase;
)
else
SnippetKey := ImportInfo.OrigKey;
- Editor.AddSnippet(SnippetKey, SnippetInfo.Data);
+ Editor.AddSnippet(SnippetKey, CollectionID, SnippetInfo.Data);
{TODO -cVault: Reintroduce the option to overwrite a snippet with matching
ID, but allow user to select whether this can happen.}
end;
From b7e65378dfe177c89cd2f42d78ba6082134cb888 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 9 Nov 2024 03:18:10 +0000
Subject: [PATCH 057/222] Remove key parameter from TDatabase.UpdateSnippet
Revised TDatabase.UpdateSnippet to prevent the snippet key from being
changed. The `NewKey` parameter was removed.
Revised calling code in FmSnippetsEditorDlg re the changed signature of
TDatabase.UpdateSnippet.
---
Src/DB.UMain.pas | 122 +++++++++++++++++-------------------
Src/FmSnippetsEditorDlg.pas | 4 +-
2 files changed, 59 insertions(+), 67 deletions(-)
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index 59d089cfb..1078fd939 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -209,16 +209,18 @@ interface
@param Snippet [in] Snippet for which cross referers are required.
@return List of IDs of referring snippets.
}
- function UpdateSnippet(const Snippet: TSnippet;
- const Data: TSnippetEditData; const NewKey: string = ''): TSnippet;
- {Updates a user defined snippet's properties and references using provided
- data.
- @param Snippet [in] Snippet to be updated. Must be user-defined.
- @param Data [in] Record containing revised data.
- @param NewKey [in] New snippet's key. Set to '' or Snippet.Key if
- key is not to change.
- @return Reference to updated snippet. Will have changed.
- }
+
+ /// Updates a snippet's properties and references using the
+ /// provided data.
+ /// TSnippet [in] Snippet to be updated.
+ ///
+ /// TSnippetEditData [in] Record containing the
+ /// revised data.
+ /// TSnippet. Reference to the updated snippet.
+ /// The returned TSnippet object will be a different object
+ /// to ASnippet.
+ function UpdateSnippet(const ASnippet: TSnippet;
+ const AData: TSnippetEditData): TSnippet;
/// Adds a new snippet to the database.
/// string [in] New snippet's key.
@@ -503,16 +505,21 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
@param Snippet [in] Snippet which is cross referenced.
@return List of IDs of referring snippets.
}
- function UpdateSnippet(const Snippet: TSnippet;
- const Data: TSnippetEditData; const NewKey: string = ''): TSnippet;
- {Updates a user defined snippet's properties and references using provided
- data.
- @param Snippet [in] Snippet to be updated. Must be user-defined.
- @param Data [in] Record containing revised data.
- @param NewKey [in] New snippet's key. Set to '' or Snippet.Key if
- key is not to change.
- @return Reference to updated snippet. Will have changed.
- }
+
+ /// Updates a snippet's properties and references using the
+ /// provided data.
+ /// TSnippet [in] Snippet to be updated.
+ ///
+ /// TSnippetEditData [in] Record containing the
+ /// revised data.
+ /// TSnippet. Reference to the updated snippet.
+ ///
+ /// The returned TSnippet object will be a different object
+ /// to ASnippet.
+ /// Method of IDatabaseEdit.
+ ///
+ function UpdateSnippet(const ASnippet: TSnippet;
+ const AData: TSnippetEditData): TSnippet;
/// Adds a new snippet to the database.
/// string [in] New snippet's key.
@@ -1201,70 +1208,57 @@ function TDatabase.Updated: Boolean;
Result := fUpdated;
end;
-function TDatabase.UpdateSnippet(const Snippet: TSnippet;
- const Data: TSnippetEditData; const NewKey: string): TSnippet;
- {TODO -cCollections: Don't need NewKey parameter: key never changes. Also
- don't pass a collection ID, since that can never change either,
- because to do so would (1) invalidate the key because key is only
- guaranteed unique in collection and (2) would change the snippet ID}
- {Updates a user defined snippet's properties and references using provided
- data.
- @param Snippet [in] Snippet to be updated. Must be user-defined.
- @param Data [in] Record containing revised data.
- @param NewKey [in] New snippet's key. Set to '' or Snippet.Key if key
- is not to change.
- @return Reference to updated snippet. Will have changed.
- }
+function TDatabase.UpdateSnippet(const ASnippet: TSnippet;
+ const AData: TSnippetEditData): TSnippet;
var
- SnippetKey: string; // snippet key
- Dependent: TSnippet; // loops thru each snippetthat depends on Snippet
Dependents: TSnippetList; // list of dependent snippets
- Referrer: TSnippet; // loops thru snippets that cross references Snippet
+ Dependent: TSnippet; // each snippet that depend on ASnippet
Referrers: TSnippetList; // list of referencing snippets
-resourcestring
- // Error message
- sCantChangeKey = 'Can''t change key of snippet with key %0:s to %1:s: '
- + 'Snippet with key %1:s already exists in user database';
+ Referrer: TSnippet; // each snippet that cross references ASnippet
+ PreservedSnippetID: TSnippetID;
begin
- Result := Snippet; // keeps compiler happy
- Assert(Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID,
- ClassName + '.UpdateSnippet: Snippet is not user-defined');
Referrers := nil;
Dependents := nil;
+
TriggerEvent(evChangeBegin);
- TriggerEvent(evBeforeSnippetChange, Snippet);
+ TriggerEvent(evBeforeSnippetChange, ASnippet);
+
try
- // Calculate new key
- if NewKey <> '' then
- SnippetKey := NewKey
- else
- SnippetKey := Snippet.Key;
- // If key has changed then new key musn't exist in user database
- if not StrSameText(SnippetKey, Snippet.Key) then
- if fSnippets.Find(SnippetKey, TCollectionID.__TMP__UserDBCollectionID) <> nil then
- raise ECodeSnip.CreateFmt(sCantChangeKey, [Snippet.Key, SnippetKey]);
// We update by deleting old snippet and inserting new one
+
// get lists of snippets that cross reference or depend on this snippet
Dependents := TSnippetList.Create;
- GetDependentList(Snippet, Dependents);
+ GetDependentList(ASnippet, Dependents);
Referrers := TSnippetList.Create;
- GetReferrerList(Snippet, Referrers);
- // remove invalid references from referring snippets
+ GetReferrerList(ASnippet, Referrers);
+
+ // remove references to pre-update snippet from referring snippets
for Referrer in Referrers do
- (Referrer.XRef as TSnippetListEx).Delete(Snippet);
+ (Referrer.XRef as TSnippetListEx).Delete(ASnippet);
for Dependent in Dependents do
- (Dependent.Depends as TSnippetListEx).Delete(Snippet);
- // delete the snippet
- InternalDeleteSnippet(Snippet);
- // add new snippet
- Result := InternalAddSnippet(SnippetKey, TCollectionID.__TMP__UserDBCollectionID, Data);
- // add new snippet to referrer list of referring snippets
+ (Dependent.Depends as TSnippetListEx).Delete(ASnippet);
+
+ // record snippet's key and collection ID for use in re-created updated
+ // snippet
+ PreservedSnippetID := ASnippet.ID;
+
+ // delete the old, pre-update snippet
+ InternalDeleteSnippet(ASnippet);
+ // add new, post-update snippet with same key & collection ID as old snippet
+ Result := InternalAddSnippet(
+ PreservedSnippetID.Key, PreservedSnippetID.CollectionID, AData
+ );
+
+ // add updated snippet to referrer lists of referring snippets
for Referrer in Referrers do
Referrer.XRef.Add(Result);
for Dependent in Dependents do
Dependent.Depends.Add(Result);
+
Query.Update;
+
TriggerEvent(evSnippetChanged, Result);
+
finally
fUpdated := True;
Referrers.Free;
diff --git a/Src/FmSnippetsEditorDlg.pas b/Src/FmSnippetsEditorDlg.pas
index a93d070cd..b4745cae2 100644
--- a/Src/FmSnippetsEditorDlg.pas
+++ b/Src/FmSnippetsEditorDlg.pas
@@ -642,9 +642,7 @@ procedure TSnippetsEditorDlg.btnOKClick(Sender: TObject);
fEditData.Assign(UpdateData);
// Add or update snippet
if Assigned(fSnippet) then
- (Database as IDatabaseEdit).UpdateSnippet(
- fSnippet, fEditData, UniqueSnippetKey
- )
+ (Database as IDatabaseEdit).UpdateSnippet(fSnippet, fEditData)
else
begin
(Database as IDatabaseEdit).AddSnippet(
From 7d6622d37c481812e66272730c3b97ea87102a60 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 9 Nov 2024 09:46:41 +0000
Subject: [PATCH 058/222] Add collection ID param to TDatabase.DuplicateSnippet
Updated TDatabase.DuplicateSnippet to take an additional TCollectionID
parameter and to use that as the duplicate snippet's collection ID
instead of always using the "user" collection.
Renamed some the parameters.
Updated calling code in FmDuplicateSnippetDlg to pass the required
collection ID.
---
Src/DB.UMain.pas | 55 ++++++++++++++++++++++++++++-------
Src/FmDuplicateSnippetDlg.pas | 9 +++---
2 files changed, 49 insertions(+), 15 deletions(-)
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index 1078fd939..0bf1a344c 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -232,8 +232,22 @@ interface
function AddSnippet(const AKey: string; const ACollectionID: TCollectionID;
const AData: TSnippetEditData): TSnippet;
- function DuplicateSnippet(const Snippet: TSnippet;
- const UniqueKey, DisplayName: string; const CatID: string): TSnippet;
+ /// Duplicates a snippet in the database.
+ /// TSnippet [in] Snippet to be duplicated.
+ ///
+ /// string [in] Key to be used for duplicated
+ /// snippet.
+ /// TCollectionID [in] ID of
+ /// collection the duplicated snippet belongs to.
+ /// string [in] Display name of the
+ /// duplicated snippet.
+ /// string [in] ID of the category to which the
+ /// duplicated snippet will belong.
+ /// TSnippet. Reference to the duplicated snippet.
+ ///
+ function DuplicateSnippet(const ASnippet: TSnippet; const ANewKey: string;
+ const ANewCollectionID: TCollectionID; const ANewDisplayName: string;
+ const ACatID: string): TSnippet;
function CreateTempSnippet(const SnippetKey: string;
const Data: TSnippetEditData): TSnippet; overload;
{Creates a new temporary snippet without adding it to the Snippets
@@ -532,8 +546,24 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
function AddSnippet(const AKey: string; const ACollectionID: TCollectionID;
const AData: TSnippetEditData): TSnippet;
- function DuplicateSnippet(const Snippet: TSnippet;
- const UniqueKey, DisplayName: string; const CatID: string): TSnippet;
+ /// Duplicates a snippet in the database.
+ /// TSnippet [in] Snippet to be duplicated.
+ ///
+ /// string [in] Key to be used for duplicated
+ /// snippet.
+ /// TCollectionID [in] ID of
+ /// collection the duplicated snippet belongs to.
+ /// string [in] Display name of the
+ /// duplicated snippet.
+ /// string [in] ID of the category to which the
+ /// duplicated snippet will belong.
+ /// TSnippet. Reference to the duplicated snippet.
+ ///
+ /// Method of IDatabaseEdit.
+ function DuplicateSnippet(const ASnippet: TSnippet; const ANewKey: string;
+ const ANewCollectionID: TCollectionID; const ANewDisplayName: string;
+ const ACatID: string): TSnippet;
+
function CreateTempSnippet(const SnippetKey: string;
const Data: TSnippetEditData): TSnippet; overload;
{Creates a new temporary user defined snippet without adding it to the
@@ -543,6 +573,7 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
@param Data [in] Record storing new snippet's properties and references.
@return Reference to new snippet.
}
+
function CreateTempSnippet(const Snippet: TSnippet): TSnippet; overload;
{Creates a new temporary copy of a snippet without adding it to the
Snippets object's snippets list. The new instance may not be added to the
@@ -836,16 +867,18 @@ destructor TDatabase.Destroy;
inherited;
end;
-function TDatabase.DuplicateSnippet(const Snippet: TSnippet;
- const UniqueKey, DisplayName: string; const CatID: string): TSnippet;
- {TODO -cCollections: Add collection ID parameter}
+function TDatabase.DuplicateSnippet(const ASnippet: TSnippet;
+ const ANewKey: string; const ANewCollectionID: TCollectionID;
+ const ANewDisplayName: string; const ACatID: string): TSnippet;
var
Data: TSnippetEditData;
begin
- Data := (Snippet as TSnippetEx).GetEditData;
- Data.Props.Cat := CatID;
- Data.Props.DisplayName := DisplayName;
- Result := AddSnippet(UniqueKey, TCollectionID.__TMP__UserDBCollectionID, Data);
+ {TODO -cVault: Update edit data before calling this method and replace
+ and ANewDisplayName and ACatID with a single AData parameter.}
+ Data := (ASnippet as TSnippetEx).GetEditData;
+ Data.Props.Cat := ACatID;
+ Data.Props.DisplayName := ANewDisplayName;
+ Result := AddSnippet(ANewKey, ANewCollectionID, Data);
end;
function TDatabase.GetCategories: TCategoryList;
diff --git a/Src/FmDuplicateSnippetDlg.pas b/Src/FmDuplicateSnippetDlg.pas
index 1910b83dd..b43e946cd 100644
--- a/Src/FmDuplicateSnippetDlg.pas
+++ b/Src/FmDuplicateSnippetDlg.pas
@@ -82,6 +82,9 @@ implementation
{$R *.dfm}
+{TODO -cTidy: Re-order methods alphabetically}
+{TODO -cRefactor: Add method to get display name from ctrl and strip whitespace}
+
{ TDuplicateSnippetDlg }
procedure TDuplicateSnippetDlg.ArrangeForm;
@@ -183,14 +186,12 @@ function TDuplicateSnippetDlg.SelectedCollectionID: TCollectionID;
end;
procedure TDuplicateSnippetDlg.UpdateDatabase;
-var
- DisplayName: string;
begin
- DisplayName := StrTrim(edDisplayName.Text);
(Database as IDatabaseEdit).DuplicateSnippet(
fSnippet,
fSnippetKey,
- DisplayName,
+ SelectedCollectionID,
+ StrTrim(edDisplayName.Text),
fCatList.CatID(cbCategory.ItemIndex)
);
end;
From 9c708b1ce07991064d248fd9871d39fd2f31782f Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 9 Nov 2024 10:24:43 +0000
Subject: [PATCH 059/222] Add collection ID param to
TDatabase.CreateTempSnippet
Updated TDatabase.CreateTempSnippet to take an additional TCollectionID
parameter and to use that as the temporary snippet's collection ID
instead of always using the "user" collection.
Renamed some the parameters.
Updated affected calling code:
* Updated one of the TSnippetValidator.ValidateDependsList overloaded
methods to also add a collection ID parameter so that it can pass it
along to the revised TDatabase.CreateTempSnippet method.
* Updated FmSnippetsEditorDlg to pass the required collection ID
parameter to both TDatabase.CreateTempSnippet and
TSnippetValidator.ValidateDependsList.
---
Src/DB.UMain.pas | 63 ++++++++++++++++++++-----------------
Src/FmSnippetsEditorDlg.pas | 4 +--
Src/USnippetValidator.pas | 46 +++++++++++++++++----------
3 files changed, 65 insertions(+), 48 deletions(-)
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index 0bf1a344c..ca030ef0b 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -248,15 +248,21 @@ interface
function DuplicateSnippet(const ASnippet: TSnippet; const ANewKey: string;
const ANewCollectionID: TCollectionID; const ANewDisplayName: string;
const ACatID: string): TSnippet;
- function CreateTempSnippet(const SnippetKey: string;
- const Data: TSnippetEditData): TSnippet; overload;
- {Creates a new temporary snippet without adding it to the Snippets
- object's snippets list. The new instance may not be added to the
- Snippets object.
- @param SnippetKey [in] New snippet's key.
- @param Data [in] Record storing new snippet's properties and references.
- @return Reference to new snippet.
- }
+
+ /// Creates a new temporary snippet without adding it to the
+ /// database.
+ /// string [in] The new nippet's key.
+ /// TCollectionID [in] ID of the
+ /// collection to which the new snippet belongs.
+ /// TSnippetEditData [in] Record storing the new
+ /// snippet's properties and references.
+ /// TSnippet Reference to new snippet.
+ /// The returned snippet must not be added to the database.
+ ///
+ function CreateTempSnippet(const AKey: string;
+ const ACollectionID: TCollectionID; const AData: TSnippetEditData):
+ TSnippet; overload;
+
function CreateTempSnippet(const Snippet: TSnippet): TSnippet; overload;
{Creates a new temporary copy of a snippet without adding it to the
Snippets object's snippets list. The new instance may not be added to the
@@ -564,15 +570,21 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
const ANewCollectionID: TCollectionID; const ANewDisplayName: string;
const ACatID: string): TSnippet;
- function CreateTempSnippet(const SnippetKey: string;
- const Data: TSnippetEditData): TSnippet; overload;
- {Creates a new temporary user defined snippet without adding it to the
- Snippets object's snippets list. The new instance may not be added to the
- Snippets object.
- @param SnippetKey [in] New snippet's key.
- @param Data [in] Record storing new snippet's properties and references.
- @return Reference to new snippet.
- }
+ /// Creates a new temporary snippet without adding it to the
+ /// database.
+ /// string [in] The new nippet's key.
+ /// TCollectionID [in] ID of the
+ /// collection to which the new snippet belongs.
+ /// TSnippetEditData [in] Record storing the new
+ /// snippet's properties and references.
+ /// TSnippet Reference to new snippet.
+ ///
+ /// The returned snippet must not be added to the database.
+ /// Method of IDatabaseEdit.
+ ///
+ function CreateTempSnippet(const AKey: string;
+ const ACollectionID: TCollectionID; const AData: TSnippetEditData):
+ TSnippet; overload;
function CreateTempSnippet(const Snippet: TSnippet): TSnippet; overload;
{Creates a new temporary copy of a snippet without adding it to the
@@ -781,18 +793,11 @@ function TDatabase.CreateTempSnippet(const Snippet: TSnippet): TSnippet;
);
end;
-function TDatabase.CreateTempSnippet(const SnippetKey: string;
- const Data: TSnippetEditData): TSnippet;
- {Creates a new temporary user defined snippet without adding it to the
- Snippets object's snippets list. The new instance may not be added to the
- Snippets object.
- @param SnippetKey [in] New snippet's key.
- @param Data [in] Record storing new snippet's properties and references.
- @return Reference to new snippet.
- }
+function TDatabase.CreateTempSnippet(const AKey: string;
+ const ACollectionID: TCollectionID; const AData: TSnippetEditData): TSnippet;
begin
- Result := TTempSnippet.Create(SnippetKey, TCollectionID.__TMP__UserDBCollectionID, Data.Props);
- (Result as TTempSnippet).UpdateRefs(Data.Refs, fSnippets);
+ Result := TTempSnippet.Create(AKey, ACollectionID, AData.Props);
+ (Result as TTempSnippet).UpdateRefs(AData.Refs, fSnippets);
end;
procedure TDatabase.DeleteCategory(const Category: TCategory);
diff --git a/Src/FmSnippetsEditorDlg.pas b/Src/FmSnippetsEditorDlg.pas
index b4745cae2..633a7fab0 100644
--- a/Src/FmSnippetsEditorDlg.pas
+++ b/Src/FmSnippetsEditorDlg.pas
@@ -692,7 +692,7 @@ function TSnippetsEditorDlg.CreateTempSnippet: TSnippet;
// Create snippet object from entered data
EditData.Assign(UpdateData);
Result := (Database as IDatabaseEdit).CreateTempSnippet(
- UniqueSnippetKey, EditData
+ UniqueSnippetKey, SelectedCollectionID, EditData
);
end;
@@ -1046,7 +1046,7 @@ procedure TSnippetsEditorDlg.ValidateData;
raise EDataEntry.Create(ErrorMessage, edSourceCode, ErrorSelection);
frmExtra.Validate;
if not TSnippetValidator.ValidateDependsList(
- UniqueSnippetKey, UpdateData, ErrorMessage
+ UniqueSnippetKey, SelectedCollectionID, UpdateData, ErrorMessage
) then
raise EDataEntry.Create( // selection not applicable to list boxes
StrMakeSentence(ErrorMessage) + EOL2 + sDependencyPrompt, clbDepends
diff --git a/Src/USnippetValidator.pas b/Src/USnippetValidator.pas
index 0cbcdd7c9..2674623b8 100644
--- a/Src/USnippetValidator.pas
+++ b/Src/USnippetValidator.pas
@@ -17,7 +17,12 @@ interface
uses
// Project
- ActiveText.UMain, DB.USnippet, DB.USnippetKind, UBaseObjects, UStructs;
+ ActiveText.UMain,
+ DB.UCollections,
+ DB.USnippet,
+ DB.USnippetKind,
+ UBaseObjects,
+ UStructs;
type
@@ -50,17 +55,24 @@ TSnippetValidator = class(TNoConstructObject)
returned.
@return True if dependency list is valid or False if not.
}
- class function ValidateDependsList(const SnippetKey: string;
- const Data: TSnippetEditData; out ErrorMsg: string): Boolean; overload;
- {Recursively checks dependency list of a snippet for validity.
- @param SnippetKey [in] Key of snippet for which dependencies are to be
- checked.
- @param Data [in] Data describing properties and references of snippet
- for which dependencies are to be checked.
- @param ErrorMsg [out] Message that describes error. Undefined if True
- returned.
- @return True if dependency list is valid or False if not.
- }
+
+ /// Recursively checks dependency list of a snippet for validity.
+ ///
+ /// string [in] Key of snippet for which
+ /// dependencies are to be checked.
+ /// TCollectionID [in] ID of the
+ /// collection to which snippet belongs.
+ /// TSnippetEditData [in] Data describing
+ /// properties and references of snippet for which dependencies are to be
+ /// checked.
+ /// string [out] Message that describes any
+ /// error. Undefined if True is returned.
+ /// Boolean. True if dependency list is valid or
+ /// False if not.
+ class function ValidateDependsList(const AKey: string;
+ const ACollectionID: TCollectionID; const AData: TSnippetEditData;
+ out AErrorMsg: string): Boolean; overload;
+
class function ValidateSourceCode(const Source: string;
out ErrorMsg: string; out ErrorSel: TSelection): Boolean;
{Validates a source code from a snippet.
@@ -121,7 +133,6 @@ implementation
SysUtils,
// Project
ActiveText.UValidator,
- DB.UCollections,
DB.UMain,
UStrUtils;
@@ -256,8 +267,9 @@ class function TSnippetValidator.ValidateDependsList(const Snippet: TSnippet;
);
end;
-class function TSnippetValidator.ValidateDependsList(const SnippetKey: string;
- const Data: TSnippetEditData; out ErrorMsg: string): Boolean;
+class function TSnippetValidator.ValidateDependsList(const AKey: string;
+ const ACollectionID: TCollectionID; const AData: TSnippetEditData;
+ out AErrorMsg: string): Boolean;
{Recursively checks dependency list of a snippet for validity.
@param SnippetKey [in] Key of snippet for which dependencies are to be
checked.
@@ -271,10 +283,10 @@ class function TSnippetValidator.ValidateDependsList(const SnippetKey: string;
TempSnippet: TSnippet; // temporary snippet that is checked for dependencies
begin
TempSnippet := (Database as IDatabaseEdit).CreateTempSnippet(
- SnippetKey, Data
+ AKey, ACollectionID, AData
);
try
- Result := ValidateDependsList(TempSnippet, ErrorMsg);
+ Result := ValidateDependsList(TempSnippet, AErrorMsg);
finally
TempSnippet.Free;
end;
From 1cc19233e22da3837e1887dcb43868bb96d98dbc Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 10 Nov 2024 09:06:50 +0000
Subject: [PATCH 060/222] All categories now display in same colour
The code that checks which collection a category belongs to was removed
from:
* tree-view drawing code
* HTML rendering code for category views rendered in the Details pane
* RTF rendering code for category documentation in TRTFCategoryDoc.
Consequently, all categories descriptions are now drawn in the same
colour.
---
Src/FrOverview.pas | 3 ---
Src/FrSelectSnippetsBase.pas | 2 --
Src/UDetailPageHTML.pas | 11 -----------
Src/URTFCategoryDoc.pas | 1 -
4 files changed, 17 deletions(-)
diff --git a/Src/FrOverview.pas b/Src/FrOverview.pas
index d097cff68..aaeaf6e39 100644
--- a/Src/FrOverview.pas
+++ b/Src/FrOverview.pas
@@ -969,14 +969,11 @@ function TOverviewFrame.TTVDraw.GetCollectionID(const Node: TTreeNode):
var
ViewItem: IView; // view item represented by node
SnippetView: ISnippetView; // view item if node represents a snippet
- CategoryView: ICategoryView; // view item if node represents a category
begin
// TODO -cBug: Exception reported as issue #70 could have moved here
ViewItem := (Node as TViewItemTreeNode).ViewItem;
if Supports(ViewItem, ISnippetView, SnippetView) then
Result := SnippetView.Snippet.CollectionID
- else if Supports(ViewItem, ICategoryView, CategoryView) then
- Result := CategoryView.Category.CollectionID
else
Result := TCollectionID.CreateNull;
end;
diff --git a/Src/FrSelectSnippetsBase.pas b/Src/FrSelectSnippetsBase.pas
index 50b233e4d..71a08498d 100644
--- a/Src/FrSelectSnippetsBase.pas
+++ b/Src/FrSelectSnippetsBase.pas
@@ -283,8 +283,6 @@ function TSelectSnippetsBaseFrame.TTVDraw.GetCollectionID(
SnipObj := TObject(Node.Data);
if SnipObj is TSnippet then
Result := (SnipObj as TSnippet).CollectionID
- else if SnipObj is TCategory then
- Result := (SnipObj as TCategory).CollectionID
else
Result := TCollectionID.CreateNull
end;
diff --git a/Src/UDetailPageHTML.pas b/Src/UDetailPageHTML.pas
index e231822f6..1710e1e02 100644
--- a/Src/UDetailPageHTML.pas
+++ b/Src/UDetailPageHTML.pas
@@ -278,9 +278,6 @@ TCategoryPageHTML = class sealed(TSnippetListPageHTML)
/// The snippet is to be displayed if it is in the category being
/// displayed.
function IsSnippetRequired(const Snippet: TSnippet): Boolean; override;
- /// Returns name of CSS class to be used for page heading.
- ///
- function GetH1ClassName: string; override;
/// Returns narrative to be used at top of any page that displays
/// a snippet list.
function GetNarrative: string; override;
@@ -665,14 +662,6 @@ function TCategoryPageHTML.GetEmptyListNote: string;
Result := sNote;
end;
-function TCategoryPageHTML.GetH1ClassName: string;
-begin
- if (View as ICategoryView).Category.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
- Result := 'userdb'
- else
- Result := inherited GetH1ClassName;
-end;
-
function TCategoryPageHTML.GetNarrative: string;
resourcestring
sNarrative = 'List of selected snippets in this category.';
diff --git a/Src/URTFCategoryDoc.pas b/Src/URTFCategoryDoc.pas
index 35070366e..8d2bc6bbd 100644
--- a/Src/URTFCategoryDoc.pas
+++ b/Src/URTFCategoryDoc.pas
@@ -216,7 +216,6 @@ procedure TRTFCategoryDoc.OutputCategoryHeading(const Category: TCategory);
fBuilder.SetFont(MainFontName);
fBuilder.SetFontSize(HeadingFontSize);
fBuilder.SetFontStyle([fsBold]);
- SetColour(Preferences.GetDBHeadingColour(Category.CollectionID));
fBuilder.AddText(Category.Description);
fBuilder.EndPara;
fBuilder.EndGroup;
From 95ec483812971f81cfb43d221b6e35ba55060c75 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 10 Nov 2024 11:08:44 +0000
Subject: [PATCH 061/222] Permit any category to be renamed or deleted
Implemented new rules that (1) any non-empty category can be deleted and
(2) Any category can be renamed at any time.
Changed FmDeleteCategoryDlg in light of these changes. The dialogue box
is now only given empty categories to display, so checks for non-empty
categories were removed along with the label used to display warning of
non-empty categories.
Lifted restriction in database object on editing a non-user-defined
cateogory.
---
Src/DB.UCategory.pas | 6 ++--
Src/DB.UMain.pas | 2 --
Src/FmDeleteCategoryDlg.dfm | 12 +-------
Src/FmDeleteCategoryDlg.pas | 45 ++++++++----------------------
Src/UUserDBMgr.pas | 55 ++++++++++++-------------------------
5 files changed, 31 insertions(+), 89 deletions(-)
diff --git a/Src/DB.UCategory.pas b/Src/DB.UCategory.pas
index 11415a8f6..171c58acd 100644
--- a/Src/DB.UCategory.pas
+++ b/Src/DB.UCategory.pas
@@ -193,7 +193,7 @@ implementation
// Delphi
SysUtils,
// Project
- UReservedCategories, UStrUtils;
+ UStrUtils;
{ TCategory }
@@ -203,9 +203,7 @@ function TCategory.CanDelete: Boolean;
@return True if deletion allowed, False if not.
}
begin
- Result := (fCollectionID <> TCollectionID.__TMP__MainDBCollectionID)
- and fSnippets.IsEmpty
- and not TReservedCategories.IsReserved(Self);
+ Result := fSnippets.IsEmpty;
end;
function TCategory.CompareDescriptionTo(const Cat: TCategory): Integer;
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index ca030ef0b..cce30a1a4 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -934,8 +934,6 @@ function TDatabase.GetEditableCategoryInfo(
@return Required data.
}
begin
- Assert(not Assigned(Category) or (Category.CollectionID <> TCollectionID.__TMP__MainDBCollectionID),
- ClassName + '.GetEditableCategoryInfo: Category is not user-defined');
if Assigned(Category) then
Result := (Category as TCategoryEx).GetEditData
else
diff --git a/Src/FmDeleteCategoryDlg.dfm b/Src/FmDeleteCategoryDlg.dfm
index 48c13e494..67f1b748f 100644
--- a/Src/FmDeleteCategoryDlg.dfm
+++ b/Src/FmDeleteCategoryDlg.dfm
@@ -1,15 +1,9 @@
inherited DeleteCategoryDlg: TDeleteCategoryDlg
Caption = 'Delete Category'
+ ExplicitHeight = 375
PixelsPerInch = 96
TextHeight = 13
inherited pnlBody: TPanel
- object lblErrorMsg: TLabel
- Left = 0
- Top = 144
- Width = 156
- Height = 13
- Caption = 'Non-empty category: can'#39't delete'
- end
inline frmCategories: TCategoryListFrame
Left = 0
Top = 0
@@ -18,10 +12,6 @@ inherited DeleteCategoryDlg: TDeleteCategoryDlg
TabOrder = 0
TabStop = True
ExplicitHeight = 138
- inherited lblCategories: TLabel
- Width = 60
- ExplicitWidth = 60
- end
inherited lbCategories: TListBox
Height = 108
ExplicitHeight = 108
diff --git a/Src/FmDeleteCategoryDlg.pas b/Src/FmDeleteCategoryDlg.pas
index 3f6a65b0f..0f3677660 100644
--- a/Src/FmDeleteCategoryDlg.pas
+++ b/Src/FmDeleteCategoryDlg.pas
@@ -5,8 +5,7 @@
*
* Copyright (C) 2009-2023, Peter Johnson (gravatar.com/delphidabbler).
*
- * Implements a dialogue box that permits user to select and delete a user
- * defined category.
+ * Implements a dialogue box that permits user to select and delete a category.
}
@@ -24,13 +23,11 @@ interface
type
- {
- TDeleteCategoryDlg:
- Dialog box that permits user to select and delete a user-defined category.
- }
+
+ /// Dialogue box that permits the user to select and delete a
+ /// category.
TDeleteCategoryDlg = class(TCategoryEditDlg, INoPublicConstruct)
frmCategories: TCategoryListFrame;
- lblErrorMsg: TLabel;
procedure btnOKClick(Sender: TObject);
strict private
fCategories: TCategoryList; // List of categories that can be deleted
@@ -39,14 +36,12 @@ TDeleteCategoryDlg = class(TCategoryEditDlg, INoPublicConstruct)
according to changes.
@param Sender [in] Not used.
}
- procedure UpdateErrorLabelState;
- {Shows or hides error state label depending of whether selected category
- can be deleted.
- }
+
+ /// Deletes a category from the database.
+ /// TCategory [in] Category to be deleted.
+ /// The category must be empty.
procedure DeleteCategory(const Cat: TCategory);
- {Deletes category and all its snippets from database.
- @param Cat [in] Category to be deleted.
- }
+
strict protected
procedure ConfigForm; override;
{Configures form. Populates controls and supplies event handler to frame.
@@ -86,8 +81,6 @@ procedure TDeleteCategoryDlg.ArrangeForm;
}
begin
frmCategories.ArrangeFrame;
- TCtrlArranger.SetLabelHeight(lblErrorMsg);
- lblErrorMsg.Top := TCtrlArranger.BottomOf(frmCategories, 8);
inherited;
end;
@@ -117,16 +110,11 @@ procedure TDeleteCategoryDlg.ConfigForm;
frmCategories.OnChange := SelectionChangeHandler;
frmCategories.Prompt := sPrompt;
frmCategories.SetCategories(fCategories);
- TFontHelper.SetDefaultFont(lblErrorMsg.Font);
- lblErrorMsg.Font.Color := clWarningText;
- lblErrorMsg.Visible := False;
end;
procedure TDeleteCategoryDlg.DeleteCategory(const Cat: TCategory);
- {Deletes category and all its snippets from database.
- @param Cat [in] Category to be deleted.
- }
begin
+ Assert(Cat.CanDelete, ClassName + '.DeleteCategory: Cat can''t be deleted');
(Database as IDatabaseEdit).DeleteCategory(Cat);
end;
@@ -156,18 +144,6 @@ procedure TDeleteCategoryDlg.SelectionChangeHandler(Sender: TObject);
}
begin
UpdateOKBtn;
- UpdateErrorLabelState;
-end;
-
-procedure TDeleteCategoryDlg.UpdateErrorLabelState;
- {Shows or hides error state label depending of whether selected category can
- be deleted.
- }
-begin
- if not frmCategories.IsValidEntry then
- lblErrorMsg.Visible := False
- else
- lblErrorMsg.Visible := not frmCategories.SelectedCategory.CanDelete;
end;
procedure TDeleteCategoryDlg.UpdateOKBtn;
@@ -176,6 +152,7 @@ procedure TDeleteCategoryDlg.UpdateOKBtn;
}
begin
btnOK.Enabled := frmCategories.IsValidEntry
+ // following check is potentially redundant, but leaving in for safety
and frmCategories.SelectedCategory.CanDelete;
end;
diff --git a/Src/UUserDBMgr.pas b/Src/UUserDBMgr.pas
index 04b8d51b4..743f027b2 100644
--- a/Src/UUserDBMgr.pas
+++ b/Src/UUserDBMgr.pas
@@ -5,7 +5,7 @@
*
* Copyright (C) 2008-2022, Peter Johnson (gravatar.com/delphidabbler).
*
- * Implements a static class that manages user's interaction with user database.
+ * Implements a static class that manages user's interaction with the database.
}
@@ -42,13 +42,6 @@ TUserDBMgr = class(TNoConstructObject)
/// Boolean [in/out] Set to True to permit dialogue
/// to close or False to inhibit closure.
class procedure CanSaveDialogClose(Sender: TObject; var CanClose: Boolean);
- /// Creates a list of user defined categories.
- /// Boolean [in] Flag indicating whether list
- /// should include special, non-deletable, categories.
- /// Required category list.
- /// Caller must free the returned object.
- class function CreateUserCatList(
- const IncludeSpecial: Boolean): TCategoryList;
public
/// Enables user to adds a new user defined snippet to the
/// database using the snippets editor.
@@ -117,7 +110,7 @@ implementation
FmDeleteUserDBDlg, FmWaitDlg,
UAppInfo,
UConsts, UExceptions, UIStringList, UMessageBox, UOpenDialogEx,
- UOpenDialogHelper, UReservedCategories, USaveDialogEx, USnippetIDs,
+ UOpenDialogHelper, USaveDialogEx, USnippetIDs,
UUserDBBackup, UWaitForThreadUI;
type
@@ -272,14 +265,12 @@ class procedure TUserDBMgr.BackupDatabase(ParentCtrl: TComponent);
class function TUserDBMgr.CanDeleteACategory: Boolean;
var
- CatList: TCategoryList; // list of user deletable categories
+ Cat: TCategory;
begin
- CatList := CreateUserCatList(False); // builds list of deletable user cats
- try
- Result := CatList.Count > 0;
- finally
- CatList.Free;
- end;
+ Result := False;
+ for Cat in Database.Categories do
+ if Cat.CanDelete then
+ Exit(True);
end;
class function TUserDBMgr.CanDuplicate(ViewItem: IView): Boolean;
@@ -321,15 +312,8 @@ class procedure TUserDBMgr.CanOpenDialogClose(Sender: TObject;
end;
class function TUserDBMgr.CanRenameACategory: Boolean;
-var
- CatList: TCategoryList; // list of user renamable categories
begin
- CatList := CreateUserCatList(True); // build list of all user categories
- try
- Result := CatList.Count > 0;
- finally
- CatList.Free;
- end;
+ Result := True;
end;
class function TUserDBMgr.CanSave: Boolean;
@@ -355,24 +339,16 @@ class procedure TUserDBMgr.CanSaveDialogClose(Sender: TObject;
);
end;
-class function TUserDBMgr.CreateUserCatList(
- const IncludeSpecial: Boolean): TCategoryList;
-var
- Cat: TCategory; // references each category in snippets database
-begin
- Result := TCategoryList.Create;
- for Cat in Database.Categories do
- if (Cat.CollectionID <> TCollectionID.__TMP__MainDBCollectionID) and
- (IncludeSpecial or not TReservedCategories.IsReserved(Cat)) then
- Result.Add(Cat);
-end;
-
class procedure TUserDBMgr.DeleteACategory;
var
CatList: TCategoryList; // list of deletable categories
+ Cat: TCategory;
begin
- CatList := CreateUserCatList(False);
+ CatList := TCategoryList.Create;
try
+ for Cat in Database.Categories do
+ if Cat.CanDelete then
+ CatList.Add(Cat);
// all work takes place in dialog box
TDeleteCategoryDlg.Execute(nil, CatList)
finally
@@ -485,10 +461,13 @@ class procedure TUserDBMgr.MoveDatabase;
class procedure TUserDBMgr.RenameACategory;
var
+ Cat: TCategory;
CatList: TCategoryList; // list of user defined categories
begin
- CatList := CreateUserCatList(True);
+ CatList := TCategoryList.Create;
try
+ for Cat in Database.Categories do
+ CatList.Add(Cat);
// all work takes place in dialog box
TRenameCategoryDlg.Execute(nil, CatList)
finally
From d0484ce00d4c181ba04259cbf47d2a62c2dc025c Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 10 Nov 2024 14:42:18 +0000
Subject: [PATCH 062/222] Make code importers ensure their categories exist
Since it is no longer guaranteed that the former "required" categories
used by the TCodeImporter and TSWAGImporter classes will automatically
exist both those classes were altered to create those categories if
they are not aleady defined.
---
Src/SWAG.UImporter.pas | 37 ++++++++++++++++++++++++--------
Src/UCodeImportExport.pas | 44 +++++++++++++++++++++++++++++----------
2 files changed, 61 insertions(+), 20 deletions(-)
diff --git a/Src/SWAG.UImporter.pas b/Src/SWAG.UImporter.pas
index 23f359efb..89cf2cdd4 100644
--- a/Src/SWAG.UImporter.pas
+++ b/Src/SWAG.UImporter.pas
@@ -21,6 +21,7 @@ interface
Generics.Collections,
// Project
ActiveText.UMain,
+ DB.UCategory,
DB.UCollections,
DB.USnippet,
SWAG.UCommon;
@@ -42,6 +43,11 @@ TSWAGImporter = class(TObject)
///
TProgressCallback = reference to procedure (
const SWAGPacket: TSWAGPacket);
+ const
+ {TODO -cVault: Let user select or create a category rather than imposing
+ this one}
+ /// ID of category used to import snippets.
+ SWAGCatID = '_swag_';
var
/// List of SWAG packets to be imported.
fImportList: TList;
@@ -60,6 +66,8 @@ TSWAGImporter = class(TObject)
/// database as a CodeSnip format snippet.
procedure ImportPacketAsSnippet(const ACollectionID: TCollectionID;
const SWAGPacket: TSWAGPacket);
+
+ class procedure EnsureSWAGCategoryExists;
public
/// Constructs new object instance.
constructor Create;
@@ -93,10 +101,8 @@ implementation
// Delphi
SysUtils,
// Project
- DB.UCategory,
DB.UMain,
DB.USnippetKind,
- UReservedCategories,
USnippetValidator;
@@ -135,7 +141,7 @@ function TSWAGImporter.BuildSnippetInfo(const SWAGPacket: TSWAGPacket):
begin
Result.Init;
Result.Props.Kind := skFreeform;
- Result.Props.Cat := TReservedCategories.SWAGCatID;
+ Result.Props.Cat := SWAGCatID;
Result.Props.Desc := BuildDescription;
Result.Props.SourceCode := SWAGPacket.SourceCode;
Result.Props.HiliteSource := not SWAGPacket.IsDocument;
@@ -148,6 +154,7 @@ constructor TSWAGImporter.Create;
begin
inherited Create;
fImportList := TList.Create;
+ EnsureSWAGCategoryExists;
end;
destructor TSWAGImporter.Destroy;
@@ -156,6 +163,22 @@ destructor TSWAGImporter.Destroy;
inherited;
end;
+class procedure TSWAGImporter.EnsureSWAGCategoryExists;
+resourcestring
+ SWAGCatDesc = 'SWAG Imports';
+var
+ SWAGCatData: TCategoryData;
+ SWAGCat: TCategory;
+begin
+ SWAGCat := Database.Categories.Find(SWAGCatID);
+ if not Assigned(SWAGCat) then
+ begin
+ SWAGCatData.Init;
+ SWAGCatData.Desc := SWAGCatDesc;
+ (Database as IDatabaseEdit).AddCategory(SWAGCatID, SWAGCatData);
+ end;
+end;
+
function TSWAGImporter.ExtraBoilerplate: IActiveText;
procedure AddText(const Text: string);
@@ -270,13 +293,9 @@ procedure TSWAGImporter.Reset;
end;
class function TSWAGImporter.SWAGCategoryDesc: string;
-var
- Cat: TCategory; // reserved SWAG category in code snippets database
begin
- Cat := Database.Categories.Find(TReservedCategories.SWAGCatID);
- Assert(Assigned(Cat),
- ClassName + '.SWAGCategoryDesc: Can''t find SWAG category');
- Result := Cat.Description;
+ EnsureSWAGCategoryExists;
+ Result := Database.Categories.Find(SWAGCatID).Description;
end;
end.
diff --git a/Src/UCodeImportExport.pas b/Src/UCodeImportExport.pas
index 6940a699d..18446c944 100644
--- a/Src/UCodeImportExport.pas
+++ b/Src/UCodeImportExport.pas
@@ -5,8 +5,7 @@
*
* Copyright (C) 2008-2023, Peter Johnson (gravatar.com/delphidabbler).
*
- * Implements classes that can import and export user defined snippets from and
- * to XML.
+ * Implements classes that can import and export snippets from and to XML.
}
@@ -22,6 +21,7 @@ interface
Classes,
XMLIntf,
// Project
+ DB.UCategory,
DB.USnippet,
UBaseObjects,
UEncodings,
@@ -52,10 +52,16 @@ TSnippetInfo = record
/// Imports code snippets from XML.
TCodeImporter = class(TNoPublicConstructObject)
strict private
- /// Version of file being imported.
- fVersion: Integer;
- /// List of snippets read from XML.
- fSnippetInfo: TSnippetInfoList;
+ const
+ {TODO -cVault: Let user select or create a category rather than imposing
+ this one}
+ /// ID of category used to import snippets.
+ ImportCatID = 'imports';
+ var
+ /// Version of file being imported.
+ fVersion: Integer;
+ /// List of snippets read from XML.
+ fSnippetInfo: TSnippetInfoList;
/// Extended XML document object.
fXMLDoc: IXMLDocumentEx;
/// Retrieves a list of all snippet nodes from XML document.
@@ -69,9 +75,13 @@ TCodeImporter = class(TNoPublicConstructObject)
///
/// ECodeImporter raised if XML is not valid.
function ValidateDoc: Integer;
+ /// Checks if the special import category exists and creates it if
+ /// not.
+ class procedure EnsureImportCategoryExists;
/// Constructs and initialises object ready to perform import.
///
constructor InternalCreate;
+
public
/// Destroys object.
destructor Destroy; override;
@@ -169,7 +179,6 @@ implementation
DB.UMain,
DB.USnippetKind,
UAppInfo,
- UReservedCategories,
USnippetExtraHelper,
USnippetIDs,
UStructs,
@@ -345,6 +354,20 @@ destructor TCodeImporter.Destroy;
inherited;
end;
+class procedure TCodeImporter.EnsureImportCategoryExists;
+resourcestring
+ ImportCatDesc = 'Imported Snippets';
+var
+ ImportCatData: TCategoryData;
+begin
+ if not Assigned(Database.Categories.Find(ImportCatID)) then
+ begin
+ ImportCatData.Init;
+ ImportCatData.Desc := ImportCatDesc;
+ (Database as IDatabaseEdit).AddCategory(ImportCatID, ImportCatData);
+ end;
+end;
+
procedure TCodeImporter.Execute(const Data: TBytes);
/// Reads list of units from under SnippetNode into Units list.
@@ -372,7 +395,7 @@ procedure TCodeImporter.Execute(const Data: TBytes);
Depends.Clear;
for SnippetName in SnippetNames do
// Note: in building snippet ID list we assume each snippet is from the
- // standard user collection. It may not be, but there is no way of telling
+ // default collection. It may not be, but there is no way of telling
// from XML.
Depends.Add(TSnippetID.Create(SnippetName, TCollectionID.__TMP__UserDBCollectionID));
end;
@@ -422,7 +445,7 @@ procedure TCodeImporter.Execute(const Data: TBytes);
fSnippetInfo[Idx].Key := SnippetNode.Attributes[cSnippetNameAttr];
fSnippetInfo[Idx].Data :=
(Database as IDatabaseEdit).GetEditableSnippetInfo;
- fSnippetInfo[Idx].Data.Props.Cat := TReservedCategories.ImportsCatID;
+ fSnippetInfo[Idx].Data.Props.Cat := ImportCatID;
fSnippetInfo[Idx].Data.Props.Desc := GetDescription(SnippetNode);
fSnippetInfo[Idx].Data.Props.DisplayName := TXMLDocHelper.GetSubTagText(
fXMLDoc, SnippetNode, cDisplayNameNode
@@ -511,11 +534,10 @@ class procedure TCodeImporter.ImportData(out SnippetInfo: TSnippetInfoList;
constructor TCodeImporter.InternalCreate;
begin
inherited InternalCreate;
- // Set up XML document that will read data
OleInitialize(nil);
fXMLDoc := TXMLDocHelper.CreateXMLDoc;
- // Initialise fields that receive imported data
SetLength(fSnippetInfo, 0);
+ EnsureImportCategoryExists;
end;
function TCodeImporter.ValidateDoc: Integer;
From cc146bf94fc8718d4e307dcedad15d6c745d9cdb Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 10 Nov 2024 14:51:33 +0000
Subject: [PATCH 063/222] Ensure a default category is always created
A new TCategoryEx.CreateDefault method was added that creates a default
category with ID '__default__' and description "My Snippets".
TDatabase.Load now call the above method to create a default category if
one with the same ID was not loaded. This new category can be deleted,
but it will always be recreated. The category can, though, be renamed.
Updated FmSnippetsEditorDlg to use the new category as the default
selection in the snippets editor dialogue box.
---
Src/DB.UCategory.pas | 22 ++++++++++++++++++++++
Src/DB.UMain.pas | 4 ++++
Src/FmSnippetsEditorDlg.pas | 5 +++--
3 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/Src/DB.UCategory.pas b/Src/DB.UCategory.pas
index 171c58acd..000565173 100644
--- a/Src/DB.UCategory.pas
+++ b/Src/DB.UCategory.pas
@@ -62,6 +62,10 @@ TCategory = class(TObject)
are equal or +1 if this category's ID is greater than Cat's.
}
public
+ const
+ /// ID of default category.
+ DefaultID = '__default__';
+
/// Object constructor. Sets up category object with given
/// property values.
/// CatID [in] Category ID.
@@ -112,6 +116,10 @@ TCategory = class(TObject)
}
TCategoryEx = class(TCategory)
public
+ /// Creates the default category with its default description.
+ ///
+ class function CreateDefault: TCategory;
+
function GetEditData: TCategoryData;
{Gets details of all editable data of category.
@return Required editable data.
@@ -235,6 +243,9 @@ function TCategory.CompareIDTo(const Cat: TCategory): Integer;
constructor TCategory.Create(const CatID: string;
const ACollectionID: TCollectionID; const Data: TCategoryData);
begin
+ {TODO -cVault: Add a simpler contructor that takes only the category ID and
+ description and creates does all the convoluted TCategoryData setting!
+ }
Assert(ClassType <> TCategory,
ClassName + '.Create: must only be called from descendants.');
inherited Create;
@@ -271,6 +282,17 @@ procedure TCategory.SetCollectionID(const AValue: TCollectionID);
{ TCategoryEx }
+class function TCategoryEx.CreateDefault: TCategory;
+var
+ Data: TCategoryData;
+resourcestring
+ sDefCatDesc = 'My Snippets';
+begin
+ Data.Init;
+ Data.Desc := sDefCatDesc;
+ Result := Create(DefaultID, TCollectionID.__TMP__UserDBCollectionID, Data);
+end;
+
function TCategoryEx.GetEditData: TCategoryData;
{Gets details of all editable data of category.
@return Required editable data.
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index cce30a1a4..14851782e 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -1121,6 +1121,10 @@ procedure TDatabase.Load;
Loader.Load(fSnippets, fCategories, Factory);
end;
+ // Ensure that the default category is present, if it's not already loaded
+ if not Assigned(fCategories.Find(TCategory.DefaultID)) then
+ fCategories.Add(TCategoryEx.CreateDefault);
+
fUpdated := False;
except
// If an exception occurs clear the database
diff --git a/Src/FmSnippetsEditorDlg.pas b/Src/FmSnippetsEditorDlg.pas
index 633a7fab0..9bd91f635 100644
--- a/Src/FmSnippetsEditorDlg.pas
+++ b/Src/FmSnippetsEditorDlg.pas
@@ -270,9 +270,10 @@ implementation
// Delphi
Windows {for inlining}, Graphics,
// Project
+ DB.UCategory,
DB.UMain, DB.USnippetKind, FmDependenciesDlg, IntfCommon, UColours, UConsts,
UCSSUtils, UCtrlArranger, UExceptions, UFontHelper, UIStringList,
- UReservedCategories, USnippetExtraHelper, USnippetValidator, UMessageBox,
+ USnippetExtraHelper, USnippetValidator, UMessageBox,
USnippetIDs, UStructs, UStrUtils, UTestUnitDlgMgr, UThemesEx, UUtils;
@@ -850,7 +851,7 @@ procedure TSnippetsEditorDlg.InitControls;
frmDescription.DefaultEditMode := emPlainText;
frmDescription.Clear;
edDisplayName.Clear;
- cbCategories.ItemIndex := fCatList.IndexOf(TReservedCategories.UserCatID);
+ cbCategories.ItemIndex := fCatList.IndexOf(TCategory.DefaultID);
if cbCategories.ItemIndex = -1 then
cbCategories.ItemIndex := 0;
cbKind.ItemIndex := fSnipKindList.IndexOf(skFreeform);
From 5c5ab00b5553e61ee8544b4dffaf6563891bd7fb Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 10 Nov 2024 15:01:16 +0000
Subject: [PATCH 064/222] No longer forcibly create reserved categories
The v4 "native" loader used to ensure that all the "reserved" categories
defined in UReservedCategories were created if they weren't stored in
the "user database". This no longer happens.
---
Src/DB.UDatabaseIO.pas | 25 +------------------------
1 file changed, 1 insertion(+), 24 deletions(-)
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index 16a02c42c..df4fc38d5 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -107,7 +107,6 @@ implementation
UConsts,
UFolderBackup,
UIStringList,
- UReservedCategories,
USnippetIDs;
@@ -169,7 +168,7 @@ TDatabaseLoader = class(TInterfacedObject, IDataFormatLoader)
{Returns heading to use in error messages. Should identify the database.
@return Required heading.
}
- procedure LoadCategories; virtual;
+ procedure LoadCategories;
{Loads all categories from storage.
}
procedure CreateCategory(const CatID: string;
@@ -248,9 +247,6 @@ TNativeV4FormatLoader = class(TDatabaseLoader, IDataFormatLoader)
{Returns heading to use in error messages. Identifies main database.
@return Required heading.
}
- procedure LoadCategories; override;
- {Loads all categories from storage and adds user category if not present.
- }
end;
/// Base for classes that save a collection to storage.
@@ -687,25 +683,6 @@ function TNativeV4FormatLoader.FindSnippet(const SnippetKey: string;
Result := SnipList.Find(SnippetKey, TCollectionID.__TMP__MainDBCollectionID);
end;
-procedure TNativeV4FormatLoader.LoadCategories;
- {Loads all categories from storage and adds user and imports categories if not
- present.
- }
-var
- ResCatIdx: Integer; // loops thru all reserved categories
- ResCatInfo: TReservedCategoryInfo; // info about a reserved category
-begin
- // Get all categories from storage
- inherited;
- // Add default user-defined categories if not present
- for ResCatIdx := 0 to Pred(TReservedCategories.Count) do
- begin
- ResCatInfo := TReservedCategories.Info(ResCatIdx);
- if Categories.Find(ResCatInfo.Name) = nil then
- CreateCategory(ResCatInfo.Name, ResCatInfo.Data);
- end;
-end;
-
{ TFormatSaver }
constructor TFormatSaver.Create(const ACollection: TCollection);
From e217d4cb1a7c55bf46a99d0083fa36ac5699f988 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 10 Nov 2024 15:05:40 +0000
Subject: [PATCH 065/222] Remove UReservedCategories unit from project
This unit is now redundant and has been removed.
---
Src/CodeSnip.dpr | 1 -
Src/CodeSnip.dproj | 1 -
Src/UReservedCategories.pas | 166 ------------------------------------
3 files changed, 168 deletions(-)
delete mode 100644 Src/UReservedCategories.pas
diff --git a/Src/CodeSnip.dpr b/Src/CodeSnip.dpr
index 98cb69a47..02ba3d324 100644
--- a/Src/CodeSnip.dpr
+++ b/Src/CodeSnip.dpr
@@ -297,7 +297,6 @@ uses
UProtocols in 'UProtocols.pas',
UQuery in 'UQuery.pas',
UREMLDataIO in 'UREMLDataIO.pas',
- UReservedCategories in 'UReservedCategories.pas',
UResourceUtils in 'UResourceUtils.pas',
URTFBuilder in 'URTFBuilder.pas',
URTFCategoryDoc in 'URTFCategoryDoc.pas',
diff --git a/Src/CodeSnip.dproj b/Src/CodeSnip.dproj
index 1141453ca..48eb74367 100644
--- a/Src/CodeSnip.dproj
+++ b/Src/CodeSnip.dproj
@@ -499,7 +499,6 @@
-
diff --git a/Src/UReservedCategories.pas b/Src/UReservedCategories.pas
deleted file mode 100644
index dc8db26e4..000000000
--- a/Src/UReservedCategories.pas
+++ /dev/null
@@ -1,166 +0,0 @@
-{
- * This Source Code Form is subject to the terms of the Mozilla Public License,
- * v. 2.0. If a copy of the MPL was not distributed with this file, You can
- * obtain one at https://mozilla.org/MPL/2.0/
- *
- * Copyright (C) 2009-2021, Peter Johnson (gravatar.com/delphidabbler).
- *
- * Implements a static class that provides information about reserved user
- * defined categories.
-}
-
-
-unit UReservedCategories;
-
-
-interface
-
-
-uses
- // Project
- DB.UCategory, UBaseObjects;
-
-
-type
-
- {
- TReservedCategoryInfo:
- Record that fully describes a category, i.e. contains all the required data.
- }
- TReservedCategoryInfo = record
- Name: string; // Name (unique id) of category
- Data: TCategoryData; // Category's properties
- procedure Assign(const Src: TReservedCategoryInfo);
- {Sets this record's fields to be same as another TReservedCategoryInfo
- record.
- @param Src [in] Record containing fields to be copied.
- }
- procedure Init;
- {Initialises record to nul values.
- }
- end;
-
- {
- TReservedCategories:
- Static class that provides information about reserved user defined
- categories.
- }
- TReservedCategories = class(TNoConstructObject)
- strict private
- class function IsReservedName(const CatID: string): Boolean;
- {Checks if a category name is the id of a reserved category.
- @param CatID [in] ID to be checked.
- @return True if category is reserved, False if not.
- }
- public
- const UserCatID = 'user'; // default category for user snippets
- const ImportsCatID = 'imports'; // category for imported user snippets
- const SWAGCatID = '_swag_'; // category for imported SWAG snippets
- class function IsReserved(const Cat: TCategory): Boolean;
- {Checks if a category is reserved.
- @param Cat [in] Category to be checked.
- @return True if category is reserved, False if not.
- }
- class function Info(Idx: Integer): TReservedCategoryInfo;
- {Gets information about a reserved category.
- @param Idx [in] Index of required category.
- @return Record containing information about category.
- }
- class function Count: Integer;
- {Gets number of reserved categories.
- @return Number of reserved categories.
- }
- end;
-
-
-implementation
-
-
-uses
- // Delphi
- Windows {for inlining},
- // Project
- UStrUtils;
-
-
-resourcestring
- // Default reserved category descriptions
- sUserDesc = 'User Defined Snippets';
- sImportsDesc = 'Imported Snippets';
- sSWAGDesc = 'SWAG Imports';
-
-const
- // Maps reserved category ids onto info that describes category
- cReservedCats: array[0..2] of TReservedCategoryInfo = (
- (Name: TReservedCategories.UserCatID; Data: (Desc: sUserDesc)),
- (Name: TReservedCategories.ImportsCatID; Data: (Desc: sImportsDesc)),
- (Name: TReservedCategories.SWAGCatID; Data: (Desc: sSWAGDesc))
- );
-
-{ TReservedCategories }
-
-class function TReservedCategories.Count: Integer;
- {Gets number of reserved categories.
- @return Number of reserved categories.
- }
-begin
- Result := Length(cReservedCats);
-end;
-
-class function TReservedCategories.Info(Idx: Integer): TReservedCategoryInfo;
- {Gets information about a reserved category.
- @param Idx [in] Index of required category.
- @return Record containing information about category.
- }
-begin
- Result.Assign(cReservedCats[Idx]);
-end;
-
-class function TReservedCategories.IsReserved(const Cat: TCategory): Boolean;
- {Checks if a category is reserved.
- @param Cat [in] Category to be checked.
- @return True if category is reserved, False if not.
- }
-begin
- Result := IsReservedName(Cat.ID);
-end;
-
-class function TReservedCategories.IsReservedName(
- const CatID: string): Boolean;
- {Checks if a category name is the id of a reserved category.
- @param CatID [in] ID to be checked.
- @return True if category is reserved, False if not.
- }
-var
- Idx: Integer; // loops thru all reserved categories
-begin
- Result := False;
- for Idx := 0 to Pred(Count) do
- if StrSameText(CatID, Info(Idx).Name) then
- begin
- Result := True;
- Exit;
- end;
-end;
-
-{ TReservedCategoryInfo }
-
-procedure TReservedCategoryInfo.Assign(const Src: TReservedCategoryInfo);
- {Sets this record's fields to be same as another TReservedCategoryInfo record.
- @param Src [in] Record containing fields to be copied.
- }
-begin
- Name := Src.Name;
- Data.Assign(Src.Data);
-end;
-
-procedure TReservedCategoryInfo.Init;
- {Initialises record to nul values.
- }
-begin
- Name := '';
- Data.Init;
-end;
-
-end.
-
From c9ebccf203e5b7c67ec561e277428a639ebb19c4 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 11 Nov 2024 17:48:56 +0000
Subject: [PATCH 066/222] Fix bug in DBIO.UIniData
If the "main" collection is not loaded first then any categories that
have already been loaded that it doesn't recognise would cause a crash
when the loader tried to open a non-existent category .ini fle.
Added an if statement to check for the existance of the required .ini
file before trying to open it.
---
Src/DBIO.UIniData.pas | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/Src/DBIO.UIniData.pas b/Src/DBIO.UIniData.pas
index d314f8a61..e54c5c20a 100644
--- a/Src/DBIO.UIniData.pas
+++ b/Src/DBIO.UIniData.pas
@@ -514,16 +514,24 @@ procedure TIniDataReader.GetCatProps(const CatID: string;
function TIniDataReader.GetCatSnippets(const CatID: string): IStringList;
var
+ CatIniFile: string;
CatIni: TCustomIniFile; // accesses .ini file associated with category
SnipList: TStringList; // list of snippets in category
begin
+ Result := TIStringList.Create;
try
// Snippet names are names of sections in category's .ini file
+ CatIniFile := CatToCatIni(CatID);
+ if not TFile.Exists(CatIniFile) then
+ // This is not an error since it is possible that a category exists in
+ // another collection and loader will request info from that collection
+ // too.
+ Exit;
CatIni := fIniCache.GetIniFile(CatToCatIni(CatID));
SnipList := TStringList.Create;
try
CatIni.ReadSections(SnipList);
- Result := TIStringList.Create(SnipList);
+ Result.Add(SnipList);
finally
SnipList.Free;
end;
From fad930cfd8b6ea2382358f1ca339854b00e433ac Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 11 Nov 2024 20:21:12 +0000
Subject: [PATCH 067/222] Add new C escape char routines to UStrUtils
New StrCEscapeStr and StrCUnEscapeStr routines escape and un-escape
specified characters in a string with C-style escape character
sequences, respectively.
---
Src/UStrUtils.pas | 144 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 144 insertions(+)
diff --git a/Src/UStrUtils.pas b/Src/UStrUtils.pas
index 4e0e29584..b56d8005c 100644
--- a/Src/UStrUtils.pas
+++ b/Src/UStrUtils.pas
@@ -289,6 +289,45 @@ function StrOfChar(const Ch: Char; const Count: Word): string;
/// If Count is zero then an empty string is returned.
function StrOfSpaces(const Count: Word): string;
+/// Escapes specified characters in a string using C format escape
+/// sequences.
+/// string [in] String to be escaped.
+/// string [in] String of characters to be
+/// used in the escape sequence.
+/// string [in] String of characters to be
+/// escaped.
+/// string. String with all characters from
+/// EscapableChars replaced by a backslash followed by the character at
+/// the same index in EscapeChars
+///
+/// NOTE: The backslash symbol is always escaped regardless of whether it
+/// is included in EscapeChars and EscapableChars.
+/// EscapeChars and EscapableChars must be the same
+/// length.
+///
+function StrCEscapeStr(const S: string; EscapeChars, EscapableChars: string):
+ string;
+
+/// Un-escapes a string containing C format escape sequences.
+///
+/// string [in] String to be un-escaped.
+/// string [in] String of characters used in
+/// the escape sequences.
+/// string [in] String of characters to be
+/// used to replace the escape sequences.
+/// string. String with all escape sequences comprising a
+/// backslash followed by a character from EscapeChars replaced by a
+/// corresponding character from EscapableChars.
+///
+/// NOTE: The backslash symbol is always unescaped regardless of whether
+/// it is included in EscapeChars and EscapableChars.
+/// EscapeChars and EscapableChars must be the same
+/// length.
+///
+function StrCUnEscapeStr(const S: string; EscapeChars, EscapableChars: string):
+ string;
+
+
implementation
@@ -944,5 +983,110 @@ function StrOfSpaces(const Count: Word): string;
Result := StrOfChar(' ', Count);
end;
+function StrCEscapeStr(const S: string; EscapeChars, EscapableChars: string):
+ string;
+const
+ cEscChar = '\'; // the C escape character
+var
+ EscCount: Integer; // count of escaped characters in string
+ Idx: Integer; // loops thru string
+ PRes: PChar; // points to chars in result string
+ EscCharPos: Integer; // position of esc chars in EscapeChars & EscapableChars
+begin
+ Assert(Length(EscapeChars) = Length(EscapableChars),
+ 'StrCEscapeStr: EscapeChars & EscapableChars are different lengths');
+ // Ensure '\' get escaped
+ if StrPos(cEscChar, EscapeChars) = 0 then
+ EscapeChars := cEscChar + EscapeChars;
+ if StrPos(cEscChar, EscapableChars) = 0 then
+ EscapableChars := cEscChar + EscapableChars;
+ // Check for empty string and treat specially
+ // (empty string crashes main code)
+ if S = '' then
+ begin
+ Result := '';
+ Exit;
+ end;
+ // Count escapable characters in string
+ EscCount := 0;
+ for Idx := 1 to Length(S) do
+ begin
+ if SysUtils.AnsiPos(S[Idx], EscapableChars) > 0 then
+ Inc(EscCount);
+ end;
+ // Set size of result string and get pointer to it
+ SetLength(Result, Length(S) + EscCount);
+ PRes := PChar(Result);
+ // Replace escapable chars with the escaped version
+ for Idx := 1 to Length(S) do
+ begin
+ EscCharPos := SysUtils.AnsiPos(S[Idx], EscapableChars);
+ if EscCharPos > 0 then
+ begin
+ PRes^ := cEscChar;
+ Inc(PRes);
+ PRes^ := EscapeChars[EscCharPos];
+ end
+ else
+ PRes^ := S[Idx];
+ Inc(PRes);
+ end;
+end;
+
+function StrCUnEscapeStr(const S: string; EscapeChars, EscapableChars: string):
+ string;
+const
+ cEscChar = '\'; // the C escape character
+var
+ EscCount: Integer; // counts escaped characters in string
+ Idx: Integer; // loops thru source string
+ PRes: PChar; // points to chars in result string
+ EscCharPos: Integer; // position of esc chars in EscapeChars & EscapableChars
+begin
+ Assert(Length(EscapeChars) = Length(EscapableChars),
+ 'StrCUnEscapeStr: EscapeChars & EscapableChars are different lengths');
+ // Ensure '\' get unescaped
+ if StrPos(cEscChar, EscapeChars) = 0 then
+ EscapeChars := cEscChar + EscapeChars;
+ if StrPos(cEscChar, EscapableChars) = 0 then
+ EscapableChars := cEscChar + EscapableChars;
+ // Count escape sequences
+ EscCount := 0;
+ Idx := 1;
+ while Idx < Length(S) do // don't count '\' if last character
+ begin
+ if S[Idx] = cEscChar then
+ begin
+ Inc(EscCount);
+ Inc(Idx);
+ end;
+ Inc(Idx);
+ end;
+ // Set length of result string and get pointer to it
+ SetLength(Result, Length(S) - EscCount);
+ PRes := PChar(Result);
+ // Replace escaped chars with literal ones
+ Idx := 1;
+ while Idx <= Length(S) do
+ begin
+ // check for escape char (unless last char when treat literally)
+ if (S[Idx] = cEscChar) and (Idx <> Length(S)) then
+ begin
+ // we have an escape char
+ Inc(Idx); // skip over '\'
+ // get index of escaped char (0 if not valid)
+ EscCharPos := SysUtils.AnsiPos(S[Idx], EscapeChars);
+ if EscCharPos > 0 then
+ PRes^ := EscapableChars[EscCharPos]
+ else
+ PRes^ := S[Idx]; // invalid escape char: copy literally
+ end
+ else
+ PRes^ := S[Idx];
+ Inc(Idx);
+ Inc(PRes);
+ end;
+end;
+
end.
From daaf730b8aa005ceaea8bc1c27a4d1cba1272759 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 11 Nov 2024 19:51:31 +0000
Subject: [PATCH 068/222] Add UTabSeparatedFileIO unit to project
This defines classes that read and write tab separated values from/to
UTF8 text files.
---
Src/CodeSnip.dpr | 3 +-
Src/CodeSnip.dproj | 1 +
Src/UTabSeparatedFileIO.pas | 250 ++++++++++++++++++++++++++++++++++++
3 files changed, 253 insertions(+), 1 deletion(-)
create mode 100644 Src/UTabSeparatedFileIO.pas
diff --git a/Src/CodeSnip.dpr b/Src/CodeSnip.dpr
index 02ba3d324..f86338372 100644
--- a/Src/CodeSnip.dpr
+++ b/Src/CodeSnip.dpr
@@ -374,7 +374,8 @@ uses
FmRegisterCompilersDlg in 'FmRegisterCompilersDlg.pas' {RegisterCompilersDlg},
ClassHelpers.UGraphics in 'ClassHelpers.UGraphics.pas',
ClassHelpers.UActions in 'ClassHelpers.UActions.pas',
- DB.UCollections in 'DB.UCollections.pas';
+ DB.UCollections in 'DB.UCollections.pas',
+ UTabSeparatedFileIO in 'UTabSeparatedFileIO.pas';
// Include resources
{$Resource ExternalObj.tlb} // Type library file
diff --git a/Src/CodeSnip.dproj b/Src/CodeSnip.dproj
index 48eb74367..ba059b80d 100644
--- a/Src/CodeSnip.dproj
+++ b/Src/CodeSnip.dproj
@@ -581,6 +581,7 @@
+ Base
diff --git a/Src/UTabSeparatedFileIO.pas b/Src/UTabSeparatedFileIO.pas
new file mode 100644
index 000000000..0c411c570
--- /dev/null
+++ b/Src/UTabSeparatedFileIO.pas
@@ -0,0 +1,250 @@
+{
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/
+ *
+ * Copyright (C) 2024, Peter Johnson (gravatar.com/delphidabbler).
+ *
+ * Classes that can read and write UTF8 files containing a watermark line
+ * followed by lines of tabbed separated values.
+}
+
+unit UTabSeparatedFileIO;
+
+interface
+
+uses
+ // Delphi
+ SysUtils,
+ // Project
+ UExceptions,
+ UIStringList;
+
+type
+
+ /// Class that writes UTF8 files beginning with a watermark line
+ /// followed by and blank line then lines of tabbed separated values.
+ ///
+ TTabSeparatedFileWriter = class(TObject)
+ strict private
+ var
+ fFileName: string;
+ fBuilder: TStringBuilder;
+ /// Convert any characters in AValue that can't appear in a
+ /// field into C-style escape sequences.
+ function Escape(const AValue: string): string;
+ /// Outputs the watermark AWatermark on a line on its own.
+ ///
+ procedure WriteWatermark(const AWaterMark: string);
+ public
+ /// Creates object to write file AFileName with watermark
+ /// AWatermark.
+ constructor Create(const AFileName: string; const AWatermark: string);
+ /// Object destructor.
+ destructor Destroy; override;
+ /// Writes data to file just before the object is destroyed.
+ ///
+ procedure BeforeDestruction; override;
+ /// Writes a line of data with tabbed separated fields.
+ /// array of string [in] Fields to be written.
+ ///
+ procedure WriteLine(const AFields: array of string);
+ end;
+
+ /// Class that reads UTF8 files beginning with a watermark line
+ /// followed by lines of tabbed separated values.
+ /// Any blank lines are ignored.
+ TTabSeparatedReader = class(TObject)
+ public
+ type
+ /// Type of callback trigged when each line is pardsed.
+ ///
+ /// TArray<string> [in] Fields defined
+ /// in the line.
+ TLineCallback = reference to procedure(AFields: TArray);
+ strict private
+ var
+ fFileName: string;
+ fWatermark: string;
+ fLines: IStringList;
+ /// Un-escapes any a C style escape sequences in AValue.
+ ///
+ function UnEscape(const AValue: string): string;
+ /// Reads file and splits into lines.
+ /// ETabSeparatedReader raised if file can't be read.
+ ///
+ procedure ReadFile;
+ /// Removes all blank lines from the data.
+ procedure PreProcess;
+ /// Parses the data. See the Read method for details of the
+ /// ALineCallback parameter.
+ procedure Parse(const ALineCallback: TLineCallback);
+ public
+ /// Creates object to read file AFileName which must begin
+ /// with watermark AWatermark.
+ constructor Create(const AFileName: string; const AWatermark: string);
+ /// Reads all data from the file.
+ /// TLineCallback [in] Callback called
+ /// for each line of data read. Passed an array of fields read from the
+ /// line. Caller must process the fields in this callback.
+ /// ETabSeparatedReader raised if file can't be read or
+ /// if watermark is not valid.
+ procedure Read(const ALineCallback: TLineCallback);
+ end;
+
+ ETabSeparatedReader = class(ECodeSnip);
+
+implementation
+
+uses
+ // Delphi
+ Classes,
+ // Project
+ UConsts,
+ UIOUtils,
+ UStrUtils;
+
+const
+ EscapeableChars = TAB + CR + LF;
+ EscapedChars = 'trn';
+
+{ TTabSeparatedFileWriter }
+
+procedure TTabSeparatedFileWriter.BeforeDestruction;
+begin
+ inherited;
+ TFileIO.WriteAllText(fFileName, fBuilder.ToString, TEncoding.UTF8, True);
+end;
+
+constructor TTabSeparatedFileWriter.Create(const AFileName, AWatermark: string);
+begin
+ Assert(not StrIsEmpty(AFileName), ClassName + '.Create: AFileName is empty');
+ Assert(not StrIsEmpty(AWatermark, True),
+ ClassName + '.Create: AWatermark is empty');
+
+ inherited Create;
+ fFileName := StrTrim(AFileName);
+ fBuilder := TStringBuilder.Create;
+ WriteWatermark(AWaterMark);
+end;
+
+destructor TTabSeparatedFileWriter.Destroy;
+begin
+ fBuilder.Free;
+ inherited;
+end;
+
+function TTabSeparatedFileWriter.Escape(const AValue: string): string;
+begin
+ // Perform character escaping per
+ // https://en.wikipedia.org/wiki/Tab-separated_values
+ Result := StrCEscapeStr(AValue, EscapedChars, EscapeableChars);
+end;
+
+procedure TTabSeparatedFileWriter.WriteLine(const AFields: array of string);
+var
+ Data: TStringList;
+ Item: string;
+begin
+ Data := TStringList.Create;
+ try
+ // escape each data item in array
+ for Item in AFields do
+ Data.Add(Escape(Item));
+ fBuilder.AppendLine(StrJoin(Data, TAB, True));
+ finally
+ Data.Free;
+ end;
+end;
+
+procedure TTabSeparatedFileWriter.WriteWatermark(const AWaterMark: string);
+begin
+ if StrTrim(AWaterMark) <> '' then
+ begin
+ fBuilder.AppendLine(AWaterMark);
+ fBuilder.AppendLine;
+ end;
+end;
+
+{ TTabSeparatedReader }
+
+constructor TTabSeparatedReader.Create(const AFileName, AWatermark: string);
+begin
+ Assert(not StrIsEmpty(AFileName), ClassName + '.Create: AFileName is empty');
+ Assert(not StrIsEmpty(AWatermark, True),
+ ClassName + '.Create: AWatermark is empty');
+
+ inherited Create;
+ fFileName := StrTrim(AFileName);
+ fWatermark := StrTrim(AWatermark);
+ fLines := TIStringList.Create;
+end;
+
+procedure TTabSeparatedReader.Parse(const ALineCallback: TLineCallback);
+resourcestring
+ sBadFileFormat = 'Invalid tab separated list file format';
+var
+ Line: string;
+ Fields: TStringList;
+ Idx: Integer;
+begin
+ // check for watermark in 1st line
+ if (fLines.Count <= 1) or (fLines[0] <> fWatermark) then
+ raise ETabSeparatedReader.Create(sBadFileFormat);
+ // delete watermark line
+ fLines.Delete(0);
+ for Line in fLines do
+ begin
+ Fields := TStringList.Create;
+ try
+ StrExplode(Line, TAB, Fields);
+ for Idx := 0 to Pred(Fields.Count) do
+ Fields[Idx] := UnEscape(Fields[Idx]);
+ ALineCallback(Fields.ToStringArray);
+ finally
+ Fields.Free;
+ end;
+ end;
+end;
+
+procedure TTabSeparatedReader.PreProcess;
+var
+ Idx: Integer;
+begin
+ for Idx := Pred(fLines.Count) downto 0 do
+ if StrIsEmpty(fLines[Idx], True) then
+ fLines.Delete(Idx);
+end;
+
+procedure TTabSeparatedReader.ReadFile;
+begin
+ try
+ fLines.SetText(
+ TFileIO.ReadAllText(fFileName, TEncoding.UTF8, True), CRLF, False, True
+ );
+ except
+ on E: EStreamError do
+ raise ETabSeparatedReader.Create(E);
+ on E: EIOUtils do
+ raise ETabSeparatedReader.Create(E);
+ else
+ raise;
+ end;
+end;
+
+procedure TTabSeparatedReader.Read(const ALineCallback: TLineCallback);
+begin
+ ReadFile;
+ Preprocess;
+ Parse(ALineCallback);
+end;
+
+function TTabSeparatedReader.UnEscape(const AValue: string): string;
+begin
+ // Perform character un-escaping per
+ // https://en.wikipedia.org/wiki/Tab-separated_values
+ Result := StrCUnEscapeStr(AValue, EscapedChars, EscapeableChars);
+end;
+
+end.
+
From 20f4f1256ae96698194e45e569382c052caf9782 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 11 Nov 2024 20:18:46 +0000
Subject: [PATCH 069/222] Add new DBIO.UCategoryIO unit to project
This unit defines class that read / write category data from / to a
categories file that is stored in tab separated value format, with a
leading watermark line.
---
Src/CodeSnip.dpr | 3 +-
Src/CodeSnip.dproj | 1 +
Src/DBIO.UCategoryIO.pas | 163 +++++++++++++++++++++++++++++++++++++++
3 files changed, 166 insertions(+), 1 deletion(-)
create mode 100644 Src/DBIO.UCategoryIO.pas
diff --git a/Src/CodeSnip.dpr b/Src/CodeSnip.dpr
index f86338372..32805a495 100644
--- a/Src/CodeSnip.dpr
+++ b/Src/CodeSnip.dpr
@@ -375,7 +375,8 @@ uses
ClassHelpers.UGraphics in 'ClassHelpers.UGraphics.pas',
ClassHelpers.UActions in 'ClassHelpers.UActions.pas',
DB.UCollections in 'DB.UCollections.pas',
- UTabSeparatedFileIO in 'UTabSeparatedFileIO.pas';
+ UTabSeparatedFileIO in 'UTabSeparatedFileIO.pas',
+ DBIO.UCategoryIO in 'DBIO.UCategoryIO.pas';
// Include resources
{$Resource ExternalObj.tlb} // Type library file
diff --git a/Src/CodeSnip.dproj b/Src/CodeSnip.dproj
index ba059b80d..921ecf1e5 100644
--- a/Src/CodeSnip.dproj
+++ b/Src/CodeSnip.dproj
@@ -582,6 +582,7 @@
+ Base
diff --git a/Src/DBIO.UCategoryIO.pas b/Src/DBIO.UCategoryIO.pas
new file mode 100644
index 000000000..4c058c641
--- /dev/null
+++ b/Src/DBIO.UCategoryIO.pas
@@ -0,0 +1,163 @@
+{
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/
+ *
+ * Copyright (C) 2024, Peter Johnson (gravatar.com/delphidabbler).
+ *
+ * Class that read and write category information from and to files.
+}
+
+unit DBIO.UCategoryIO;
+
+interface
+
+uses
+ // Delphi
+ SysUtils,
+ Generics.Collections,
+ // Project
+ DB.UCategory,
+ UExceptions,
+ UTabSeparatedFileIO;
+
+type
+ /// Base class for category reader and writer classes.
+ TCategoryIO = class abstract(TObject)
+ strict protected
+ const
+ /// Watermark that is present on the first line of a valid
+ /// categories file.
+ Watermark = #$25BA + ' CodeSnip Categories v1 ' + #$25C4;
+ end;
+
+ /// Class used to read category information from a file.
+ TCategoryReader = class sealed(TCategoryIO)
+ public
+ type
+ /// Key / Value pair associating the category ID (key) with the
+ /// category data (value).
+ TCategoryIDAndData = TPair;
+ strict private
+ var
+ /// Object that read data from a tab delimited UTF8 text file.
+ ///
+ fFileReader: TTabSeparatedReader;
+ /// List of category data read from file.
+ fCatData: TList;
+ /// Parses fields that have been split out from each text line.
+ ///
+ /// ECategoryReader raised if the fields are not valid.
+ ///
+ procedure ParseFields(AFields: TArray);
+ public
+ /// Creates object to read from file AFileName.
+ constructor Create(const AFileName: string);
+ /// Object destructor.
+ destructor Destroy; override;
+ /// Reads data about each category defined in file.
+ /// TArray<TCategoryIDAndData>. Array of category
+ /// data.
+ /// ECategoryReader raised if the file can't be read or
+ /// if its contents are invalid.
+ function Read: TArray;
+ end;
+
+ /// Class of exception raised by TCategoryReader.
+ ECategoryReader = class(ECodeSnip);
+
+ /// Class used to write category information to a file.
+ TCategoryWriter = class sealed(TCategoryIO)
+ strict private
+ var
+ /// Object that writes data to a tab delimited UTF8 text file.
+ ///
+ fFileWriter: TTabSeparatedFileWriter;
+ public
+ /// Creates object to write to file AFileName.
+ constructor Create(const AFileName: string);
+ /// Object destructor.
+ destructor Destroy; override;
+ /// Writes information about each category in ACategoryList
+ ///
+ procedure Write(const ACategoryList: TCategoryList);
+ end;
+
+implementation
+
+uses
+ // Project
+ UStrUtils;
+
+{ TCategoryReader }
+
+constructor TCategoryReader.Create(const AFileName: string);
+begin
+ Assert(not StrIsEmpty(AFileName), ClassName + '.Create: AFileName is empty');
+ inherited Create;
+ fFileReader := TTabSeparatedReader.Create(AFileName, Watermark);
+ fCatData := TList.Create;
+end;
+
+destructor TCategoryReader.Destroy;
+begin
+ fCatData.Free;
+ fFileReader.Free;
+ inherited;
+end;
+
+procedure TCategoryReader.ParseFields(AFields: TArray);
+resourcestring
+ sMalformedLine = 'Malformed line in categories file';
+var
+ CatID: string;
+ Data: TCategoryData;
+begin
+ if Length(AFields) <> 2 then
+ raise ECategoryReader.Create(sMalformedLine);
+ if StrIsEmpty(AFields[0]) or StrIsEmpty(AFields[1]) then
+ raise ECategoryReader.Create(sMalformedLine);
+ CatID := StrTrim(AFields[0]);
+ Data.Init;
+ Data.Desc := StrTrim(AFields[1]);
+ fCatData.Add(TCategoryIDAndData.Create(CatID, Data));
+end;
+
+function TCategoryReader.Read: TArray;
+begin
+ fCatData.Clear;
+ try
+ fFileReader.Read(ParseFields);
+ except
+ on E: ETabSeparatedReader do
+ raise ECategoryReader.Create(E);
+ else
+ raise;
+ end;
+ Result := fCatData.ToArray;
+end;
+
+{ TCategoryWriter }
+
+constructor TCategoryWriter.Create(const AFileName: string);
+begin
+ Assert(not StrIsEmpty(AFileName), ClassName + '.Create: AFileName is empty');
+ inherited Create;
+ fFileWriter := TTabSeparatedFileWriter.Create(AFileName, Watermark);
+end;
+
+destructor TCategoryWriter.Destroy;
+begin
+ fFileWriter.Free;
+ inherited;
+end;
+
+procedure TCategoryWriter.Write(const ACategoryList: TCategoryList);
+var
+ Cat: TCategory;
+begin
+ for Cat in ACategoryList do
+ fFileWriter.WriteLine(TArray.Create(Cat.ID, Cat.Description));
+end;
+
+end.
From b3f8c537f6732c95b97025d9911f95939be2ba6e Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 11 Nov 2024 21:05:03 +0000
Subject: [PATCH 070/222] Add new TCategory.Update method
This method permits a category's properties to be updated.
---
Src/DB.UCategory.pas | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/Src/DB.UCategory.pas b/Src/DB.UCategory.pas
index 000565173..6fdb3a3b6 100644
--- a/Src/DB.UCategory.pas
+++ b/Src/DB.UCategory.pas
@@ -79,6 +79,12 @@ TCategory = class(TObject)
destructor Destroy; override;
{Destructor. Tears down object.
}
+
+ /// Updates category properties.
+ /// TCategoryData [in] Updated category
+ /// properties.
+ procedure Update(const Data: TCategoryData);
+
function IsEqual(const Cat: TCategory): Boolean;
{Checks if this category is same as another category. Categories are
considered equal if they have the same ID.
@@ -280,6 +286,11 @@ procedure TCategory.SetCollectionID(const AValue: TCollectionID);
fCollectionID := AValue;
end;
+procedure TCategory.Update(const Data: TCategoryData);
+begin
+ fDescription := Data.Desc;
+end;
+
{ TCategoryEx }
class function TCategoryEx.CreateDefault: TCategory;
From 9e27f4bdf60c9e9dd8eb82853e1b292c5bd4702b Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 12 Nov 2024 00:38:53 +0000
Subject: [PATCH 071/222] Add code to load/save categories to their own file
Categories are now loaded and saved to a single global file per user
that is separate from the category information stored in collection
files.
Collection files still store this information, but in future will not
store information about empty categories. Therefore this new feature
ensures that empty categories are not lost until explicitly deleted.
To do this IGlobalCategoryLoader and IGlobalCategorySaver interfaces
were added to DB.UDatabaseIO unit, along with implementing private
TGlobalCategoryLoader and TGlobalCategorySaver classes and new
factory methods to create them.
TDatabase.Load and TDatabase.Save were extended to load and save the
categories to file.
TAppInfo had a new UserCategoriesFileName method added to return the
full path to a per-user global categories file.
---
Src/DB.UDatabaseIO.pas | 123 ++++++++++++++++++++++++++++++++++++++++-
Src/DB.UMain.pas | 19 +++++--
Src/UAppInfo.pas | 10 ++++
3 files changed, 144 insertions(+), 8 deletions(-)
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index df4fc38d5..d92d32dcb 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -53,17 +53,39 @@ interface
IDataFormatSaver = interface(IInterface)
['{F46EE2E3-68A7-4877-9E04-192D15D29BB1}']
/// Saves data to storage.
- /// TSnippetList [in] Contains information
+ /// TSnippetList [in] Contains information
/// about each snippet to be saved.
/// TCategoryList [in] Contains information
/// about each category to be saved.
/// IDBDataProvider [in] Object used to
/// obtain details of the data to be stored.
- /// Method of IDataFormatSaver.
procedure Save(const SnipList: TSnippetList;
const Categories: TCategoryList; const Provider: IDBDataProvider);
end;
+ /// Interface to object that can save global category information,
+ /// regardless of any categories saved with collections.
+ IGlobalCategoryLoader = interface(IInterface)
+ ['{0029F641-FAC4-43C8-A412-F70554BDCF28}']
+ /// Loads categories data from global storage.
+ /// TCategoryList [in] Receives information
+ /// about each category loaded.
+ /// IDBDataItemFactory [in] Object
+ /// used to create new categories.
+ procedure Load(const Categories: TCategoryList;
+ const DBDataItemFactory: IDBDataItemFactory);
+ end;
+
+ /// Interface to object that can load global category information,
+ /// regardless of any categories loaded with collections.
+ IGlobalCategorySaver = interface(IInterface)
+ ['{D967E4FC-32FA-47F8-9BE0-4B25C7215CCA}']
+ /// Saves category data to global storage.
+ /// TCategoryList [in] Contains information
+ /// about each category to be saved.
+ procedure Save(const Categories: TCategoryList);
+ end;
+
{
TDatabaseIOFactory:
Factory class that can create instances of writer and loader objects for the
@@ -72,7 +94,7 @@ interface
TDatabaseIOFactory = class(TNoConstructObject)
public
/// Creates and returns an object to be used to load the given
- /// collection's data in the correct format. Nil is returned if no loader
+ /// collection's data in the correct format. Nil is returned if no loader
/// object is supported.
class function CreateDBLoader(const Collection: TCollection):
IDataFormatLoader;
@@ -82,6 +104,15 @@ TDatabaseIOFactory = class(TNoConstructObject)
/// object is supported.
class function CreateDBSaver(const Collection: TCollection):
IDataFormatSaver;
+
+ /// Creates and returns an object to be used to load a list of
+ /// globally stored categories.
+ class function CreateGlobalCategoryLoader: IGlobalCategoryLoader;
+
+ /// Creates and returns an object to be used to save a list of
+ /// categories to global storage.
+ class function CreateGlobalCategorySaver: IGlobalCategorySaver;
+
end;
{
@@ -97,8 +128,10 @@ implementation
uses
// Delphi
SysUtils,
+ Generics.Collections,
IOUtils,
// Project
+ DBIO.UCategoryIO,
DBIO.UFileIOIntf,
DBIO.UIniData,
DBIO.UNulDataReader,
@@ -407,6 +440,31 @@ TNativeV4FormatSaver = class(TFormatSaver,
const Provider: IDBDataProvider); override;
end;
+ /// Class used to save global category information, regardless of
+ /// any categories saved with collections.
+ TGlobalCategoryLoader = class(TInterfacedObject, IGlobalCategoryLoader)
+ public
+ /// Loads categories data from global storage.
+ /// TCategoryList [in] Receives information
+ /// about each category loaded.
+ /// IDBDataItemFactory [in] Object
+ /// used to create new categories.
+ /// Method of IGlobalCategoryLoader.
+ procedure Load(const Categories: TCategoryList;
+ const DBDataItemFactory: IDBDataItemFactory);
+ end;
+
+ /// Class used to save global category information, regardless of
+ /// any categories saved with collections.
+ TGlobalCategorySaver = class(TInterfacedObject, IGlobalCategorySaver)
+ public
+ /// Saves category data to global storage.
+ /// TCategoryList [in] Contains information
+ /// about each category to be saved.
+ /// Method of IGlobalCategorySaver.
+ procedure Save(const Categories: TCategoryList);
+ end;
+
{ TDatabaseIOFactory }
class function TDatabaseIOFactory.CreateDBLoader(const Collection: TCollection):
@@ -437,6 +495,18 @@ class function TDatabaseIOFactory.CreateDBSaver(
end;
end;
+class function TDatabaseIOFactory.CreateGlobalCategoryLoader:
+ IGlobalCategoryLoader;
+begin
+ Result := TGlobalCategoryLoader.Create;
+end;
+
+class function TDatabaseIOFactory.CreateGlobalCategorySaver:
+ IGlobalCategorySaver;
+begin
+ Result := TGlobalCategorySaver.Create;
+end;
+
{ TDatabaseLoader }
constructor TDatabaseLoader.Create(const ACollection: TCollection);
@@ -842,5 +912,52 @@ procedure TNativeV4FormatSaver.Save(const SnipList: TSnippetList;
DoSave(SnipList, Categories, Provider);
end;
+{ TGlobalCategoryLoader }
+
+procedure TGlobalCategoryLoader.Load(const Categories: TCategoryList;
+ const DBDataItemFactory: IDBDataItemFactory);
+var
+ Reader: TCategoryReader;
+ CatInfo: TCategoryReader.TCategoryIDAndData;
+ Cat: TCategory;
+begin
+ if not TFile.Exists(TAppInfo.UserCategoriesFileName) then
+ Exit;
+ Reader := TCategoryReader.Create(TAppInfo.UserCategoriesFileName);
+ try
+ for CatInfo in Reader.Read do
+ begin
+ Cat := Categories.Find(CatInfo.Key);
+ if not Assigned(Cat) then
+ begin
+ Categories.Add(
+ DBDataItemFactory.CreateCategory(CatInfo.Key, TCollectionID.__TMP__UserDBCollectionID, CatInfo.Value)
+ )
+ end
+ else
+ begin
+ if Cat.Description <> CatInfo.Value.Desc then
+ Cat.Update(CatInfo.Value);
+ end;
+ end;
+ finally
+ Reader.Free;
+ end;
+end;
+
+{ TGlobalCategorySaver }
+
+procedure TGlobalCategorySaver.Save(const Categories: TCategoryList);
+var
+ Writer: TCategoryWriter;
+begin
+ Writer := TCategoryWriter.Create(TAppInfo.UserCategoriesFileName);
+ try
+ Writer.Write(Categories);
+ finally
+ Writer.Free;
+ end;
+end;
+
end.
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index 14851782e..610bcb3ee 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -325,6 +325,7 @@ implementation
Generics.Defaults,
// Project
DB.UDatabaseIO,
+ DBIO.UCategoryIO,
IntfCommon,
UExceptions,
UQuery,
@@ -1084,6 +1085,7 @@ procedure TDatabase.Load;
Loader: IDataFormatLoader;
Collections: TCollections;
Collection: TCollection;
+ CatLoader: IGlobalCategoryLoader;
begin
Clear;
@@ -1121,6 +1123,11 @@ procedure TDatabase.Load;
Loader.Load(fSnippets, fCategories, Factory);
end;
+ // Read categories from categories file to get any empty categories not
+ // created by format loaders
+ CatLoader := TDatabaseIOFactory.CreateGlobalCategoryLoader;
+ CatLoader.Load(fCategories, Factory);
+
// Ensure that the default category is present, if it's not already loaded
if not Assigned(fCategories.Find(TCategory.DefaultID)) then
fCategories.Add(TCategoryEx.CreateDefault);
@@ -1145,22 +1152,24 @@ procedure TDatabase.Save;
{Saves user defined snippets and all categories to user database.
}
var
- MainProvider, UserProvider: IDBDataProvider; // object that supplies info to writer
+ MainProvider, UserProvider: IDBDataProvider;
MainCollectionIdx, UserCollectionIdx: Integer;
Saver: IDataFormatSaver;
Collections: TCollections;
Collection: TCollection;
+ CatSaver: IGlobalCategorySaver;
begin
+ // Save categories
+ CatSaver := TDatabaseIOFactory.CreateGlobalCategorySaver;
+ CatSaver.Save(fCategories);
+
Collections := TCollections.Instance;
{TODO: -cVault: The following code is a kludge to maintain compatibility with
CodeSnip 4. In CodeSnip Vault we should iterate over all collections
creating a writer for each one. }
- // *** The following code is a stub for later versions. For CodeSnip 4
- // compatibility this code does nothing because there is no writer for
- // the "main" collection. TDatabaseIOFactory.CreateDBWriter will return
- // nil for this format, so Saver.Write will never be called.
+ // *** The following code is a stub for later versions.
MainCollectionIdx := TCollections.Instance.IndexOfID(
TCollectionID.__TMP__MainDBCollectionID
);
diff --git a/Src/UAppInfo.pas b/Src/UAppInfo.pas
index 67f967565..7b6d1a45b 100644
--- a/Src/UAppInfo.pas
+++ b/Src/UAppInfo.pas
@@ -81,6 +81,11 @@ TAppInfo = class(TNoConstructObject)
class function UserConfigFileName: string;
{Returns fully specified name of per-user config file.
}
+
+ /// Returns fully specified name of the current user's global
+ /// categories file.
+ class function UserCategoriesFileName: string;
+
class function ProgramReleaseInfo: string;
{Gets information about the current program release. Includes any special
build information if present in version information.
@@ -237,6 +242,11 @@ class function TAppInfo.UserAppDir: string;
{$ENDIF}
end;
+class function TAppInfo.UserCategoriesFileName: string;
+begin
+ Result := UserAppDir + '\Categories';
+end;
+
class function TAppInfo.UserConfigFileName: string;
begin
Result := UserAppDir + '\User.config';
From 392ec7b37b4e53148f70ac34c8cc352261ed77b5 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 12 Nov 2024 01:04:36 +0000
Subject: [PATCH 072/222] Change native file format to ignore empty categories
The "native" CodeSnip 4 file format (formerly the user database format)
no longer saves details of empty categories.
Because TNativeV4FormatSaver now behaves exactly the same as
TDCSCV2FormatSaver in not writing empty categories, the code that
ensures this was pushed up into the parent class and a virtual abstract
method and its overrides were able to be removed.
---
Src/DB.UDatabaseIO.pas | 45 ++----------------------------------------
1 file changed, 2 insertions(+), 43 deletions(-)
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index d92d32dcb..2b15f3ee4 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -321,16 +321,6 @@ TFormatSaver = class abstract (TInterfacedObject,
/// IDataWriter. Required writer object.
function CreateWriter: IDataWriter; virtual; abstract;
- /// Checks if a category can be written to storage.
- /// TCategory [in] The category being
- /// queried.
- /// IStringList [in] List of the
- /// keys of all snippets in the category.
- /// Boolean. True if category can be written, False
- /// otherwise.
- function CanWriteCategory(const ACategory: TCategory;
- const ASnippetsInCategory: IStringList): Boolean; virtual; abstract;
-
/// Collection being saved.
property Collection: TCollection read fCollection;
@@ -375,16 +365,6 @@ TDCSCV2FormatSaver = class(TFormatSaver,
/// IDataWriter. Required writer object.
function CreateWriter: IDataWriter; override;
- /// Checks if a category can be written to storage.
- /// TCategory [in] The category being
- /// queried.
- /// IStringList [in] List of the
- /// keys of all snippets in the category.
- /// Boolean. True if category contains snippets, False
- /// otherwise.
- function CanWriteCategory(const ACategory: TCategory;
- const ASnippetsInCategory: IStringList): Boolean; override;
-
public
/// Creates object that can save the given collection.
@@ -415,16 +395,6 @@ TNativeV4FormatSaver = class(TFormatSaver,
/// IDataWriter. Required writer object.
function CreateWriter: IDataWriter; override;
- /// Checks if a category can be written to storage.
- /// TCategory [in] The category being
- /// queried.
- /// IStringList [in] List of the
- /// keys of all snippets in the category.
- /// Boolean. Always True: all categories are written.
- ///
- function CanWriteCategory(const ACategory: TCategory;
- const ASnippetsInCategory: IStringList): Boolean; override;
-
public
/// Saves data to storage.
@@ -783,7 +753,8 @@ procedure TFormatSaver.WriteCategories;
for Cat in fCategories do
begin
SnipList := fProvider.GetCategorySnippets(Cat);
- if CanWriteCategory(Cat, SnipList) then
+ // only write category info when not empty
+ if SnipList.Count > 0 then
begin
Props := fProvider.GetCategoryProps(Cat);
fWriter.WriteCatProps(Cat.ID, Props);
@@ -841,12 +812,6 @@ procedure TDCSCV2FormatSaver.Backup;
end;
end;
-function TDCSCV2FormatSaver.CanWriteCategory(const ACategory: TCategory;
- const ASnippetsInCategory: IStringList): Boolean;
-begin
- Result := ASnippetsInCategory.Count > 0
-end;
-
constructor TDCSCV2FormatSaver.Create(const ACollection: TCollection);
begin
inherited Create(ACollection);
@@ -895,12 +860,6 @@ procedure TDCSCV2FormatSaver.Save(const SnipList: TSnippetList;
{ TNativeV4FormatSaver }
-function TNativeV4FormatSaver.CanWriteCategory(const ACategory: TCategory;
- const ASnippetsInCategory: IStringList): Boolean;
-begin
- Result := True;
-end;
-
function TNativeV4FormatSaver.CreateWriter: IDataWriter;
begin
Result := TXMLDataWriter.Create(Collection.Location.Directory);
From a43345b82f0f9725415e7cb1d0a0d690e932f413 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 12 Nov 2024 01:56:44 +0000
Subject: [PATCH 073/222] Remove unused collection ID property from TCategory
Removed redundant and unused TCategory.CollectionID property.
Removed collection ID parameter from TCategory constructor.
Removed redundant collection ID parameter from
IDBDataItemFactory.CreateCategory method and its implementation.
Updated all code affected by the changes to TCategory constructor and
IDBDataItemFactory.CreateCategory parameter lists.
---
Src/DB.UCategory.pas | 23 +++--------------------
Src/DB.UDatabaseIO.pas | 4 ++--
Src/DB.UMain.pas | 18 +++++++-----------
3 files changed, 12 insertions(+), 33 deletions(-)
diff --git a/Src/DB.UCategory.pas b/Src/DB.UCategory.pas
index 6fdb3a3b6..5a613c68d 100644
--- a/Src/DB.UCategory.pas
+++ b/Src/DB.UCategory.pas
@@ -52,8 +52,6 @@ TCategory = class(TObject)
fSnippets: TSnippetList; // List of snippet objects in category
fID: string; // Category id
fDescription: string; // Category description
- fCollectionID: TCollectionID;
- procedure SetCollectionID(const AValue: TCollectionID);
function CompareIDTo(const Cat: TCategory): Integer;
{Compares this category's ID to that of a given category. The check is not
case sensitive.
@@ -69,12 +67,9 @@ TCategory = class(TObject)
/// Object constructor. Sets up category object with given
/// property values.
/// CatID [in] Category ID.
- /// TCollectionID [in] ID of collection
- /// that defines this category. ID must not be null.
/// TCategoryData [in] category properties.
///
- constructor Create(const CatID: string; const ACollectionID: TCollectionID;
- const Data: TCategoryData);
+ constructor Create(const CatID: string; const Data: TCategoryData);
destructor Destroy; override;
{Destructor. Tears down object.
@@ -110,10 +105,6 @@ TCategory = class(TObject)
{Description of category}
property Snippets: TSnippetList read fSnippets;
{List of snippets in this category}
- /// ID of collection that defines this category.
- /// ID must not be null.
- property CollectionID: TCollectionID
- read fCollectionID write SetCollectionID;
end;
{
@@ -246,8 +237,7 @@ function TCategory.CompareIDTo(const Cat: TCategory): Integer;
Result := StrCompareText(Self.ID, Cat.ID);
end;
-constructor TCategory.Create(const CatID: string;
- const ACollectionID: TCollectionID; const Data: TCategoryData);
+constructor TCategory.Create(const CatID: string; const Data: TCategoryData);
begin
{TODO -cVault: Add a simpler contructor that takes only the category ID and
description and creates does all the convoluted TCategoryData setting!
@@ -257,7 +247,6 @@ constructor TCategory.Create(const CatID: string;
inherited Create;
fID := CatID;
fDescription := Data.Desc;
- SetCollectionID(ACollectionID);
// Create list to store snippets in category
fSnippets := TSnippetListEx.Create;
end;
@@ -280,12 +269,6 @@ function TCategory.IsEqual(const Cat: TCategory): Boolean;
Result := CompareIDTo(Cat) = 0;
end;
-procedure TCategory.SetCollectionID(const AValue: TCollectionID);
-begin
- Assert(not AValue.IsNull, ClassName + '.SetCollectionID: Value is null');
- fCollectionID := AValue;
-end;
-
procedure TCategory.Update(const Data: TCategoryData);
begin
fDescription := Data.Desc;
@@ -301,7 +284,7 @@ class function TCategoryEx.CreateDefault: TCategory;
begin
Data.Init;
Data.Desc := sDefCatDesc;
- Result := Create(DefaultID, TCollectionID.__TMP__UserDBCollectionID, Data);
+ Result := Create(DefaultID, Data);
end;
function TCategoryEx.GetEditData: TCategoryData;
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index 2b15f3ee4..d265d42cb 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -492,7 +492,7 @@ procedure TDatabaseLoader.CreateCategory(const CatID: string;
@param CatData [in] Properties of category.
}
begin
- fCategories.Add(fFactory.CreateCategory(CatID, Collection.UID, CatData));
+ fCategories.Add(fFactory.CreateCategory(CatID, CatData));
end;
procedure TDatabaseLoader.HandleException(const E: Exception);
@@ -890,7 +890,7 @@ procedure TGlobalCategoryLoader.Load(const Categories: TCategoryList;
if not Assigned(Cat) then
begin
Categories.Add(
- DBDataItemFactory.CreateCategory(CatInfo.Key, TCollectionID.__TMP__UserDBCollectionID, CatInfo.Value)
+ DBDataItemFactory.CreateCategory(CatInfo.Key, CatInfo.Value)
)
end
else
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index 610bcb3ee..16c6decf1 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -120,13 +120,11 @@ interface
/// Creates a new category object.
/// string [in] ID of new category. Must be
/// unique.
- /// TCollectionID [in] Collection with
- /// which the category is associated.
/// TCategoryData [in] Record describing
/// category's properties.
/// TCategory. Instance of new category object.
- function CreateCategory(const CatID: string;
- const ACollectionID: TCollectionID; const Data: TCategoryData): TCategory;
+ function CreateCategory(const CatID: string; const Data: TCategoryData):
+ TCategory;
/// Creates a new snippet object.
/// string [in] New snippet's key. Must not
@@ -347,13 +345,11 @@ TDBDataItemFactory = class(TInterfacedObject, IDBDataItemFactory)
/// Creates a new category object.
/// string [in] ID of new category. Must be
/// unique.
- /// TCollectionID [in] Collection with
- /// which the category is associated.
/// TCategoryData [in] Record describing
/// category's properties.
/// TCategory. Instance of new category object.
- function CreateCategory(const CatID: string;
- const ACollectionID: TCollectionID; const Data: TCategoryData): TCategory;
+ function CreateCategory(const CatID: string; const Data: TCategoryData):
+ TCategory;
/// Creates a new snippet object.
/// string [in] New snippet's key. Must not
@@ -1031,7 +1027,7 @@ function TDatabase.InternalAddCategory(const CatID: string;
@return Reference to new category object.
}
begin
- Result := TCategoryEx.Create(CatID, TCollectionID.__TMP__UserDBCollectionID, Data);
+ Result := TCategoryEx.Create(CatID, Data);
fCategories.Add(Result);
end;
@@ -1350,9 +1346,9 @@ function TDatabase.TEventInfo.GetKind: TDatabaseChangeEventKind;
{ TDBDataItemFactory }
function TDBDataItemFactory.CreateCategory(const CatID: string;
- const ACollectionID: TCollectionID; const Data: TCategoryData): TCategory;
+ const Data: TCategoryData): TCategory;
begin
- Result := TCategoryEx.Create(CatID, ACollectionID, Data);
+ Result := TCategoryEx.Create(CatID, Data);
end;
function TDBDataItemFactory.CreateSnippet(const Key: string;
From ebd04ac07e822eaae02f68eca28e8310aacc3a41 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 12 Nov 2024 02:34:08 +0000
Subject: [PATCH 074/222] Change branding, directories & version for CS Vault
Changed per-user and global application directories from CodeSnip.4
to CodeSnip.Vault to avoid changes to file formats when developing
Vault from destroying files required to run existing CodeSnip 4
installations.
Changed program name to CodeSnip.Vault to make it easy to see that the
development version of CodeSnip vault is being run. This change also
made in version information.
Changed version number to 4.900.0 and build number to 1000.
Changed splash screen to one with "Vault" overlaid on it.
---
Src/Res/Img/Branding/Splash.gif | Bin 10841 -> 16775 bytes
Src/UAppInfo.pas | 11 ++++++-----
Src/VersionInfo.vi-inc | 6 +++---
3 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/Src/Res/Img/Branding/Splash.gif b/Src/Res/Img/Branding/Splash.gif
index 6bddefedfae467c08db1f1f0286d6ba8cc168790..496a900db2c678ffaa6852a61e54c003fdbe0b0b 100644
GIT binary patch
literal 16775
zcmV(?K-a%VNk%w1VMPI(0B`^REC2ui07U_t0Eh2>BJP1E?t?4vhA-`gGVh5r?Tb6`
zh%@eyJn)b|?T$h0l}YfCLF$@W?V45UoLupnRPUfn?WJ1tpZEM)r)%!E
zZ0f6c?YVXEyLI)of9}I~ATPBwMZY*lzdA_2K2OFzP{u7n|36g!LsP~{SH?qtMOptz
zTmMaB|6gzRQe*d0W&KuZ|5|PTUUB|mZ}Mez^dvI|B;^h
zjG^q9r|XTP|BR#XmZ$cWsqvbv@ROwfld1ojt^b>{^_8;!nzsL)x&NiD=%}^ruC?T<
zwClCIqrLyDy#KPk`n|-}y~F3H!2hhn|G38XvBv+q#{ad-
z|GLiqzR>^7&ClM<#ogD$-q^&~)y~@1%iP$@#mU#s(ALe--rU&M)zsA4*3#0{+uhvU
z=g-0B)yL%A#OdF{<=)Kt-NfkH+2h{S;oaHt-qP#g!{^}5=-|rx;mhUV(fH-o#mMK%
z&*RL|ck;?CtII=;ZwF;r;dQ=jrp~>;LKR|MBnf
z?ehQh^7Q`s^z!!q_W1w*|NjX80AmOoNU)&6g9sBUT*$DY!-o(fN}NcsqQ#3CGiuz(
zv7^V2AVZ2AX|a>ZlPFW3^wf!^OHVLkdipf;lg*nqRejQ_s;AGNuT;GnN^~f!SFn;Q
zT?$K9Q&~`>%Az%ODy^$nY1PtNtE*S9w!(@XJI+?wacI-3B{z<3IdX8{mYYkrZn<=K
z)9Kx-mt8t`fCCF|$F7~>!-(6tQ|zv><9qJzNuE3z-#vVoGi%1DkF&ndpg;H1*RQnc
z)BXIV_Q$%l>wo@W|C>#_w(Z-vbL*~cEgM0XDpRsV30&q(<2Z5Z+{yf>(4IkyA}yK}
z=~AanvrCmqHLG{7T)W!;`bxIES+i@?vK?2BJ^Q$J@7l%7x9?xUfC=X>TsZM!!;Uou
z*<+MhM%iVTW!Bkdp^ercX{V`{+G?)FW+7{^St#3X9Cp|tLBWM+QgJP{WZZGdDYp|(
z&H)vjbk;GI6n0N-7gcxPX%$|0U)3_+SYn-po?1k!@Vioh;SlT6P-M**y3|~!YHGRP}OK-p;`6lEI2+Y
z+9;9Kx+f`nbSb%HlY2c0n5I&8S|wtjUK!cBSxVL=mz|}$YM5g7bBiDJ*6YU~_x_>p
zzWnYh$RGa-BJjWj%VVpDZR#3aoF<+~r%k~M3lyGv8XF^x$!mak4Jv%>iS}>CDd)qR59|5Yej+>e`8P6aDB9#LiWb{#%Z}~a
zanH?8Irm4Y``w)C4ZOMM641_k1~^ouYG|iHL-UTdw0td2Ujl<5^&D3W>+L3CDB+$-
zG#Dc9Wo}Lnix}tbWU-1NYepL5PRCNGBh`(kb*?*4+t4CEZPAWWa-$oj?1mrx_>fA#
z`_z^HAR`rE5#3Lf!#Y)em3zVS)8ZS_Av_FQ+~3aR#$sZZLQf?rD#M#4%CUw3eJ;
z*~x3g`dZkqlQGhrE=OlWo7xyZs4j}@5qHSz73Cvelz6HPL)W|818UTWZ)wg7qIDFQEHXM%_U7ji41md
zjAZ;|_`LQai-iq^+EL*fRT;K2G8LyU2U4+d&U~gIqA5-6sid0SZ;4hwiq-X!?xwqg64_%cR;PDnzOnoqNpvsIM)FSxIK@1`o
z4808(yQnY^`pTkR8zK3=iNevP@G2iQ6e~l56P&7ifrc|Ml7R*_=+lUr(5MYUU|CEmZI)`yOzvu;ob+T)xYo5iWmKaZ&5qav
z#W6Udj(tB0QhDkqR!ObQowkJ84*N2tnR-fy!Yg7hg_%SHI*2seD1%*}2vnv2JtpVybRwRjVLvnloS;
z?~roshdpGgz`G(%ulz!&Bo+GCh4yx^4yD{C5ld0;k0-Kf-7ebsjAMDLAJ9Us1(s_#lAXjw?=(0
zd<7CB!)~%+*i>wtqKZ-J@E5sJQLg$fi`jFc6RgrrX*0D?3vj08ZD(4KA
zL;_hkWG|-BXlhI`x(FSw21wkWso$BD=InM;5ec1zF+L=2OF&
zd4~Z4V24M81{jgHa$V`rNG$`b4_qFYrco^B+2BgPyfX8dagvI~;&;ty$_95J0017>_ESVbXUUaUHbW
z2SGHv;er5!mkEYqFY~tAzoFbjV?1h7=cFg5)~~U?$;OO{(`?}XVPCA-t!K5|Q7$ay
z<4et|zwG*Mt)SBPsGQ8&&13-J03dc~##?1cmzUXiUEISR4sn4=JmMCgxKUG#@qxVL
zYS|u+s4=IxZQ{vAqcjSCF&0jbjx(gq71=9U4rG+Q=WWz=Den3x&j?3&yM+#*TQmIK
zX9xi30Dyo!KvQKa%a#syP3FS?P=`9`s}InQe8l?zh^GU>s1vvN)Q?*2F;~rUT89&i
z<%AsYnK6{2v~jA%R(1em)w1bcot;g(Hg(o|QgO%Kb&;H8e0!?bL;Q7@jPZA%TY&I|
zx3XPlYcIz;o?nokUc)O7^~y^e#hW)Or#o$R(F4c(65Trgn!T;&Zac+2RaXl{2MhOnk2ir1CvntweV3A
zobd&K2LM~35BE?8aj<~OCs0V|2N4*7k_UN{7jc*WXMKZkc~dxbfzWxL$AKW&D`UiQ
zqh?=TSX?!Bf@_q5m9>Iu*n$TpOKvEG^tL}W*h5r;gTQBD`NV_x@NaQL
zCNnmtWd5@^ee;gS<1@xU0Dxx!z>tra0(1gM8`$7VGj-fcnUxUl*x-{5C$C(0SK@GWNMx~UNc!^fXg{rx2Bj}pP37akeZm9bf@6~?)s9`FH*z?>gB4$tWU(J4ReM4cY61hq7S*y#a&=m$E7Phhl!Jh!`7oda!F6BiE6_N8;G>|9fD
zup$_yIl-$EbDI5oau__=5
zSaAv_@UkXw3LfeKA>c~100OTmsJ4I#DgXjL3j!yg2x@VnEPw(b;IlLk3nR&*D{ulK
zaI`e=4YqUw*_n=uV6;!W0-=x}?NA6PfC7a;2u~XVE3lYDm#v55&Y`vLK13oP)ON)Q&N0HXghkQOYupdg?K
zb3qQXdz>M#2-jJ)QL+LcdINz$2(K9eu}KL3aZh_!NIau1n85{on5l7lqyr!U7*Gau
zumKwo2X!C^l-CCof}d1Ml&u;FeA}O~n!Z^I4TC!nI02?8Vz`RCSaIqI&fy5a3UVKs
z0#)e(z?!iTiknLDp(bDhHqZheIs%>xn<`)fND!wca22e81RshC#pwYcFnf^e0n=I*
zClHrPAOpzB3TSbnARq%vumn_#!Km;SED8cNkisz<0P;JyFgOCi>`2Sm9C=X<_M
zImTlQ4Q31t%h-9f`o0eXjixt^%fYMn3#>umzaG$_L{S5;=>kY$tOFdP7nu~7@S&2x
zo3BX&-N6bK{4sHA!Ce8ZX|us6P%xG|CzjF-8s$iVKDjnL~$8Gw@AD}G1>H#)j$a0z$Gw_;DfEA5=
z!5Q3DwjjxL#0rX_1WAz29zX+Vp{Q-4B(Z?AAutz;dOQE$fU_WAR-+8O9r7
z%CA|r$;*;0X|8FD56s}i01yEZ5C&vGguM)SNUE>H%&%a~wj9@w4xLOFK0KqN?89Gs)<&D1>>$L1KrU>BPf460YEa7upa2*E
z2IfCW^^MV!R*_3%lK-m4e~lpcmiD4#pb-
zH?YHmaN;N)#IM=bzmtRRNGg1%2YArjZ~zB*aN}|S2h?2$_-J(6Ez$rdaDeR(;a%8!
zkPL^7-pj#QAa{E2-4p+I`~i8=&0`3be%uuO9ThF`n&nIj%Uar}
zts@66)ngH-lMLIhxttL`;aYv$M)J=XEYPpX1aq(jeg@ejt6p(2SAFC0QKWXY5*5deB2G#;C0Tj-nHUKG~ECYJ(0XGnbpG*ULG0KII!{l(vHFM}SMbS5fwmgFwt-uD3{^*b{
z>D5gKaexMx9&`oZ2J_Gbm>O_ykPrW0T-XFJ>Z1+~rrzW+Ez_Xr6XgfTU-%P2U9qu=
z$3vkAu=xR02?G_o6rwHEvOvHFoB|)J0;SW)1Af|vvgQ~}@uABo_#6UGFbN{urgiQC
zC@ceA4FV;(;rYA-G~mM_Fb;b$=G?A3LQexHj-8{xAL!0xZG~u;u?=ic_3=yMeh;D%yujy-703S6uj$CO(ACFz0)l!LH+!5uoA?zDq970o@#f$l%F1Sy4w`@Y
zfPo6b9h)oAA5TxNH$|z>!>1Y9BhCvXa0!2%}$vn+rFrXVe>pz}T}1FV1vK3fRmumk`BV#cBqAV8d0QjT0X
zhD$)$ScD?PK_=wg&NgCKdSxw&Fc~XY8E`nynan4E$mpa(x91@
zCau^%wr$VUx>sQs_z=I7Req}iEE5?l-JBAfm@?=@C
zK6v;bOY>&Vv}nol9NKd&TBJ+YLY*45E!M4BkFy0^cIZ{r&g1D+a*+5^TW32s<#r!4gyDF$ZCJWikmTl;yGyVBu`D&qU);
zG}2T9(KQiYi;cG1P8_G46jSs~A>f1)?l|N?qA{f9lv63k=%SmhI(M%75j&n*>5jXf
zfMO#&WRTLsyz~D8K)`_kpqk1mf3C_3y)5>ShCcezN-Hcd$CTzjGtXozzyt#`@UXrV
zJdi=g7JQH~2PmOB?M&)oeLbMA%BS&BPN`tWCw?T|x5K}>YS)@DP|Hb@s@
zaiL0K94^z0WbE|D8=)JOR8vi@4oD$$TF2F11kR@fv(G>ibTmQ>JuNjv
zR~vCrbRB&(QllB7G)7D>%4pLXZL}9hnDUK@x_*C5HK(53X|?OFdjT74U3x)S7lv)!
zfW2HNUQdf)YZc%QWR#(sV~&rFMw(zk<~vPiPX-)tIq9^vu{>YavodaL)-dOs!$qxU
za%(ZSL`Kt9cf}QdV;9~SnYKvY8KV|;>K&!y*GKFA^}2Ol!iGI;WO_lSji(SuyB~e3
z+DBKY446170oqUonYrzjMwz@h&O2}Z`VM*Iz^7lZLF)@Q+|HIGL!3{Tw`Kfh$Oj$Q
zXQ2Pho$YeWH{bkSrHyl%(;7XE`Z=oi<*}xmY{JfvUH%84>s}YT*tKB+S=gQKs^Tl(
z)e0)ZQ^p-AkcH#bEgH&`M)S%9z3BaodVw39%CLv0?qzFF;H#PV9tXMdg@|&MBav*@
z$37M%jYXaVUFc}UDX87cey7Wy>Q=WCYyfZ$
z5X&M}x}X3D4zC#!3?3|zF-vOPvY%yKOD>lcAO?Lsv(TawfkS6VY#$j5fFj6mVKGHcVm88|M1_>SPU;y4&wc!n+Dwe1QsAn3Ak&6mMcD&{_FEyG0)%03bv+u=mof`UzDhPoGB`Cp#
zfy@IbY(jCw#3Rn~Xx2UUcQuKk!i6nNU<1!Enk#ZwT!jOPALKv>7S=(Se{cjy*n+MQ
z{_St|CES^OS;{0h1c!;y;W>X8y3?KRVGlc0#g_6J4jh1rdGXy^iMJQcaK?ERUEaOb
z_&)^Aaiq1!GEWF0$Zy6p392yGBr93JXVqC+`zsmblMZdo{jqQ(D(en2n~J#A{wxEWM+
z^jshP|NYpRjY6fDD
zR2O9_`=Gg8O?e-g=(k;6fFqpJt+f%Pk@=opadX@sNw_H#cxgFou>1!Eh%`!l7hD1btv
zfMDQ;|7*S16S+Ic0RAh$14O{K{~)LbY``sKneCAfBgix=5UV5Ww3$mjP-88%da@CT
zw^&0pw|c95gOOLWuqx1@7o;m~@*!KBq*KAX9_+z8JFGnWJj9YeZMZtDBfX0Al`FZp
z2cm#tXu|)SL@1O()dPSkyh1Egz_+8LF5E(}YA8y`v`ss*F+3reQz3Qh5Yx!Jz1t`e
zX+sP90TZdWdwZ*PaUVJ)fmJw;_@N&?yep&&u2Y!_Uw|$i1cp0X#)m6J_{)Yw6us-R
zKdSH*tFV%IP=kh1fHcqsZfL?ul*HD%11!K8E&_lt*hEgO3+@TU1`MmoXt_6&g2bu2
zP79Prcme?9M=AIOTCllx|5HQCfrNeJ$0yhXTe!XpqXOx>4Ns_oACO3ilmbeCs~1@X
z7QDj;)5BTV1S$Z6B5)3JpoAv?f|CRSDqw|MtBF~d1ym4)n3PHATE=DE22ub8M(6=+
zI4oCCgdX?-ANTzKn+oaBA7)?;{i%|#Y54AAXrOz14AiG$n{ADA>c(*s{#dMh>U!*
zOem>5gc>^3fp!>&?}IfUm<6Sy34_D593TdpoXkX^Lq)iTBiKs|3xZkDoryC-E4h+x
zAkC)C#HR$uaBMH@ZS0|+p{E6l>Lbf|co#|z5=3bdoM{FV)og1LmXB2XsP
zK)l4euvKW3+o*-Q9J(Ly9A5l^7kseg$W0Q^0pfBw9RLS{bBA2Zv>eF1nj{8Bc(Wc5
zPE3o0V_Ph1ypqxE25smD(+mLA498+%O-y`>tBlP|K)G;>Qb
z5k$@-@W9kqg$PW%9Pp@dNQLwiHz9zRy?lcBIWrzgjuk}C3o`=m%mi5T0rKoTQ5aDv
zONGxQy=%nA_asekkWc!wPj0{kb97DEgaBcgO|=uyt|U@ea83&=0p653-~2QQwXhs0
z0Sw)Q@{t7$|8==qM3Ge3%rL{yRDcnI)(`6k$w`N9ea5*h~@thw2~#SWATI0*1o^
z1{Q5m3)_KejHhe7l6WA^KJ^A1g~}bRN~pjBAAOP_4N$u%QX;L=H^V?AQ_zV@x8szu
zAkc)+NQEQiOh0l`5(olFNQF?<&Nt&ZM`=_RqykzX2Xa^iS9`N6P@2uGMfssY54th|_JLQx-geMF0nIcm&9NvrS;n1+qrb{DpJq
z(-E7`_pksi;8FA-)U}v{AI-$@ss|xe)J2WQPnb(es5{?Gx6c4mDVu_Dq0}b@k>`6e
z9!N+L|GCgNqXHBWf-qIpRbAC`*o0SwmxawV9e@SKyOCR!vPbA9UVH?aFo(&UOdohN
zQm9EiThrV$-hOJyzb~P>U
zA;odaz%smlvoHtM8PS-_DMgJ{m`fgjA(eGeM;Tfv`vKaLlvM@H3xn0*U>bhK
zG#$_cY+{alC4o)gCZ;30^Fvl-{e`vEfn(hUWZi~Ec(WroM0}7&ePGZFyVDqT&zJ26
zm?g~-^M*A*$Md)XNfZNfMaQ1?*>(ilhdM=Au-Xgb0dA4kdBqvE<$>|31qp?O)KJ?T
z|A2+c8HWhe0Thu?9f%EuI3!Jlg!f5@6NR-ItRFhu0UgPg3X`&5bq8Sh1!N@#Qg|~T
zxZCE%hHWrUDI0}t@CCocx`nh;JT1NVyb{EXSsVS+#>H81Hi37vw}z*uHlOA5UWhm|r)C_IG_(O9d6cv+fMkk-8=(*_0t
zTYG{x`_)#6TV&N+DT4y%-G=A&Si#MPXw(P4{o4lKfkl*2?v00YU}5j|h8JGk#>E17
zC*
z)qzJ?g;h|6EbcMkJOWF}AzKhSOyk|<0M8410txHYS;&S9M%F}lGetmFY@p-krQ2<=
z-oF(p6K>CIeNST0R_~SB_l?(N<{Mu(V{Ss0Gt@#O{^7T2g~DC4p23wNNYFH}eG4cv{$s4J0N30zTzBC4nDU1u))7i;(3D{}ajOaODe|
z1#Th-!_;MDrCVTl-a5vHQFyaPAYnb$2X^4&K4#`{VBu$m=9%>dZYX2`K;&vx@-%U1@|0S?m_}|ry;xV4G+rZulodTt~lzmPIO(@&$
zRF3OBOsaVaR#@JHc7?U{0Xjacg^pf%raKDBeX99y8<
z6Hx^gL}eW~f?0qUMGBofK
zH=6=wUgr0Vhj2g#vWDgwjb<1Y=_g@iG^vLLcmuhH9=c|n`y%4J?$@KOD88n-zkahH
z*yPg)XbUp})Ie-ep5l8xk?r2vROqpZtO7`oh1+7~9J;3D;Kejfjx)9}kzBK0HP$(v
zV>p&FMp)<$&W3H^WfItdJeKHBe$k5a<3A1uj3(=6F6$SLW{>s;To4v)UY2P%fB+b7
z4l?fKPVUWpQdLkbJvuAE7HqY8TFS|8#cmW1Cjp-G>F7q-gbfb&*_5TB&Q9r7AP5z}
zwpeazU=jdXWW5Gp2=dgHGGFdsI?e`cSj!;DV@0HB)wXES|MUlp#%Oe~^4ykY-Ztc@
zmHCipu-&K
zT1gqHM7l%K$);YV0_BirS?DI1Xy6=(+aM2SV4z!9Kyvxp28WiiNC0rGJ75co?a)-p
zE3xe=Pw=ufYu=vbrA
z(Mg9@*h^SWj$7s?cc54cBLX3(Z_!>}Y)JAXr(-C1GjeG1603Pn|7u3O5__QXdAIT_
z-)L!8hmO|w3vlbXpof1)kAPP%GKXot?s`v4H&`%d&eQ}|_-iT%f=k;3artCT0})D?
z%N%$G5z*8YkD*5p&ezQxa`@?cZgy%)1SM@#fEFBV?}r~{N{O{m%sid0Vw#X(YJ<6{{a1a#`liK_tj5LZcv8*|KfRLE<1n9X}T4(1Gxw4pZXDO(bWLT)B%F$%W&XE?l^CBF~{K*$tgH
zbltqMY}t|1F(00{7)4a}VIVD98rjN8AU^u`FF8Q@L5ph}lART|@I3|UfX$)akt
zD%Gl5X>sK`RqE6t566;4xT#hxT4~c7|0(PCAf#Hh=F+v*_U&6LDybkl`CCx^H!W2u9-C(;LHj0=TB$9me$jvTmaIh+MPn}YPIWD
zuj0Xq_s;dmYlJ*rrR|Eg7LW8fGS#hb>qlePnf~r2H_rbmuDMmkVTYvyNqVq7#!fp7
ziuDjUn7MP=EMw(x4KUbzwvA{8A(VqaAr4eZf(ZS<%0wyJwqi!*oKp^NBK2m{Z^IGC
z5==4~#hi0G`2^2W^e{k^QQ2+R{}fbFWp&keT5W}uc~R0rNqmFl@Pu0Ky@%El9=er-
z5wzH6-(7AQQRYFZ{P&k%8Ic2v5RE-jPC5pb^N4_M6){d^4YtGC4wz+TnLC?|HAIG@
zkw(f`K8UDVHc^zALloi2rs9ehr9;j+oSH+2~dB9=?C9t$S!h@FxmB2$4tF-rCmTIB3N|%f^#4IdwjX91j
z+;+Q35Dg_H#3thyvCu+7@a0!ueOZ)IDnf`0n?h5_VrQL*rIX4OKM1G;5LC?4AY=r$
zQv?tR1M!5Q6K0kP4n9cy|AQiE^Tq}vRXjcEyCa)b`n>L5fUm(G@AZMJRN
z5l0+>MAD2UrDP6pHoAnPajyd4z!%Q-1e8!i5_$Ady!QIfuTm0AY_U_t&*gf~$b<(LX--yY=3gCZ7
zHaLR}`Y9;lnz{2ChMT#`lBa;CNRKP`#FgYU>u1Dtzz^+R(-JR6MN8O%xYh|fCTFY}S*L${TJ9gRL
zR&O@9ZS&<{yX~_3|L%Vn;f=T6iP5SYgm+PfjU-qt3=h;Mv8+#CA(mJY}av3-N{ll%}z
zDEm!_aT+4c{`mK(|7BwoV~Iim4TwNYjm|coN{2W;qMI?UZY32&)$5GIvsS^xIJx5n
zJVJ;x02F`&L%EKTwv)mY9?v{3eBleV<~$fmPlhy{OAQlg!?yV+hx`#=U)t0|@)anE
zK};X}iU_|={~|GQ4Rc2}Km$enK}w2{`dFmKVu=D0u$7mh$SXl-8#l$wMIHeOI%w7#
zobl3iY2+C<*r>*#!K4~S`&}J{G6oao5lO`3W7K8=NI7$I$Z-RIqZ3v9yQ+HIk8VWW*dV
zGAKw?7r~Uc4jrqqATZTL2AhGjQi}(KB|u}A
zDVW(Z{~RCLjV^n$4s@8K8|w(pI$ZKl*%b#K5_Kak3@}GJa-b}JU
znn+K2O>9OldfRO2^|JR(x5-q8Eqa$t&u2a%4l#X=cI=-4JoVDbk-XQB)d7)M!DJP@C
z0rUUuT=P28;Ziee7B(qg`#dVkW=K&Lg^SvV+nL6GKUw
z(1a$ll-uk;Dse^mZV{?oEG?&kj5-$?)Eq@7)mH-yoCFmHeOVvbuM&-6z
zxmUl17ODk_VZB-t%!b@Bhv}k7G!K@r{NW+46MNI__D!8DZeJ%|yytkjgT^$T98&+;
zi{k>GgU3Ct$bAKB5z~Td(x^+FZdPlOuWr>F1QzfGW$VV-U9`%j_9#?Xt!lk`+0`-(
z^YoU>QZqvr#QnLo_ik-iHy5aUi4o#X+4;W6<{7BNR@`Nc3TR|28S>~
z>z3HWiv2g8y!+T+13P}gE-$f*4VqAa61aqEqA#qSDSQ^_g~8l(^}iQU4GwTi*%hgboQF?L?k-lE;C+uCfyyrpmG14
zPWfd&9Pj+e~Cfa!T!N;pFK+7tz6uXP4_mR
zb>4fQZ+!1iZh$Wzul<{2MaHj%SBs4oj2&E1jRw<&5>nk*)HRjVWuD4(%4l`O#Vrsy
zRN4mK(x`wPfQ_HGc^lcWL%F-9SuVMHHD;fuI#q&{lEV2(AR{#g=gh
zg9^r8%c)e%r4+o04Xni=z1^K)or!)1~6OGkc1(G
zjUgJo;FzVN8QNY99ugZak{j|}+^kvO3E%JuAc_qgWEGv_DG|~U+aLzxJq#l;7UMAD
z!#&`GGA<)C;)6aoqdr8VH0nb?P$M<=12$%(Hu^(9_=7io<3Im=V+VH1X>Fa6W!w0f
z!&ae$I-&z9z9YJsqAJqdJSG>-wc-rEqD$ppt+C6R=@2>9VI}n&I^`k}6&;=#ot^<=
zDKyHCCfGZsRwGq&J2mC5oQLnIl(?UrLe+Jhmiv
zJcWIXS$(J?KF*N!$RMr7V%zv*I91o&^qh$S9i8do;kAgQANXCPZQJVO9T{@&B*!|bo6@yEw&Ys6C27*zneF3;)u62b_*r2}u48D5CRC7SE8gUpbyyqD
zB_rXR?>$oR`JY~rkH4XhU;gDT`k^OLR&EC4Lqeot#wTL}r$$!gMoK1D<|lGmrazF*
zI9B2ng5ZoyCp?a(b><#UYUl2urfP0aT}Dz4#^DbB-_I4^P|hY#b<*G^=z;$Nmfa;NYR+JTs@eXD6NHLWUi#c?
z3SOKEop%A@E)v}GC18gRqG9r8MEYhj&Zk8N=Wv$jiFPB3hGaOtL-&c^#w}-nt|VH@
zXc*Gyfp(L2&YCyrWIxK{9I}brl$bygqyRFOE(YP@Y$)TASMv!YluqQ7is&7E|lixnoIBBr2myO(O`C7PqZ$mz=kTd
z7Hkhq(nbhr-}qpP9VEEk=43g{#Cm9;hA6rkDrB;2yKd>P`olZ$kcu{^nAWQm?vBd3
z9m_UrTyAHlK9|?p(6q|bblqDxwHc|Js+}@y`V?NBA*pyJWG@=rpH}Q{&MJt?=dEI-
zx?bsU7N?@Vt3OyKF>u|N>I>C&rltR0?aC#IT)J%6eiPX4=$rQFT^_9eP3W5~?6#gK
zQTl9#0_{7&SYgU)p!z1da%_DnZM*vFNRA}bZlK8;6o5|Zy(;eF>MMg{kIQ=Pc1muo
z-QXMcXe}D-&GKN{-s$={Y(CyVuh#hp(^qkpRW-hLb?;5O32U}X5B(*
zVrDE<7AlGMt%+tM>$a}zmZUk7ZzX=+i=OYfG42h)V!-+?@5L`I!eQmMh)){tkP@HZ
zU8vh8AM=JQhmNZt3NU=yt?B<#DFRdFp<<);pXQ@5^a3fm@b4hpQkaJly8QyQ?wB5n3Auzva~4->;-bl?}6
zBLz=t;vVq|Ch-!_@x6uEsOlRCk5A4DX}{eek#-l`Ua<;da7
z(ne+ugDmUzaNw3C`NA&WL~!|z9~@g52GcPIH*vKZ7GB~SBn2M{`!Tn&Ehc@dAct4n
zzUt_@=Kx#m>27QSBkIylvIBcBolxQ$8?Nk5Y9}Lc`hv1*0`CVu@pl?*EoLhpmvE{U
zY4QRg@-goL%CZ&{VIu!qY?OkrBcraa>hg&;u=i53X@M_*>PxYnY*`j_93L|>ujWj>
zp(wMabp@$wW^MrHRL}0Oo)&V@2Jmjyatu@Ne2Q^olCir2ZtHp}Fkdnevnbe|tP#WW
zmBqk3Q!5Vc-5uXxMnEVWR#%-4-z}OjzztxM-kD%7>5CmQ3?uSE*Xj&MW%cgup_23V
zIy5DRV=zGQqv{J-ZXFRD*&AbYJZiKu57rGfwb=4s_keUBM=>f(sPSs50$*#t8Jrd5G!wRC<>|u`GHt^XPzho;m+rZ$cT`4p(thl3Z#X6Y3wL}6Mc|qN
zUjd;0I4LqNo0<0f(jiUBO==rBG()pFRcHWmtBv#THLLKBBc%c=<%HAf^d4=MKC*jL
zwmI`>PdB-frzMnMZiL3^PxjyMS=T8KZ+7om;1OTLru6!F?&rd?U@qiK|EYNc`C@{z
z^%^P;7kQ$V@rDO?oHvD>&-s(nb%0a3h#}S~x27JOGGL#ozhSjjZ#9_n?;!WdgNN=c
zKPdrAq;3iAYjKV0GdK~U?kp3Q?V{5KyIl`j4f#4$HCGUa@
zvQdh+Wo#&UyKt;_u{SFtq~r3sPP$q5D%19QS_}8D2YaVK1+iO1iw9}nWcl5wmy@$+
zcfu}~P^QxfS9?*uvXXvvk8?AvD>B}yxfpkBn;*HaH$0Os#ip}+z9tF9SG>hvJjQ3d
u#&0~wcf7}cJjjQ<$d5e9m%PcJJj$oM%C9`jx4g^0Jj}_SH?VsX-8cH3uo)@6CyYkJmee%pF_$#H(xU~lqZaP?w!{$+XpYI*c(
zeg18L+;f1|bcEY?h~IdJ+kA@KZGr!BhvamMf`ev#yPkm!Ap|A36!hLqommfwq*-+_$mfQ|5lmE?q)>xq=@i<;zzl=gy?|AwCM
zhMND0mhp&}|A?RPikttGp5&9A>yn=Hke&aGpzMsI@QkAWlAz?3rtFuf?3$|UlBe*K
zr2mwu@RO&by?xd~orLyd;wBxF@>aMx(qqOm&wEw2K^P#%?pt}E}y#J-S|E9eA
zrM~~Gw)3d9{j9q1s=NNRyWz9D=(E1@u)hDi!_>XS*{8t&slorP!TYSj|E0qwL+Q;Mcw7+Oy)>
zyXoAs>fXEX-lOo}sqx^S@8GTO;I!@GyYk?p@!_lS;A}tS!Oi~5(B#X~>ciCj%hU79*8R`e^~>7+(bVG5)#%mP<<;5j+uY>Y-0INR
z^w8J&)Y|mX-Tm3$^4;O=)!_f#;_}+${@>{TKY+=IHJ0?Cjy@^5yCC+qZ7P
z$(>6VoVdGq^Xk1jt}ng6fCCE-Y_D+Pdx#S&UYxJ7GLd2qn^3iX6v1=V+Wm0JLzrQx_9@!
z3jDY5uf+uj)^W)dxZGRK)dk&x(pBf+U)LR`U3T4Z_Z@iTWvF3!1EJ@kX=q*NK1v5?CN|2ga4)Tnj?i;DgmgXwQTcR`}S3l5ObZ
zllz#b5*k!ec^-%&!bD!t?x`4e*aWKUpNIBZ=%T>J;^?CtqBQBTm0Bv|
zmhWvUU#GNvN~WlzPE~4f!l9b#s;tI2r(Li{=hv))8ENaSkIl2IuD-S#EU?3JCgrj8
zCVSeYBsLr0v(VZHYN%#b>)W-QoT{x@ZgM+KtKWtz?sVkRdfmC(Id;#w?6!O8yYR-V
z*}U{lYHx`6wx_R8DXPe#QPScUaJ2*%obAB~tEw=2Co*W48|Y`m
zx5(O=@OzP4qIM*Cz*JDuU6yPhCavh9k!dkC%!7{?zbH5j!srsML*
diff --git a/Src/UDetailPageHTML.pas b/Src/UDetailPageHTML.pas
index 91abcffc0..84f6a9d9f 100644
--- a/Src/UDetailPageHTML.pas
+++ b/Src/UDetailPageHTML.pas
@@ -419,8 +419,9 @@ function TWelcomePageHTML.GetTemplateResName: string;
procedure TWelcomePageHTML.ResolvePlaceholders(const Tplt: THTMLTemplate);
var
- UserDBCount: Integer;
- MainDBCount: Integer;
+ Collection: TCollection;
+ CollectionCount: Integer;
+ CollectionList: TStringBuilder;
Compilers: ICompilers;
Compiler: ICompiler;
CompilerList: TStringBuilder;
@@ -430,31 +431,24 @@ procedure TWelcomePageHTML.ResolvePlaceholders(const Tplt: THTMLTemplate);
'externalScript', TJavaScript.LoadScript('external.js', etWindows1252)
);
- UserDBCount := Database.Snippets.Count(
- TCollectionID.__TMP__UserDBCollectionID
- );
- Tplt.ResolvePlaceholderHTML(
- 'HaveUserDB', TCSS.BlockDisplayProp(UserDBCount > 0)
- );
+ CollectionCount := TCollections.Instance.Count;
Tplt.ResolvePlaceholderHTML(
- 'NoUserDB', TCSS.BlockDisplayProp(UserDBCount <= 0)
- );
- Tplt.ResolvePlaceholderText(
- 'UserDBCount', IntToStr(UserDBCount)
+ 'CollectionCount', IntToStr(CollectionCount)
);
- MainDBCount := Database.Snippets.Count(
- TCollectionID.__TMP__MainDBCollectionID
- );
- Tplt.ResolvePlaceholderHTML(
- 'HaveMainDB', TCSS.BlockDisplayProp(MainDBCount > 0)
- );
- Tplt.ResolvePlaceholderHTML(
- 'NoMainDB', TCSS.BlockDisplayProp(MainDBCount <= 0)
- );
- Tplt.ResolvePlaceholderText(
- 'MainDBCount', IntToStr(MainDBCount)
- );
+ CollectionList := TStringBuilder.Create;
+ try
+ for Collection in TCollections.Instance do
+ CollectionList.AppendLine(
+ THTML.CompoundTag(
+ 'li',
+ THTML.Entities(Collection.Name)
+ )
+ );
+ Tplt.ResolvePlaceholderHTML('CollectionList', CollectionList.ToString);
+ finally
+ CollectionList.Free;
+ end;
Compilers := TCompilersFactory.CreateAndLoadCompilers;
Tplt.ResolvePlaceholderHTML(
From e3848f4ed485b14e5f3c5d50320877f440a8c9d5 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Wed, 13 Nov 2024 22:15:42 +0000
Subject: [PATCH 087/222] Remove redundant external object methods
UpdateDbase and NewSnippet methods were removed from the browser's
external object.
Remove JavaScript functions that called the removed external object
methods and Pascal implemention of external object in UWBExternal unit.
Various associated INotifier methods and their implementations were
removed, along with associated actions that are no longer required as a
result of these changes.
Also removed a commented out function from external.js
---
Src/ExternalObj.ridl | 11 ---------
Src/FmMain.pas | 2 --
Src/IntfNotifier.pas | 15 ------------
Src/Res/Scripts/external.js | 33 --------------------------
Src/UNotifier.pas | 47 -------------------------------------
Src/UWBExternal.pas | 28 ----------------------
6 files changed, 136 deletions(-)
diff --git a/Src/ExternalObj.ridl b/Src/ExternalObj.ridl
index b60a9553e..b4f29f734 100644
--- a/Src/ExternalObj.ridl
+++ b/Src/ExternalObj.ridl
@@ -38,11 +38,6 @@ library ExternalObj
]
interface IWBExternal15: IDispatch
{
- /*
- * Update database from internet.
- */
- [id(0x00000065)]
- HRESULT _stdcall UpdateDbase(void);
/*
* Display snippet identified by key and collection ID.
@@ -76,12 +71,6 @@ library ExternalObj
[id(0x0000006E)]
HRESULT _stdcall DisplayCategory([in] BSTR CatID, [in] VARIANT_BOOL NewTab);
- /*
- * Open Snippets Editor ready to create a new snippet.
- */
- [id(0x0000006F)]
- HRESULT _stdcall NewSnippet(void);
-
/*
* Show news items from CodeSnip news feed.
*/
diff --git a/Src/FmMain.pas b/Src/FmMain.pas
index 00293661c..25e81385b 100644
--- a/Src/FmMain.pas
+++ b/Src/FmMain.pas
@@ -1398,7 +1398,6 @@ procedure TMainForm.InitForm;
// note that actions created on fly are automatically freed
fNotifier := TNotifier.Create;
ActionSetter := fNotifier as ISetActions;
- ActionSetter.SetUpdateDbaseAction(actUpdateDbase);
ActionSetter.SetDisplaySnippetAction(
TActionFactory.CreateSnippetAction(Self)
);
@@ -1418,7 +1417,6 @@ procedure TMainForm.InitForm;
ActionSetter.SetEditSnippetAction(
TActionFactory.CreateEditSnippetAction(Self, ActEditSnippetByIDExecute)
);
- ActionSetter.SetNewSnippetAction(actAddSnippet);
ActionSetter.SetNewsAction(actBlog);
ActionSetter.SetAboutBoxAction(actAbout);
diff --git a/Src/IntfNotifier.pas b/Src/IntfNotifier.pas
index c24d19c40..5e07ab102 100644
--- a/Src/IntfNotifier.pas
+++ b/Src/IntfNotifier.pas
@@ -30,9 +30,6 @@ interface
INotifier = interface(IInterface)
['{13962DE4-784A-4B70-9D3F-FD434FAE4F4F}']
- /// Requests a database update.
- procedure UpdateDbase;
-
/// Displays a snippet.
/// WideString [in] Required snippet's key.
///
@@ -74,9 +71,6 @@ interface
procedure EditSnippet(const Key: WideString;
const ACollectionID: TCollectionID);
- /// Opens Snippets Editor ready to create a new snippet.
- procedure NewSnippet;
-
/// Displays news items from the CodeSnip news feed.
procedure ShowNews;
@@ -93,10 +87,6 @@ interface
ISetActions = interface(IInterface)
['{A4B7AFE2-EE6C-4D39-BEA6-B52CC8AAC1DE}']
- /// Sets action used to request a database update.
- /// TBasicAction [in] Required action.
- procedure SetUpdateDbaseAction(const Action: TBasicAction);
-
/// Sets action used to display a snippet.
/// TBasicAction [in] Required action.
procedure SetDisplaySnippetAction(const Action: TBasicAction);
@@ -133,11 +123,6 @@ interface
/// TBasicAction [in] Required action.
procedure SetDisplayCategoryAction(const Action: TBasicAction);
- /// Sets action used to open snippets editor to create a new
- /// snippet.
- /// TBasicAction [in] Required action.
- procedure SetNewSnippetAction(const Action: TBasicAction);
-
/// Sets action used to display news items from the CodeSnip news
/// feed.
/// TBasicAction [in] Required action.
diff --git a/Src/Res/Scripts/external.js b/Src/Res/Scripts/external.js
index faf53d1f8..09a050cf6 100644
--- a/Src/Res/Scripts/external.js
+++ b/Src/Res/Scripts/external.js
@@ -21,29 +21,6 @@ function configCompilers() {
return false;
}
-/*
- * Calls external object to get host application to display Update Database
- * dialog box.
- * @return False.
- */
-function updateDbase() {
- external.UpdateDbase();
- return false;
-}
-
-/*
- * Calls external object to get host application to display a named snippet.
- * @param string snippet [in] Name of snippet to be displayed.
- * @param boolean userdefined [in] Whether snippet is user defined.
- * @return False.
- *
-function displaySnippet(snippet, userdefined) {
- var e = window.event;
- external.DisplaySnippet(snippet, userdefined, e.ctrlKey);
- return false;
-}
-*/
-
/*
* Calls external object to get host application to display a named snippet.
* @param string snippet [in] Key of snippet to be displayed.
@@ -80,16 +57,6 @@ function editSnippet(snippet, collectionId) {
return false;
}
-/*
- * Calls external object to get host application to start Snippets Editor ready
- * for a new snippet to be entered.
- * @return False.
- */
-function newSnippet() {
- external.NewSnippet();
- return false;
-}
-
/*
* Calls external object to get host application to display the CodeSnip news
* blog.
diff --git a/Src/UNotifier.pas b/Src/UNotifier.pas
index cc8dc7c23..a5d4174e2 100644
--- a/Src/UNotifier.pas
+++ b/Src/UNotifier.pas
@@ -37,8 +37,6 @@ interface
TNotifier = class(TInterfacedObject, INotifier, ISetActions)
strict private
var
- /// Action that triggers a database update.
- fUpdateDbaseAction: TBasicAction;
/// Action that causes a named snippet to be displayed.
///
fDisplaySnippetAction: TBasicAction;
@@ -58,9 +56,6 @@ TNotifier = class(TInterfacedObject, INotifier, ISetActions)
fEditSnippetAction: TBasicAction;
/// Action that causes a category to be displayed.
fDisplayCategoryAction: TBasicAction;
- /// Action that causes the Snippets Editor to be opened ready to
- /// create a new snippet.
- fNewSnippetAction: TBasicAction;
/// Action that causes news items from CodeSnip news feed to be
/// displayed.
fNewsAction: TBasicAction;
@@ -69,10 +64,6 @@ TNotifier = class(TInterfacedObject, INotifier, ISetActions)
public
- /// Requests a database update.
- /// Methods of INotifier.
- procedure UpdateDbase;
-
/// Displays a snippet.
/// WideString [in] Required snippet's key.
///
@@ -122,10 +113,6 @@ TNotifier = class(TInterfacedObject, INotifier, ISetActions)
procedure EditSnippet(const Key: WideString;
const ACollectionID: TCollectionID);
- /// Opens Snippets Editor ready to create a new snippet.
- /// Methods of INotifier.
- procedure NewSnippet;
-
/// Displays news items from the CodeSnip news feed.
/// Methods of INotifier.
procedure ShowNews;
@@ -134,11 +121,6 @@ TNotifier = class(TInterfacedObject, INotifier, ISetActions)
/// Methods of INotifier.
procedure ShowAboutBox;
- /// Sets action used to request a database update.
- /// TBasicAction [in] Required action.
- /// Methods of ISetActions.
- procedure SetUpdateDbaseAction(const Action: TBasicAction);
-
/// Sets action used to display a snippet.
/// TBasicAction [in] Required action.
/// Methods of ISetActions.
@@ -184,12 +166,6 @@ TNotifier = class(TInterfacedObject, INotifier, ISetActions)
/// Methods of ISetActions.
procedure SetDisplayCategoryAction(const Action: TBasicAction);
- /// Sets action used to open snippets editor to create a new
- /// snippet.
- /// TBasicAction [in] Required action.
- /// Methods of ISetActions.
- procedure SetNewSnippetAction(const Action: TBasicAction);
-
/// Sets action used to display news items from the CodeSnip news
/// feed.
/// TBasicAction [in] Required action.
@@ -279,12 +255,6 @@ procedure TNotifier.EditSnippet(const Key: WideString;
end;
end;
-procedure TNotifier.NewSnippet;
-begin
- if Assigned(fNewSnippetAction) then
- fNewSnippetAction.Execute;
-end;
-
procedure TNotifier.SetAboutBoxAction(const Action: TBasicAction);
begin
fAboutBoxAction := Action;
@@ -335,11 +305,6 @@ procedure TNotifier.SetNewsAction(const Action: TBasicAction);
fNewsAction := Action;
end;
-procedure TNotifier.SetNewSnippetAction(const Action: TBasicAction);
-begin
- fNewSnippetAction := Action;
-end;
-
procedure TNotifier.SetOverviewStyleChangeActions(
const Actions: array of TBasicAction);
var
@@ -355,12 +320,6 @@ procedure TNotifier.SetShowViewItemAction(const Action: TBasicAction);
fShowViewItemAction := Action;
end;
-procedure TNotifier.SetUpdateDbaseAction(
- const Action: TBasicAction);
-begin
- fUpdateDbaseAction := Action;
-end;
-
procedure TNotifier.ShowAboutBox;
begin
if Assigned(fAboutBoxAction) then
@@ -383,11 +342,5 @@ procedure TNotifier.ShowViewItem(ViewItem: IView; const NewTab: Boolean);
end;
end;
-procedure TNotifier.UpdateDbase;
-begin
- if Assigned(fUpdateDbaseAction) then
- fUpdateDbaseAction.Execute;
-end;
-
end.
diff --git a/Src/UWBExternal.pas b/Src/UWBExternal.pas
index 10995e94e..851b1e93a 100644
--- a/Src/UWBExternal.pas
+++ b/Src/UWBExternal.pas
@@ -53,10 +53,6 @@ TWBExternal = class(TAutoIntfObject, IWBExternal15, ISetNotifier)
/// library.
constructor Create;
- /// Updates database from internet.
- /// Method of IWBExternal15.
- procedure UpdateDbase; safecall;
-
/// Display snippet identified by key and collection ID.
/// WideString [in] Snippet's key.
/// WideString [in] Hex representation of
@@ -92,10 +88,6 @@ TWBExternal = class(TAutoIntfObject, IWBExternal15, ISetNotifier)
procedure DisplayCategory(const CatID: WideString; NewTab: WordBool);
safecall;
- /// Opens Snippet Editor ready to create a new snippet.
- /// Method of IWBExternal15.
- procedure NewSnippet; safecall;
-
/// Shows latest news items from CodeSnip news feed.
/// Method of IWBExternal15.
procedure ShowNews; safecall;
@@ -192,16 +184,6 @@ procedure TWBExternal.HandleException;
Application.HandleException(ExceptObject);
end;
-procedure TWBExternal.NewSnippet;
-begin
- try
- if Assigned(fNotifier) then
- fNotifier.NewSnippet;
- except
- HandleException;
- end;
-end;
-
procedure TWBExternal.SetNotifier(const Notifier: INotifier);
begin
fNotifier := Notifier;
@@ -227,15 +209,5 @@ procedure TWBExternal.ShowNews;
end;
end;
-procedure TWBExternal.UpdateDbase;
-begin
- try
- if Assigned(fNotifier) then
- fNotifier.UpdateDbase;
- except
- HandleException;
- end;
-end;
-
end.
From 860faa378260b4fbb44f9f282b1a31584978f3ae Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Thu, 14 Nov 2024 19:32:20 +0000
Subject: [PATCH 088/222] Add TCollectionID.TComparer and TCollectionID.Hash
Added a new Hash method to TCollectionID.
Added a new TComparer nested class to TCollectionID that implements
IComparer and IEqualityComparer. This
provides Compare, Equals and GetHashCode methods. The GetHashCode method
calls the new TCollectionID.Hash method.
---
Src/DB.UCollections.pas | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
index 3e321aa42..4a575c1e6 100644
--- a/Src/DB.UCollections.pas
+++ b/Src/DB.UCollections.pas
@@ -18,6 +18,7 @@ interface
uses
SysUtils,
Generics.Collections,
+ Generics.Defaults,
UEncodings,
UExceptions,
USettings,
@@ -81,6 +82,17 @@ TCollectionID = record
var
fID: TBytes;
public
+ type
+ TComparer = class(TInterfacedObject,
+ IComparer, IEqualityComparer
+ )
+ public
+ function Compare(const Left, Right: TCollectionID): Integer;
+ function Equals(const Left, Right: TCollectionID): Boolean;
+ reintroduce;
+ function GetHashCode(const Value: TCollectionID): Integer;
+ reintroduce;
+ end;
const
DCSC_v2_ID: TGUID = '{9F3A4A8A-0A2B-4088-B7C9-AE1D32D3FF9A}';
SWAG_v1_ID: TGUID = '{ADA985E0-0929-4986-A3FE-B2C981D430F1}';
@@ -96,6 +108,7 @@ TCollectionID = record
function ToHexString: string;
function IsBuiltInID: Boolean;
function IsNull: Boolean;
+ function Hash: Integer;
class function Compare(Left, Right: TCollectionID): Integer; static;
class operator Equal(Left, Right: TCollectionID): Boolean;
class operator NotEqual(Left, Right: TCollectionID): Boolean;
@@ -239,9 +252,11 @@ TCollectionsPersist = record
implementation
uses
+ // Delphi
RTLConsts,
IOUtils,
Math,
+ // Project
UAppInfo, // TODO -cVault: needed only for v4 emulation
UStrUtils,
UUtils;
@@ -528,6 +543,11 @@ class function TCollectionID.CreateNull: TCollectionID;
Result := IsEqualBytes(Left.fID, Right.fID);
end;
+function TCollectionID.Hash: Integer;
+begin
+ Result := BobJenkinsHash(fID[0], Length(fID), 0);
+end;
+
function TCollectionID.IsBuiltInID: Boolean;
begin
Result := (TCollectionID.Create(DCSC_v2_ID) = Self)
@@ -565,6 +585,26 @@ class function TCollectionID.__TMP__UserDBCollectionID: TCollectionID;
Result := TCollectionID.Create(Native_v4_ID);
end;
+{ TCollectionID.TComparer }
+
+function TCollectionID.TComparer.Compare(const Left,
+ Right: TCollectionID): Integer;
+begin
+ Result := TCollectionID.Compare(Left, Right);
+end;
+
+function TCollectionID.TComparer.Equals(const Left,
+ Right: TCollectionID): Boolean;
+begin
+ Result := Left = Right;
+end;
+
+function TCollectionID.TComparer.GetHashCode(
+ const Value: TCollectionID): Integer;
+begin
+ Result := Value.Hash;
+end;
+
{ TCollectionsPersist }
class procedure TCollectionsPersist.Load(
From a2c16aa1acb28ac0bef8e6c2a45095fc53f4e516 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Fri, 15 Nov 2024 09:14:54 +0000
Subject: [PATCH 089/222] Revise display preferences re collections
Updated display preferences stored in config file by removing settings
for the old "main" and "user" database snippet colours and replacing
them with separate settings for snippet heading colours for each
collection and a different colour setting for group headings.
Heavily revised the Display page of the Preferences dialogue box to
allow the user to enter and edit the new colour preferences.
Replaced default colours for "main" and "user" snippets with default
colours for snippet and group headings.
Made minimal changes to code that uses the changed preferences to
display snippet headings and tree nodes in the colour assigned to their
collection and/or to display group headings in the colour assigned to
them. It most cases preferences method calls on one or two lines were
all that was required. In other cases more significant changes were
required.
---
Src/FmDependenciesDlg.pas | 4 +-
Src/FmFavouritesDlg.pas | 4 +-
Src/FmFindXRefsDlg.pas | 2 +-
Src/FmTestCompileDlg.pas | 2 +-
Src/FrDetailView.pas | 34 +++-
Src/FrDisplayPrefs.dfm | 54 ++---
Src/FrDisplayPrefs.pas | 247 ++++++++++++++++++-----
Src/UColours.pas | 10 +-
Src/UDetailPageHTML.pas | 2 +-
Src/UPreferences.pas | 379 +++++++++++++++++++++---------------
Src/URTFCategoryDoc.pas | 6 +-
Src/URTFSnippetDoc.pas | 6 +-
Src/USnippetsChkListMgr.pas | 2 +-
Src/USnippetsTVDraw.pas | 4 +-
14 files changed, 507 insertions(+), 249 deletions(-)
diff --git a/Src/FmDependenciesDlg.pas b/Src/FmDependenciesDlg.pas
index 5a7c32bb4..cc723100b 100644
--- a/Src/FmDependenciesDlg.pas
+++ b/Src/FmDependenciesDlg.pas
@@ -419,7 +419,9 @@ procedure TDependenciesDlg.lbDependentsDrawItem(Control: TWinControl;
LB := Control as TListBox;
Canvas := LB.Canvas;
if not (odSelected in State) then
- Canvas.Font.Color := Preferences.GetDBHeadingColour(ExtractCollectionItem);
+ Canvas.Font.Color := Preferences.GetSnippetHeadingColour(
+ ExtractCollectionItem
+ );
Canvas.TextRect(
Rect,
Rect.Left + 2,
diff --git a/Src/FmFavouritesDlg.pas b/Src/FmFavouritesDlg.pas
index 06f92d52f..5148b5252 100644
--- a/Src/FmFavouritesDlg.pas
+++ b/Src/FmFavouritesDlg.pas
@@ -583,7 +583,9 @@ procedure TFavouritesDlg.LVCustomDrawItem(Sender: TCustomListView;
CollectionID: TCollectionID;
begin
CollectionID := (Item as TFavouriteListItem).Favourite.SnippetID.CollectionID;
- fLVFavs.Canvas.Font.Color := Preferences.GetDBHeadingColour(CollectionID);
+ fLVFavs.Canvas.Font.Color := Preferences.GetSnippetHeadingColour(
+ CollectionID
+ );
end;
procedure TFavouritesDlg.LVCustomDrawSubItem(Sender: TCustomListView;
diff --git a/Src/FmFindXRefsDlg.pas b/Src/FmFindXRefsDlg.pas
index b85259741..829cf9873 100644
--- a/Src/FmFindXRefsDlg.pas
+++ b/Src/FmFindXRefsDlg.pas
@@ -235,7 +235,7 @@ procedure TFindXRefsDlg.ConfigForm;
// Set label font styles and colours
lblSnippetName.Font.Style := [fsBold];
lblSnippetName.Font.Color :=
- Preferences.GetDBHeadingColour(fSnippet.CollectionID);
+ Preferences.GetSnippetHeadingColour(fSnippet.CollectionID);
// Display selected snippet name in appropriate controls
lblSnippetName.Caption := fSnippet.DisplayName;
chkIncludeSnippet.Caption := Format(
diff --git a/Src/FmTestCompileDlg.pas b/Src/FmTestCompileDlg.pas
index c35ea4c24..359c09892 100644
--- a/Src/FmTestCompileDlg.pas
+++ b/Src/FmTestCompileDlg.pas
@@ -289,7 +289,7 @@ procedure TTestCompileDlg.ConfigForm;
// Set required label fonts and captions
TFontHelper.SetDefaultBaseFont(lblSnippetName.Font);
lblSnippetName.Font.Color :=
- Preferences.GetDBHeadingColour(fSnippet.CollectionID);
+ Preferences.GetSnippetHeadingColour(fSnippet.CollectionID);
lblSnippetName.Caption := fSnippet.DisplayName;
end;
diff --git a/Src/FrDetailView.pas b/Src/FrDetailView.pas
index 65411bf8f..e8e8cbff5 100644
--- a/Src/FrDetailView.pas
+++ b/Src/FrDetailView.pas
@@ -17,7 +17,7 @@ interface
uses
// Delphi
- OleCtrls, SHDocVw, Classes, Controls, ExtCtrls, Windows, ActiveX,
+ OleCtrls, SHDocVw, Classes, Controls, ExtCtrls, Windows, ActiveX, Graphics,
// Project
FrBrowserBase, IntfFrameMgrs, UCommandBars, UCSSBuilder, UDetailPageLoader,
USearch, UView, UWBPopupMenus;
@@ -44,6 +44,14 @@ TDetailViewFrame = class {sealed}(TBrowserBaseFrame,
/// Generates and loads HTML representing a view into browser
/// control.
fPageLoader: TDetailPageLoader;
+ /// Records colour to be defined when defining CSS classes to
+ /// display page heading.
+ fHeadingColour: TColor;
+ /// Calculates colour of page heading, according to the type of
+ /// view being displayed.
+ /// IView [in] View for which heading colour is
+ /// required.
+ function GetHeadingColour(AView: IView): TColor;
/// Handles web browser UI manager's OnMenuPopup event. Pops up
/// relevant menu if appropriate.
/// TObject [in] Not used.
@@ -107,7 +115,7 @@ implementation
uses
// Delphi
- SysUtils, Graphics, Menus, Math,
+ SysUtils, Menus, Math,
// Project
ActiveText.UHTMLRenderer, Browser.UHighlighter,
DB.UCollections,
@@ -228,10 +236,13 @@ procedure TDetailViewFrame.BuildCSS(const CSSBuilder: TCSSBuilder);
.AddProperty(TCSS.BorderProp(cssAll, 1, cbsSolid, clBorder));
// Heading colours for user & main databases
+ {TODO -vault: replace all following classes with single ".heading" class}
CSSBuilder.AddSelector('.userdb')
- .AddProperty(TCSS.ColorProp(Preferences.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID)));
+ .AddProperty(TCSS.ColorProp(fHeadingColour));
CSSBuilder.AddSelector('.maindb')
- .AddProperty(TCSS.ColorProp(Preferences.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID)));
+ .AddProperty(TCSS.ColorProp(fHeadingColour));
+ CSSBuilder.AddSelector('.group-heading')
+ .AddProperty(TCSS.ColorProp(fHeadingColour));
// Sets CSS for style of New Tab text
CSSFont.Assign(ContentFont);
@@ -356,6 +367,8 @@ procedure TDetailViewFrame.Display(View: IView);
var
Filter: ITextSearchFilter; // text search filter containing criteria
begin
+ fHeadingColour := GetHeadingColour(View);
+
// Load view's HTML into browser control
fPageLoader.LoadPage(View);
// Clear any existing text selection
@@ -366,6 +379,19 @@ procedure TDetailViewFrame.Display(View: IView);
Supports(Query.LatestSearch.Filter, ITextSearchFilter, Filter)
then
HighlightSearchResults(Filter);
+
+end;
+
+function TDetailViewFrame.GetHeadingColour(AView: IView): TColor;
+var
+ SnippetView: ISnippetView;
+begin
+ if Supports(AView, ISnippetView, SnippetView) then
+ Result := Preferences.GetSnippetHeadingColour(
+ SnippetView.Snippet.CollectionID
+ )
+ else
+ Result := Preferences.GroupHeadingColour;
end;
procedure TDetailViewFrame.HighlightSearchResults(
diff --git a/Src/FrDisplayPrefs.dfm b/Src/FrDisplayPrefs.dfm
index 80a7370ef..d34c1c858 100644
--- a/Src/FrDisplayPrefs.dfm
+++ b/Src/FrDisplayPrefs.dfm
@@ -1,8 +1,8 @@
inherited DisplayPrefsFrame: TDisplayPrefsFrame
- Width = 397
- Height = 311
- ExplicitWidth = 397
- ExplicitHeight = 311
+ Width = 438
+ Height = 347
+ ExplicitWidth = 438
+ ExplicitHeight = 347
object lblOverviewTree: TLabel
Left = 16
Top = 6
@@ -11,30 +11,31 @@ inherited DisplayPrefsFrame: TDisplayPrefsFrame
Caption = 'Start &overview pane treeview as:'
FocusControl = cbOverviewTree
end
- object lblMainColour: TLabel
+ object lblGroupHeadingColour: TLabel
Left = 16
- Top = 96
- Width = 193
+ Top = 112
+ Width = 191
Height = 13
- Caption = 'Heading colour for &main database items:'
+ Caption = '&Group heading colour in overview pane:'
end
- object lblUserColour: TLabel
+ object lblCollectionColours: TLabel
Left = 16
- Top = 115
- Width = 192
+ Top = 139
+ Width = 240
Height = 13
- Caption = 'Heading colour for &user database items:'
+ Caption = 'Heading colour snippets from different &collections:'
+ FocusControl = cbCollection
end
object lblSourceBGColour: TLabel
Left = 16
- Top = 134
+ Top = 200
Width = 170
Height = 13
Caption = 'Background colour for &source code:'
end
object lblOverviewFontSize: TLabel
Left = 16
- Top = 200
+ Top = 253
Width = 145
Height = 13
Caption = 'Overview tree view &font size: '
@@ -42,7 +43,7 @@ inherited DisplayPrefsFrame: TDisplayPrefsFrame
end
object lblDetailFontSize: TLabel
Left = 16
- Top = 232
+ Top = 280
Width = 105
Height = 13
Caption = 'Detail pane font si&ze: '
@@ -50,9 +51,9 @@ inherited DisplayPrefsFrame: TDisplayPrefsFrame
end
object lblHiliterInfo: TLabel
Left = 16
- Top = 256
- Width = 370
- Height = 36
+ Top = 304
+ Width = 358
+ Height = 26
Caption =
'To change the size of the source code font use the the Syntax Hi' +
'ghlighter options page.'
@@ -88,16 +89,16 @@ inherited DisplayPrefsFrame: TDisplayPrefsFrame
end
object btnDefColours: TButton
Left = 16
- Top = 156
+ Top = 219
Width = 192
Height = 25
- Caption = 'Use Default &Colours'
+ Caption = 'Use &Default Colours'
TabOrder = 3
OnClick = btnDefColoursClick
end
object cbOverviewFontSize: TComboBox
Left = 192
- Top = 197
+ Top = 250
Width = 57
Height = 21
TabOrder = 4
@@ -105,10 +106,19 @@ inherited DisplayPrefsFrame: TDisplayPrefsFrame
end
object cbDetailFontSize: TComboBox
Left = 192
- Top = 229
+ Top = 277
Width = 57
Height = 21
TabOrder = 5
OnChange = FontSizeChange
end
+ object cbCollection: TComboBox
+ Left = 16
+ Top = 158
+ Width = 170
+ Height = 21
+ Style = csDropDownList
+ TabOrder = 6
+ OnChange = cbCollectionChange
+ end
end
diff --git a/Src/FrDisplayPrefs.pas b/Src/FrDisplayPrefs.pas
index 3f0433599..926c561a5 100644
--- a/Src/FrDisplayPrefs.pas
+++ b/Src/FrDisplayPrefs.pas
@@ -19,9 +19,18 @@ interface
uses
// Delphi
- Controls, StdCtrls, Classes,
+ Controls,
+ StdCtrls,
+ Classes,
+ Graphics,
+ Generics.Collections,
// Project
- FrPrefsBase, UColorBoxEx, UColorDialogEx, UPreferences;
+ DB.UCollections,
+ FrPrefsBase,
+ UCollectionListAdapter,
+ UColorBoxEx,
+ UColorDialogEx,
+ UPreferences;
type
@@ -31,8 +40,8 @@ TDisplayPrefsFrame = class(TPrefsBaseFrame)
cbOverviewTree: TComboBox;
chkHideEmptySections: TCheckBox;
chkSnippetsInNewTab: TCheckBox;
- lblMainColour: TLabel;
- lblUserColour: TLabel;
+ lblGroupHeadingColour: TLabel;
+ lblCollectionColours: TLabel;
btnDefColours: TButton;
lblSourceBGColour: TLabel;
lblOverviewFontSize: TLabel;
@@ -40,19 +49,29 @@ TDisplayPrefsFrame = class(TPrefsBaseFrame)
lblDetailFontSize: TLabel;
cbDetailFontSize: TComboBox;
lblHiliterInfo: TLabel;
+ cbCollection: TComboBox;
procedure chkHideEmptySectionsClick(Sender: TObject);
procedure btnDefColoursClick(Sender: TObject);
procedure FontSizeChange(Sender: TObject);
+ procedure cbCollectionChange(Sender: TObject);
strict private
var
/// Flag indicating if changes affect UI.
fUIChanged: Boolean;
- fMainColourBox: TColorBoxEx;
- fMainColourDlg: TColorDialogEx;
- fUserColourBox: TColorBoxEx;
- fUserColourDlg: TColorDialogEx;
+
+ /// Local copy of snippet heading / tree node colour for each
+ /// collection.
+ fSnippetHeadingColours: TDictionary;
+
+ fGroupHeadingColourBox: TColorBoxEx;
+ fGroupHeadingColourDlg: TColorDialogEx;
+ fSnippetHeadingColourBox: TColorBoxEx;
+ fSnippetHeadingColourDlg: TColorDialogEx;
fSourceBGColourBox: TColorBoxEx;
fSourceBGColourDlg: TColorDialogEx;
+
+ fCollList: TCollectionListAdapter;
+
procedure SelectOverviewTreeState(const State: TOverviewStartState);
{Selects combo box item associated with a overview treeview startup state.
@param State [in] Startup state to be selected.
@@ -62,15 +81,23 @@ TDisplayPrefsFrame = class(TPrefsBaseFrame)
@param State [in] State for which description is required.
@return Required description.
}
- function CreateCustomColourBox(const ColourDlg: TColorDialogEx):
+ function CreateCustomColourBox(const ColourDlg: TColorDialogEx;
+ ChangeHandler: TNotifyEvent):
TColorBoxEx;
procedure ColourBoxChangeHandler(Sender: TObject);
+ procedure SnippetHeadingColourBoxChange(Sender: TObject);
procedure PopulateFontSizeCombos;
+ procedure SetTabOrder;
+ function SelectedCollectionID: TCollectionID;
public
constructor Create(AOwner: TComponent); override;
- {Class constructor. Sets up frame and populates controls.
+ {Object constructor. Sets up frame and populates controls.
@param AOwner [in] Component that owns frame.
}
+
+ /// Object destructor. Frees owned objects.
+ destructor Destroy; override;
+
procedure Activate(const Prefs: IPreferences; const Flags: UInt64);
override;
{Called when page activated. Updates controls.
@@ -105,10 +132,16 @@ implementation
uses
// Delphi
- SysUtils, Math, Graphics, ExtCtrls,
+ SysUtils,
+ Generics.Defaults,
+ Math,
+ ExtCtrls,
// Project
- DB.UCollections,
- FmPreferencesDlg, UColours, UCtrlArranger, UFontHelper, UGraphicUtils,
+ FmPreferencesDlg,
+ UColours,
+ UCtrlArranger,
+ UFontHelper,
+ UGraphicUtils,
UMessageBox;
@@ -128,93 +161,146 @@ procedure TDisplayPrefsFrame.Activate(const Prefs: IPreferences;
{Called when page activated. Updates controls.
@param Prefs [in] Object that provides info used to update controls.
}
+var
+ Collection: TCollection;
begin
+ {TODO -cCollections: Replace __TMP__ method below with call to a new
+ TCollections.Default method or similar.}
+ cbCollection.ItemIndex := TCollections.Instance.IndexOfID(TCollectionID.__TMP__UserDBCollectionID);
+ Assert(cbCollection.ItemIndex >= 0,
+ ClassName + '.Activate: no default collection found');
+
SelectOverviewTreeState(Prefs.OverviewStartState);
chkHideEmptySections.OnClick := nil; // prevent OnClick when Checked set
chkHideEmptySections.Checked := not Prefs.ShowEmptySections;
chkHideEmptySections.OnClick := chkHideEmptySectionsClick;
chkSnippetsInNewTab.Checked := Prefs.ShowNewSnippetsInNewTabs;
- fMainColourBox.Selected := Prefs.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID);
- fUserColourBox.Selected := Prefs.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID);
+ fGroupHeadingColourBox.Selected := Prefs.GroupHeadingColour;
+ fSnippetHeadingColours.Clear;
+ for Collection in TCollections.Instance do
+ fSnippetHeadingColours.Add(
+ Collection.UID, Prefs.GetSnippetHeadingColour(Collection.UID)
+ );
+ fSnippetHeadingColourBox.Selected :=
+ Prefs.GetSnippetHeadingColour(SelectedCollectionID);
fSourceBGColourBox.Selected := Prefs.SourceCodeBGcolour;
- Prefs.GetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID).CopyTo(fMainColourDlg.CustomColors, True);
- Prefs.GetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID).CopyTo(fUserColourDlg.CustomColors, True);
+ Prefs.GroupHeadingCustomColours.CopyTo(
+ fGroupHeadingColourDlg.CustomColors, True
+ );
Prefs.SourceCodeBGCustomColours.CopyTo(fSourceBGColourDlg.CustomColors, True);
cbOverviewFontSize.Tag := Prefs.OverviewFontSize; // store font size in .Tag
cbOverviewFontSize.Text := IntToStr(Prefs.OverviewFontSize);
cbDetailFontSize.Tag := Prefs.DetailFontSize; // store font size in .Tag
cbDetailFontSize.Text := IntToStr(Prefs.DetailFontSize);
+
end;
procedure TDisplayPrefsFrame.ArrangeControls;
{Arranges controls on frame. Called after frame has been sized.
}
begin
+ // Align controls on left
TCtrlArranger.AlignLefts(
[
- lblOverviewTree, chkHideEmptySections, chkSnippetsInNewTab,
- lblMainColour, lblUserColour, lblSourceBGColour, btnDefColours,
- lblOverviewFontSize, lblDetailFontSize, lblHiliterInfo
+ lblOverviewTree, chkSnippetsInNewTab, chkHideEmptySections,
+ lblGroupHeadingColour, lblCollectionColours, lblSourceBGColour,
+ btnDefColours, lblOverviewFontSize, lblDetailFontSize, lblHiliterInfo
],
0
);
+ // Align collections combo indented from left
+ cbCollection.Left := 8;
+
+ // Align controls on right: make sure they are all to right of everything
+ // on left that is on same line as any of them.
TCtrlArranger.AlignLefts(
[
- cbOverviewTree, fMainColourBox, fUserColourBox, fSourceBGColourBox,
- cbOverviewFontSize, cbDetailFontSize
+ cbOverviewTree, fGroupHeadingColourBox, fSnippetHeadingColourBox,
+ fSourceBGColourBox, cbOverviewFontSize, cbDetailFontSize
],
TCtrlArranger.RightOf(
- [lblOverviewTree, lblMainColour, lblUserColour, lblSourceBGColour],
+ [
+ lblOverviewTree, lblGroupHeadingColour, cbCollection, lblSourceBGColour,
+ lblOverviewFontSize, lblDetailFontSize
+ ],
8
)
);
+
+ // Align rows:
+ // 1st row
TCtrlArranger.AlignVCentres(3, [lblOverviewTree, cbOverviewTree]);
+ // 2nd row
TCtrlArranger.MoveBelow(
[lblOverviewTree, cbOverviewTree], chkSnippetsInNewTab, 12
);
+ chkSnippetsInNewTab.Width := Self.Width - 16;
+ // 3rd row
TCtrlArranger.MoveBelow(chkSnippetsInNewTab, chkHideEmptySections, 8);
+ chkHideEmptySections.Width := Self.Width - 16;
+ // 4th row
TCtrlArranger.AlignVCentres(
TCtrlArranger.BottomOf(chkHideEmptySections, 12),
- [lblMainColour, fMainColourBox]
+ [lblGroupHeadingColour, fGroupHeadingColourBox]
+ );
+ // 5th row
+ TCtrlArranger.MoveBelow(
+ [lblGroupHeadingColour, fGroupHeadingColourBox],
+ lblCollectionColours,
+ 12
);
+ // 6th row
TCtrlArranger.AlignVCentres(
- TCtrlArranger.BottomOf([lblMainColour, fMainColourBox], 6),
- [lblUserColour, fUserColourBox]
+ TCtrlArranger.BottomOf(lblCollectionColours, 6),
+ [cbCollection, fSnippetHeadingColourBox]
);
+ // 7th row
TCtrlArranger.AlignVCentres(
- TCtrlArranger.BottomOf([lblUserColour, fUserColourBox], 6),
+ TCtrlArranger.BottomOf([cbCollection, fSnippetHeadingColourBox], 18),
[lblSourceBGColour, fSourceBGColourBox]
);
+ // 8th row
TCtrlArranger.MoveBelow(
- [lblSourceBGColour, fSourceBGColourBox], btnDefColours, 6
+ [lblSourceBGColour, fSourceBGColourBox], btnDefColours, 12
);
+ // 9th row
TCtrlArranger.AlignVCentres(
TCtrlArranger.BottomOf(btnDefColours, 12),
[lblOverviewFontSize, cbOverviewFontSize]
);
+ // 10th row
TCtrlArranger.AlignVCentres(
- TCtrlArranger.BottomOf(cbOverviewFontSize, 8),
+ TCtrlArranger.BottomOf([lblOverviewFontSize, cbOverviewFontSize], 8),
[lblDetailFontSize, cbDetailFontSize]
);
+ // 11th row
TCtrlArranger.MoveBelow(
[lblDetailFontSize, cbDetailFontSize], lblHiliterInfo, 12
);
lblHiliterInfo.Width := Self.ClientWidth;
TCtrlArranger.SetLabelHeight(lblHiliterInfo);
- chkHideEmptySections.Width := Self.Width - 16;
- chkSnippetsInNewTab.Width := Self.Width - 16;
end;
procedure TDisplayPrefsFrame.btnDefColoursClick(Sender: TObject);
+var
+ Collection: TCollection;
begin
// Restores default heading and source code background colours in colour
// combo boxes
- fMainColourBox.Selected := clMainSnippet;
- fUserColourBox.Selected := clUserSnippet;
+ fGroupHeadingColourBox.Selected := clDefGroupHeading;
+ fSnippetHeadingColourBox.Selected := clDefSnippetHeading;
+ for Collection in TCollections.Instance do
+ fSnippetHeadingColours[Collection.UID] := clDefSnippetHeading;
fSourceBGColourBox.Selected := clSourceBg;
fUIChanged := True;
end;
+procedure TDisplayPrefsFrame.cbCollectionChange(Sender: TObject);
+begin
+ fSnippetHeadingColourBox.Selected :=
+ fSnippetHeadingColours[SelectedCollectionID];
+end;
+
procedure TDisplayPrefsFrame.chkHideEmptySectionsClick(Sender: TObject);
{Handles clicks on "Hide Empty Sections" check box. Flags UI preferences has
having changed.
@@ -235,6 +321,7 @@ constructor TDisplayPrefsFrame.Create(AOwner: TComponent);
}
resourcestring
sHeadingColourDlgTitle = 'Heading Colour';
+ sGroupHeadingColourDlgTitle = 'Group Heading Colour';
sSourceBGColourDlgTitle = 'Source Code Background Colour';
var
OTStateIdx: TOverviewStartState; // loops thru each overview tree start state
@@ -247,28 +334,42 @@ constructor TDisplayPrefsFrame.Create(AOwner: TComponent);
OverviewTreeStateDesc(OTStateIdx), TObject(OTStateIdx)
);
// Create colour dialogue boxes
- fMainColourDlg := TColorDialogEx.Create(Self);
- fMainColourDlg.Title := sHeadingColourDlgTitle;
- fUserColourDlg := TColorDialogEx.Create(Self);
- fUserColourDlg.Title := sHeadingColourDlgTitle;
+ fGroupHeadingColourDlg := TColorDialogEx.Create(Self);
+ fGroupHeadingColourDlg.Title := sGroupHeadingColourDlgTitle;
+ fSnippetHeadingColourDlg := TColorDialogEx.Create(Self);
+ fSnippetHeadingColourDlg.Title := sHeadingColourDlgTitle;
fSourceBGColourDlg := TColorDialogEx.Create(Self);
fSourceBGColourDlg.Title := sSourceBGColourDlgTitle;
// Create colour combo boxes
- fMainColourBox := CreateCustomColourBox(fMainColourDlg);
- fMainColourBox.TabOrder := 3;
- lblMainColour.FocusControl := fMainColourBox;
- fUserColourBox := CreateCustomColourBox(fUserColourDlg);
- fUserColourBox.TabOrder := 4;
- lblUserColour.FocusControl := fUserColourBox;
- fSourceBGColourBox := CreateCustomColourBox(fSourceBGColourDlg);
- fSourceBGColourBox.TabOrder := 5;
+ fGroupHeadingColourBox := CreateCustomColourBox(
+ fGroupHeadingColourDlg, ColourBoxChangeHandler
+ );
+ lblGroupHeadingColour.FocusControl := fGroupHeadingColourBox;
+ fSnippetHeadingColourBox := CreateCustomColourBox(
+ fSnippetHeadingColourDlg, SnippetHeadingColourBoxChange
+ );
+ fSnippetHeadingColourBox.OnChange := SnippetHeadingColourBoxChange;
+ lblCollectionColours.FocusControl := cbCollection;
+ fSourceBGColourBox := CreateCustomColourBox(
+ fSourceBGColourDlg, ColourBoxChangeHandler
+ );
lblSourceBGColour.FocusControl := fSourceBGColourBox;
PopulateFontSizeCombos;
+
+ fSnippetHeadingColours := TDictionary.Create(
+ TCollectionID.TComparer.Create
+ );
+
+ fCollList := TCollectionListAdapter.Create;
+ fCollList.ToStrings(cbCollection.Items);
+ Assert(cbCollection.Items.Count > 0, ClassName + '.Create: no collections');
+
+ SetTabOrder;
end;
function TDisplayPrefsFrame.CreateCustomColourBox(
- const ColourDlg: TColorDialogEx): TColorBoxEx;
+ const ColourDlg: TColorDialogEx; ChangeHandler: TNotifyEvent): TColorBoxEx;
begin
// Create and initialise custom color combo box
Result := TColorBoxEx.Create(Self); // automatically freed
@@ -282,28 +383,31 @@ function TDisplayPrefsFrame.CreateCustomColourBox(
Result.ItemHeight := 16;
if Assigned(ColourDlg) then
Result.ColorDialog := ColourDlg;
- Result.OnChange := ColourBoxChangeHandler;
+ Result.OnChange := ChangeHandler;
end;
procedure TDisplayPrefsFrame.Deactivate(const Prefs: IPreferences);
{Called when page is deactivated. Stores information entered by user.
@param Prefs [in] Object used to store information.
}
+var
+ Collection: TCollection;
begin
Prefs.ShowNewSnippetsInNewTabs := chkSnippetsInNewTab.Checked;
Prefs.ShowEmptySections := not chkHideEmptySections.Checked;
Prefs.OverviewStartState := TOverviewStartState(
cbOverviewTree.Items.Objects[cbOverviewTree.ItemIndex]
);
- Prefs.SetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID, fMainColourBox.Selected);
- Prefs.SetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID, fUserColourBox.Selected);
+ Prefs.GroupHeadingColour := fGroupHeadingColourBox.Selected;
Prefs.SourceCodeBGcolour := fSourceBGColourBox.Selected;
- Prefs.GetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID).CopyFrom(
- fMainColourDlg.CustomColors, True
- );
- Prefs.GetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID).CopyFrom(
- fUserColourDlg.CustomColors, True
+ Prefs.GroupHeadingCustomColours.CopyFrom(
+ fGroupHeadingColourDlg.CustomColors, True
);
+
+ for Collection in TCollections.Instance do
+ Prefs.SetSnippetHeadingColour(
+ Collection.UID, fSnippetHeadingColours[Collection.UID]
+ );
Prefs.SourceCodeBGCustomColours.CopyFrom(
fSourceBGColourDlg.CustomColors, True
);
@@ -313,6 +417,13 @@ procedure TDisplayPrefsFrame.Deactivate(const Prefs: IPreferences);
Prefs.DetailFontSize := StrToIntDef(cbDetailFontSize.Text, -1);
end;
+destructor TDisplayPrefsFrame.Destroy;
+begin
+ fCollList.Free;
+ fSnippetHeadingColours.Free;
+ inherited;
+end;
+
function TDisplayPrefsFrame.DisplayName: string;
{Caption that is displayed in the tab sheet that contains this frame when
displayed in the preference dialog box.
@@ -401,6 +512,13 @@ procedure TDisplayPrefsFrame.PopulateFontSizeCombos;
TFontHelper.ListCommonFontSizes(cbDetailFontSize.Items);
end;
+function TDisplayPrefsFrame.SelectedCollectionID: TCollectionID;
+begin
+ Assert(cbCollection.ItemIndex >= 0,
+ ClassName + '.SelectedCollectionID: no collection selected');
+ Result := fCollList.Collection(cbCollection.ItemIndex).UID;
+end;
+
procedure TDisplayPrefsFrame.SelectOverviewTreeState(
const State: TOverviewStartState);
{Selects combo box item associated with a overview treeview startup state.
@@ -419,6 +537,27 @@ procedure TDisplayPrefsFrame.SelectOverviewTreeState(
end;
end;
+procedure TDisplayPrefsFrame.SetTabOrder;
+begin
+ cbOverviewTree.TabOrder := 0;
+ chkSnippetsInNewTab.TabOrder := 1;
+ chkHideEmptySections.TabOrder := 2;
+ fGroupHeadingColourBox.TabOrder := 3;
+ cbCollection.TabOrder := 4;
+ fSnippetHeadingColourBox.TabOrder := 5;
+ fSourceBGColourBox.TabOrder := 6;
+ btnDefColours.TabOrder := 7;
+ cbOverviewFontSize.TabOrder := 8;
+ cbDetailFontSize.TabOrder := 9;
+end;
+
+procedure TDisplayPrefsFrame.SnippetHeadingColourBoxChange(Sender: TObject);
+begin
+ ColourBoxChangeHandler(Sender);
+ fSnippetHeadingColours[SelectedCollectionID] :=
+ fSnippetHeadingColourBox.Selected
+end;
+
function TDisplayPrefsFrame.UIUpdated: Boolean;
begin
Result := fUIChanged;
diff --git a/Src/UColours.pas b/Src/UColours.pas
index 219745f46..e0e9bef20 100644
--- a/Src/UColours.pas
+++ b/Src/UColours.pas
@@ -53,11 +53,13 @@ interface
clSplashShadowText = clWhite; // splash screen text shadow
// new tab
- clNewTabText = cl3DLight; // color of text displayed in new tabs
+ clNewTabText = cl3DLight; // text displayed in new tabs
- // colours of snippet titles / heading
- clMainSnippet = clWindowText; // main database snippets
- clUserSnippet = clBlue; // user database snippets
+ // group headings
+ clDefGroupHeading = clWindowText; // default for overview group headings
+
+ // snippet headings
+ clDefSnippetHeading = clWindowText; // default for snippet headings
// markup tags
clVarText = clPurple; // tag text
diff --git a/Src/UDetailPageHTML.pas b/Src/UDetailPageHTML.pas
index 84f6a9d9f..78727dab8 100644
--- a/Src/UDetailPageHTML.pas
+++ b/Src/UDetailPageHTML.pas
@@ -578,7 +578,7 @@ destructor TSnippetListPageHTML.Destroy;
function TSnippetListPageHTML.GetH1ClassName: string;
begin
- Result := 'maindb';
+ Result := 'group-heading';
end;
function TSnippetListPageHTML.GetHeading: string;
diff --git a/Src/UPreferences.pas b/Src/UPreferences.pas
index 1137db604..da22563ff 100644
--- a/Src/UPreferences.pas
+++ b/Src/UPreferences.pas
@@ -137,35 +137,61 @@ interface
property ShowNewSnippetsInNewTabs: Boolean
read GetShowNewSnippetsInNewTabs write SetShowNewSnippetsInNewTabs;
- /// Gets heading colour used for snippets from a specified
- /// collection.
- /// TCollectionID [in] ID of required
+ /// Gets colour used for group heading / tree nodes.
+ /// TColor [in] Required colour.
+ function GetGroupHeadingColour: TColor;
+ /// Sets colour to be used for group heading / tree nodes.
+ ///
+ /// TColor [in] Colour to be used.
+ procedure SetGroupHeadingColour(const AColour: TColor);
+ /// Colour to be used for group headings / tree nodes.
+ property GroupHeadingColour: TColor
+ read GetGroupHeadingColour write SetGroupHeadingColour;
+
+ /// Gets custom colours available for use for group headings /
+ /// tree nodes.
+ /// IStringList. List of hex representations of custom
+ /// colours.
+ function GetGroupHeadingCustomColours: IStringList;
+ /// Sets custom colours available for use for group headings /
+ /// tree nodes.
+ /// IStringList. List of hex representations
+ /// of custom colours.
+ procedure SetGroupHeadingCustomColours(const AColours: IStringList);
+ /// Custom colours available for use for group headings /
+ /// tree nodes.
+ property GroupHeadingCustomColours: IStringList
+ read GetGroupHeadingCustomColours write SetGroupHeadingCustomColours;
+
+ /// Gets the heading / tree node colour used for snippets from a
+ /// specified collection.
+ /// TCollectionID [in] ID of required
/// collection.
/// TColor. Required colour.
- function GetDBHeadingColour(const ACollectionID: TCollectionID): TColor;
- /// Sets heading colour used for snippets from a specified
- /// collection.
- /// TCollectionID [in] ID of required
+ function GetSnippetHeadingColour(const ACollectionID: TCollectionID):
+ TColor;
+ /// Sets heading / tree node colour used for snippets from a
+ /// specified collection.
+ /// TCollectionID [in] ID of required
/// collection.
- /// TColor. Required colour.
- procedure SetDBHeadingColour(const ACollectionID: TCollectionID;
+ /// TColor. Required colour.
+ procedure SetSnippetHeadingColour(const ACollectionID: TCollectionID;
const Value: TColor);
- /// Gets custom colours available for headings for specified
- /// collection.
- /// TCollectionID [in] ID of required
- /// collection.
- /// IStringList. String list containing custom colours.
- function GetDBHeadingCustomColours(const ACollectionID: TCollectionID):
- IStringList;
- /// Sets custom colours available for headings for specified
- /// collection.
- /// TCollectionID [in] ID of required
- /// collection.
- /// IStringList [in] String list containing custom
- /// colours.
- procedure SetDBHeadingCustomColours(const ACollectionID: TCollectionID;
- Value: IStringList);
+ /// Gets custom colours available for snippet headings / tree
+ /// nodes.
+ /// IStringList. String list containing custom colours.
+ ///
+ function GetSnippetHeadingCustomColours: IStringList;
+ /// Sets custom colours available for snippet headings / tree
+ /// nodes.
+ /// IStringList [in] String list containing
+ /// custom colours.
+ procedure SetSnippetHeadingCustomColours(const AColours: IStringList);
+ /// Custom colours available for snippet headings / tree nodes.
+ ///
+ property SnippetHeadingCustomColours: IStringList
+ read GetSnippetHeadingCustomColours write SetSnippetHeadingCustomColours;
/// Gets size of font used in overview pane tree view.
function GetOverviewFontSize: Integer;
@@ -287,6 +313,8 @@ implementation
uses
// Delphi
SysUtils,
+ Generics.Collections,
+ Generics.Defaults,
// Project
Hiliter.UAttrs, Hiliter.UPersist, IntfCommon, UExceptions, UColours,
UFontHelper, USettings;
@@ -328,21 +356,20 @@ TPreferences = class(TInterfacedObject,
/// Indicates whether empty sections are displayed in overview
/// pane.
fShowEmptySections: Boolean;
- /// Indicates whether new snippets and ca-tegories are displayed
+ /// Indicates whether new snippets and categories are displayed
/// in new tabs in details pane.
fShowNewSnippetsInNewTabs: Boolean;
- /// Records colour to be used for headings of items from either
- /// main (False) or user (True) collections.
- fDBHeadingColours: array[Boolean] of TColor;
- {TODO -cCollections: WARNING. The fDBHeadingColours field only supports
- the two original main & user collections. This MUST be changed
- once more than two snippet collections are supported}
- /// Records custom colours available for headings of items from
- /// either main (False) or user (True) collections.
- fDBHeadingCustomColours: array[Boolean] of IStringList;
- {TODO -cCollections: WARNING. The fDBHeadingCustomColours field only
- supports the two original main & user collections. This MUST be
- changed once more than two snippet collections are supported}
+ /// Records colour to be used for group headings.
+ fGroupHeadingColour: TColor;
+ /// Records custom colours available for group headings.
+ ///
+ fGroupHeadingCustomColours: IStringList;
+ /// Records colour to be used for snippet headings and tree
+ /// nodes for each collection.
+ fSnippetHeadingColours: TDictionary;
+ /// Records custom colours available for snippet heading and
+ /// tree nodes.
+ fSnippetHeadingCustomColours: IStringList;
/// Records size of font used in overview pane tree view.
///
fOverviewFontSize: Integer;
@@ -377,9 +404,6 @@ TPreferences = class(TInterfacedObject,
function DefaultOverviewFontSize: Integer;
/// Returns default font size for details pane.
function DefaultDetailFontSize: Integer;
-
- function __TMP__UseUserDBHeadingColour(const ACollectionID: TCollectionID):
- Boolean;
public
/// Constructs a new object instance.
constructor Create;
@@ -481,41 +505,68 @@ TPreferences = class(TInterfacedObject,
/// Method of IPreferences.
procedure SetShowNewSnippetsInNewTabs(const Value: Boolean);
- /// Gets heading colour used for snippets from a specified
- /// collection.
- /// TCollectionID [in] ID of required
- /// collection.
- /// TColor. Required colour.
+ /// Gets colour used for group heading / tree nodes.
+ /// TColor [in] Required colour.
+ /// Method of IPreferences.
+ function GetGroupHeadingColour: TColor;
+
+ /// Sets colour to be used for group heading / tree nodes.
+ ///
+ /// TColor [in] Colour to be used.
+ /// Method of IPreferences.
+ procedure SetGroupHeadingColour(const AColour: TColor);
+
+ /// Gets custom colours available for use for group headings /
+ /// tree nodes.
+ /// IStringList. List of hex representations of custom
+ /// colours.
/// Method of IPreferences.
- function GetDBHeadingColour(const ACollectionID: TCollectionID): TColor;
+ function GetGroupHeadingCustomColours: IStringList;
- /// Sets heading colour used for snippets from a specified
- /// collection.
- /// TCollectionID [in] ID of required
- /// collection.
- /// TColor. Required colour.
+ /// Sets custom colours available for use for group headings /
+ /// tree nodes.
+ /// IStringList. List of hex representations
+ /// of custom colours.
/// Method of IPreferences.
- procedure SetDBHeadingColour(const ACollectionID: TCollectionID;
- const Value: TColor);
+ procedure SetGroupHeadingCustomColours(const AColours: IStringList);
- /// Gets custom colours available for headings for specified
- /// collection.
- /// TCollectionID [in] ID of required
+ /// Gets the heading / tree node colour used for snippets from a
+ /// specified collection.
+ /// TCollectionID [in] ID of required
/// collection.
- /// IStringList. String list containing custom colours.
- /// Method of IPreferences.
- function GetDBHeadingCustomColours(const ACollectionID: TCollectionID):
- IStringList;
+ /// TColor. Required colour.
+ /// Method of IPreferences.
+ function GetSnippetHeadingColour(const ACollectionID: TCollectionID):
+ TColor;
- /// Sets custom colours available for headings for specified
- /// collection.
- /// TCollectionID [in] ID of required
+ /// Sets heading / tree node colour used for snippets from a
+ /// specified collection.
+ /// TCollectionID [in] ID of required
/// collection.
- /// IStringList [in] String list containing custom
- /// colours.
- /// Method of IPreferences.
- procedure SetDBHeadingCustomColours(const ACollectionID: TCollectionID;
- Value: IStringList);
+ /// TColor. Required colour.
+ /// Method of IPreferences.
+ procedure SetSnippetHeadingColour(const ACollectionID: TCollectionID;
+ const Value: TColor);
+
+ /// Gets custom colours available for snippet headings / tree
+ /// nodes.
+ /// IStringList. String list containing custom colours.
+ ///
+ ///
+ /// All collections share this one custom colour list.
+ /// Method of IPreferences.
+ ///
+ function GetSnippetHeadingCustomColours: IStringList;
+
+ /// Sets custom colours available for snippet headings / tree
+ /// nodes.
+ /// IStringList [in] String list containing
+ /// custom colours.
+ ///
+ /// All collections share this one custom colour list.
+ /// Method of IPreferences.
+ ///
+ procedure SetSnippetHeadingCustomColours(const AColours: IStringList);
/// Gets size of font used in overview pane tree view.
/// Method of IPreferences.
@@ -681,6 +732,7 @@ function Preferences: IPreferences;
procedure TPreferences.Assign(const Src: IInterface);
var
SrcPref: IPreferences; // IPreferences interface of Src
+ Collection: TCollection;
begin
// Get IPreferences interface of given object
if not Supports(Src, IPreferences, SrcPref) then
@@ -695,10 +747,13 @@ procedure TPreferences.Assign(const Src: IInterface);
Self.fOverviewStartState := SrcPref.OverviewStartState;
Self.fShowEmptySections := SrcPref.ShowEmptySections;
Self.fShowNewSnippetsInNewTabs := SrcPref.ShowNewSnippetsInNewTabs;
- Self.SetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID, SrcPref.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID));
- Self.SetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID, SrcPref.GetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID));
- Self.SetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID, SrcPref.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID));
- Self.SetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID, SrcPref.GetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID));
+ Self.fGroupHeadingColour := SrcPref.GetGroupHeadingColour;
+ Self.fGroupHeadingCustomColours := SrcPref.GetGroupHeadingCustomColours;
+ for Collection in TCollections.Instance do
+ Self.SetSnippetHeadingColour(
+ Collection.UID, SrcPref.GetSnippetHeadingColour(Collection.UID)
+ );
+ Self.fSnippetHeadingCustomColours := SrcPref.GetSnippetHeadingCustomColours;
Self.fOverviewFontSize := SrcPref.OverviewFontSize;
Self.fDetailFontSize := SrcPref.DetailFontSize;
Self.fSourceCodeBGColour := SrcPref.SourceCodeBGColour;
@@ -719,8 +774,9 @@ constructor TPreferences.Create;
fNamedHiliteAttrs := THiliteAttrsFactory.CreateNamedAttrs;
fHiliteCustomColours := TIStringList.Create;
fWarnings := TWarnings.Create;
- fDBHeadingCustomColours[False] := TIStringList.Create;
- fDBHeadingCustomColours[True] := TIStringList.Create;
+ fSnippetHeadingColours := TDictionary.Create(
+ TCollectionID.TComparer.Create
+ );
fPageStructures := TSnippetPageStructures.Create;
TDefaultPageStructures.SetDefaults(fPageStructures);
end;
@@ -738,6 +794,7 @@ function TPreferences.DefaultOverviewFontSize: Integer;
destructor TPreferences.Destroy;
begin
fPageStructures.Free;
+ fSnippetHeadingColours.Free;
inherited;
end;
@@ -746,31 +803,19 @@ function TPreferences.GetCustomHiliteColours: IStringList;
Result := fHiliteCustomColours;
end;
-function TPreferences.GetDBHeadingColour(
- const ACollectionID: TCollectionID): TColor;
+function TPreferences.GetDetailFontSize: Integer;
begin
- {TODO -cCollections: WARNING: This implementation of GetDBHeadingColour only
- supports the old main and user collections. It will break when further
- collections are added.
- }
- Result := fDBHeadingColours[__TMP__UseUserDBHeadingColour(ACollectionID)];
+ Result := fDetailFontSize;
end;
-function TPreferences.GetDBHeadingCustomColours(
- const ACollectionID: TCollectionID): IStringList;
+function TPreferences.GetGroupHeadingColour: TColor;
begin
- {TODO -cCollections: WARNING: This implementation of GetDBHeadingCustomColours
- only supports the old main and user collections. It will break when
- further collections are added.
- }
- Result := fDBHeadingCustomColours[
- __TMP__UseUserDBHeadingColour(ACollectionID)
- ];
+ Result := fGroupHeadingColour;
end;
-function TPreferences.GetDetailFontSize: Integer;
+function TPreferences.GetGroupHeadingCustomColours: IStringList;
begin
- Result := fDetailFontSize;
+ Result := fGroupHeadingCustomColours;
end;
function TPreferences.GetHiliteAttrs: IHiliteAttrs;
@@ -828,6 +873,20 @@ function TPreferences.GetShowNewSnippetsInNewTabs: Boolean;
Result := fShowNewSnippetsInNewTabs;
end;
+function TPreferences.GetSnippetHeadingColour(
+ const ACollectionID: TCollectionID): TColor;
+begin
+ if fSnippetHeadingColours.ContainsKey(ACollectionID) then
+ Result := fSnippetHeadingColours[ACollectionID]
+ else
+ Result := clDefSnippetHeading;
+end;
+
+function TPreferences.GetSnippetHeadingCustomColours: IStringList;
+begin
+ Result := fSnippetHeadingCustomColours;
+end;
+
function TPreferences.GetSourceCodeBGColour: TColor;
begin
Result := fSourceCodeBGColour;
@@ -868,34 +927,23 @@ procedure TPreferences.SetCustomHiliteColours(const Colours: IStringList);
fHiliteCustomColours := Colours;
end;
-procedure TPreferences.SetDBHeadingColour(const ACollectionID: TCollectionID;
- const Value: TColor);
+procedure TPreferences.SetDetailFontSize(const Value: Integer);
begin
- {TODO -cCollections: WARNING: This implementation of SetDBHeadingColour only
- supports the old main and user collections. It will break when further
- collections are added.
- }
- fDBHeadingColours[__TMP__UseUserDBHeadingColour(ACollectionID)] := Value;
+ if TFontHelper.IsInCommonFontSizeRange(Value) then
+ fDetailFontSize := Value
+ else
+ fDetailFontSize := DefaultDetailFontSize;
end;
-procedure TPreferences.SetDBHeadingCustomColours(
- const ACollectionID: TCollectionID; Value: IStringList);
+procedure TPreferences.SetGroupHeadingColour(const AColour: TColor);
begin
- {TODO -cCollections: WARNING: This implementation of SetDBHeadingCustomColours
- only supports the old main and user collections. It will break when
- further collections are added.
- }
- fDBHeadingCustomColours[
- __TMP__UseUserDBHeadingColour(ACollectionID)
- ] := Value;
+ fGroupHeadingColour := AColour;
end;
-procedure TPreferences.SetDetailFontSize(const Value: Integer);
+procedure TPreferences.SetGroupHeadingCustomColours(
+ const AColours: IStringList);
begin
- if TFontHelper.IsInCommonFontSizeRange(Value) then
- fDetailFontSize := Value
- else
- fDetailFontSize := DefaultDetailFontSize;
+ fGroupHeadingCustomColours := AColours;
end;
procedure TPreferences.SetHiliteAttrs(const Attrs: IHiliteAttrs);
@@ -957,6 +1005,18 @@ procedure TPreferences.SetShowNewSnippetsInNewTabs(const Value: Boolean);
fShowNewSnippetsInNewTabs := Value;
end;
+procedure TPreferences.SetSnippetHeadingColour(
+ const ACollectionID: TCollectionID; const Value: TColor);
+begin
+ fSnippetHeadingColours.AddOrSetValue(ACollectionID, Value);
+end;
+
+procedure TPreferences.SetSnippetHeadingCustomColours(
+ const AColours: IStringList);
+begin
+ fSnippetHeadingCustomColours := AColours;
+end;
+
procedure TPreferences.SetSourceCodeBGColour(const Value: TColor);
begin
fSourceCodeBGColour := Value;
@@ -992,18 +1052,12 @@ procedure TPreferences.SetWarnings(Warnings: IWarnings);
(fWarnings as IAssignable).Assign(Warnings);
end;
-function TPreferences.__TMP__UseUserDBHeadingColour(
- const ACollectionID: TCollectionID): Boolean;
-begin
- Result := (ACollectionID <> TCollectionID.__TMP__MainDBCollectionID)
- and not ACollectionID.IsNull;
-end;
-
{ TPreferencesPersist }
function TPreferencesPersist.Clone: IInterface;
var
NewPref: IPreferences; // reference to new object's IPreferences interface
+ Collection: TCollection;
begin
// Create new object
Result := TPreferences.Create;
@@ -1018,10 +1072,13 @@ function TPreferencesPersist.Clone: IInterface;
NewPref.OverviewStartState := Self.fOverviewStartState;
NewPref.ShowEmptySections := Self.fShowEmptySections;
NewPref.ShowNewSnippetsInNewTabs := Self.fShowNewSnippetsInNewTabs;
- NewPref.SetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID, Self.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID));
- NewPref.SetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID, Self.GetDBHeadingCustomColours(TCollectionID.__TMP__MainDBCollectionID));
- NewPref.SetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID, Self.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID));
- NewPref.SetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID, Self.GetDBHeadingCustomColours(TCollectionID.__TMP__UserDBCollectionID));
+ NewPref.GroupHeadingColour := Self.fGroupHeadingColour;
+ NewPref.GroupHeadingCustomColours := Self.fGroupHeadingCustomColours;
+ for Collection in TCollections.Instance do
+ NewPref.SetSnippetHeadingColour(
+ Collection.UID, Self.GetSnippetHeadingColour(Collection.UID)
+ );
+ NewPref.SnippetHeadingCustomColours := Self.fSnippetHeadingCustomColours;
NewPref.OverviewFontSize := Self.fOverviewFontSize;
NewPref.DetailFontSize := Self.fDetailFontSize;
NewPref.SourceCodeBGColour := Self.fSourceCodeBGColour;
@@ -1038,6 +1095,7 @@ function TPreferencesPersist.Clone: IInterface;
constructor TPreferencesPersist.Create;
var
Storage: ISettingsSection; // object used to access persistent storage
+ Collection: TCollection;
const
// Default margin size in millimeters
cPrintPageMarginSizeMM = 25.0;
@@ -1063,22 +1121,32 @@ constructor TPreferencesPersist.Create;
fShowNewSnippetsInNewTabs := Storage.GetBoolean(
'ShowNewSnippetsInNewTabs', False
);
- SetDBHeadingColour(
- TCollectionID.__TMP__MainDBCollectionID,
- TColor(Storage.GetInteger('MainDBHeadingColour', clMainSnippet))
- );
- SetDBHeadingColour(
- TCollectionID.__TMP__UserDBCollectionID,
- TColor(Storage.GetInteger('UserDBHeadingColour', clUserSnippet))
- );
fSourceCodeBGColour := TColor(
Storage.GetInteger('SourceCodeBGColour', clSourceBg)
);
- fDBHeadingCustomColours[False] := Storage.GetStrings(
- 'MainDBHeadingCustomColourCount', 'MainDBHeadingCustomColour%d'
+ fGroupHeadingColour := TColor(
+ Storage.GetInteger('GroupHeadingColour', clDefGroupHeading)
);
- fDBHeadingCustomColours[True] := Storage.GetStrings(
- 'UserDBHeadingCustomColourCount', 'UserDBHeadingCustomColour%d'
+ fGroupHeadingCustomColours := Storage.GetStrings(
+ 'GroupHeadingCustomColourCount', 'GroupHeadingCustomColour%d'
+ );
+
+ fSnippetHeadingColours.Clear;
+ for Collection in TCollections.Instance do
+ begin
+ fSnippetHeadingColours.AddOrSetValue(
+ Collection.UID,
+ TColor(
+ Storage.GetInteger(
+ 'SnippetHeadingColour:' + Collection.UID.ToHexString,
+ clDefSnippetHeading
+ )
+ )
+ );
+ end;
+
+ fSnippetHeadingCustomColours := Storage.GetStrings(
+ 'SnippetHeadingCustomColourCount', 'SnippetHeadingCustomColour%d'
);
fOverviewFontSize := Storage.GetInteger(
'OverviewFontSize', DefaultOverviewFontSize
@@ -1138,6 +1206,7 @@ constructor TPreferencesPersist.Create;
destructor TPreferencesPersist.Destroy;
var
Storage: ISettingsSection; // object used to access persistent storage
+ Collection: TCollection;
begin
// Wreite meta section (no sub-section name)
Storage := Settings.EmptySection(ssPreferences);
@@ -1154,27 +1223,33 @@ destructor TPreferencesPersist.Destroy;
Storage.SetInteger('OverviewStartState', Ord(fOverviewStartState));
Storage.SetBoolean('ShowEmptySections', fShowEmptySections);
Storage.SetBoolean('ShowNewSnippetsInNewTabs', fShowNewSnippetsInNewTabs);
- Storage.SetInteger(
- 'MainDBHeadingColour',
- GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID)
+ Storage.SetInteger('GroupHeadingColour', fGroupHeadingColour);
+ Storage.SetStrings(
+ 'GroupHeadingCustomColourCount',
+ 'GroupHeadingCustomColour%d',
+ fGroupHeadingCustomColours
);
- Storage.SetInteger(
- 'UserDBHeadingColour',
- GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID)
+ for Collection in TCollections.Instance do
+ begin
+ if fSnippetHeadingColours.ContainsKey(Collection.UID) then
+ Storage.SetInteger(
+ 'SnippetHeadingColour:' + Collection.UID.ToHexString,
+ fSnippetHeadingColours[Collection.UID]
+ )
+ else
+ Storage.SetInteger(
+ 'SnippetHeadingColour:' + Collection.UID.ToHexString,
+ clDefSnippetHeading
+ )
+ end;
+ Storage.SetStrings(
+ 'SnippetHeadingCustomColourCount',
+ 'SnippetHeadingCustomColour%d',
+ fSnippetHeadingCustomColours
);
Storage.SetInteger('OverviewFontSize', fOverviewFontSize);
Storage.SetInteger('DetailFontSize', fDetailFontSize);
Storage.SetInteger('SourceCodeBGColour', fSourceCodeBGColour);
- Storage.SetStrings(
- 'MainDBHeadingCustomColourCount',
- 'MainDBHeadingCustomColour%d',
- fDBHeadingCustomColours[False]
- );
- Storage.SetStrings(
- 'UserDBHeadingCustomColourCount',
- 'UserDBHeadingCustomColour%d',
- fDBHeadingCustomColours[True]
- );
Storage.SetStrings(
'SourceCodeBGCustomColourCount',
'SourceCodeBGCustomColour%d',
diff --git a/Src/URTFCategoryDoc.pas b/Src/URTFCategoryDoc.pas
index 8d2bc6bbd..73f6e6858 100644
--- a/Src/URTFCategoryDoc.pas
+++ b/Src/URTFCategoryDoc.pas
@@ -106,8 +106,8 @@ constructor TRTFCategoryDoc.Create(const UseColour: Boolean);
// Set up colour table
{TODO -cCollection: Replace following 2 statements with loop that iterates
over all collections.}
- fBuilder.ColourTable.Add(Preferences.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID));
- fBuilder.ColourTable.Add(Preferences.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID));
+ fBuilder.ColourTable.Add(Preferences.GetSnippetHeadingColour(TCollectionID.__TMP__MainDBCollectionID));
+ fBuilder.ColourTable.Add(Preferences.GetSnippetHeadingColour(TCollectionID.__TMP__UserDBCollectionID));
fBuilder.ColourTable.Add(clExternalLink);
fDescStyles := TActiveTextRTFStyleMap.Create;
InitStyles;
@@ -228,7 +228,7 @@ procedure TRTFCategoryDoc.OutputSnippetSubHeading(const Snippet: TSnippet);
fBuilder.SetFont(MainFontName);
fBuilder.SetFontSize(SubHeadingFontSize);
fBuilder.SetFontStyle([fsBold]);
- SetColour(Preferences.GetDBHeadingColour(Snippet.CollectionID));
+ SetColour(Preferences.GetSnippetHeadingColour(Snippet.CollectionID));
fBuilder.AddText(Snippet.DisplayName);
fBuilder.EndPara;
fBuilder.EndGroup;
diff --git a/Src/URTFSnippetDoc.pas b/Src/URTFSnippetDoc.pas
index 6781dd3a6..5893e8dd3 100644
--- a/Src/URTFSnippetDoc.pas
+++ b/Src/URTFSnippetDoc.pas
@@ -176,8 +176,8 @@ procedure TRTFSnippetDoc.InitialiseDoc;
{ TODO -cCollections: Replace following two statements with iteration over all
supported collections when support for multiple collections is added.
}
- fBuilder.ColourTable.Add(Preferences.GetDBHeadingColour(TCollectionID.__TMP__MainDBCollectionID));
- fBuilder.ColourTable.Add(Preferences.GetDBHeadingColour(TCollectionID.__TMP__UserDBCollectionID));
+ fBuilder.ColourTable.Add(Preferences.GetSnippetHeadingColour(TCollectionID.__TMP__MainDBCollectionID));
+ fBuilder.ColourTable.Add(Preferences.GetSnippetHeadingColour(TCollectionID.__TMP__UserDBCollectionID));
end;
procedure TRTFSnippetDoc.InitStyles;
@@ -426,7 +426,7 @@ procedure TRTFSnippetDoc.RenderHeading(const Heading: string;
fBuilder.SetFontStyle([fsBold]);
fBuilder.SetFontSize(HeadingFontSize);
if fUseColour then
- fBuilder.SetColour(Preferences.GetDBHeadingColour(ACollectionID));
+ fBuilder.SetColour(Preferences.GetSnippetHeadingColour(ACollectionID));
fBuilder.SetParaSpacing(TRTFParaSpacing.Create(0.0, ParaSpacing));
fBuilder.AddText(Heading);
fBuilder.EndPara;
diff --git a/Src/USnippetsChkListMgr.pas b/Src/USnippetsChkListMgr.pas
index b8b8b708a..bbc9a8ba5 100644
--- a/Src/USnippetsChkListMgr.pas
+++ b/Src/USnippetsChkListMgr.pas
@@ -203,7 +203,7 @@ procedure TSnippetsChkListMgr.DrawItem(Control: TWinControl; Index: Integer;
Assert(fCLB = Control, ClassName + '.DrawItem: Control <> fCLB');
Canvas := fCLB.Canvas;
if not (odSelected in State) then
- Canvas.Font.Color := Preferences.GetDBHeadingColour(
+ Canvas.Font.Color := Preferences.GetSnippetHeadingColour(
(fCLB.Items.Objects[Index] as TSnippet).CollectionID
);
Canvas.TextRect(
diff --git a/Src/USnippetsTVDraw.pas b/Src/USnippetsTVDraw.pas
index 073444c3d..cd3191ad7 100644
--- a/Src/USnippetsTVDraw.pas
+++ b/Src/USnippetsTVDraw.pas
@@ -122,9 +122,11 @@ procedure TSnippetsTVDraw.CustomDrawItem(Sender: TCustomTreeView;
if IsErrorNode(Node) then
// colour unselected error nodes differently
TV.Canvas.Font.Color := clWarningText
+ else if IsSectionHeadNode(Node) then
+ TV.Canvas.Font.Color := Preferences.GroupHeadingColour
else
TV.Canvas.Font.Color :=
- Preferences.GetDBHeadingColour(GetCollectionID(Node));
+ Preferences.GetSnippetHeadingColour(GetCollectionID(Node));
TV.Canvas.Brush.Color := TV.Color;
end;
if IsSectionHeadNode(Node) then
From 16a70cf6766fb2a87532b84b3aef73059a94ffbd Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Fri, 15 Nov 2024 12:55:00 +0000
Subject: [PATCH 090/222] Enable collection selection in Snippets Editor
Added new collections combo box to allow the collections to be chosen
for new snippets. Collection of existing snippet being edited is
displayed but can't be changed.
Snippet references page now only lists snippets in the same collection:
cross-collection references are no longer to be supported.
---
Src/FmSnippetsEditorDlg.dfm | 42 ++++++++++++----
Src/FmSnippetsEditorDlg.pas | 96 +++++++++++++++++++++++++++++++------
2 files changed, 116 insertions(+), 22 deletions(-)
diff --git a/Src/FmSnippetsEditorDlg.dfm b/Src/FmSnippetsEditorDlg.dfm
index bbb544308..92c6a994b 100644
--- a/Src/FmSnippetsEditorDlg.dfm
+++ b/Src/FmSnippetsEditorDlg.dfm
@@ -19,7 +19,7 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
Top = 0
Width = 662
Height = 504
- ActivePage = tsCompileResults
+ ActivePage = tsCode
Align = alClient
TabOrder = 0
OnChange = pcMainChange
@@ -90,6 +90,22 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
Caption = 'Displa&y Name:'
FocusControl = edDisplayName
end
+ object lblCollection: TLabel
+ Left = 3
+ Top = 10
+ Width = 50
+ Height = 13
+ Caption = 'C&ollection:'
+ FocusControl = cbCollection
+ end
+ object lblCollectionInfo: TLabel
+ Left = 411
+ Top = 10
+ Width = 76
+ Height = 13
+ Caption = 'lblCollectionInfo'
+ FocusControl = cbCollection
+ end
object edSourceCode: TMemo
Left = 4
Top = 224
@@ -103,7 +119,7 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
ParentFont = False
PopupMenu = mnuEditCtrls
ScrollBars = ssBoth
- TabOrder = 5
+ TabOrder = 6
end
object cbCategories: TComboBox
Left = 93
@@ -111,7 +127,7 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
Width = 209
Height = 21
Style = csDropDownList
- TabOrder = 4
+ TabOrder = 5
end
object cbKind: TComboBox
Left = 93
@@ -119,7 +135,7 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
Width = 209
Height = 21
Style = csDropDownList
- TabOrder = 3
+ TabOrder = 4
OnChange = cbKindChange
end
inline frmDescription: TSnippetsActiveTextEdFrame
@@ -130,7 +146,7 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
Color = clWindow
ParentBackground = False
ParentColor = False
- TabOrder = 1
+ TabOrder = 2
ExplicitLeft = 93
ExplicitTop = 67
ExplicitWidth = 462
@@ -138,12 +154,14 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
inherited edText: TMemo
Width = 462
Height = 55
+ TabOrder = 1
ExplicitWidth = 462
ExplicitHeight = 55
end
inherited tcEditMode: TTabControl
Top = 55
Width = 462
+ TabOrder = 0
ExplicitTop = 55
ExplicitWidth = 462
end
@@ -155,7 +173,7 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
Height = 25
Action = actViewDescription
Caption = 'Previe&w...'
- TabOrder = 2
+ TabOrder = 3
end
object edDisplayName: TEdit
Left = 93
@@ -163,7 +181,7 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
Width = 298
Height = 21
PopupMenu = mnuEditCtrls
- TabOrder = 0
+ TabOrder = 1
end
object chkUseHiliter: TCheckBox
Left = 3
@@ -171,7 +189,15 @@ inherited SnippetsEditorDlg: TSnippetsEditorDlg
Width = 478
Height = 17
Caption = 'Synta&x highlight this snippet as Pascal code'
- TabOrder = 6
+ TabOrder = 7
+ end
+ object cbCollection: TComboBox
+ Left = 93
+ Top = 7
+ Width = 298
+ Height = 21
+ Style = csDropDownList
+ TabOrder = 0
end
end
object tsReferences: TTabSheet
diff --git a/Src/FmSnippetsEditorDlg.pas b/Src/FmSnippetsEditorDlg.pas
index 9bd91f635..ab8c331c2 100644
--- a/Src/FmSnippetsEditorDlg.pas
+++ b/Src/FmSnippetsEditorDlg.pas
@@ -24,6 +24,7 @@ interface
ActiveText.UMain, Compilers.UGlobals,
DB.UCollections, DB.USnippet, FmGenericOKDlg,
FrBrowserBase, FrFixedHTMLDlg, FrHTMLDlg, UBaseObjects, UCategoryListAdapter,
+ UCollectionListAdapter,
UCompileMgr, UCompileResultsLBMgr, UCSSBuilder, UMemoCaretPosDisplayMgr,
UMemoHelper, USnipKindListAdapter, USnippetsChkListMgr, UUnitsChkListMgr,
FmSnippetsEditorDlg.FrActiveTextEditor;
@@ -117,6 +118,9 @@ TSnippetsEditorDlg = class(TGenericOKDlg, INoPublicConstruct)
actClearUnits: TAction;
miClearUnits: TMenuItem;
miSpacer3: TMenuItem;
+ lblCollection: TLabel;
+ cbCollection: TComboBox;
+ lblCollectionInfo: TLabel;
procedure actAddUnitExecute(Sender: TObject);
procedure actAddUnitUpdate(Sender: TObject);
procedure actCompileExecute(Sender: TObject);
@@ -157,6 +161,8 @@ TSnippetsEditorDlg = class(TGenericOKDlg, INoPublicConstruct)
strict private
fSnippet: TSnippet; // Snippet being edited: nil for new snippet
fCatList: TCategoryListAdapter; // Accesses sorted list of categories
+ fCollList:
+ TCollectionListAdapter; // Accesses sorted list of collections
fSnipKindList:
TSnipKindListAdapter; // Accesses sorted list of snippet kinds
fEditData: TSnippetEditData; // Record storing a snippet's editable data
@@ -441,7 +447,7 @@ procedure TSnippetsEditorDlg.actViewDependenciesExecute(Sender: TObject);
fDependsCLBMgr.GetCheckedSnippets(DependsList);
TDependenciesDlg.Execute(
Self,
- TSnippetID.Create(UniqueSnippetKey, TCollectionID.__TMP__UserDBCollectionID),
+ TSnippetID.Create(UniqueSnippetKey, SelectedCollectionID),
StrTrim(edDisplayName.Text),
DependsList,
[tiDependsUpon],
@@ -569,39 +575,65 @@ procedure TSnippetsEditorDlg.ArrangeForm;
begin
// tsCode
edSourceCode.Width := tsCode.ClientWidth - 8;
+ // Column 1
TCtrlArranger.AlignLefts(
[
- lblDisplayName, lblDescription, lblKind, lblCategories,
+ lblCollection, lblDisplayName, lblDescription, lblKind, lblCategories,
lblSourceCode, edSourceCode
],
3
);
+ // Column 2
+ TCtrlArranger.AlignLefts(
+ [
+ cbCollection, lblCollectionInfo, edDisplayName, frmDescription, cbKind,
+ cbCategories
+ ],
+ TCtrlArranger.RightOf(
+ [lblCollection, lblDisplayName, lblDescription, lblKind, lblCategories],
+ 12
+ )
+ );
+ // Right hand sides
TCtrlArranger.AlignRights(
[edSourceCode, lblSourceCaretPos, btnViewDescription]
);
frmDescription.Width := btnViewDescription.Left - frmDescription.Left - 8;
- TCtrlArranger.AlignVCentres(3, [lblDisplayName, edDisplayName]
+ // Row 1
+ TCtrlArranger.AlignVCentres(
+ 3, [lblCollection, cbCollection, lblCollectionInfo]
);
+ // Row 2
+ TCtrlArranger.AlignVCentres(
+ TCtrlArranger.BottomOf([lblCollection, cbCollection], 8),
+ [lblDisplayName, edDisplayName]
+ );
+ // Row 3
TCtrlArranger.AlignTops(
[lblDescription, frmDescription, btnViewDescription],
TCtrlArranger.BottomOf([lblDisplayName, edDisplayName], 8)
);
+ // Row 4
TCtrlArranger.AlignVCentres(
TCtrlArranger.BottomOf(
[lblDescription, frmDescription, btnViewDescription], 8
),
[lblKind, cbKind, lblSnippetKindHelp]
);
+ // Row 5
TCtrlArranger.AlignVCentres(
TCtrlArranger.BottomOf([lblKind, cbKind, lblSnippetKindHelp], 8),
[lblCategories, cbCategories]
);
+ // Row 6
TCtrlArranger.MoveToRightOf(cbKind, lblSnippetKindHelp, 12);
TCtrlArranger.AlignTops(
[lblSourceCode, lblSourceCaretPos],
TCtrlArranger.BottomOf([lblCategories, cbCategories], 8)
);
+ // Row 7
TCtrlArranger.MoveBelow([lblSourceCode, lblSourceCaretPos], edSourceCode, 4);
+ // Row 8
TCtrlArranger.MoveBelow(edSourceCode, chkUseHiliter, 8);
// tsReferences
@@ -766,6 +798,7 @@ procedure TSnippetsEditorDlg.FormCreate(Sender: TObject);
begin
inherited;
fCatList := TCategoryListAdapter.Create(Database.Categories);
+ fCollList := TCollectionListAdapter.Create;
fSnipKindList := TSnipKindListAdapter.Create;
fCompileMgr := TCompileMgr.Create(Self); // auto-freed
fMemoCaretPosDisplayMgr := TMemoCaretPosDisplayMgr.Create;
@@ -790,6 +823,7 @@ procedure TSnippetsEditorDlg.FormDestroy(Sender: TObject);
FreeAndNil(fXRefsCLBMgr);
FreeAndNil(fDependsCLBMgr);
FreeAndNil(fSnipKindList);
+ FreeAndNil(fCollList);
FreeAndNil(fCatList);
fMemoCaretPosDisplayMgr.Free;
end;
@@ -833,6 +867,10 @@ procedure TSnippetsEditorDlg.InitControls;
frmDescription.ActiveText := fSnippet.Description;
edDisplayName.Text := fSnippet.DisplayName;
cbCategories.ItemIndex := fCatList.IndexOf(fSnippet.Category);
+ cbCollection.ItemIndex := fCollList.IndexOfUID(fSnippet.CollectionID);
+ cbCollection.Visible := False; // can't change existing snippet collection
+ lblCollectionInfo.Caption := cbCollection.Text;
+ lblCollectionInfo.Visible := True;
frmExtra.DefaultEditMode := emAuto;
frmExtra.ActiveText := fSnippet.Extra;
cbKind.ItemIndex := fSnipKindList.IndexOf(fSnippet.Kind);
@@ -854,6 +892,13 @@ procedure TSnippetsEditorDlg.InitControls;
cbCategories.ItemIndex := fCatList.IndexOf(TCategory.DefaultID);
if cbCategories.ItemIndex = -1 then
cbCategories.ItemIndex := 0;
+ {TODO -cCollections: Replace following __TMP__ method call with call to new
+ TCollections.Default method or similar.}
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.__TMP__UserDBCollectionID);
+ if cbCollection.ItemIndex = -1 then
+ cbCollection.ItemIndex := 0;
+ cbCollection.Visible := True; // can select collection of new snippet
+ lblCollectionInfo.Visible := False;
cbKind.ItemIndex := fSnipKindList.IndexOf(skFreeform);
frmExtra.DefaultEditMode := emPlainText;
frmExtra.Clear;
@@ -931,17 +976,19 @@ procedure TSnippetsEditorDlg.PopulateControls;
fSnipKindList.ToStrings(cbKind.Items);
// Display all available categories in drop down list
fCatList.ToStrings(cbCategories.Items);
+ // Display all available collections in drop down list
+ fCollList.ToStrings(cbCollection.Items);
end;
function TSnippetsEditorDlg.SelectedCollectionID: TCollectionID;
begin
+ // If editing existing snippet ID then the collection cannot be edited
if Assigned(fSnippet) then
+ // Editing existing snippet: can't change collection
Result := fSnippet.CollectionID
else
- {TODO -cCollections: Replace the following __TMP__ method with collection ID
- selected by user from a combo box. DO NOT permit this choice when
- editing an existing snippet.}
- Result := TCollectionID.__TMP__UserDBCollectionID;
+ // Editing new snippet: chosing collection is permitted
+ Result := fCollList.Collection(cbCollection.ItemIndex).UID;
end;
procedure TSnippetsEditorDlg.SetAllCompilerResults(
@@ -999,15 +1046,17 @@ procedure TSnippetsEditorDlg.UpdateReferences;
EditSnippetID := TSnippetID.Create(UniqueSnippetKey, SelectedCollectionID);
EditSnippetKind := fSnipKindList.SnippetKind(cbKind.ItemIndex);
+
+ {TODO -cVault: We do following kind of filtering of Database.Snippets so
+ often it would be useful to have a Filter or Select method of
+ TSnippetList that can be passed a predicate to do this and return a
+ filtered snippet list.
+ }
for Snippet in Database.Snippets do
begin
- // We ignore snippet being edited and main database snippets if there is
- // a user-defined one with same key
- if (Snippet.ID <> EditSnippetID) and
- (
- (Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID) or
- not Assigned(Database.Snippets.Find(Snippet.Key, TCollectionID.__TMP__UserDBCollectionID))
- ) then
+ if Snippet.CollectionID <> SelectedCollectionID then
+ Continue;
+ if Snippet.ID <> EditSnippetID then
begin
// Decide if snippet can be added to depends list: must be correct kind
if Snippet.Kind in
@@ -1017,6 +1066,25 @@ procedure TSnippetsEditorDlg.UpdateReferences;
fXRefsCLBMgr.AddSnippet(Snippet);
end;
end;
+
+// for Snippet in Database.Snippets do
+// begin
+// // We ignore snippet being edited and main database snippets if there is
+// // a user-defined one with same key
+// if (Snippet.ID <> EditSnippetID) and
+// (
+// (Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID) or
+// not Assigned(Database.Snippets.Find(Snippet.Key, TCollectionID.__TMP__UserDBCollectionID))
+// ) then
+// begin
+// // Decide if snippet can be added to depends list: must be correct kind
+// if Snippet.Kind in
+// TSnippetValidator.ValidDependsKinds(EditSnippetKind) then
+// fDependsCLBMgr.AddSnippet(Snippet);
+// // Anything can be in XRefs list
+// fXRefsCLBMgr.AddSnippet(Snippet);
+// end;
+// end;
// Restore checks to any saved checked item that still exist in new list
fDependsCLBMgr.Restore;
fXRefsCLBMgr.Restore;
From 1c51d2143a98639e5e4e87aec9cb6231184704ce Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Fri, 15 Nov 2024 17:15:31 +0000
Subject: [PATCH 091/222] Add a permanent "default" collection
Added TCollectionID.Default method to return the ID of the default
collection: the ID is an empty GUID, i.e. 16 zero bytes. Removed
redundant Native_v4_ID that represented the former "user" database.
Added TCollection.IsDefault method to if a collection ID is the default.
Added TCollections.Default method that returns the default collection.
Modified TCollections.Delete to prevent the default collection from
being deleted.
Modified TCollection.Initialize to create the default collection if it
is not read from settings. Removed creation of "user" database
collection and moved the auto-creation of the "main" database to after
the Default collection is created.
Modified TCollectionID.__TMP__UserDBCollectionID to call
TCollectionID.Default instead of creating the now-removed "user
database" collection.
Also deleted the redundant TCollectionID.IsBuiltInID method.
---
Src/DB.UCollections.pas | 64 +++++++++++++++++++++++++++--------------
1 file changed, 42 insertions(+), 22 deletions(-)
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
index 4a575c1e6..ae10638f1 100644
--- a/Src/DB.UCollections.pas
+++ b/Src/DB.UCollections.pas
@@ -94,19 +94,20 @@ TComparer = class(TInterfacedObject,
reintroduce;
end;
const
+ {TODO -cCollections: remove DCSC_v2_ID and SWAG_v1_ID once there are no
+ built-in collections except Default}
DCSC_v2_ID: TGUID = '{9F3A4A8A-0A2B-4088-B7C9-AE1D32D3FF9A}';
SWAG_v1_ID: TGUID = '{ADA985E0-0929-4986-A3FE-B2C981D430F1}';
- Native_v4_ID: TGUID = '{E63E7160-2389-45F2-B712-EA0449D30B1F}';
constructor Create(const ABytes: TBytes); overload;
constructor Create(const AStr: string); overload;
constructor Create(const AGUID: TGUID); overload;
class function CreateFromHexString(const AHexStr: string): TCollectionID;
static;
class function CreateNull: TCollectionID; static;
+ class function Default: TCollectionID; static;
function Clone: TCollectionID;
function ToArray: TBytes;
function ToHexString: string;
- function IsBuiltInID: Boolean;
function IsNull: Boolean;
function Hash: Integer;
class function Compare(Left, Right: TCollectionID): Integer; static;
@@ -200,6 +201,8 @@ TCollection = record
read fCollectionFormatKind;
/// Checks if this record's fields are valid.
function IsValid: Boolean;
+ /// Checks if this record is the default collection.
+ function IsDefault: Boolean;
end;
TCollections = class sealed(TSingleton)
@@ -218,6 +221,7 @@ TCollections = class sealed(TSingleton)
function ContainsID(const AUID: TCollectionID): Boolean;
function ContainsName(const AName: string): Boolean;
function GetCollection(const AUID: TCollectionID): TCollection;
+ function Default: TCollection;
procedure Add(const ACollection: TCollection);
procedure Update(const ACollection: TCollection);
procedure AddOrUpdate(const ACollection: TCollection);
@@ -315,6 +319,11 @@ constructor TCollection.Create(const AUID: TCollectionID;
fCollectionFormatKind := ACollectionFormatKind;
end;
+function TCollection.IsDefault: Boolean;
+begin
+ Result := UID = TCollectionID.Default;
+end;
+
function TCollection.IsValid: Boolean;
begin
{TODO: Constructor enforces all these requirements, so #TCollection.IsValid
@@ -370,10 +379,19 @@ function TCollections.Count: Integer;
Result := fItems.Count;
end;
+function TCollections.Default: TCollection;
+begin
+ Result := GetCollection(TCollectionID.Default);
+end;
+
procedure TCollections.Delete(const AUID: TCollectionID);
+resourcestring
+ sCantDelete = 'Cannot delete the default collection';
var
Idx: Integer;
begin
+ if TCollectionID.Default = AUID then
+ raise EArgumentException.Create(sCantDelete);
Idx := IndexOfID(AUID);
if Idx >= 0 then
fItems.Delete(Idx);
@@ -433,8 +451,18 @@ procedure TCollections.Initialize;
begin
fItems := TList.Create;
TCollectionsPersist.Load(Self);
- { TODO -cCollections: following lines are for v4 compatibility
- Remove if not required in v5 }
+ // Ensure there is always at least the default collection present
+ if not ContainsID(TCollectionID.Default) then
+ Add(
+ TCollection.Create(
+ TCollectionID.Default,
+ 'Default',
+ TCollectionLocation.Create(TAppInfo.DefaultUserDataDir, '', etUTF8),
+ TCollectionFormatKind.Native_v4
+ )
+ );
+ { TODO -cCollections: following line is for v4 main database compatibility
+ Remove when reduce to only one compulsory collection }
if not ContainsID(TCollectionID.__TMP__MainDBCollectionID) then
Add(
TCollection.Create(
@@ -446,17 +474,6 @@ procedure TCollections.Initialize;
TCollectionFormatKind.DCSC_v2
)
);
- if not ContainsID(TCollectionID.__TMP__UserDBCollectionID) then
- Add(
- TCollection.Create(
- TCollectionID.__TMP__UserDBCollectionID,
- { TODO -cVault: change name - this text matches name used in CodeSnip
- v4}
- 'User Database',
- TCollectionLocation.Create(TAppInfo.DefaultUserDataDir, '', etUTF8),
- TCollectionFormatKind.Native_v4
- )
- );
end;
procedure TCollections.Save;
@@ -537,6 +554,12 @@ class function TCollectionID.CreateNull: TCollectionID;
Result := TCollectionID.Create(NullID);
end;
+class function TCollectionID.Default: TCollectionID;
+begin
+ // Default collection is an empty GUID = 16 zero bytes
+ Result := TCollectionID.Create(TGUID.Empty);
+end;
+
class operator TCollectionID.Equal(Left, Right: TCollectionID):
Boolean;
begin
@@ -548,12 +571,6 @@ function TCollectionID.Hash: Integer;
Result := BobJenkinsHash(fID[0], Length(fID), 0);
end;
-function TCollectionID.IsBuiltInID: Boolean;
-begin
- Result := (TCollectionID.Create(DCSC_v2_ID) = Self)
- or (TCollectionID.Create(SWAG_v1_ID) = Self);
-end;
-
function TCollectionID.IsNull: Boolean;
begin
Result := Length(fID) = 0;
@@ -582,7 +599,7 @@ class function TCollectionID.__TMP__MainDBCollectionID: TCollectionID;
class function TCollectionID.__TMP__UserDBCollectionID: TCollectionID;
begin
- Result := TCollectionID.Create(Native_v4_ID);
+ Result := TCollectionID.Default;
end;
{ TCollectionID.TComparer }
@@ -632,6 +649,9 @@ class procedure TCollectionsPersist.LoadCollection(const AOrdinal: Cardinal;
begin
Storage := Settings.ReadSection(ssCollection, IntToStr(AOrdinal));
UID := TCollectionID.Create(Storage.GetBytes(UIDKey));
+ if ACollections.ContainsID(UID) then
+ // Don't load a duplicate collection
+ Exit;
Name := Storage.GetString(NameKey, '');
Location := TCollectionLocation.Create(
Storage.GetString(LocationDirectoryKey, ''),
From 58970657160d7e66034a0a63aea2137d0459c5ba Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Fri, 15 Nov 2024 19:41:46 +0000
Subject: [PATCH 092/222] Update various units to work with default collection
Several units that formerly used the
TCollectionID.__TMP__UserDBCollectionID method were altered to use the
new default collection or default collection ID.
NOTE: not all __TMP__UserDBCollectionID calls were replaced: those that
were inserted for a different purpose than to stand in for the default
collection were left in place.
Also some previously commented out code was deleted.
---
Src/DB.UMain.pas | 43 +++++++++++++++----------------------
Src/FmCodeImportDlg.pas | 8 ++-----
Src/FmSWAGImportDlg.pas | 10 +++------
Src/FmSnippetsEditorDlg.pas | 26 +++-------------------
Src/FrDisplayPrefs.pas | 7 ++----
Src/UCodeImportExport.pas | 10 ++-------
Src/UCodeImportMgr.pas | 4 +---
7 files changed, 30 insertions(+), 78 deletions(-)
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index fced065ae..2ca5089c8 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -1073,7 +1073,7 @@ procedure TDatabase.Load;
}
var
Factory: IDBDataItemFactory; // object reader uses to create snippets objects
- MainCollectionIdx, UserCollectionIdx: Integer;
+ MainCollectionIdx: Integer;
Loader: IDataFormatLoader;
Collections: TCollections;
Collection: TCollection;
@@ -1104,16 +1104,12 @@ procedure TDatabase.Load;
Loader.Load(fSnippets, fCategories, Factory);
end;
- UserCollectionIdx := TCollections.Instance.IndexOfID(
- TCollectionID.__TMP__UserDBCollectionID
- );
- if UserCollectionIdx >= 0 then
- begin
- Collection := Collections[UserCollectionIdx];
- Loader := TDatabaseIOFactory.CreateDBLoader(Collection);
- if Assigned(Loader) then
- Loader.Load(fSnippets, fCategories, Factory);
- end;
+ // Load default collection
+ Collection := Collections.Default;
+ Loader := TDatabaseIOFactory.CreateDBLoader(Collection);
+ Assert(Assigned(Loader),
+ ClassName + '.Load: No loader for default collection');
+ Loader.Load(fSnippets, fCategories, Factory);
// Read categories from categories file to get any empty categories not
// created by format loaders
@@ -1144,8 +1140,8 @@ procedure TDatabase.Save;
{Saves user defined snippets and all categories to user database.
}
var
- MainProvider, UserProvider: IDBDataProvider;
- MainCollectionIdx, UserCollectionIdx: Integer;
+ MainProvider, DefaultProvider: IDBDataProvider;
+ MainCollectionIdx: Integer;
Saver: IDataFormatSaver;
Collections: TCollections;
Collection: TCollection;
@@ -1169,26 +1165,21 @@ procedure TDatabase.Save;
begin
Collection := Collections[MainCollectionIdx];
MainProvider := TCollectionDataProvider.Create(
- TCollectionID.__TMP__MainDBCollectionID, fSnippets, fCategories
+ Collection.UID, fSnippets, fCategories
);
Saver := TDatabaseIOFactory.CreateDBSaver(Collection);
if Assigned(Saver) then
Saver.Save(fSnippets, fCategories, MainProvider);
end;
- UserCollectionIdx := TCollections.Instance.IndexOfID(
- TCollectionID.__TMP__UserDBCollectionID
+ Collection := Collections.Default;
+ DefaultProvider := TCollectionDataProvider.Create(
+ Collection.UID, fSnippets, fCategories
);
- if UserCollectionIdx >= 0 then
- begin
- Collection := Collections[UserCollectionIdx];
- UserProvider := TCollectionDataProvider.Create(
- TCollectionID.__TMP__UserDBCollectionID, fSnippets, fCategories
- );
- Saver := TDatabaseIOFactory.CreateDBSaver(Collection);
- if Assigned(Saver) then
- Saver.Save(fSnippets, fCategories, UserProvider);
- end;
+ Saver := TDatabaseIOFactory.CreateDBSaver(Collection);
+ Assert(Assigned(Saver),
+ ClassName + '.Save: No saver for default collection');
+ Saver.Save(fSnippets, fCategories, DefaultProvider);
fUpdated := False;
end;
diff --git a/Src/FmCodeImportDlg.pas b/Src/FmCodeImportDlg.pas
index 1a131ce41..7b9bfa4f8 100644
--- a/Src/FmCodeImportDlg.pas
+++ b/Src/FmCodeImportDlg.pas
@@ -339,13 +339,9 @@ procedure TCodeImportDlg.InitForm;
begin
fCollList.ToStrings(cbCollection.Items);
Assert(cbCollection.Items.Count > 0, ClassName + '.InitForm: no collections');
- {TODO -cCollections: Replace following __TMP__ method calls with a calls to
- TCollections.DefaultCollection or similar.}
- Assert(TCollections.Instance.ContainsID(TCollectionID.__TMP__UserDBCollectionID),
+ Assert(TCollections.Instance.ContainsID(TCollectionID.Default),
ClassName + '.InitForm: default collection not found');
- cbCollection.ItemIndex := cbCollection.Items.IndexOf(
- TCollections.Instance.GetCollection(TCollectionID.__TMP__UserDBCollectionID).Name
- );
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
Assert(cbCollection.ItemIndex >= 0,
ClassName + '.InitForm: default collection name not in cbCollection');
diff --git a/Src/FmSWAGImportDlg.pas b/Src/FmSWAGImportDlg.pas
index 873f9bb71..e33029319 100644
--- a/Src/FmSWAGImportDlg.pas
+++ b/Src/FmSWAGImportDlg.pas
@@ -535,15 +535,11 @@ procedure TSWAGImportDlg.ConfigForm;
fCollList.ToStrings(cbCollection.Items);
Assert(cbCollection.Items.Count > 0,
ClassName + '.ConfigForm: no collections');
- {TODO -cCollections: Replace following __TMP__ method calls with a calls to
- TCollections.DefaultCollection or similar.}
- Assert(TCollections.Instance.ContainsID(TCollectionID.__TMP__UserDBCollectionID),
+ Assert(TCollections.Instance.ContainsID(TCollectionID.Default),
ClassName + '.ConfigForm: default collection not found');
- cbCollection.ItemIndex := cbCollection.Items.IndexOf(
- TCollections.Instance.GetCollection(TCollectionID.__TMP__UserDBCollectionID).Name
- );
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
Assert(cbCollection.ItemIndex >= 0,
- ClassName + '.ConfigForm: default collection name not in cbCollection');
+ ClassName + '.ConfigForm: default collection not in cbCollection');
end;
destructor TSWAGImportDlg.Destroy;
diff --git a/Src/FmSnippetsEditorDlg.pas b/Src/FmSnippetsEditorDlg.pas
index ab8c331c2..5c7079dc3 100644
--- a/Src/FmSnippetsEditorDlg.pas
+++ b/Src/FmSnippetsEditorDlg.pas
@@ -892,11 +892,9 @@ procedure TSnippetsEditorDlg.InitControls;
cbCategories.ItemIndex := fCatList.IndexOf(TCategory.DefaultID);
if cbCategories.ItemIndex = -1 then
cbCategories.ItemIndex := 0;
- {TODO -cCollections: Replace following __TMP__ method call with call to new
- TCollections.Default method or similar.}
- cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.__TMP__UserDBCollectionID);
- if cbCollection.ItemIndex = -1 then
- cbCollection.ItemIndex := 0;
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
+ Assert(cbCollection.ItemIndex >= 0,
+ ClassName + '.InitControls: No default collection in cbCollection');
cbCollection.Visible := True; // can select collection of new snippet
lblCollectionInfo.Visible := False;
cbKind.ItemIndex := fSnipKindList.IndexOf(skFreeform);
@@ -1067,24 +1065,6 @@ procedure TSnippetsEditorDlg.UpdateReferences;
end;
end;
-// for Snippet in Database.Snippets do
-// begin
-// // We ignore snippet being edited and main database snippets if there is
-// // a user-defined one with same key
-// if (Snippet.ID <> EditSnippetID) and
-// (
-// (Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID) or
-// not Assigned(Database.Snippets.Find(Snippet.Key, TCollectionID.__TMP__UserDBCollectionID))
-// ) then
-// begin
-// // Decide if snippet can be added to depends list: must be correct kind
-// if Snippet.Kind in
-// TSnippetValidator.ValidDependsKinds(EditSnippetKind) then
-// fDependsCLBMgr.AddSnippet(Snippet);
-// // Anything can be in XRefs list
-// fXRefsCLBMgr.AddSnippet(Snippet);
-// end;
-// end;
// Restore checks to any saved checked item that still exist in new list
fDependsCLBMgr.Restore;
fXRefsCLBMgr.Restore;
diff --git a/Src/FrDisplayPrefs.pas b/Src/FrDisplayPrefs.pas
index 926c561a5..41c8834d1 100644
--- a/Src/FrDisplayPrefs.pas
+++ b/Src/FrDisplayPrefs.pas
@@ -164,12 +164,9 @@ procedure TDisplayPrefsFrame.Activate(const Prefs: IPreferences;
var
Collection: TCollection;
begin
- {TODO -cCollections: Replace __TMP__ method below with call to a new
- TCollections.Default method or similar.}
- cbCollection.ItemIndex := TCollections.Instance.IndexOfID(TCollectionID.__TMP__UserDBCollectionID);
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
Assert(cbCollection.ItemIndex >= 0,
- ClassName + '.Activate: no default collection found');
-
+ ClassName + '.Activate: no default collection found in cbCollection');
SelectOverviewTreeState(Prefs.OverviewStartState);
chkHideEmptySections.OnClick := nil; // prevent OnClick when Checked set
chkHideEmptySections.Checked := not Prefs.ShowEmptySections;
diff --git a/Src/UCodeImportExport.pas b/Src/UCodeImportExport.pas
index e422bf338..c90d10d7d 100644
--- a/Src/UCodeImportExport.pas
+++ b/Src/UCodeImportExport.pas
@@ -295,18 +295,12 @@ procedure TCodeExporter.WriteSnippet(const ParentNode: IXMLNode;
begin
// Create snippet node with attribute that specifies snippet key
SnippetNode := fXMLDoc.CreateElement(ParentNode, cSnippetNode);
- (Database as IDatabaseEdit).GetUniqueSnippetKey(TCollectionID.__TMP__UserDBCollectionID);
// Export snippet under a new unique key within the default collection
// we use default collection because code importer assumes snippet id from
// that collection. We create new unique key because more than one snippet
// could be exported that have the same key but are in different collections.
SnippetNode.Attributes[cSnippetNameAttr] :=
- (Database as IDatabaseEdit).GetUniqueSnippetKey(
- {TODO -cVault: Replace following __TMP__ method call with a call to get
- default collection, which should be common to databases used by
- every user}
- TCollectionID.__TMP__UserDBCollectionID
- );
+ (Database as IDatabaseEdit).GetUniqueSnippetKey(TCollectionID.Default);
// Add nodes for properties: (ignore category and xrefs)
// description node is written even if empty (which it shouldn't be)
fXMLDoc.CreateElement(
@@ -412,7 +406,7 @@ procedure TCodeImporter.Execute(const Data: TBytes);
// Note: in building snippet ID list we assume each snippet is from the
// default collection. It may not be, but there is no way of telling
// from XML.
- Depends.Add(TSnippetID.Create(SnippetName, TCollectionID.__TMP__UserDBCollectionID));
+ Depends.Add(TSnippetID.Create(SnippetName, TCollectionID.Default));
end;
// Reads description node and converts to active text.
diff --git a/Src/UCodeImportMgr.pas b/Src/UCodeImportMgr.pas
index 8a91a2560..1a5ff89b6 100644
--- a/Src/UCodeImportMgr.pas
+++ b/Src/UCodeImportMgr.pas
@@ -168,9 +168,7 @@ constructor TCodeImportMgr.Create;
// set default event handler
fRequestCollectionCallback := function: TCollectionID
begin
- {TODO -cCollections: Require a TCollections.DefaultCollection method or
- similar to replace the following __TMP__ method call.}
- Result := TCollectionID.__TMP__UserDBCollectionID;
+ Result := TCollectionID.Default;
end;
end;
From 9fbae1e78baa1f19cc21ec8167bb1f102c4d02c4 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Fri, 15 Nov 2024 20:22:54 +0000
Subject: [PATCH 093/222] Update RTF colour table used in TRTFSnippetDoc
TRTFSnippetDoc changed to add to RTF colour table all colours used to
render snippet display names from every collection.
---
Src/URTFSnippetDoc.pas | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/Src/URTFSnippetDoc.pas b/Src/URTFSnippetDoc.pas
index 5893e8dd3..3c560586d 100644
--- a/Src/URTFSnippetDoc.pas
+++ b/Src/URTFSnippetDoc.pas
@@ -163,6 +163,8 @@ function TRTFSnippetDoc.FinaliseDoc: TEncodedData;
end;
procedure TRTFSnippetDoc.InitialiseDoc;
+var
+ Collection: TCollection;
begin
// Create object used to build main rich text document
fBuilder := TRTFBuilder.Create(0); // Use default code page
@@ -173,11 +175,10 @@ procedure TRTFSnippetDoc.InitialiseDoc;
fBuilder.ColourTable.Add(clWarningText);
fBuilder.ColourTable.Add(clVarText);
fBuilder.ColourTable.Add(clExternalLink);
- { TODO -cCollections: Replace following two statements with iteration over all
- supported collections when support for multiple collections is added.
- }
- fBuilder.ColourTable.Add(Preferences.GetSnippetHeadingColour(TCollectionID.__TMP__MainDBCollectionID));
- fBuilder.ColourTable.Add(Preferences.GetSnippetHeadingColour(TCollectionID.__TMP__UserDBCollectionID));
+ for Collection in TCollections.Instance do
+ fBuilder.ColourTable.Add(
+ Preferences.GetSnippetHeadingColour(Collection.UID)
+ );
end;
procedure TRTFSnippetDoc.InitStyles;
From acd5c87ef9c459232e512cbc1ef6d1e38a179a3a Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Fri, 15 Nov 2024 20:25:45 +0000
Subject: [PATCH 094/222] Update RTF colour table used in TRTFCategoryDoc
TRTFCategoryDoc changed to add to RTF colour table all colours used to
render snippet display names from every collection and the colour used
for category headings.
---
Src/URTFCategoryDoc.pas | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/Src/URTFCategoryDoc.pas b/Src/URTFCategoryDoc.pas
index 73f6e6858..0d4009200 100644
--- a/Src/URTFCategoryDoc.pas
+++ b/Src/URTFCategoryDoc.pas
@@ -96,6 +96,8 @@ implementation
{ TRTFCategoryDoc }
constructor TRTFCategoryDoc.Create(const UseColour: Boolean);
+var
+ Collection: TCollection;
begin
inherited Create;
fUseColour := UseColour;
@@ -104,10 +106,11 @@ constructor TRTFCategoryDoc.Create(const UseColour: Boolean);
fBuilder.FontTable.Add(MainFontName, rgfSwiss, 0);
fBuilder.FontTable.Add(MonoFontName, rgfModern, 0);
// Set up colour table
- {TODO -cCollection: Replace following 2 statements with loop that iterates
- over all collections.}
- fBuilder.ColourTable.Add(Preferences.GetSnippetHeadingColour(TCollectionID.__TMP__MainDBCollectionID));
- fBuilder.ColourTable.Add(Preferences.GetSnippetHeadingColour(TCollectionID.__TMP__UserDBCollectionID));
+ for Collection in TCollections.Instance do
+ fBuilder.ColourTable.Add(
+ Preferences.GetSnippetHeadingColour(Collection.UID)
+ );
+ fBuilder.ColourTable.Add(Preferences.GroupHeadingColour);
fBuilder.ColourTable.Add(clExternalLink);
fDescStyles := TActiveTextRTFStyleMap.Create;
InitStyles;
@@ -216,6 +219,7 @@ procedure TRTFCategoryDoc.OutputCategoryHeading(const Category: TCategory);
fBuilder.SetFont(MainFontName);
fBuilder.SetFontSize(HeadingFontSize);
fBuilder.SetFontStyle([fsBold]);
+ SetColour(Preferences.GroupHeadingColour);
fBuilder.AddText(Category.Description);
fBuilder.EndPara;
fBuilder.EndGroup;
From d28b49b743fda158c9c610f320afe32a82123489 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 16 Nov 2024 10:30:27 +0000
Subject: [PATCH 095/222] Split DB.UMetaData unit into two units
Removed all "main" database specific code from DB.UMetaData and placed
it in a new DBIO.MetaData.DCSC unit that was added to the project.
DB.UMetaData now just declares the IDBMetaData interface to be supported
by all objects that encapsulate a collection's meta along with two
records referenced by the interface.
DBIO.MetaData.DCSC contains the implementation of IDBMetaData for
various versions of the old "main" database, now referred to as the
DelphiDabbler Code Snippets Collection (DCSC).
Added a reference to DBIO.MetaData.DCSC to all units that previously
accessed its code via DB.MetaData.
---
Src/CodeSnip.dpr | 3 +-
Src/CodeSnip.dproj | 1 +
Src/DB.UMetaData.pas | 866 ++-----------------------------------
Src/DBIO.MetaData.DCSC.pas | 830 +++++++++++++++++++++++++++++++++++
Src/FmAboutDlg.pas | 1 +
Src/UDBUpdateMgr.pas | 1 +
Src/USaveUnitMgr.pas | 1 +
Src/USnippetDoc.pas | 1 +
Src/USnippetSourceGen.pas | 1 +
9 files changed, 865 insertions(+), 840 deletions(-)
create mode 100644 Src/DBIO.MetaData.DCSC.pas
diff --git a/Src/CodeSnip.dpr b/Src/CodeSnip.dpr
index e345c810e..73f6da5c6 100644
--- a/Src/CodeSnip.dpr
+++ b/Src/CodeSnip.dpr
@@ -377,7 +377,8 @@ uses
DB.UCollections in 'DB.UCollections.pas',
UTabSeparatedFileIO in 'UTabSeparatedFileIO.pas',
DBIO.UCategoryIO in 'DBIO.UCategoryIO.pas',
- UCollectionListAdapter in 'UCollectionListAdapter.pas';
+ UCollectionListAdapter in 'UCollectionListAdapter.pas',
+ DBIO.MetaData.DCSC in 'DBIO.MetaData.DCSC.pas';
// Include resources
{$Resource ExternalObj.tlb} // Type library file
diff --git a/Src/CodeSnip.dproj b/Src/CodeSnip.dproj
index 3524fb160..d5132b5a5 100644
--- a/Src/CodeSnip.dproj
+++ b/Src/CodeSnip.dproj
@@ -584,6 +584,7 @@
+ Base
diff --git a/Src/DB.UMetaData.pas b/Src/DB.UMetaData.pas
index 1c26520f3..8e4b69cf3 100644
--- a/Src/DB.UMetaData.pas
+++ b/Src/DB.UMetaData.pas
@@ -5,104 +5,26 @@
*
* Copyright (C) 2020-2021, Peter Johnson (gravatar.com/delphidabbler).
*
- * Provides meta data for the current main database and for any database
- * updates.
+ * Declares interface and defines records required to support collection
+ * metadata.
}
unit DB.UMetaData;
-{
- Notes About Database Versions And Meta Files.
- =============================================
-
- Versions
- --------
-
- v1 of the Code Snippets Database was not considered to have a version number
- until the arrival of v2. Therefore v1 did not have any means of identifying
- its version number. Although the database format changed slightly over time
- there is not enough historical information to identify different minor
- releases, so all are considered to be v1.0.0.0
-
- Database v2 has a VERSION file that specifies the version number as a dotted
- quad, of the form v2.0.0.0.
-
- Note that semantic versioning is now being used so any database with major
- version 2 will be backwards compatible with earlier v2 minor release.
-
- If a breaking change is introduced the major version will be bumped to v3 and
- so on.
-
- Meta Files
- ----------
-
- Database v1 had only two meta files:
- + contrib.txt - lists of contributors to the database, one per line
- + testers.txt - lists of database testers, one per line
- If those two files are present the database is assumed to be v1
-
- Database v2 has the following meta files:
- + VERSION - version number (v2.x.x.x)
- + CONTRIBUTORS - lists of contributors to the database, one per line
- + TESTERS - lists of database testers, one per line
- + LICENSE - full text of the license that applies to the snippets
- + LICENSE-INFO - furter information about the license
-
- For database v1 the license text, license information are hard-wired in the
- absence of meta files. As noted above the version number is deduced.
-
- File encoding
- -------------
-
- All meta files are plain text.
-
- Early v1 database meta files were encoded in the system default encoding.
- Later v1 databases encoded meta files in UTF-8. To distinguish between UTF-8
- and default encoded files the UTF-8 files use the UTF-8 preamble (BOM).
-
- v2 database meta files are all encoded in UTF-8 with preamble (BOM).
-
- Future major versions
- ---------------------
-
- Future major database releases MUST include backwards compatibility with
- earlier versions of CodeSnip in as much as those versions must be able to
- easily detect and reject the format.
-
- To achieve this new major releases MUST include a VERSION file encoded in
- UTF-8 with BOM. Existing code can detect and will reject any unsupported
- version.
-
- CodeSnip support
- ----------------
-
- CodeSnip versions earlier than v4.16 are only ever delivered v1 database files
- via their built in web update code. There is no way for these versions to
- access v2 databases.
-
- CodeSnip from v4.16 get their main snippets database from files downloaded
- manually. All such databases are v2. CodeSnip v4.16 also supports v1 format
- because such a database may be resident on the user's computer at install
- time.
-}
-
interface
uses
- // VCL
- Classes,
// Project
- UExceptions,
UIStringList,
UVersionInfo;
type
- /// Record providing information about the main database license.
+ /// Record providing information about a collection's license.
///
TDBLicenseInfo = record
strict private
@@ -112,6 +34,7 @@ TDBLicenseInfo = record
fText: string;
public
/// Record constructor: sets all fields of record.
+ /// Any or all parameters may be the empty string
constructor Create(const AName, ASPDX, AURL, AText: string);
/// Name of license.
property Name: string read fName;
@@ -132,7 +55,7 @@ TDBLicenseInfo = record
function NameWithURL: string;
end;
- /// Record providing informaton about the main database copyright.
+ /// Record providing informaton about a collection's copyright.
///
TDBCopyrightInfo = record
strict private
@@ -141,6 +64,7 @@ TDBCopyrightInfo = record
fHolderURL: string;
public
/// Record constructor: sets all fields of record.
+ /// Any or all parameters may be the empty string
constructor Create(const ADate, AHolder, AHolderURL: string);
/// Copyright date.
/// May be a single year or a range: e.g. 2020 or 2012-2016.
@@ -153,785 +77,49 @@ TDBCopyrightInfo = record
property HolderURL: string read fHolderURL;
end;
- /// Interface supported by classes providing database meta data.
- ///
+ /// Interface that provides information about any meta data
+ /// supported by a collection.
IDBMetaData = interface(IInterface)
- /// Returns database version number.
- /// A null version number is returned if the meta data does not
- /// come from a recognised database.
+ /// Returns the collection's version number.
+ /// A null version number is returned if the collection does not
+ /// include Version in its capabilities.
function GetVersion: TVersionNumber;
- /// Returns database license information.
- /// Return value is meaningless if the meta data does not come
- /// from a supported database.
+ /// Returns the collection's license information.
+ /// Return value is meaningless if the collection does not include
+ /// License in its capabilities.
function GetLicenseInfo: TDBLicenseInfo;
- /// Returns database copyright informatiom.
- /// Return value is meaningless if the meta data does not come
- /// from a supported database.
+ /// Returns the collection's copyright informatiom.
+ /// Return value is meaningless if the collection does not include
+ /// Copyright in its capabilities.
function GetCopyrightInfo: TDBCopyrightInfo;
- /// Returns list of contributors to database.
- /// Return value is meaningless if the meta data does not come
- /// from a supported database.
+ /// Returns a list of contributors to the collection.
+ /// Return value is meaningless if the collection does not include
+ /// Contributors in its capabilities.
function GetContributors: IStringList;
- /// Returns list of testers of database.
- /// Return value is meaningless if the meta data does not come
- /// from a supported database.
+ /// Returns a list of testers of the collection.
+ /// Return value is meaningless if the collection does not include
+ /// Testers in its capabilities.
function GetTesters: IStringList;
/// Checks if meta data is recognised as belonging to a valid
- /// database, whether supported or not.
+ /// collection, whether supported or not.
function IsRecognised: Boolean;
/// Checks if meta data is recognised as belonging to a supported
- /// database version.
+ /// collection version.
function IsSupportedVersion: Boolean;
/// Checks if meta data is corrupt.
/// Should only be called if meta data belongs to a supported
- /// database. An exception should be raised if called on unsupported
+ /// collection. An exception should be raised if called on unsupported
/// versions.
function IsCorrupt: Boolean;
- /// Refreshes the meta information by re-reading from database
+ /// Refreshes the meta information by re-reading from collection
/// meta files.
procedure Refresh;
end;
- /// Factory that creates instances of objects that provide
- /// information about the main database and database updates.
- TMainDBMetaDataFactory = record
- public
- /// Returns instance of class that provides meta data for the
- /// main database.
- class function MainDBMetaDataInstance: IDBMetaData; static;
- /// Returns instance of class that provides meta data for the
- /// database update stored in the given folder.
- class function UpdateMetaDataInstance(const UpdateDir: string):
- IDBMetaData; static;
- end;
-
- /// Class of exception raised by meta data classes.
- EDBMetaData = class(ECodeSnip);
-
implementation
-uses
- // Project
- SysUtils,
- IOUtils,
- Types,
- // VCL
- UAppInfo,
- UEncodings,
- UIOUtils,
- UResourceUtils,
- UStructs,
- UStrUtils;
-
-
-const
- DBValidVersions: TRange = (Min: 1; Max: 2);
-
-type
-
- /// Provides names of meta data files supported by various database
- /// versions.
- TDBMetaFileNames = record
- public
- const
- ContributorsV1 = 'contrib.txt';
- TestersV1 = 'testers.txt';
- VersionV2AndLater = 'VERSION';
- LicenseV2 = 'LICENSE';
- LicenseInfoV2 = 'LICENSE-INFO';
- ContributorsV2 = 'CONTRIBUTORS';
- TestersV2 = 'TESTERS';
- end;
-
- /// Abstract base class for classes that access or emulate database
- /// meta data files.
- TDBMetaFiles = class abstract(TObject)
- strict private
- var
- /// Directory of database for which meta data files are being
- /// accessed.
- fDBDir: string;
- /// Returns encoding used by given meta file.
- function GetFileEncoding(const FileName: TFileName): TEncoding;
- strict protected
- /// Makes a fully specified path to a given database file.
- ///
- /// FileName must contain no path information.
- function MakePath(const FileName: string): string;
- /// Checks if a given file exists in database directory.
- function DBFileExists(const FileName: string): Boolean;
- /// Reads all lines from given file and returns them as an array.
- ///
- /// FileName must contain no path information.
- function ReadFileLines(const FileName: TFileName): TStringDynArray;
- /// Reads all text from given file and returns it.
- /// FileName must contain no path information.
- function ReadFileText(const FileName: TFileName): string;
- public
- /// Constructs object that accesses meta data database files in
- /// given directory.
- constructor Create(const DBDir: string);
- /// Returns text of the version file, or surrogate value.
- ///
- function Version: string; virtual; abstract;
- /// Returns content license text file or surrogate value.
- ///
- function LicenseText: string; virtual; abstract;
- /// Returns lines of license information file or surrogate value.
- ///
- function LicenseInfo: TStringDynArray; virtual; abstract;
- /// Returns lines of contributors file or surrogate value.
- ///
- function Contributors: TStringDynArray; virtual; abstract;
- /// Returns lines of testers file or surrogate value.
- function Testers: TStringDynArray; virtual; abstract;
- /// Checks if all the expected meta files are present. Returns
- /// True if so or False if not.
- /// ENotSupportedException must be raised if called on an
- /// unsupported database version.
- function AreAllFilesPresent: Boolean; virtual; abstract;
- end;
-
- /// Class that accesses content of version 1 main database meta data
- /// files.
- /// Not all meta files are present in version main databases so
- /// invariant placeholder content is provided to substitute for missing
- /// files.
- TV1DBMetaFiles = class sealed(TDBMetaFiles)
- strict private
- const
- cContributorsFile = TDBMetaFileNames.ContributorsV1;
- cTestersFile = TDBMetaFileNames.TestersV1;
- public
- /// Returns an surrogate, invariant value of 1 for the version
- /// number.
- /// No version file exists for this database version. The value
- /// returned is deduced using documentation from the current code snippets
- /// database project.
- function Version: string; override;
- /// Returns an surrogate, invariant value for the license text.
- ///
- /// No license text file exists for this database version. The
- /// value returned is based on documentation of the database.
- function LicenseText: string; override;
- /// Returns an surrogate, invariant value for the lines of license
- /// information.
- function LicenseInfo: TStringDynArray; override;
- /// Returns the lines of the contributors file.
- function Contributors: TStringDynArray; override;
- /// Returns the lines of the testers file.
- function Testers: TStringDynArray; override;
- /// Checks if all the expected meta files are present. Returns
- /// True if so or False if not.
- function AreAllFilesPresent: Boolean; override;
- end;
-
- /// Class that accesses content of supported version 2 main database
- /// meta files.
- TV2DBMetaFiles = class sealed(TDBMetaFiles)
- strict private
- const
- cVersionFile = TDBMetaFileNames.VersionV2AndLater;
- cLicenseFile = TDBMetaFileNames.LicenseV2;
- cLicenseInfoFile = TDBMetaFileNames.LicenseInfoV2;
- cContributorsFile = TDBMetaFileNames.ContributorsV2;
- cTestersFile = TDBMetaFileNames.TestersV2;
- public
- /// Returns the contents of the version file.
- function Version: string; override;
- /// Returns the contents of the license text file.
- function LicenseText: string; override;
- /// Returns the lines of the license info file.
- function LicenseInfo: TStringDynArray; override;
- /// Returns the lines of the contributors file.
- function Contributors: TStringDynArray; override;
- /// Returns the lines of the testers file.
- function Testers: TStringDynArray; override;
- /// Checks if all the expected meta files are present. Returns
- /// True if so or False if not.
- function AreAllFilesPresent: Boolean; override;
- end;
-
- /// Class that represents later versions of database meta file
- /// formats.
- /// These formats have a valid version file but the version is not
- /// supported and nothing is known about any other meta data files.
- TLaterDBMetaFiles = class sealed(TDBMetaFiles)
- strict private
- const
- cVersionFile = TDBMetaFileNames.VersionV2AndLater;
- public
- /// Returns the contents of the version file.
- function Version: string; override;
- /// Returns the empty string.
- /// The file format is unknown, so the license text file cannot be
- /// read and there is no information to deduce the value.
- function LicenseText: string; override;
- /// Returns an empty string array.
- /// The file format is unknown, so the license information file
- /// cannot be read and there is no information to deduce the value.
- ///
- function LicenseInfo: TStringDynArray; override;
- /// Returns an empty string array.
- /// The file format is unknown, so the contributors file cannot be
- /// read and there is no information to deduce the value.
- function Contributors: TStringDynArray; override;
- /// Returns an empty string array.
- /// The file format is unknown, so the testers file cannot be read
- /// and there is no information to deduce the value.
- function Testers: TStringDynArray; override;
- /// Checks if all the expected meta files are present only if
- /// the meta files come from a supported database format.
- /// ENotSupportedException always raised since there is no way
- /// of knowing what files should be present in an unsupported database
- /// format.
- function AreAllFilesPresent: Boolean; override;
- end;
-
- /// Class that is present to represent unknown database meta file
- /// formats. Also used when database is not present.
- /// Accesses no files and returns null results for all methods
- /// except IsVersionSupported.
- TUnknownOrMissingMetaFiles = class sealed(TDBMetaFiles)
- public
- /// Returns the empty string.
- /// The file format is unknown, so the version file cannot be read
- /// and there is no information to deduce the value.
- function Version: string; override;
- /// Returns the empty string.
- /// The file format is unknown, so the license text file cannot be
- /// read and there is no information to deduce the value.
- function LicenseText: string; override;
- /// Returns an empty string array.
- /// The file format is unknown, so the license information file
- /// cannot be read and there is no information to deduce the value.
- ///
- function LicenseInfo: TStringDynArray; override;
- /// Returns an empty string array.
- /// The file format is unknown, so the contributors file cannot be
- /// read and there is no information to deduce the value.
- function Contributors: TStringDynArray; override;
- /// Returns an empty string array.
- /// The file format is unknown, so the testers file cannot be read
- /// and there is no information to deduce the value.
- function Testers: TStringDynArray; override;
- /// Checks if all the expected meta files are present only if
- /// the meta files come from a supported database format.
- /// ENotSupportedException always raised since there is no way
- /// of knowing what files should be present in an unrecognised database
- /// format.
- function AreAllFilesPresent: Boolean; override;
- end;
-
- /// Factory to create the correct instance of database meta file
- /// classes that can read the version of a database in a given folder.
- ///
- TDBMetaFilesFactory = record
- public
- class function GetInstance(const DBDir: string): TDBMetaFiles;
- static;
- end;
-
- /// Abstract base class for classes that provide main database meta
- /// data.
- TAbstractMainDBMetaData = class abstract(TInterfacedObject)
- strict private
- var
- fMetaFiles: TDBMetaFiles;
- fIsVersionLoaded: Boolean;
- fVersion: TVersionNumber;
- fIsLicenseAndCopyrightInfoLoaded: Boolean;
- fLicenseInfo: TDBLicenseInfo;
- fCopyrightInfo: TDBCopyrightInfo;
- fContributors: IStringList;
- fTesters: IStringList;
-
- procedure LoadLicenseAndCopyrightInfo;
-
- strict protected
- function GetDBDir: string; virtual; abstract;
- public
- constructor Create;
- procedure AfterConstruction; override;
- destructor Destroy; override;
- /// Returns database version number.
- ///
- /// A null version number is returned if the meta data does not come
- /// from a recognised database.
- /// Method of IDBMetaData.
- ///
- function GetVersion: TVersionNumber;
- /// Returns database license information.
- ///
- /// Return value is meaningless if the meta data does not come
- /// from a supported database.
- /// Method of IDBMetaData.
- ///
- function GetLicenseInfo: TDBLicenseInfo;
- /// Returns database copyright informatiom.
- ///
- /// Return value is meaningless if the meta data does not come
- /// from a supported database.
- /// Method of IDBMetaData.
- ///
- function GetCopyrightInfo: TDBCopyrightInfo;
- /// Returns list of contributors to database.
- ///
- /// Return value is meaningless if the meta data does not come
- /// from a supported database.
- /// Method of IDBMetaData.
- ///
- function GetContributors: IStringList;
- /// Returns list of testers of database.
- ///
- /// Return value is meaningless if the meta data does not come
- /// from a supported database.
- /// Method of IDBMetaData.
- ///
- function GetTesters: IStringList;
- /// Checks if meta data is recognised as belonging to a valid
- /// database, whether supported or not.
- /// Method of IDBMetaData.
- function IsRecognised: Boolean;
- /// Checks if meta data is recognised as belonging to a supported
- /// database version.
- /// Method of IDBMetaData.
- function IsSupportedVersion: Boolean;
- /// Checks if meta data is corrupt.
- ///
- /// Should only be called if meta data belongs to a supported
- /// database.
- /// Method of IDBMetaData.
- ///
- /// ENotSupportedException raised if called on an unsupported
- /// database.
- function IsCorrupt: Boolean;
- /// Refreshes the meta information by re-reading from database
- /// meta files.
- /// Method of IDBMetaData.
- procedure Refresh;
- end;
-
- /// Class that provides meta data for the main database.
- TMainDBMetaData = class sealed(TAbstractMainDBMetaData, IDBMetaData)
- strict protected
- function GetDBDir: string; override;
- end;
-
- /// Class that provides meta data for update database directories.
- ///
- TUpdateDBMetaData = class sealed(TAbstractMainDBMetaData, IDBMetaData)
- strict private
- var
- fUpdateDir: string;
- strict protected
- function GetDBDir: string; override;
- public
- constructor Create(const UpdateDir: string);
- end;
-
-{ TMainDBMetaDataFactory }
-
-class function TMainDBMetaDataFactory.MainDBMetaDataInstance:
- IDBMetaData;
-begin
- Result := TMainDBMetaData.Create;
-end;
-
-class function TMainDBMetaDataFactory.UpdateMetaDataInstance(
- const UpdateDir: string): IDBMetaData;
-begin
- Result := TUpdateDBMetaData.Create(UpdateDir);
-end;
-
-{ TAbstractMainDBMetaData }
-
-procedure TAbstractMainDBMetaData.AfterConstruction;
-begin
- inherited;
- Refresh;
-end;
-
-constructor TAbstractMainDBMetaData.Create;
-begin
- inherited;
-// Refresh;
-end;
-
-destructor TAbstractMainDBMetaData.Destroy;
-begin
- fMetaFiles.Free;
- inherited;
-end;
-
-function TAbstractMainDBMetaData.GetContributors: IStringList;
-begin
- if not Assigned(fContributors) then
- fContributors := TIStringList.Create(fMetaFiles.Contributors);
- Result := fContributors;
-end;
-
-function TAbstractMainDBMetaData.GetCopyrightInfo: TDBCopyrightInfo;
-begin
- if not fIsLicenseAndCopyrightInfoLoaded then
- LoadLicenseAndCopyrightInfo;
- Result := fCopyrightInfo;
-end;
-
-function TAbstractMainDBMetaData.GetLicenseInfo: TDBLicenseInfo;
-begin
- if not fIsLicenseAndCopyrightInfoLoaded then
- LoadLicenseAndCopyrightInfo;
- Result := fLicenseInfo;
-end;
-
-function TAbstractMainDBMetaData.GetTesters: IStringList;
-begin
- if not Assigned(fTesters) then
- fTesters := TIStringList.Create(fMetaFiles.Testers);
- Result := fTesters;
-end;
-
-function TAbstractMainDBMetaData.GetVersion: TVersionNumber;
-begin
- if not fIsVersionLoaded then
- begin
- if not TVersionNumber.TryStrToVersionNumber(
- StrTrim(fMetaFiles.Version), fVersion
- ) then
- fVersion := TVersionNumber.Nul;
- end;
- fIsVersionLoaded := True;
- Result := fVersion;
-end;
-
-function TAbstractMainDBMetaData.IsCorrupt: Boolean;
-resourcestring
- sNotSupportedError = 'Can''t call IDBMetaData.IsCorrupt for an unsupported '
- + 'database version';
-begin
- if not IsSupportedVersion then
- raise ENotSupportedException.Create(sNotSupportedError);
- Result := not fMetaFiles.AreAllFilesPresent;
-end;
-
-function TAbstractMainDBMetaData.IsRecognised: Boolean;
-begin
- Result := not GetVersion.IsNull;
-end;
-
-function TAbstractMainDBMetaData.IsSupportedVersion: Boolean;
-var
- ThisVersion: TVersionNumber;
-begin
- ThisVersion := GetVersion;
- Result := DBValidVersions.Contains(ThisVersion.V1);
-end;
-
-procedure TAbstractMainDBMetaData.LoadLicenseAndCopyrightInfo;
-var
- SL: TStringList;
-begin
- if fIsLicenseAndCopyrightInfoLoaded then
- Exit;
- SL := TStringList.Create;
- try
- StrArrayToStrList(fMetaFiles.LicenseInfo, SL);
- fLicenseInfo := TDBLicenseInfo.Create(
- SL.Values['LicenseName'],
- SL.Values['LicenseSPDX'],
- SL.Values['LicenseURL'],
- fMetaFiles.LicenseText
- );
- fCopyrightInfo := TDBCopyrightInfo.Create(
- SL.Values['CopyrightDate'],
- SL.Values['CopyrightHolder'],
- SL.Values['CopyrightHolderURL']
- );
- finally
- SL.Free;
- end;
- fIsLicenseAndCopyrightInfoLoaded := True;
-end;
-
-procedure TAbstractMainDBMetaData.Refresh;
-begin
- FreeAndNil(fMetaFiles);
- fMetaFiles := TDBMetaFilesFactory.GetInstance(GetDBDir);
- fIsVersionLoaded := False;
- fIsLicenseAndCopyrightInfoLoaded := False;
- fContributors := nil;
- fTesters := nil;
-end;
-
-{ TMainDBMetaData }
-
-function TMainDBMetaData.GetDBDir: string;
-begin
- Result := TAppInfo.AppDataDir;
-end;
-
-{ TUpdateDBMetaData }
-
-constructor TUpdateDBMetaData.Create(const UpdateDir: string);
-begin
- inherited Create;
- fUpdateDir := ExcludeTrailingPathDelimiter(UpdateDir);
-end;
-
-function TUpdateDBMetaData.GetDBDir: string;
-begin
- Result := fUpdateDir;
-end;
-
-{ TDBMetaFiles }
-
-constructor TDBMetaFiles.Create(const DBDir: string);
-begin
- inherited Create;
- fDBDir := DBDir;
-end;
-
-function TDBMetaFiles.DBFileExists(const FileName: string): Boolean;
-begin
- Result := TFile.Exists(MakePath(FileName), False);
-end;
-
-function TDBMetaFiles.GetFileEncoding(const FileName: TFileName): TEncoding;
-begin
- // Old v1 database meta files may be in the system default encodings, v1 and
- // all v2 and later use UTF-8 with BOM.
- if TFileIO.CheckBOM(MakePath(FileName), TEncoding.UTF8) then
- Result := TEncoding.UTF8
- else
- Result := TEncoding.Default;
-end;
-
-function TDBMetaFiles.MakePath(const FileName: string): string;
-begin
- Assert(not StrContainsStr(PathDelim, FileName),
- ClassName + '.MakePath: FileName must be a base file name.');
- Result := IncludeTrailingPathDelimiter(fDBDir) + FileName;
-end;
-
-function TDBMetaFiles.ReadFileLines(const FileName: TFileName): TStringDynArray;
-var
- Encoding: TEncoding;
-begin
- if not DBFileExists(FileName) then
- begin
- SetLength(Result, 0);
- Exit;
- end;
- Encoding := GetFileEncoding(FileName);
- try
- Result := TFileIO.ReadAllLines(MakePath(FileName), Encoding, True);
- finally
- TEncodingHelper.FreeEncoding(Encoding);
- end;
-end;
-
-function TDBMetaFiles.ReadFileText(const FileName: TFileName): string;
-begin
- if not DBFileExists(FileName) then
- Exit('');
- Result := TFileIO.ReadAllText(
- MakePath(FileName), GetFileEncoding(FileName), True
- );
-end;
-
-{ TV1DBMetaFiles }
-
-function TV1DBMetaFiles.AreAllFilesPresent: Boolean;
-begin
- Result := DBFileExists(cContributorsFile) and DBFileExists(cTestersFile);
-end;
-
-function TV1DBMetaFiles.Contributors: TStringDynArray;
-begin
- Result := ReadFileLines(cContributorsFile)
-end;
-
-function TV1DBMetaFiles.LicenseInfo: TStringDynArray;
-begin
- Result := TStringDynArray.Create(
- 'LicenseName=MIT License',
- 'LicenseSPDX=MIT',
- 'LicenseURL=https://opensource.org/licenses/MIT',
- 'CopyrightDate=2005-2016',
- 'CopyrightHolder=Peter Johnson & Contributors',
- 'CopyrightHolderURL=https://gravatar.com/delphidabbler'
- );
-end;
-
-function TV1DBMetaFiles.LicenseText: string;
-begin
- Result := LoadResourceAsString(HInstance, 'CSDBLICENSE', RT_RCDATA, etUTF8);
-end;
-
-function TV1DBMetaFiles.Testers: TStringDynArray;
-begin
- Result := ReadFileLines(cTestersFile);
-end;
-
-function TV1DBMetaFiles.Version: string;
-begin
- Result := '1';
-end;
-
-{ TV2DBMetaFiles }
-
-function TV2DBMetaFiles.AreAllFilesPresent: Boolean;
-begin
- Result := DBFileExists(cVersionFile)
- and DBFileExists(cLicenseFile)
- and DBFileExists(cLicenseInfoFile)
- and DBFileExists(cContributorsFile)
- and DBFileExists(cTestersFile);
-end;
-
-function TV2DBMetaFiles.Contributors: TStringDynArray;
-begin
- Result := ReadFileLines(cContributorsFile);
-end;
-
-function TV2DBMetaFiles.LicenseInfo: TStringDynArray;
-begin
- Result := ReadFileLines(cLicenseInfoFile);
-end;
-
-function TV2DBMetaFiles.LicenseText: string;
-begin
- Result := StrTrimRight(ReadFileText(cLicenseFile));
-end;
-
-function TV2DBMetaFiles.Testers: TStringDynArray;
-begin
- Result := ReadFileLines(cTestersFile);
-end;
-
-function TV2DBMetaFiles.Version: string;
-begin
- Result := StrTrim(ReadFileText(cVersionFile));
-end;
-
-{ TLaterDBMetaFiles }
-
-function TLaterDBMetaFiles.AreAllFilesPresent: Boolean;
-resourcestring
- sNotSupportedError = 'Calling %s.AreAllFilesPresent is not supported for an '
- + 'unsupported database format';
-begin
- raise ENotSupportedException.CreateFmt(sNotSupportedError, [ClassName]);
-end;
-
-function TLaterDBMetaFiles.Contributors: TStringDynArray;
-begin
- SetLength(Result, 0);
-end;
-
-function TLaterDBMetaFiles.LicenseInfo: TStringDynArray;
-begin
- SetLength(Result, 0);
-end;
-
-function TLaterDBMetaFiles.LicenseText: string;
-begin
- Result := '';
-end;
-
-function TLaterDBMetaFiles.Testers: TStringDynArray;
-begin
- SetLength(Result, 0);
-end;
-
-function TLaterDBMetaFiles.Version: string;
-begin
- Result := StrTrim(ReadFileText(cVersionFile));
-end;
-
-{ TUnknownOrMissingMetaFiles }
-
-function TUnknownOrMissingMetaFiles.AreAllFilesPresent: Boolean;
-resourcestring
- sNotSupportedError = 'Calling %s.AreAllFilesPresent is not supported for an '
- + 'unrecognised database format or missing database';
-begin
- raise ENotSupportedException.CreateFmt(sNotSupportedError, [ClassName]);
-end;
-
-function TUnknownOrMissingMetaFiles.Contributors: TStringDynArray;
-begin
- SetLength(Result, 0);
-end;
-
-function TUnknownOrMissingMetaFiles.LicenseInfo: TStringDynArray;
-begin
- SetLength(Result, 0);
-end;
-
-function TUnknownOrMissingMetaFiles.LicenseText: string;
-begin
- Result := '';
-end;
-
-function TUnknownOrMissingMetaFiles.Testers: TStringDynArray;
-begin
- SetLength(Result, 0);
-end;
-
-function TUnknownOrMissingMetaFiles.Version: string;
-begin
- Result := '';
-end;
-
-{ TDBMetaFilesFactory }
-
-class function TDBMetaFilesFactory.GetInstance(const DBDir: string):
- TDBMetaFiles;
-var
- VersionFile: string;
- VersionStr: string;
- Version: TVersionNumber;
- DBPath: string;
-begin
- if not TDirectory.Exists(ExcludeTrailingPathDelimiter(DBDir)) then
- // Database is not installed
- Exit(TUnknownOrMissingMetaFiles.Create(DBDir));
-
- DBPath := IncludeTrailingPathDelimiter(DBDir);
-
- // Check if VERSION file exists:
- // Yes:
- // either: version is invalid - database format unknown
- // or: version is 2.x.x.x - database format v2 recognised
- // or: version is >2 - database format recognised but not supported
- // No:
- // either: expected v1 meta files exist - database format v1 recognised
- // or: no v1 meta files - database format unknown
- VersionFile := DBPath + TDBMetaFileNames.VersionV2AndLater;
- if TFile.Exists(VersionFile, False) then
- begin
- VersionStr := TFileIO.ReadAllText(VersionFile, TEncoding.UTF8, True);
- if not TVersionNumber.TryStrToVersionNumber(VersionStr, Version) then
- Result := TUnknownOrMissingMetaFiles.Create(DBDir)
- else if Version.V1 = 2 then
- Result := TV2DBMetaFiles.Create(DBDir)
- else
- Result := TLaterDBMetaFiles.Create(DBDir);
- end
- else
- begin
- if TFile.Exists(DBPath + TDBMetaFileNames.ContributorsV1, False)
- and TFile.Exists(DBPath + TDBMetaFileNames.TestersV1, False) then
- Result := TV1DBMetaFiles.Create(DBDir)
- else
- Result := TUnknownOrMissingMetaFiles.Create(DBDir);
- end;
-end;
-
{ TDBLicenseInfo }
constructor TDBLicenseInfo.Create(const AName, ASPDX, AURL, AText: string);
diff --git a/Src/DBIO.MetaData.DCSC.pas b/Src/DBIO.MetaData.DCSC.pas
new file mode 100644
index 000000000..984f00cc0
--- /dev/null
+++ b/Src/DBIO.MetaData.DCSC.pas
@@ -0,0 +1,830 @@
+{
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/
+ *
+ * Copyright (C) 2024, Peter Johnson (gravatar.com/delphidabbler).
+ *
+ * Loads and vaildates meta data supported by the DelphiDabbler Code Snippets
+ * Collection.
+}
+
+
+unit DBIO.MetaData.DCSC;
+
+interface
+
+{
+ Notes About Database Versions And Meta Files.
+ =============================================
+
+ Versions
+ --------
+
+ v1 of the Code Snippets Database was not considered to have a version number
+ until the arrival of v2. Therefore v1 did not have any means of identifying
+ its version number. Although the database format changed slightly over time
+ there is not enough historical information to identify different minor
+ releases, so all are considered to be v1.0.0.0
+
+ Database v2 has a VERSION file that specifies the version number as a dotted
+ quad, of the form v2.0.0.0.
+
+ Note that semantic versioning is now being used so any database with major
+ version 2 will be backwards compatible with earlier v2 minor release.
+
+ If a breaking change is introduced the major version will be bumped to v3 and
+ so on.
+
+ Meta Files
+ ----------
+
+ Database v1 had only two meta files:
+ + contrib.txt - lists of contributors to the database, one per line
+ + testers.txt - lists of database testers, one per line
+ If those two files are present the database is assumed to be v1
+
+ Database v2 has the following meta files:
+ + VERSION - version number (v2.x.x.x)
+ + CONTRIBUTORS - lists of contributors to the database, one per line
+ + TESTERS - lists of database testers, one per line
+ + LICENSE - full text of the license that applies to the snippets
+ + LICENSE-INFO - furter information about the license
+
+ For database v1 the license text, license information are hard-wired in the
+ absence of meta files. As noted above the version number is deduced.
+
+ File encoding
+ -------------
+
+ All meta files are plain text.
+
+ Early v1 database meta files were encoded in the system default encoding.
+ Later v1 databases encoded meta files in UTF-8. To distinguish between UTF-8
+ and default encoded files the UTF-8 files use the UTF-8 preamble (BOM).
+
+ v2 database meta files are all encoded in UTF-8 with preamble (BOM).
+
+ Future major versions
+ ---------------------
+
+ Future major database releases MUST include backwards compatibility with
+ earlier versions of CodeSnip in as much as those versions must be able to
+ easily detect and reject the format.
+
+ To achieve this new major releases MUST include a VERSION file encoded in
+ UTF-8 with BOM. Existing code can detect and will reject any unsupported
+ version.
+
+ CodeSnip support
+ ----------------
+
+ CodeSnip versions earlier than v4.16 are only ever delivered v1 database files
+ via their built in web update code. There is no way for these versions to
+ access v2 databases.
+
+ CodeSnip from v4.16 get their main snippets database from files downloaded
+ manually. All such databases are v2. CodeSnip v4.16 also supports v1 format
+ because such a database may be resident on the user's computer at install
+ time.
+}
+
+
+
+uses
+ // Project
+ SysUtils,
+ Types,
+ // VCL
+ DB.UMetaData,
+ UIStringList,
+ UStructs,
+ UVersionInfo;
+
+
+const
+ DBValidVersions: TRange = (Min: 1; Max: 2);
+
+type
+
+ /// Provides names of meta data files supported by various database
+ /// versions.
+ TDBMetaFileNames = record
+ public
+ const
+ ContributorsV1 = 'contrib.txt';
+ TestersV1 = 'testers.txt';
+ VersionV2AndLater = 'VERSION';
+ LicenseV2 = 'LICENSE';
+ LicenseInfoV2 = 'LICENSE-INFO';
+ ContributorsV2 = 'CONTRIBUTORS';
+ TestersV2 = 'TESTERS';
+ end;
+
+ /// Abstract base class for classes that access or emulate database
+ /// meta data files.
+ TDBMetaFiles = class abstract(TObject)
+ strict private
+ var
+ /// Directory of database for which meta data files are being
+ /// accessed.
+ fDBDir: string;
+ /// Returns encoding used by given meta file.
+ function GetFileEncoding(const FileName: TFileName): TEncoding;
+ strict protected
+ /// Makes a fully specified path to a given database file.
+ ///
+ /// FileName must contain no path information.
+ function MakePath(const FileName: string): string;
+ /// Checks if a given file exists in database directory.
+ function DBFileExists(const FileName: string): Boolean;
+ /// Reads all lines from given file and returns them as an array.
+ ///
+ /// FileName must contain no path information.
+ function ReadFileLines(const FileName: TFileName): TStringDynArray;
+ /// Reads all text from given file and returns it.
+ /// FileName must contain no path information.
+ function ReadFileText(const FileName: TFileName): string;
+ public
+ /// Constructs object that accesses meta data database files in
+ /// given directory.
+ constructor Create(const DBDir: string);
+ /// Returns text of the version file, or surrogate value.
+ ///
+ function Version: string; virtual; abstract;
+ /// Returns content license text file or surrogate value.
+ ///
+ function LicenseText: string; virtual; abstract;
+ /// Returns lines of license information file or surrogate value.
+ ///
+ function LicenseInfo: TStringDynArray; virtual; abstract;
+ /// Returns lines of contributors file or surrogate value.
+ ///
+ function Contributors: TStringDynArray; virtual; abstract;
+ /// Returns lines of testers file or surrogate value.
+ function Testers: TStringDynArray; virtual; abstract;
+ /// Checks if all the expected meta files are present. Returns
+ /// True if so or False if not.
+ /// ENotSupportedException must be raised if called on an
+ /// unsupported database version.
+ function AreAllFilesPresent: Boolean; virtual; abstract;
+ end;
+
+ /// Class that accesses content of version 1 main database meta data
+ /// files.
+ /// Not all meta files are present in version main databases so
+ /// invariant placeholder content is provided to substitute for missing
+ /// files.
+ TV1DBMetaFiles = class sealed(TDBMetaFiles)
+ strict private
+ const
+ cContributorsFile = TDBMetaFileNames.ContributorsV1;
+ cTestersFile = TDBMetaFileNames.TestersV1;
+ public
+ /// Returns an surrogate, invariant value of 1 for the version
+ /// number.
+ /// No version file exists for this database version. The value
+ /// returned is deduced using documentation from the current code snippets
+ /// database project.
+ function Version: string; override;
+ /// Returns an surrogate, invariant value for the license text.
+ ///
+ /// No license text file exists for this database version. The
+ /// value returned is based on documentation of the database.
+ function LicenseText: string; override;
+ /// Returns an surrogate, invariant value for the lines of license
+ /// information.
+ function LicenseInfo: TStringDynArray; override;
+ /// Returns the lines of the contributors file.
+ function Contributors: TStringDynArray; override;
+ /// Returns the lines of the testers file.
+ function Testers: TStringDynArray; override;
+ /// Checks if all the expected meta files are present. Returns
+ /// True if so or False if not.
+ function AreAllFilesPresent: Boolean; override;
+ end;
+
+ /// Class that accesses content of supported version 2 main database
+ /// meta files.
+ TV2DBMetaFiles = class sealed(TDBMetaFiles)
+ strict private
+ const
+ cVersionFile = TDBMetaFileNames.VersionV2AndLater;
+ cLicenseFile = TDBMetaFileNames.LicenseV2;
+ cLicenseInfoFile = TDBMetaFileNames.LicenseInfoV2;
+ cContributorsFile = TDBMetaFileNames.ContributorsV2;
+ cTestersFile = TDBMetaFileNames.TestersV2;
+ public
+ /// Returns the contents of the version file.
+ function Version: string; override;
+ /// Returns the contents of the license text file.
+ function LicenseText: string; override;
+ /// Returns the lines of the license info file.
+ function LicenseInfo: TStringDynArray; override;
+ /// Returns the lines of the contributors file.
+ function Contributors: TStringDynArray; override;
+ /// Returns the lines of the testers file.
+ function Testers: TStringDynArray; override;
+ /// Checks if all the expected meta files are present. Returns
+ /// True if so or False if not.
+ function AreAllFilesPresent: Boolean; override;
+ end;
+
+ /// Class that represents later versions of database meta file
+ /// formats.
+ /// These formats have a valid version file but the version is not
+ /// supported and nothing is known about any other meta data files.
+ TLaterDBMetaFiles = class sealed(TDBMetaFiles)
+ strict private
+ const
+ cVersionFile = TDBMetaFileNames.VersionV2AndLater;
+ public
+ /// Returns the contents of the version file.
+ function Version: string; override;
+ /// Returns the empty string.
+ /// The file format is unknown, so the license text file cannot be
+ /// read and there is no information to deduce the value.
+ function LicenseText: string; override;
+ /// Returns an empty string array.
+ /// The file format is unknown, so the license information file
+ /// cannot be read and there is no information to deduce the value.
+ ///
+ function LicenseInfo: TStringDynArray; override;
+ /// Returns an empty string array.
+ /// The file format is unknown, so the contributors file cannot be
+ /// read and there is no information to deduce the value.
+ function Contributors: TStringDynArray; override;
+ /// Returns an empty string array.
+ /// The file format is unknown, so the testers file cannot be read
+ /// and there is no information to deduce the value.
+ function Testers: TStringDynArray; override;
+ /// Checks if all the expected meta files are present only if
+ /// the meta files come from a supported database format.
+ /// ENotSupportedException always raised since there is no way
+ /// of knowing what files should be present in an unsupported database
+ /// format.
+ function AreAllFilesPresent: Boolean; override;
+ end;
+
+ /// Class that is present to represent unknown database meta file
+ /// formats. Also used when database is not present.
+ /// Accesses no files and returns null results for all methods
+ /// except IsVersionSupported.
+ TUnknownOrMissingMetaFiles = class sealed(TDBMetaFiles)
+ public
+ /// Returns the empty string.
+ /// The file format is unknown, so the version file cannot be read
+ /// and there is no information to deduce the value.
+ function Version: string; override;
+ /// Returns the empty string.
+ /// The file format is unknown, so the license text file cannot be
+ /// read and there is no information to deduce the value.
+ function LicenseText: string; override;
+ /// Returns an empty string array.
+ /// The file format is unknown, so the license information file
+ /// cannot be read and there is no information to deduce the value.
+ ///
+ function LicenseInfo: TStringDynArray; override;
+ /// Returns an empty string array.
+ /// The file format is unknown, so the contributors file cannot be
+ /// read and there is no information to deduce the value.
+ function Contributors: TStringDynArray; override;
+ /// Returns an empty string array.
+ /// The file format is unknown, so the testers file cannot be read
+ /// and there is no information to deduce the value.
+ function Testers: TStringDynArray; override;
+ /// Checks if all the expected meta files are present only if
+ /// the meta files come from a supported database format.
+ /// ENotSupportedException always raised since there is no way
+ /// of knowing what files should be present in an unrecognised database
+ /// format.
+ function AreAllFilesPresent: Boolean; override;
+ end;
+
+ /// Factory to create the correct instance of database meta file
+ /// classes that can read the version of a database in a given folder.
+ ///
+ TDBMetaFilesFactory = record
+ public
+ class function GetInstance(const DBDir: string): TDBMetaFiles;
+ static;
+ end;
+
+ /// Abstract base class for classes that provide main database meta
+ /// data.
+ TAbstractMainDBMetaData = class abstract(TInterfacedObject)
+ strict private
+ var
+ fMetaFiles: TDBMetaFiles;
+ fIsVersionLoaded: Boolean;
+ fVersion: TVersionNumber;
+ fIsLicenseAndCopyrightInfoLoaded: Boolean;
+ fLicenseInfo: TDBLicenseInfo;
+ fCopyrightInfo: TDBCopyrightInfo;
+ fContributors: IStringList;
+ fTesters: IStringList;
+
+ procedure LoadLicenseAndCopyrightInfo;
+
+ strict protected
+ function GetDBDir: string; virtual; abstract;
+ public
+ procedure AfterConstruction; override;
+ destructor Destroy; override;
+ /// Returns database version number.
+ ///
+ /// A null version number is returned if the meta data does not come
+ /// from a recognised database.
+ /// Method of IDBMetaData.
+ ///
+ function GetVersion: TVersionNumber;
+ /// Returns database license information.
+ ///
+ /// Return value is meaningless if the meta data does not come
+ /// from a supported database.
+ /// Method of IDBMetaData.
+ ///
+ function GetLicenseInfo: TDBLicenseInfo;
+ /// Returns database copyright informatiom.
+ ///
+ /// Return value is meaningless if the meta data does not come
+ /// from a supported database.
+ /// Method of IDBMetaData.
+ ///
+ function GetCopyrightInfo: TDBCopyrightInfo;
+ /// Returns list of contributors to database.
+ ///
+ /// Return value is meaningless if the meta data does not come
+ /// from a supported database.
+ /// Method of IDBMetaData.
+ ///
+ function GetContributors: IStringList;
+ /// Returns list of testers of database.
+ ///
+ /// Return value is meaningless if the meta data does not come
+ /// from a supported database.
+ /// Method of IDBMetaData.
+ ///
+ function GetTesters: IStringList;
+ /// Checks if meta data is recognised as belonging to a valid
+ /// database, whether supported or not.
+ /// Method of IDBMetaData.
+ function IsRecognised: Boolean;
+ /// Checks if meta data is recognised as belonging to a supported
+ /// database version.
+ /// Method of IDBMetaData.
+ function IsSupportedVersion: Boolean;
+ /// Checks if meta data is corrupt.
+ ///
+ /// Should only be called if meta data belongs to a supported
+ /// database.
+ /// Method of IDBMetaData.
+ ///
+ /// ENotSupportedException raised if called on an unsupported
+ /// database.
+ function IsCorrupt: Boolean;
+ /// Refreshes the meta information by re-reading from database
+ /// meta files.
+ /// Method of IDBMetaData.
+ procedure Refresh;
+ end;
+
+ /// Class that provides meta data for the main database.
+ TMainDBMetaData = class sealed(TAbstractMainDBMetaData, IDBMetaData)
+ strict protected
+ function GetDBDir: string; override;
+ end;
+
+ /// Class that provides meta data for update database directories.
+ ///
+ TUpdateDBMetaData = class sealed(TAbstractMainDBMetaData, IDBMetaData)
+ strict private
+ var
+ fUpdateDir: string;
+ strict protected
+ function GetDBDir: string; override;
+ public
+ constructor Create(const UpdateDir: string);
+ end;
+
+ /// Factory that creates instances of objects that provide
+ /// information about the main database and database updates.
+ TMainDBMetaDataFactory = record
+ public
+ /// Returns instance of class that provides meta data for the
+ /// main database.
+ class function MainDBMetaDataInstance: IDBMetaData; static;
+ /// Returns instance of class that provides meta data for the
+ /// database update stored in the given folder.
+ class function UpdateMetaDataInstance(const UpdateDir: string):
+ IDBMetaData; static;
+ end;
+
+implementation
+
+uses
+ // Project
+ Classes,
+ IOUtils,
+ // VCL
+ UAppInfo,
+ UEncodings,
+ UIOUtils,
+ UResourceUtils,
+ UStrUtils;
+
+{ TMainDBMetaDataFactory }
+
+class function TMainDBMetaDataFactory.MainDBMetaDataInstance:
+ IDBMetaData;
+begin
+ Result := TMainDBMetaData.Create;
+end;
+
+class function TMainDBMetaDataFactory.UpdateMetaDataInstance(
+ const UpdateDir: string): IDBMetaData;
+begin
+ Result := TUpdateDBMetaData.Create(UpdateDir);
+end;
+
+{ TAbstractMainDBMetaData }
+
+procedure TAbstractMainDBMetaData.AfterConstruction;
+begin
+ inherited;
+ Refresh;
+end;
+
+destructor TAbstractMainDBMetaData.Destroy;
+begin
+ fMetaFiles.Free;
+ inherited;
+end;
+
+function TAbstractMainDBMetaData.GetContributors: IStringList;
+begin
+ if not Assigned(fContributors) then
+ fContributors := TIStringList.Create(fMetaFiles.Contributors);
+ Result := fContributors;
+end;
+
+function TAbstractMainDBMetaData.GetCopyrightInfo: TDBCopyrightInfo;
+begin
+ if not fIsLicenseAndCopyrightInfoLoaded then
+ LoadLicenseAndCopyrightInfo;
+ Result := fCopyrightInfo;
+end;
+
+function TAbstractMainDBMetaData.GetLicenseInfo: TDBLicenseInfo;
+begin
+ if not fIsLicenseAndCopyrightInfoLoaded then
+ LoadLicenseAndCopyrightInfo;
+ Result := fLicenseInfo;
+end;
+
+function TAbstractMainDBMetaData.GetTesters: IStringList;
+begin
+ if not Assigned(fTesters) then
+ fTesters := TIStringList.Create(fMetaFiles.Testers);
+ Result := fTesters;
+end;
+
+function TAbstractMainDBMetaData.GetVersion: TVersionNumber;
+begin
+ if not fIsVersionLoaded then
+ begin
+ if not TVersionNumber.TryStrToVersionNumber(
+ StrTrim(fMetaFiles.Version), fVersion
+ ) then
+ fVersion := TVersionNumber.Nul;
+ end;
+ fIsVersionLoaded := True;
+ Result := fVersion;
+end;
+
+function TAbstractMainDBMetaData.IsCorrupt: Boolean;
+resourcestring
+ sNotSupportedError = 'Can''t call IDBMetaData.IsCorrupt for an unsupported '
+ + 'database version';
+begin
+ if not IsSupportedVersion then
+ raise ENotSupportedException.Create(sNotSupportedError);
+ Result := not fMetaFiles.AreAllFilesPresent;
+end;
+
+function TAbstractMainDBMetaData.IsRecognised: Boolean;
+begin
+ Result := not GetVersion.IsNull;
+end;
+
+function TAbstractMainDBMetaData.IsSupportedVersion: Boolean;
+var
+ ThisVersion: TVersionNumber;
+begin
+ ThisVersion := GetVersion;
+ Result := DBValidVersions.Contains(ThisVersion.V1);
+end;
+
+procedure TAbstractMainDBMetaData.LoadLicenseAndCopyrightInfo;
+var
+ SL: TStringList;
+begin
+ if fIsLicenseAndCopyrightInfoLoaded then
+ Exit;
+ SL := TStringList.Create;
+ try
+ StrArrayToStrList(fMetaFiles.LicenseInfo, SL);
+ fLicenseInfo := TDBLicenseInfo.Create(
+ SL.Values['LicenseName'],
+ SL.Values['LicenseSPDX'],
+ SL.Values['LicenseURL'],
+ fMetaFiles.LicenseText
+ );
+ fCopyrightInfo := TDBCopyrightInfo.Create(
+ SL.Values['CopyrightDate'],
+ SL.Values['CopyrightHolder'],
+ SL.Values['CopyrightHolderURL']
+ );
+ finally
+ SL.Free;
+ end;
+ fIsLicenseAndCopyrightInfoLoaded := True;
+end;
+
+procedure TAbstractMainDBMetaData.Refresh;
+begin
+ FreeAndNil(fMetaFiles);
+ fMetaFiles := TDBMetaFilesFactory.GetInstance(GetDBDir);
+ fIsVersionLoaded := False;
+ fIsLicenseAndCopyrightInfoLoaded := False;
+ fContributors := nil;
+ fTesters := nil;
+end;
+
+{ TMainDBMetaData }
+
+function TMainDBMetaData.GetDBDir: string;
+begin
+ Result := TAppInfo.AppDataDir;
+end;
+
+{ TUpdateDBMetaData }
+
+constructor TUpdateDBMetaData.Create(const UpdateDir: string);
+begin
+ inherited Create;
+ fUpdateDir := ExcludeTrailingPathDelimiter(UpdateDir);
+end;
+
+function TUpdateDBMetaData.GetDBDir: string;
+begin
+ Result := fUpdateDir;
+end;
+
+{ TDBMetaFiles }
+
+constructor TDBMetaFiles.Create(const DBDir: string);
+begin
+ inherited Create;
+ fDBDir := DBDir;
+end;
+
+function TDBMetaFiles.DBFileExists(const FileName: string): Boolean;
+begin
+ Result := TFile.Exists(MakePath(FileName), False);
+end;
+
+function TDBMetaFiles.GetFileEncoding(const FileName: TFileName): TEncoding;
+begin
+ // Old v1 database meta files may be in the system default encodings, v1 and
+ // all v2 and later use UTF-8 with BOM.
+ if TFileIO.CheckBOM(MakePath(FileName), TEncoding.UTF8) then
+ Result := TEncoding.UTF8
+ else
+ Result := TEncoding.Default;
+end;
+
+function TDBMetaFiles.MakePath(const FileName: string): string;
+begin
+ Assert(not StrContainsStr(PathDelim, FileName),
+ ClassName + '.MakePath: FileName must be a base file name.');
+ Result := IncludeTrailingPathDelimiter(fDBDir) + FileName;
+end;
+
+function TDBMetaFiles.ReadFileLines(const FileName: TFileName): TStringDynArray;
+var
+ Encoding: TEncoding;
+begin
+ if not DBFileExists(FileName) then
+ begin
+ SetLength(Result, 0);
+ Exit;
+ end;
+ Encoding := GetFileEncoding(FileName);
+ try
+ Result := TFileIO.ReadAllLines(MakePath(FileName), Encoding, True);
+ finally
+ TEncodingHelper.FreeEncoding(Encoding);
+ end;
+end;
+
+function TDBMetaFiles.ReadFileText(const FileName: TFileName): string;
+begin
+ if not DBFileExists(FileName) then
+ Exit('');
+ Result := TFileIO.ReadAllText(
+ MakePath(FileName), GetFileEncoding(FileName), True
+ );
+end;
+
+{ TV1DBMetaFiles }
+
+function TV1DBMetaFiles.AreAllFilesPresent: Boolean;
+begin
+ Result := DBFileExists(cContributorsFile) and DBFileExists(cTestersFile);
+end;
+
+function TV1DBMetaFiles.Contributors: TStringDynArray;
+begin
+ Result := ReadFileLines(cContributorsFile)
+end;
+
+function TV1DBMetaFiles.LicenseInfo: TStringDynArray;
+begin
+ Result := TStringDynArray.Create(
+ 'LicenseName=MIT License',
+ 'LicenseSPDX=MIT',
+ 'LicenseURL=https://opensource.org/licenses/MIT',
+ 'CopyrightDate=2005-2016',
+ 'CopyrightHolder=Peter Johnson & Contributors',
+ 'CopyrightHolderURL=https://gravatar.com/delphidabbler'
+ );
+end;
+
+function TV1DBMetaFiles.LicenseText: string;
+begin
+ Result := LoadResourceAsString(HInstance, 'CSDBLICENSE', RT_RCDATA, etUTF8);
+end;
+
+function TV1DBMetaFiles.Testers: TStringDynArray;
+begin
+ Result := ReadFileLines(cTestersFile);
+end;
+
+function TV1DBMetaFiles.Version: string;
+begin
+ Result := '1';
+end;
+
+{ TV2DBMetaFiles }
+
+function TV2DBMetaFiles.AreAllFilesPresent: Boolean;
+begin
+ Result := DBFileExists(cVersionFile)
+ and DBFileExists(cLicenseFile)
+ and DBFileExists(cLicenseInfoFile)
+ and DBFileExists(cContributorsFile)
+ and DBFileExists(cTestersFile);
+end;
+
+function TV2DBMetaFiles.Contributors: TStringDynArray;
+begin
+ Result := ReadFileLines(cContributorsFile);
+end;
+
+function TV2DBMetaFiles.LicenseInfo: TStringDynArray;
+begin
+ Result := ReadFileLines(cLicenseInfoFile);
+end;
+
+function TV2DBMetaFiles.LicenseText: string;
+begin
+ Result := StrTrimRight(ReadFileText(cLicenseFile));
+end;
+
+function TV2DBMetaFiles.Testers: TStringDynArray;
+begin
+ Result := ReadFileLines(cTestersFile);
+end;
+
+function TV2DBMetaFiles.Version: string;
+begin
+ Result := StrTrim(ReadFileText(cVersionFile));
+end;
+
+{ TLaterDBMetaFiles }
+
+function TLaterDBMetaFiles.AreAllFilesPresent: Boolean;
+resourcestring
+ sNotSupportedError = 'Calling %s.AreAllFilesPresent is not supported for an '
+ + 'unsupported database format';
+begin
+ raise ENotSupportedException.CreateFmt(sNotSupportedError, [ClassName]);
+end;
+
+function TLaterDBMetaFiles.Contributors: TStringDynArray;
+begin
+ SetLength(Result, 0);
+end;
+
+function TLaterDBMetaFiles.LicenseInfo: TStringDynArray;
+begin
+ SetLength(Result, 0);
+end;
+
+function TLaterDBMetaFiles.LicenseText: string;
+begin
+ Result := '';
+end;
+
+function TLaterDBMetaFiles.Testers: TStringDynArray;
+begin
+ SetLength(Result, 0);
+end;
+
+function TLaterDBMetaFiles.Version: string;
+begin
+ Result := StrTrim(ReadFileText(cVersionFile));
+end;
+
+{ TUnknownOrMissingMetaFiles }
+
+function TUnknownOrMissingMetaFiles.AreAllFilesPresent: Boolean;
+resourcestring
+ sNotSupportedError = 'Calling %s.AreAllFilesPresent is not supported for an '
+ + 'unrecognised database format or missing database';
+begin
+ raise ENotSupportedException.CreateFmt(sNotSupportedError, [ClassName]);
+end;
+
+function TUnknownOrMissingMetaFiles.Contributors: TStringDynArray;
+begin
+ SetLength(Result, 0);
+end;
+
+function TUnknownOrMissingMetaFiles.LicenseInfo: TStringDynArray;
+begin
+ SetLength(Result, 0);
+end;
+
+function TUnknownOrMissingMetaFiles.LicenseText: string;
+begin
+ Result := '';
+end;
+
+function TUnknownOrMissingMetaFiles.Testers: TStringDynArray;
+begin
+ SetLength(Result, 0);
+end;
+
+function TUnknownOrMissingMetaFiles.Version: string;
+begin
+ Result := '';
+end;
+
+{ TDBMetaFilesFactory }
+
+class function TDBMetaFilesFactory.GetInstance(const DBDir: string):
+ TDBMetaFiles;
+var
+ VersionFile: string;
+ VersionStr: string;
+ Version: TVersionNumber;
+ DBPath: string;
+begin
+ if not TDirectory.Exists(ExcludeTrailingPathDelimiter(DBDir)) then
+ // Database is not installed
+ Exit(TUnknownOrMissingMetaFiles.Create(DBDir));
+
+ DBPath := IncludeTrailingPathDelimiter(DBDir);
+
+ // Check if VERSION file exists:
+ // Yes:
+ // either: version is invalid - database format unknown
+ // or: version is 2.x.x.x - database format v2 recognised
+ // or: version is >2 - database format recognised but not supported
+ // No:
+ // either: expected v1 meta files exist - database format v1 recognised
+ // or: no v1 meta files - database format unknown
+ VersionFile := DBPath + TDBMetaFileNames.VersionV2AndLater;
+ if TFile.Exists(VersionFile, False) then
+ begin
+ VersionStr := TFileIO.ReadAllText(VersionFile, TEncoding.UTF8, True);
+ if not TVersionNumber.TryStrToVersionNumber(VersionStr, Version) then
+ Result := TUnknownOrMissingMetaFiles.Create(DBDir)
+ else if Version.V1 = 2 then
+ Result := TV2DBMetaFiles.Create(DBDir)
+ else
+ Result := TLaterDBMetaFiles.Create(DBDir);
+ end
+ else
+ begin
+ if TFile.Exists(DBPath + TDBMetaFileNames.ContributorsV1, False)
+ and TFile.Exists(DBPath + TDBMetaFileNames.TestersV1, False) then
+ Result := TV1DBMetaFiles.Create(DBDir)
+ else
+ Result := TUnknownOrMissingMetaFiles.Create(DBDir);
+ end;
+end;
+
+end.
diff --git a/Src/FmAboutDlg.pas b/Src/FmAboutDlg.pas
index 22b0eb8a0..a15bbd236 100644
--- a/Src/FmAboutDlg.pas
+++ b/Src/FmAboutDlg.pas
@@ -181,6 +181,7 @@ implementation
// Project
DB.UCollections,
DB.UMain,
+ DBIO.MetaData.DCSC,
FmEasterEgg,
FmPreviewDlg,
UAppInfo,
diff --git a/Src/UDBUpdateMgr.pas b/Src/UDBUpdateMgr.pas
index 3cf1df472..f5f23bd4c 100644
--- a/Src/UDBUpdateMgr.pas
+++ b/Src/UDBUpdateMgr.pas
@@ -100,6 +100,7 @@ implementation
IOUtils,
// Project
DB.UMetaData,
+ DBIO.MetaData.DCSC,
UAppInfo,
UFileUpdater,
UStrUtils,
diff --git a/Src/USaveUnitMgr.pas b/Src/USaveUnitMgr.pas
index eb6c2f9d7..ca02bd04f 100644
--- a/Src/USaveUnitMgr.pas
+++ b/Src/USaveUnitMgr.pas
@@ -98,6 +98,7 @@ implementation
// Project
DB.UCollections,
DB.UMetaData,
+ DBIO.MetaData.DCSC,
UAppInfo,
UConsts,
UUrl,
diff --git a/Src/USnippetDoc.pas b/Src/USnippetDoc.pas
index 7d9e9763b..97ab36023 100644
--- a/Src/USnippetDoc.pas
+++ b/Src/USnippetDoc.pas
@@ -121,6 +121,7 @@ implementation
DB.UMain,
DB.UMetaData,
DB.USnippetKind,
+ DBIO.MetaData.DCSC,
UStrUtils,
UUrl;
diff --git a/Src/USnippetSourceGen.pas b/Src/USnippetSourceGen.pas
index d0bcd3721..c3855ae64 100644
--- a/Src/USnippetSourceGen.pas
+++ b/Src/USnippetSourceGen.pas
@@ -91,6 +91,7 @@ implementation
DB.UMetaData,
DB.USnippet,
DB.USnippetKind,
+ DBIO.MetaData.DCSC,
UConsts,
UAppInfo,
UQuery,
From 4ffa638b0adef03f6fea5dca0fa016332e5d1da8 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 16 Nov 2024 10:40:12 +0000
Subject: [PATCH 096/222] Add new IDBMetaData.GetCapabilities method
This new method returns a set of capabilities (TMetaDataCapabilities)
that describe the types of meta data supported by the collection.
Classes DBIO.MetaData.DCSC implemented of the new method by returning a
set of all capabilities.
---
Src/DB.UMetaData.pas | 13 +++++++++++++
Src/DBIO.MetaData.DCSC.pas | 10 ++++++++++
2 files changed, 23 insertions(+)
diff --git a/Src/DB.UMetaData.pas b/Src/DB.UMetaData.pas
index 8e4b69cf3..b2c037dae 100644
--- a/Src/DB.UMetaData.pas
+++ b/Src/DB.UMetaData.pas
@@ -24,6 +24,16 @@ interface
type
+ TMetaDataCapability = (
+ mdcVersion,
+ mdcLicense,
+ mdcCopyright,
+ mdcContributors,
+ mdcTesters
+ );
+
+ TMetaDataCapabilities = set of TMetaDataCapability;
+
/// Record providing information about a collection's license.
///
TDBLicenseInfo = record
@@ -80,6 +90,9 @@ TDBCopyrightInfo = record
/// Interface that provides information about any meta data
/// supported by a collection.
IDBMetaData = interface(IInterface)
+ /// Returns information about what, if any, meta data is supported
+ /// by a collection.
+ function GetCapabilities: TMetaDataCapabilities;
/// Returns the collection's version number.
/// A null version number is returned if the collection does not
/// include Version in its capabilities.
diff --git a/Src/DBIO.MetaData.DCSC.pas b/Src/DBIO.MetaData.DCSC.pas
index 984f00cc0..933554f3e 100644
--- a/Src/DBIO.MetaData.DCSC.pas
+++ b/Src/DBIO.MetaData.DCSC.pas
@@ -14,6 +14,8 @@
interface
+{TODO -cVault: Remove support for main database v1 (and perhaps v>2)}
+
{
Notes About Database Versions And Meta Files.
=============================================
@@ -331,6 +333,9 @@ TAbstractMainDBMetaData = class abstract(TInterfacedObject)
public
procedure AfterConstruction; override;
destructor Destroy; override;
+ /// Returns information about what, if any, meta data is supported
+ /// by a collection.
+ function GetCapabilities: TMetaDataCapabilities;
/// Returns database version number.
///
/// A null version number is returned if the meta data does not come
@@ -461,6 +466,11 @@ destructor TAbstractMainDBMetaData.Destroy;
inherited;
end;
+function TAbstractMainDBMetaData.GetCapabilities: TMetaDataCapabilities;
+begin
+ Result := [mdcVersion, mdcLicense, mdcCopyright, mdcContributors, mdcTesters];
+end;
+
function TAbstractMainDBMetaData.GetContributors: IStringList;
begin
if not Assigned(fContributors) then
From 37c52abddc0fc333b9fb61276982b27ad6ecc312 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 16 Nov 2024 16:39:38 +0000
Subject: [PATCH 097/222] Add TCollection.TComparer class
Added a new TComparer nested class to TCollection that implements
IComparer and IEqualityComparer. This
provides Compare, Equals and GetHashCode methods.
All methods rely on TCollectionID comparisons and hashes.
---
Src/DB.UCollections.pas | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
index ae10638f1..f12ae768f 100644
--- a/Src/DB.UCollections.pas
+++ b/Src/DB.UCollections.pas
@@ -178,6 +178,17 @@ TCollection = record
fLocation: TCollectionLocation;
fCollectionFormatKind: TCollectionFormatKind;
public
+ type
+ TComparer = class(TInterfacedObject,
+ IComparer, IEqualityComparer
+ )
+ public
+ function Compare(const Left, Right: TCollection): Integer;
+ function Equals(const Left, Right: TCollection): Boolean;
+ reintroduce;
+ function GetHashCode(const Value: TCollection): Integer;
+ reintroduce;
+ end;
/// Creates a collection record.
/// TCollectionID [in] Unique ID of the
/// collection. Must not be null.
@@ -726,5 +737,22 @@ class function TCollectionFormatInfo.IndexOf(
Exit(Idx);
end;
+{ TCollection.TComparer }
+
+function TCollection.TComparer.Compare(const Left, Right: TCollection): Integer;
+begin
+ Result := TCollectionID.Compare(Left.UID, Right.UID);
+end;
+
+function TCollection.TComparer.Equals(const Left, Right: TCollection): Boolean;
+begin
+ Result := Left.UID = Right.UID;
+end;
+
+function TCollection.TComparer.GetHashCode(const Value: TCollection): Integer;
+begin
+ Result := Value.UID.Hash;
+end;
+
end.
From d54c34caa71971032e68156c629972cec546a26e Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 16 Nov 2024 16:52:23 +0000
Subject: [PATCH 098/222] Add new methods to license & copyright records
Added new TDBLicenseInfo.CreateNull and TDBCopyrightInfo.CreateNull
methods to create null version of each record, with all fields set to
empty strings.
Added new TDBCopyrightInfo.ToString method to return a string
representation of all non-empty fields in the record.
---
Src/DB.UMetaData.pas | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/Src/DB.UMetaData.pas b/Src/DB.UMetaData.pas
index b2c037dae..630657a47 100644
--- a/Src/DB.UMetaData.pas
+++ b/Src/DB.UMetaData.pas
@@ -46,6 +46,9 @@ TDBLicenseInfo = record
/// Record constructor: sets all fields of record.
/// Any or all parameters may be the empty string
constructor Create(const AName, ASPDX, AURL, AText: string);
+ /// Creates and returns a null record with all fields set to the
+ /// empty string.
+ class function CreateNull: TDBLicenseInfo; static;
/// Name of license.
property Name: string read fName;
/// Open Source Initiative SPDX short idenitifier for licenses.
@@ -76,6 +79,9 @@ TDBCopyrightInfo = record
/// Record constructor: sets all fields of record.
/// Any or all parameters may be the empty string
constructor Create(const ADate, AHolder, AHolderURL: string);
+ /// Creates and returns a null record with all fields set to the
+ /// empty string.
+ class function CreateNull: TDBCopyrightInfo; static;
/// Copyright date.
/// May be a single year or a range: e.g. 2020 or 2012-2016.
///
@@ -85,6 +91,9 @@ TDBCopyrightInfo = record
/// URL of main copyright holder.
/// Optional.
property HolderURL: string read fHolderURL;
+ /// Creates and returns a string representation of all the
+ /// non-empty fields of the record.
+ function ToString: string;
end;
/// Interface that provides information about any meta data
@@ -143,6 +152,11 @@ constructor TDBLicenseInfo.Create(const AName, ASPDX, AURL, AText: string);
fText := AText;
end;
+class function TDBLicenseInfo.CreateNull: TDBLicenseInfo;
+begin
+ Result := TDBLicenseInfo.Create('', '', '', '');
+end;
+
function TDBLicenseInfo.NameWithURL: string;
begin
Result := fName;
@@ -159,4 +173,32 @@ constructor TDBCopyrightInfo.Create(const ADate, AHolder, AHolderURL: string);
fHolderURL := AHolderURL;
end;
+class function TDBCopyrightInfo.CreateNull: TDBCopyrightInfo;
+begin
+ Result := TDBCopyrightInfo.Create('', '', '');
+end;
+
+function TDBCopyrightInfo.ToString: string;
+resourcestring
+ sCopyright = 'Copyright';
+begin
+ Result := '';
+ if Date <> '' then
+ Result := Result + '(C) ' + Date;
+ if Holder <> '' then
+ begin
+ if Result <> '' then
+ Result := Result + ', ';
+ Result := Result + Holder;
+ end;
+ if HolderURL <> '' then
+ begin
+ if Result <> '' then
+ Result := Result + ', ';
+ Result := Result + HolderURL;
+ end;
+ if Result <> '' then
+ Result := sCopyright + ' ' + Result;
+end;
+
end.
From 26a9e9420b26b5f4d86b51a770824f1f7fe4cd89 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 16 Nov 2024 18:50:21 +0000
Subject: [PATCH 099/222] Add meta data factory class with registrar
Added new TMetaDataFactory class to DB.UMetaData unit with method to
create a meta data class appropriate to a given collection.
Classes that interpret meta data for a specific collection format make
themselves available to the factory by registering their class type
with it for a specified collection data format.
A new TNullMetaData class was added to provide a do-nothing meta data
class that the factory creates whenever there is no registered class
that provides meta data for a collection's data format.
Updated DBIO.MetaData.DCSC unit to register a suitable class to provide
meta data for the DelphiDabbler Code Snippets Collection data format.
---
Src/DB.UMetaData.pas | 178 +++++++++++++++++++++++++++++++++++++
Src/DBIO.MetaData.DCSC.pas | 19 +++-
2 files changed, 196 insertions(+), 1 deletion(-)
diff --git a/Src/DB.UMetaData.pas b/Src/DB.UMetaData.pas
index 630657a47..af4eefb8f 100644
--- a/Src/DB.UMetaData.pas
+++ b/Src/DB.UMetaData.pas
@@ -17,7 +17,10 @@ interface
uses
+ // Delphi
+ Generics.Collections,
// Project
+ DB.UCollections,
UIStringList,
UVersionInfo;
@@ -138,9 +141,99 @@ TDBCopyrightInfo = record
procedure Refresh;
end;
+ /// Base class for all classes that implement IDBMetaData
+ /// and can also be registered with TMetaDataFactory.
+ TRegisterableMetaData = class abstract(TInterfacedObject)
+ public
+ /// Creates an instance of a concrete descendant of this class.
+ ///
+ /// TCollection [in] Collection associated
+ /// with the meta data being created.
+ /// IDBMetaData. Required meta data object.
+ class function Instance(ACollection: TCollection): IDBMetaData;
+ virtual; abstract;
+ end;
+
+ TRegisterableMetaDataClass = class of TRegisterableMetaData;
+
+ /// Advanced record manages the registration and creation of meta
+ /// data objects for different collection data formats.
+ TMetaDataFactory = record
+ strict private
+ class var
+ /// Map of collection format kinds to functions that create
+ /// meta data objects of the required type.
+ fCallbackMap: TDictionary<
+ TCollectionFormatKind, TRegisterableMetaDataClass
+ >;
+ public
+ class constructor Create;
+ class destructor Destroy;
+ /// Registers a class type that can create a meta data object for
+ /// a given collection data format kind.
+ /// TCollectionFormatKind [in] Collection data
+ /// format for which the meta data class is being registered.
+ /// TRegisterableMetaDataClass [in] Type of
+ /// class to create.
+ class procedure RegisterCreator(AFormat: TCollectionFormatKind;
+ AClass: TRegisterableMetaDataClass); static;
+ /// Creates a meta data object instance that can read a given
+ /// collection data format.
+ /// TCollection [in] Collection for which
+ /// meta data reader object is required.
+ /// IDBMetaData. Requested object. May be a null object if
+ /// no meta data class was registered for the data format associated with
+ /// ACollection.
+ class function CreateInstance(const ACollection: TCollection):
+ IDBMetaData; static;
+ end;
implementation
+type
+ /// Implements a null, do nothing, meta data object.
+ /// Instance of this class are used when a collection format does
+ /// not support meta data.
+ TNullMetaData = class(TInterfacedObject, IDBMetaData)
+ public
+ /// Returns information about what, if any, meta data is supported
+ /// by a collection.
+ function GetCapabilities: TMetaDataCapabilities;
+ /// Returns the collection's version number.
+ /// A null version number is returned if the collection does not
+ /// include Version in its capabilities.
+ function GetVersion: TVersionNumber;
+ /// Returns the collection's license information.
+ /// Return value is meaningless if the collection does not include
+ /// License in its capabilities.
+ function GetLicenseInfo: TDBLicenseInfo;
+ /// Returns the collection's copyright informatiom.
+ /// Return value is meaningless if the collection does not include
+ /// Copyright in its capabilities.
+ function GetCopyrightInfo: TDBCopyrightInfo;
+ /// Returns a list of contributors to the collection.
+ /// Return value is meaningless if the collection does not include
+ /// Contributors in its capabilities.
+ function GetContributors: IStringList;
+ /// Returns a list of testers of the collection.
+ /// Return value is meaningless if the collection does not include
+ /// Testers in its capabilities.
+ function GetTesters: IStringList;
+ /// Checks if meta data is recognised as belonging to a valid
+ /// collection, whether supported or not.
+ function IsRecognised: Boolean;
+ /// Checks if meta data is recognised as belonging to a supported
+ /// collection version.
+ function IsSupportedVersion: Boolean;
+ /// Checks if meta data is corrupt.
+ /// Should only be called if meta data belongs to a supported
+ /// collection. An exception should be raised if called on unsupported
+ /// versions.
+ function IsCorrupt: Boolean;
+ /// Refreshes the meta information by re-reading from collection
+ /// meta files.
+ procedure Refresh;
+ end;
{ TDBLicenseInfo }
@@ -201,4 +294,89 @@ function TDBCopyrightInfo.ToString: string;
Result := sCopyright + ' ' + Result;
end;
+{ TMetaDataFactory }
+
+class constructor TMetaDataFactory.Create;
+begin
+ fCallbackMap := TDictionary<
+ TCollectionFormatKind, TRegisterableMetaDataClass
+ >.Create;
+end;
+
+class function TMetaDataFactory.CreateInstance(const ACollection: TCollection):
+ IDBMetaData;
+begin
+ if fCallbackMap.ContainsKey(ACollection.CollectionFormatKind) then
+ Result := fCallbackMap[ACollection.CollectionFormatKind].Instance(
+ ACollection
+ )
+ else
+ Result := TNullMetaData.Create;
+end;
+
+class destructor TMetaDataFactory.Destroy;
+begin
+ fCallBackMap.Free;
+end;
+
+class procedure TMetaDataFactory.RegisterCreator(
+ AFormat: TCollectionFormatKind; AClass: TRegisterableMetaDataClass);
+begin
+ fCallbackMap.AddOrSetValue(AFormat, AClass);
+end;
+
+{ TNullMetaData }
+
+function TNullMetaData.GetCapabilities: TMetaDataCapabilities;
+begin
+ Result := [];
+end;
+
+function TNullMetaData.GetContributors: IStringList;
+begin
+ Result := TIStringList.Create;
+end;
+
+function TNullMetaData.GetCopyrightInfo: TDBCopyrightInfo;
+begin
+ Result := TDBCopyrightInfo.CreateNull;
+end;
+
+function TNullMetaData.GetLicenseInfo: TDBLicenseInfo;
+begin
+ Result := TDBLicenseInfo.CreateNull;
+end;
+
+function TNullMetaData.GetTesters: IStringList;
+begin
+ Result := TIStringList.Create;
+end;
+
+function TNullMetaData.GetVersion: TVersionNumber;
+begin
+ Result := TVersionNumber.Nul;
+end;
+
+function TNullMetaData.IsCorrupt: Boolean;
+resourcestring
+ sNotSupportedError = 'Can''t call IDBMetaData.IsCorrupt for null meta data';
+begin
+ raise ENotSupportedException.Create(sNotSupportedError);
+end;
+
+function TNullMetaData.IsRecognised: Boolean;
+begin
+ Result := False;
+end;
+
+function TNullMetaData.IsSupportedVersion: Boolean;
+begin
+ Result := False;
+end;
+
+procedure TNullMetaData.Refresh;
+begin
+ // Do nothing
+end;
+
end.
diff --git a/Src/DBIO.MetaData.DCSC.pas b/Src/DBIO.MetaData.DCSC.pas
index 933554f3e..205eaa738 100644
--- a/Src/DBIO.MetaData.DCSC.pas
+++ b/Src/DBIO.MetaData.DCSC.pas
@@ -98,6 +98,7 @@ interface
SysUtils,
Types,
// VCL
+ DB.UCollections,
DB.UMetaData,
UIStringList,
UStructs,
@@ -314,7 +315,7 @@ TDBMetaFilesFactory = record
/// Abstract base class for classes that provide main database meta
/// data.
- TAbstractMainDBMetaData = class abstract(TInterfacedObject)
+ TAbstractMainDBMetaData = class abstract(TRegisterableMetaData)
strict private
var
fMetaFiles: TDBMetaFiles;
@@ -331,6 +332,10 @@ TAbstractMainDBMetaData = class abstract(TInterfacedObject)
strict protected
function GetDBDir: string; virtual; abstract;
public
+ /// Creates an instance of meta data object that can read this
+ /// collection's format.
+ /// Must be called from a concrete descendant class.
+ class function Instance(ACollection: TCollection): IDBMetaData; override;
procedure AfterConstruction; override;
destructor Destroy; override;
/// Returns information about what, if any, meta data is supported
@@ -512,6 +517,12 @@ function TAbstractMainDBMetaData.GetVersion: TVersionNumber;
Result := fVersion;
end;
+class function TAbstractMainDBMetaData.Instance(
+ ACollection: DB.UCollections.TCollection): IDBMetaData;
+begin
+ Result := TMainDBMetaDataFactory.MainDBMetaDataInstance;
+end;
+
function TAbstractMainDBMetaData.IsCorrupt: Boolean;
resourcestring
sNotSupportedError = 'Can''t call IDBMetaData.IsCorrupt for an unsupported '
@@ -837,4 +848,10 @@ class function TDBMetaFilesFactory.GetInstance(const DBDir: string):
end;
end;
+initialization
+
+TMetaDataFactory.RegisterCreator(
+ TCollectionFormatKind.DCSC_v2, TMainDBMetaData
+);
+
end.
From 0dbf89515d2bdd2c79cf816ebd667dcd669390ce Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 16 Nov 2024 19:37:44 +0000
Subject: [PATCH 100/222] Update snippet docs code re revised meta data
Modified the information that TSnippetDoc and descendants write to the
generated documents to work with the recent changes to how meta data
works with collections.
Information is now written about all collections rather than just the
"main database". License information is now for any collection whose
data format supports it.
Some methods in TSnippetDoc were renamed along with their implementation
in descended classes.
---
Src/URTFSnippetDoc.pas | 27 +++++++++++-----------
Src/USnippetDoc.pas | 50 ++++++++++++++++++++---------------------
Src/UTextSnippetDoc.pas | 17 +++++++-------
3 files changed, 46 insertions(+), 48 deletions(-)
diff --git a/Src/URTFSnippetDoc.pas b/Src/URTFSnippetDoc.pas
index 3c560586d..73afd5899 100644
--- a/Src/URTFSnippetDoc.pas
+++ b/Src/URTFSnippetDoc.pas
@@ -107,9 +107,8 @@ TRTFSnippetDoc = class(TSnippetDoc)
/// Active text formatting is observed and styled to suit
/// document.
procedure RenderExtra(const ExtraText: IActiveText); override;
- /// Adds given information about code snippets database to
- /// document.
- procedure RenderDBInfo(const Text: string); override;
+ /// Output given information about a collection.
+ procedure RenderCollectionInfo(const Text: string); override;
/// Finalises document and returns content as encoded data.
///
function FinaliseDoc: TEncodedData; override;
@@ -321,6 +320,17 @@ procedure TRTFSnippetDoc.InitStyles;
end;
end;
+procedure TRTFSnippetDoc.RenderCollectionInfo(const Text: string);
+begin
+ fBuilder.SetParaSpacing(TRTFParaSpacing.Create(ParaSpacing, 0.0));
+ fBuilder.SetFontSize(DBInfoFontSize);
+ fBuilder.SetFontStyle([fsItalic]);
+ fBuilder.AddText(Text);
+ fBuilder.EndPara;
+ fBuilder.ClearParaFormatting;
+ fBuilder.ResetCharStyle;
+end;
+
procedure TRTFSnippetDoc.RenderCompilerInfo(const Heading: string;
const Info: TCompileDocInfoArray);
@@ -376,17 +386,6 @@ procedure TRTFSnippetDoc.RenderCompilerInfo(const Heading: string;
end;
end;
-procedure TRTFSnippetDoc.RenderDBInfo(const Text: string);
-begin
- fBuilder.SetParaSpacing(TRTFParaSpacing.Create(ParaSpacing, 0.0));
- fBuilder.SetFontSize(DBInfoFontSize);
- fBuilder.SetFontStyle([fsItalic]);
- fBuilder.AddText(Text);
- fBuilder.EndPara;
- fBuilder.ClearParaFormatting;
- fBuilder.ResetCharStyle;
-end;
-
procedure TRTFSnippetDoc.RenderDescription(const Desc: IActiveText);
var
RTFWriter: TActiveTextRTF; // Object that generates RTF from active text
diff --git a/Src/USnippetDoc.pas b/Src/USnippetDoc.pas
index 97ab36023..765543073 100644
--- a/Src/USnippetDoc.pas
+++ b/Src/USnippetDoc.pas
@@ -54,8 +54,10 @@ TSnippetDoc = class(TObject)
/// information for given snippet.
function CompilerInfo(const Snippet: TSnippet): TCompileDocInfoArray;
/// Generates and returns a string containing information about
- /// the main database.
- function MainDBInfo: string;
+ /// the given collection.
+ /// Information includes license and copyright information if
+ /// the collection's data format supports it.
+ function CollectionInfo(const ACollectionID: TCollectionID): string;
strict protected
/// Initialise document.
/// Does nothing. Descendant classes should perform any required
@@ -90,9 +92,8 @@ TSnippetDoc = class(TObject)
/// Active text must be interpreted in a manner that makes sense
/// for document format.
procedure RenderExtra(const ExtraText: IActiveText); virtual; abstract;
- /// Output given information about code snippets database.
- ///
- procedure RenderDBInfo(const Text: string); virtual; abstract;
+ /// Output given information about a collection.
+ procedure RenderCollectionInfo(const Text: string); virtual; abstract;
/// Finalise document and return content as encoded data.
///
/// Descendant classes should perform any required finalisation
@@ -128,6 +129,24 @@ implementation
{ TSnippetDoc }
+function TSnippetDoc.CollectionInfo(const ACollectionID: TCollectionID): string;
+resourcestring
+ sCollectionInfo = 'A snippet from the "%s" collection.';
+var
+ MetaData: IDBMetaData;
+ Collection: TCollection;
+begin
+ Collection := TCollections.Instance.GetCollection(ACollectionID);
+ Result := Format(sCollectionInfo, [Collection.Name]);
+ MetaData := TMetaDataFactory.CreateInstance(Collection);
+ if mdcLicense in MetaData.GetCapabilities then
+ begin
+ Result := Result + ' ' + MetaData.GetLicenseInfo.NameWithURL + '.';
+ if (mdcCopyright in MetaData.GetCapabilities) then
+ Result := Result + ' ' + MetaData.GetCopyrightInfo.ToString + '.';
+ end;
+end;
+
function TSnippetDoc.CommaList(const List: IStringList): string;
resourcestring
sNone = 'None.'; // string output for empty lists
@@ -203,9 +222,7 @@ function TSnippetDoc.Generate(const Snippet: TSnippet): TEncodedData;
end;
if Snippet.Extra.HasContent then
RenderExtra(Snippet.Extra);
- if Snippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID then
- // database info written only if snippet is from main database
- RenderDBInfo(MainDBInfo);
+ RenderCollectionInfo(CollectionInfo(Snippet.CollectionID));
Result := FinaliseDoc;
end;
@@ -214,23 +231,6 @@ procedure TSnippetDoc.InitialiseDoc;
// Do nothing
end;
-function TSnippetDoc.MainDBInfo: string;
-resourcestring
- sMainDBInfo = 'A snippet from the DelphiDabbler Code Snippets Database '
- + '(%0:s), licensed under the %1:s.';
-var
- DBMetaData: IDBMetaData;
-begin
- DBMetaData := TMainDBMetaDataFactory.MainDBMetaDataInstance;
- Result := Format(
- sMainDBInfo,
- [
- TURL.CodeSnipRepo,
- DBMetaData.GetLicenseInfo.NameWithURL
- ]
- );
-end;
-
function TSnippetDoc.SnippetsToStrings(const SnippetList: TSnippetList):
IStringList;
var
diff --git a/Src/UTextSnippetDoc.pas b/Src/UTextSnippetDoc.pas
index 4e7710b5b..f131dd624 100644
--- a/Src/UTextSnippetDoc.pas
+++ b/Src/UTextSnippetDoc.pas
@@ -78,9 +78,8 @@ TTextSnippetDoc = class(TSnippetDoc)
/// Active text is converted to word-wrapped plain text
/// paragraphs.
procedure RenderExtra(const ExtraText: IActiveText); override;
- /// Adds given information about code snippets database to
- /// document.
- procedure RenderDBInfo(const Text: string); override;
+ /// Output given information about a collection.
+ procedure RenderCollectionInfo(const Text: string); override;
/// Finalises document and returns content as encoded data.
///
function FinaliseDoc: TEncodedData; override;
@@ -126,6 +125,12 @@ procedure TTextSnippetDoc.RenderActiveText(ActiveText: IActiveText);
end;
end;
+procedure TTextSnippetDoc.RenderCollectionInfo(const Text: string);
+begin
+ fWriter.WriteLine;
+ fWriter.WriteLine(StrWrap(Text, cPageWidth, 0));
+end;
+
procedure TTextSnippetDoc.RenderCompilerInfo(const Heading: string;
const Info: TCompileDocInfoArray);
var
@@ -146,12 +151,6 @@ procedure TTextSnippetDoc.RenderCompilerInfo(const Heading: string;
);
end;
-procedure TTextSnippetDoc.RenderDBInfo(const Text: string);
-begin
- fWriter.WriteLine;
- fWriter.WriteLine(StrWrap(Text, cPageWidth, 0));
-end;
-
procedure TTextSnippetDoc.RenderDescription(const Desc: IActiveText);
begin
fWriter.WriteLine;
From 4057dee79a01f6a60953aca0ae3398809a98a765 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 16 Nov 2024 18:57:48 +0000
Subject: [PATCH 101/222] Change header comments in generated source code
Updated USnippetSourceGen & USaveUnitMgr re revised meta data code.
Modified the information that is written in header comments
to work with the recent changes to how meta data works with collections.
Header comments no longer only contain license information for the "main
database" but now provide license information for any collection whose
data format supports it.
In addition all the collections providing snippets in the source code
are bullet listed.
---
Src/USaveUnitMgr.pas | 133 ++++++++++++++++++++------------------
Src/USnippetSourceGen.pas | 122 +++++++++++++++++-----------------
2 files changed, 134 insertions(+), 121 deletions(-)
diff --git a/Src/USaveUnitMgr.pas b/Src/USaveUnitMgr.pas
index ca02bd04f..6b13e0d50 100644
--- a/Src/USaveUnitMgr.pas
+++ b/Src/USaveUnitMgr.pas
@@ -17,8 +17,15 @@ interface
uses
+ // Delphi
+ Generics.Collections,
// Project
- DB.USnippet, UIStringList, USourceFileInfo, USaveSourceMgr, USourceGen;
+ DB.UCollections,
+ DB.USnippet,
+ UIStringList,
+ USourceFileInfo,
+ USaveSourceMgr,
+ USourceGen;
type
@@ -38,9 +45,9 @@ TSaveUnitMgr = class(TSaveSourceMgr)
/// Name of generated unit.
/// If empty string a default name is used.
fUnitName: string;
- /// Flag true if unit contains at least one snippet from main
- /// database, False only if unit is completely user defined.
- fContainsMainDBSnippets: Boolean;
+ /// List of collections that have contributed snippets to the
+ /// source code being generated.
+ fCollections: TList;
/// Gets name of unit to be used in generated code.
function UnitName: string;
/// Creates a string list containing comments to be written to
@@ -96,12 +103,8 @@ implementation
// Delphi
SysUtils,
// Project
- DB.UCollections,
DB.UMetaData,
- DBIO.MetaData.DCSC,
UAppInfo,
- UConsts,
- UUrl,
UUtils;
@@ -118,16 +121,10 @@ implementation
// Error message
sErrorMsg = 'Filename is not valid for a Pascal unit';
// Unit header comments
- sLicense = 'The unit is copyright '
- + COPYRIGHT
- + ' %0:s by %1:s and is licensed under the %2:s.';
- sMainDescription = 'This unit was generated automatically. It incorporates a '
- + 'selection of source code taken from the Code Snippets Database at %0:s.';
- sGenerated = 'Generated on : %0:s.';
- sGenerator = 'Generated by : %0:s %1:s.';
- sAdvert = 'The latest version of %0:s is available from the CodeSnip GitHub '
- + 'project at %1:s.';
- sUserDescription = 'This unit was generated automatically.';
+ sMainGenerator = 'This unit snippet was generated by %0:s %1:s on %2:s.';
+ sCollection = 'The code was sourced from the %s collection.';
+ sCollectionList = 'The code was sourced from the following collections:';
+ sCollectionCredit = 'Collection "%0:s" is licensed under the %1:s.';
// Output document title
sDocTitle = 'Pascal unit generated by %s';
@@ -148,54 +145,64 @@ procedure TSaveUnitMgr.CheckFileName(const FileName: string;
end;
function TSaveUnitMgr.CreateHeaderComments: IStringList;
+
+ {TODO -cRefactoring: This code has a lot in common with header comment
+ generator code in USnippetSourceGen - extract common code.}
+
+ function CreditsLine(const ACollection: TCollection): string;
+ var
+ DBMetaData: IDBMetaData;
+ begin
+ DBMetaData := TMetaDataFactory.CreateInstance(ACollection);
+ Result := '';
+ if mdcLicense in DBMetaData.GetCapabilities then
+ begin
+ Result := Result + DBMetaData.GetLicenseInfo.NameWithURL + '.';
+ if (mdcCopyright in DBMetaData.GetCapabilities) then
+ Result := Result + ' ' + DBMetaData.GetCopyrightInfo.ToString + '.';
+ end;
+ end;
+
var
- DBMetaData: IDBMetaData;
+ Collection: TCollection;
+ Credits: string;
begin
Result := TIStringList.Create;
- if fContainsMainDBSnippets then
- begin
- // Result used for units that contain any snippet(s) from main database
- Result.Add(Format(sMainDescription, [TURL.CodeSnippetsDBRepo]));
- Result.Add('');
- DBMetaData := TMainDBMetaDataFactory.MainDBMetaDataInstance;
- Result.Add(
- Format(
- sLicense,
- [
- DBMetaData.GetCopyrightInfo.Date,
- DBMetaData.GetCopyrightInfo.Holder,
- DBMetaData.GetLicenseInfo.NameWithURL
- ]
- )
- );
- Result.Add('');
- Result.Add(Format(sGenerated, [RFC1123DateStamp]));
- Result.Add(
- Format(
- sGenerator, [TAppInfo.FullProgramName, TAppInfo.ProgramReleaseInfo]
- )
- );
- Result.Add('');
- Result.Add(
- Format(sAdvert, [TAppInfo.ProgramName, TURL.CodeSnipRepo])
- );
- end
+
+ Result.Add(
+ Format(
+ sMainGenerator,
+ [TAppInfo.FullProgramName, TAppInfo.ProgramReleaseInfo, RFC1123DateStamp]
+ )
+ );
+
+ Result.Add('');
+ if fCollections.Count = 1 then
+ Result.Add(Format(sCollection, [fCollections[0].Name]))
else
begin
- // Result used for units that contain only user defined snippets
- Result.Add(sUserDescription);
- Result.Add('');
- Result.Add(Format(sGenerated, [RFC1123DateStamp]));
- Result.Add(
- Format(
- sGenerator, [TAppInfo.FullProgramName, TAppInfo.ProgramReleaseInfo]
- )
- );
+ Result.Add(sCollectionList);
+ for Collection in fCollections do
+ begin
+ Result.Add(' - ' + Collection.Name);
+ end;
+ end;
+
+ for Collection in fCollections do
+ begin
+ Credits := CreditsLine(Collection);
+ if Credits <> '' then
+ begin
+ Result.Add('');
+ Result.Add(Format(sCollectionCredit, [Collection.Name, Credits]));
+ end;
end;
+
end;
destructor TSaveUnitMgr.Destroy;
begin
+ fCollections.Free;
fSourceGen.Free;
inherited;
end;
@@ -252,23 +259,23 @@ function TSaveUnitMgr.GetFileTypeDesc(const FileType: TSourceFileType): string;
constructor TSaveUnitMgr.InternalCreate(const Snips: TSnippetList);
var
Snippet: TSnippet; // references each snippet in list
+ Collection: TCollection;
begin
Assert(Assigned(Snips), ClassName + '.InternalCreate: Snips is nil');
inherited InternalCreate;
+ fCollections := TList.Create(TCollection.TComparer.Create);
+
// Create source generator and initialize it with required snippets
fSourceGen := TSourceGen.Create;
fSourceGen.IncludeSnippets(Snips);
- // Determine if snippet list contains at least one snippet from main database
- fContainsMainDBSnippets := False;
+ // Count the number of collections containing snippet in the list
for Snippet in Snips do
begin
- if Snippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID then
- begin
- fContainsMainDBSnippets := True;
- Break;
- end;
+ Collection := TCollections.Instance.GetCollection(Snippet.CollectionID);
+ if not fCollections.Contains(Collection) then
+ fCollections.Add(Collection);
end;
end;
diff --git a/Src/USnippetSourceGen.pas b/Src/USnippetSourceGen.pas
index c3855ae64..b30a35883 100644
--- a/Src/USnippetSourceGen.pas
+++ b/Src/USnippetSourceGen.pas
@@ -17,8 +17,15 @@ interface
uses
+ // Delphi
+ Generics.Collections,
// Project
- UBaseObjects, UIStringList, USourceGen, UView;
+ DB.UCollections,
+ DB.UMetaData,
+ UBaseObjects,
+ UIStringList,
+ USourceGen,
+ UView;
type
@@ -30,9 +37,9 @@ interface
}
TSnippetSourceGen = class sealed(TNoPublicConstructObject)
strict private
- fContainsMainDBSnippets: Boolean;
- {Flag true if source code contains at least one snippet from main
- database, False only if source code is completely user defined}
+ /// List of collections that have contributed snippets to the
+ /// source code being generated.
+ fCollections: TList;
fGenerator: TSourceGen;
{Object used to generate the source code}
procedure Initialize(View: IView);
@@ -87,8 +94,6 @@ implementation
// Delphi
SysUtils,
// Project
- DB.UCollections,
- DB.UMetaData,
DB.USnippet,
DB.USnippetKind,
DBIO.MetaData.DCSC,
@@ -106,59 +111,60 @@ function TSnippetSourceGen.BuildHeaderComments: IStringList;
}
var
DBMetaData: IDBMetaData;
+ Collection: TCollection;
+ Credits: string;
resourcestring
// Comment to be included at top of snippet
// when snippets include those from main database
- sMainDBGenerator = 'This code snippet was generated by %0:s %1:s on %2:s.';
- sMainDBLicense = 'It includes code taken from the DelphiDabbler Code '
- + 'Snippets database that is copyright '
- + COPYRIGHT
- + ' %0:s by %1:s and is licensed under the %2:s.';
- // when snippets are all from user defined database
- sUserGenerator = 'This user defined code snippet was generated by '
- + '%0:s %1:s on %2:s.';
+ sMainGenerator = 'This code snippet was generated by %0:s %1:s on %2:s.';
+ sCollection = 'The code was sourced from the %s collection.';
+ sCollectionList = 'The code was sourced from the following collections:';
+ sCollectionCredit = 'Collection "%0:s" is licensed under the %1:s';
+
+ function CreditsLine(const ACollection: TCollection): string;
+ begin
+ DBMetaData := TMetaDataFactory.CreateInstance(ACollection);
+ Result := '';
+ if mdcLicense in DBMetaData.GetCapabilities then
+ begin
+ Result := Result + DBMetaData.GetLicenseInfo.NameWithURL + '.';
+ if (mdcCopyright in DBMetaData.GetCapabilities) then
+ Result := Result + ' ' + DBMetaData.GetCopyrightInfo.ToString + '.';
+ end;
+ end;
+
begin
- // Header depends on whether snippets contain any from main database or are
- // all user defined
Result := TIStringList.Create;
- if fContainsMainDBSnippets then
- begin
- Result.Add(
- Format(
- sMainDBGenerator,
- [
- TAppInfo.FullProgramName,
- TAppInfo.ProgramReleaseInfo,
- RFC1123DateStamp
- ]
- )
- );
- Result.Add('');
- DBMetaData := TMainDBMetaDataFactory.MainDBMetaDataInstance;
- Result.Add(
- Format(
- sMainDBLicense,
- [
- DBMetaData.GetCopyrightInfo.Date,
- DBMetaData.GetCopyrightInfo.Holder,
- DBMetaData.GetLicenseInfo.NameWithURL
- ]
- )
- );
- end
+
+ Result.Add(
+ Format(
+ sMainGenerator,
+ [TAppInfo.FullProgramName, TAppInfo.ProgramReleaseInfo, RFC1123DateStamp]
+ )
+ );
+
+ Result.Add('');
+ if fCollections.Count = 1 then
+ Result.Add(Format(sCollection, [fCollections[0].Name]))
else
begin
- Result.Add(
- Format(
- sUserGenerator,
- [
- TAppInfo.FullProgramName,
- TAppInfo.ProgramReleaseInfo,
- RFC1123DateStamp
- ]
- )
- );
+ Result.Add(sCollectionList);
+ for Collection in fCollections do
+ begin
+ Result.Add(' - ' + Collection.Name);
+ end;
+ end;
+
+ for Collection in fCollections do
+ begin
+ Credits := CreditsLine(Collection);
+ if Credits <> '' then
+ begin
+ Result.Add('');
+ Result.Add(Format(sCollectionCredit, [Collection.Name, Credits]));
+ end;
end;
+
end;
class function TSnippetSourceGen.CanGenerate(View: IView): Boolean;
@@ -191,6 +197,7 @@ destructor TSnippetSourceGen.Destroy;
{Class destructor. Tears down object.
}
begin
+ fCollections.Free;
fGenerator.Free;
inherited;
end;
@@ -237,15 +244,15 @@ procedure TSnippetSourceGen.Initialize(View: IView);
var
Snips: TSnippetList; // list of snippets in a category to display
Snippet: TSnippet; // a snippet in Snips list
+ Collection: TCollection;
begin
- fContainsMainDBSnippets := False;
// Record required snippet(s)
if Supports(View, ISnippetView) then
begin
// view is single snippet: just record that
Snippet := (View as ISnippetView).Snippet;
fGenerator.IncludeSnippet(Snippet);
- fContainsMainDBSnippets := Snippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID;
+ fCollections.Add(TCollections.Instance.GetCollection(Snippet.CollectionID));
end
else
begin
@@ -256,11 +263,9 @@ procedure TSnippetSourceGen.Initialize(View: IView);
fGenerator.IncludeSnippets(Snips); // ignores freeform snippets
for Snippet in Snips do
begin
- if Snippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID then
- begin
- fContainsMainDBSnippets := True;
- Break;
- end;
+ Collection := TCollections.Instance.GetCollection(Snippet.CollectionID);
+ if not fCollections.Contains(Collection) then
+ fCollections.Add(Collection);
end;
finally
Snips.Free;
@@ -278,6 +283,7 @@ constructor TSnippetSourceGen.InternalCreate(View: IView);
Assert(CanGenerate(View), ClassName + '.InternalCreate: View not supported');
inherited InternalCreate;
fGenerator := TSourceGen.Create;
+ fCollections := TList.Create(TCollection.TComparer.Create);
Initialize(View);
end;
From 6ca6e569128b493acd166cd51003ea05b4b369d5 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 17 Nov 2024 14:54:45 +0000
Subject: [PATCH 102/222] Modify About box database tab to show collection info
Replaced the About box's "About The Database" tab with an "About
Collections" tab that asks user to choose a collection and then shows
any meta data associated with the collection. The data is shown, grouped
by type, in a tree view. Where the collection has no meta data, a
message for that is shown.
Redundant code was deleted and there was some renaming for clarity.
The dlg-about-database-tplt.html HTML template file used the the "About
The Database" tab was deleted and its reference was removed from
HTML.hrc.
---
Src/FmAboutDlg.dfm | 61 ++---
Src/FmAboutDlg.pas | 274 ++++++++++------------
Src/HTML.hrc | 1 -
Src/Res/HTML/dlg-about-database-tplt.html | 114 ---------
4 files changed, 156 insertions(+), 294 deletions(-)
delete mode 100644 Src/Res/HTML/dlg-about-database-tplt.html
diff --git a/Src/FmAboutDlg.dfm b/Src/FmAboutDlg.dfm
index cfc0062f7..6f30713ad 100644
--- a/Src/FmAboutDlg.dfm
+++ b/Src/FmAboutDlg.dfm
@@ -63,37 +63,42 @@ inherited AboutDlg: TAboutDlg
end
end
end
- object tsDatabase: TTabSheet
- Caption = 'About The Database'
+ object tsCollections: TTabSheet
+ Caption = 'About Collections'
ImageIndex = 1
- inline frmDatabase: THTMLTpltDlgFrame
- Left = 0
+ DesignSize = (
+ 401
+ 190)
+ object lblCollection: TLabel
+ Left = 3
+ Top = 3
+ Width = 80
+ Height = 13
+ Caption = '&Select collection:'
+ FocusControl = cbCollection
+ end
+ object cbCollection: TComboBox
+ Left = 112
Top = 0
- Width = 401
- Height = 190
- Align = alClient
+ Width = 286
+ Height = 21
+ Style = csDropDownList
+ Anchors = [akLeft, akTop, akRight]
TabOrder = 0
- TabStop = True
- ExplicitWidth = 401
- ExplicitHeight = 190
- inherited pnlBrowser: TPanel
- Width = 401
- Height = 190
- ExplicitWidth = 401
- ExplicitHeight = 190
- inherited wbBrowser: TWebBrowser
- Width = 401
- Height = 190
- ExplicitWidth = 345
- ExplicitHeight = 133
- ControlData = {
- 4C00000072290000A31300000000000000000000000000000000000000000000
- 000000004C000000000000000000000001000000E0D057007335CF11AE690800
- 2B2E126208000000000000004C0000000114020000000000C000000000000046
- 8000000000000000000000000000000000000000000000000000000000000000
- 00000000000000000100000000000000000000000000000000000000}
- end
- end
+ OnChange = cbCollectionChange
+ end
+ object tvCollectionInfo: TTreeView
+ Left = 0
+ Top = 27
+ Width = 401
+ Height = 163
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ BorderStyle = bsNone
+ Indent = 19
+ ParentColor = True
+ ReadOnly = True
+ ShowRoot = False
+ TabOrder = 1
end
end
object tsPaths: TTabSheet
diff --git a/Src/FmAboutDlg.pas b/Src/FmAboutDlg.pas
index a15bbd236..7774645cb 100644
--- a/Src/FmAboutDlg.pas
+++ b/Src/FmAboutDlg.pas
@@ -26,11 +26,13 @@ interface
Messages,
// Project
Browser.UHTMLEvents,
+ DB.UCollections,
DB.UMetaData,
FmGenericViewDlg,
FrBrowserBase,
FrHTMLDlg,
FrHTMLTpltDlg,
+ UCollectionListAdapter,
UCSSBuilder,
UIStringList;
@@ -81,16 +83,18 @@ TPathInfoBox = class(TCustomGroupBox)
/// provides access to the program's easter egg.
TAboutDlg = class(TGenericViewDlg)
bvlSeparator: TBevel;
- frmDatabase: THTMLTpltDlgFrame;
frmProgram: THTMLTpltDlgFrame;
pcDetail: TPageControl;
- tsDatabase: TTabSheet;
+ tsCollections: TTabSheet;
tsProgram: TTabSheet;
pnlTitle: TPanel;
frmTitle: THTMLTpltDlgFrame;
tsPaths: TTabSheet;
btnViewAppConfig: TButton;
btnViewUserConfig: TButton;
+ cbCollection: TComboBox;
+ lblCollection: TLabel;
+ tvCollectionInfo: TTreeView;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
/// Handles event triggered when user clicks on one of page
@@ -105,16 +109,16 @@ TAboutDlg = class(TGenericViewDlg)
/// Handles button click event to display per-user config file.
///
procedure btnViewUserConfigClick(Sender: TObject);
+ procedure cbCollectionChange(Sender: TObject);
strict private
var
+ fCollList: TCollectionListAdapter;
/// Control that displays main database folder.
fMainDBPathGp: TPathInfoBox;
/// Control that displays user database folder.
fUserDBPathGp: TPathInfoBox;
/// Control that displays program install path.
fInstallPathGp: TPathInfoBox;
- /// Provides access to main database meta data.
- fMetaData: IDBMetaData;
/// Handles title frame's OnHTMLEvent event. Checks for mouse
/// events relating to display of the easter egg and acts accordingly.
///
@@ -123,12 +127,10 @@ TAboutDlg = class(TGenericViewDlg)
/// information about the event.
procedure HTMLEventHandler(Sender: TObject;
const EventInfo: THTMLEventInfo);
- /// Builds HTML used to display list of contributors or an error
- /// message if the list is empty.
- /// IStringList [in] List of contributors to
- /// display.
- /// string. Required HTML.
- function ContribListHTML(ContribList: IStringList): string;
+ /// Displays any meta data associated with a collection.
+ /// TCollection [in] Collection for which
+ /// meta data is to be displayed.
+ procedure DisplayCollectionInfo(ACollection: TCollection);
/// Displays content of a config file in a dialogue box or an
/// error message if the file does not exist.
/// string [in] Name of config file to display.
@@ -151,14 +153,13 @@ TAboutDlg = class(TGenericViewDlg)
/// TCSSBuilder [in] Object used to update CSS.
///
procedure UpdateTitleCSS(Sender: TObject; const CSSBuilder: TCSSBuilder);
- /// Updates CSS used for HTML displayed in detail frames.
- ///
+ /// Updates CSS used for HTML displayed in About The Program
+ /// tab frame.
/// TObject [in] Not used.
/// TCSSBuilder [in] Object used to update CSS.
///
- /// Details frames form the body of the About Box on the Program
- /// and Database tabs.
- procedure UpdateDetailCSS(Sender: TObject; const CSSBuilder: TCSSBuilder);
+ procedure UpdateProgramTabCSS(Sender: TObject;
+ const CSSBuilder: TCSSBuilder);
public
/// Displays dialog box.
/// TComponent [in] Component that owns this dialogus
@@ -179,9 +180,6 @@ implementation
ShellAPI,
IOUtils,
// Project
- DB.UCollections,
- DB.UMain,
- DBIO.MetaData.DCSC,
FmEasterEgg,
FmPreviewDlg,
UAppInfo,
@@ -192,14 +190,12 @@ implementation
UEncodings,
UFontHelper,
UGraphicUtils,
- UHTMLUtils,
UHTMLTemplate,
UIOUtils,
UMessageBox,
UResourceUtils,
UStrUtils,
- UThemesEx,
- UVersionInfo;
+ UThemesEx;
{$R *.dfm}
@@ -222,6 +218,12 @@ procedure TAboutDlg.ArrangeForm;
var
PathTabHeight: Integer;
begin
+ // Collections tab
+ TCtrlArranger.AlignVCentres(8, [lblCollection, cbCollection]);
+ TCtrlArranger.MoveToRightOf(lblCollection, cbCollection, 12);
+ TCtrlArranger.MoveBelow([lblCollection, cbCollection], tvCollectionInfo, 8);
+
+ // Paths tab
fMainDBPathGp.Top := TCtrlArranger.BottomOf(fInstallPathGp, 8);
fUserDBPathGp.Top := TCtrlArranger.BottomOf(fMainDBPathGp, 8);
TCtrlArranger.AlignTops(
@@ -239,7 +241,7 @@ procedure TAboutDlg.ArrangeForm;
pcDetail.Height - tsProgram.ClientHeight +
Max(
PathTabHeight,
- Max(frmProgram.DocHeight, frmDatabase.DocHeight)
+ frmProgram.DocHeight
) + 8;
pnlBody.ClientHeight := pnlTitle.Height + bvlSeparator.Height +
pcDetail.Height;
@@ -260,6 +262,11 @@ procedure TAboutDlg.btnViewUserConfigClick(Sender: TObject);
ViewConfigFile(TAppInfo.UserConfigFileName, sTitle);
end;
+procedure TAboutDlg.cbCollectionChange(Sender: TObject);
+begin
+ DisplayCollectionInfo(fCollList.Collection(cbCollection.ItemIndex));
+end;
+
procedure TAboutDlg.ConfigForm;
// Creates and initialises a custom path information control with given
@@ -282,8 +289,6 @@ procedure TAboutDlg.ConfigForm;
sUserDBPathGpCaption = 'User Database Directory';
begin
inherited;
- // Create meta data object for main database
- fMetaData := TMainDBMetaDataFactory.MainDBMetaDataInstance;
// Creates required custom controls
fInstallPathGp := CreatePathInfoBox(
sInstallPathGpCaption, TAppInfo.AppExeDir, 0
@@ -296,34 +301,102 @@ procedure TAboutDlg.ConfigForm;
);
btnViewAppConfig.TabOrder := fUserDBPathGp.TabOrder + 1;
btnViewUserConfig.TabOrder := btnViewAppConfig.TabOrder + 1;
+ // Load collections into combo box & select default collection
+ fCollList.ToStrings(cbCollection.Items);
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
+ DisplayCollectionInfo(fCollList.Collection(cbCollection.ItemIndex));
+ // Set collections treeview background colour
+ tvCollectionInfo.Color := ThemeServicesEx.GetTabBodyColour;
// Load content into HTML frames
InitHTMLFrames;
end;
-function TAboutDlg.ContribListHTML(ContribList: IStringList):
- string;
-resourcestring
- // Error string used when contributor file not available
- sNoContributors = 'No contributors list available. Database may be corrupt';
-var
- Contributor: string; // name of a contributor
- DivAttrs: IHTMLAttributes; // attributes of div tag
-begin
- Result := '';
- if ContribList.Count > 0 then
+procedure TAboutDlg.DisplayCollectionInfo(ACollection: TCollection);
+
+ function AddHeading(const AHeading: string): TTreeNode;
begin
- for Contributor in ContribList do
- Result := Result
- + THTML.CompoundTag('div', THTML.Entities(Contributor))
- + EOL;
- end
- else
+ Result := tvCollectionInfo.Items.AddChild(nil, AHeading);
+ end;
+
+ procedure AddChild(const AParentNode: TTreeNode; const AData: string);
begin
- // List couldn't be found: display warning message
- DivAttrs := THTMLAttributes.Create('class', 'warning');
- Result := THTML.CompoundTag(
- 'div', DivAttrs, THTML.Entities(sNoContributors)
- );
+ tvCollectionInfo.Items.AddChild(AParentNode, AData);
+ end;
+
+ procedure AddItem(const AHeading, AData: string);
+ var
+ HeadingNode: TTreeNode;
+ begin
+ HeadingNode := AddHeading(AHeading);
+ AddChild(HeadingNode, AData);
+ end;
+
+ procedure AddItems(const AHeading: string; const AData: IStringList);
+ var
+ HeadingNode: TTreeNode;
+ DataItem: string;
+ begin
+ HeadingNode := AddHeading(AHeading);
+ for DataItem in AData do
+ AddChild(HeadingNode, DataItem);
+ end;
+
+var
+ MetaData: IDBMetaData;
+ Capabilities: TMetaDataCapabilities;
+ HeadingNode: TTreeNode;
+resourcestring
+ sVersionHeading = 'Version';
+ sLicenseHeading = 'License';
+ sCopyrightHeading = 'Copyright';
+ sContributorsHeading = 'Contributors';
+ sTestersHeading = 'Testers';
+ sNoMetaData = 'No information available for this collection.';
+begin
+ tvCollectionInfo.Items.BeginUpdate;
+ try
+ tvCollectionInfo.Items.Clear;
+ MetaData := TMetaDataFactory.CreateInstance(ACollection);
+ Capabilities := MetaData.GetCapabilities;
+ if Capabilities <> [] then
+ begin
+ if mdcVersion in Capabilities then
+ AddItem(sVersionHeading, MetaData.GetVersion);
+ if mdcLicense in Capabilities then
+ begin
+ HeadingNode := AddHeading(sLicenseHeading);
+ AddChild(
+ HeadingNode,
+ StrIf(
+ MetaData.GetLicenseInfo.Name <> '',
+ MetaData.GetLicenseInfo.Name,
+ MetaData.GetLicenseInfo.SPDX
+ )
+ );
+ AddChild(HeadingNode, MetaData.GetLicenseInfo.URL);
+ end;
+ if mdcCopyright in Capabilities then
+ begin
+ HeadingNode := AddHeading(sCopyrightHeading);
+ AddChild(HeadingNode, MetaData.GetCopyrightInfo.Date);
+ AddChild(HeadingNode, MetaData.GetCopyrightInfo.Holder);
+ AddChild(HeadingNode, MetaData.GetCopyrightInfo.HolderURL);
+ end;
+ if mdcContributors in Capabilities then
+ begin
+ AddItems(sContributorsHeading, MetaData.GetContributors);
+ end;
+ if mdcTesters in Capabilities then
+ AddItems(sTestersHeading, MetaData.GetTesters);
+ end
+ else
+ begin
+ AddHeading(sNoMetaData);
+ end;
+ tvCollectionInfo.FullExpand;
+ tvCollectionInfo.Items[0].MakeVisible;
+ finally
+ tvCollectionInfo.Items.EndUpdate;
end;
end;
@@ -342,9 +415,9 @@ class procedure TAboutDlg.Execute(AOwner: TComponent);
procedure TAboutDlg.FormCreate(Sender: TObject);
begin
inherited;
+ fCollList := TCollectionListAdapter.Create;
frmTitle.OnBuildCSS := UpdateTitleCSS;
- frmProgram.OnBuildCSS := UpdateDetailCSS;
- frmDatabase.OnBuildCSS := UpdateDetailCSS;
+ frmProgram.OnBuildCSS := UpdateProgramTabCSS;
end;
procedure TAboutDlg.FormDestroy(Sender: TObject);
@@ -353,6 +426,7 @@ procedure TAboutDlg.FormDestroy(Sender: TObject);
fInstallPathGp.Free;
fMainDBPathGp.Free;
fUserDBPathGp.Free;
+ fCollList.Free;
end;
procedure TAboutDlg.HTMLEventHandler(Sender: TObject;
@@ -417,105 +491,8 @@ procedure TAboutDlg.InitHTMLFrames;
);
end;
- // Initialises and loads HTML into database frame.
- procedure InitDatabaseFrame;
- begin
- // Ensure browser loads page so we can process it
- pcDetail.ActivePage := tsDatabase;
-
- frmDatabase.Initialise(
- 'dlg-about-database-tplt.html',
- procedure(Tplt: THTMLTemplate)
- var
- IsDBAvalable: Boolean;
- IsMetaDataAvailable: Boolean;
- IsLicenseInfoAvailable: Boolean;
-
- function DBVersion: string;
- var
- Ver: TVersionNumber;
- begin
- Ver := fMetaData.GetVersion;
- if Ver.V1 = 1 then
- Result := '1'
- else
- Result := Ver;
- end;
-
- begin
- // Resolve conditionally displayed block placeholders
-// IsDBAvalable := Database.Snippets.Count(False) > 0;
- // check if DelphiDabbler Code Snippets Collection is in use
- IsDBAvalable := not Database.Snippets.IsEmpty(
- TCollectionID.__TMP__MainDBCollectionID
- );
- IsMetaDataAvailable := fMetaData.IsSupportedVersion
- and not fMetaData.IsCorrupt;
- IsLicenseInfoAvailable := IsMetaDataAvailable
- and (fMetaData.GetLicenseInfo.Name <> '')
- and (fMetaData.GetCopyrightInfo.Date <> '')
- and (fMetaData.GetCopyrightInfo.Holder <> '');
- Tplt.ResolvePlaceholderHTML(
- 'DBAvailable', TCSS.BlockDisplayProp(IsDBAvalable)
- );
- Tplt.ResolvePlaceholderHTML(
- 'DBNotAvailable', TCSS.BlockDisplayProp(not IsDBAvalable)
- );
- Tplt.ResolvePlaceholderHTML(
- 'MetaDataAvailable', TCSS.BlockDisplayProp(IsMetaDataAvailable)
- );
- Tplt.ResolvePlaceholderHTML(
- 'MetaDataNotAvailable', TCSS.BlockDisplayProp(not IsMetaDataAvailable)
- );
- Tplt.ResolvePlaceholderHTML(
- 'LicenseInfoAvailable', TCSS.BlockDisplayProp(IsLicenseInfoAvailable)
- );
- Tplt.ResolvePlaceholderHTML(
- 'LicenseInfoAvailableInline',
- TCSS.InlineDisplayProp(IsLicenseInfoAvailable)
- );
- Tplt.ResolvePlaceholderHTML(
- 'LicenseInfoNotAvailable',
- TCSS.BlockDisplayProp(not IsLicenseInfoAvailable)
- );
-
- // Resolve content placeholders
- Tplt.ResolvePlaceholderText(
- 'CopyrightYear', fMetaData.GetCopyrightInfo.Date
- );
- Tplt.ResolvePlaceholderText(
- 'CopyrightHolders', fMetaData.GetCopyrightInfo.Holder
- );
- Tplt.ResolvePlaceholderHTML(
- 'DBLicense',
- StrIf(
- fMetaData.GetLicenseInfo.URL <> '',
- THTML.CompoundTag(
- 'a',
- THTMLAttributes.Create([
- THTMLAttribute.Create('href', fMetaData.GetLicenseInfo.URL),
- THTMLAttribute.Create('class', 'external-link')
- ]),
- THTML.Entities(fMetaData.GetLicenseInfo.Name)
- ),
- THTML.Entities(fMetaData.GetLicenseInfo.Name)
- )
- );
- Tplt.ResolvePlaceholderHTML(
- 'ContribList', ContribListHTML(fMetaData.GetContributors)
- );
- Tplt.ResolvePlaceholderHTML(
- 'TesterList', ContribListHTML(fMetaData.GetTesters)
- );
- Tplt.ResolvePlaceholderText('Version', DBVersion);
- end
- );
- end;
- // ---------------------------------------------------------------------------
-
begin
InitTitleFrame;
- InitDatabaseFrame;
InitProgramFrame;
end;
@@ -526,7 +503,7 @@ procedure TAboutDlg.pcDetailMouseDown(Sender: TObject; Button: TMouseButton;
pcDetail.SetFocus;
end;
-procedure TAboutDlg.UpdateDetailCSS(Sender: TObject;
+procedure TAboutDlg.UpdateProgramTabCSS(Sender: TObject;
const CSSBuilder: TCSSBuilder);
var
ContentFont: TFont; // font used for content
@@ -548,11 +525,6 @@ procedure TAboutDlg.UpdateDetailCSS(Sender: TObject;
// Put border round scroll box
CSSBuilder.AddSelector('.scrollbox')
.AddProperty(UCSSUtils.TCSS.BorderProp(cssAll, 1, cbsSolid, clBorder));
- // Set colours and font style of contributors and testers headings
- CSSBuilder.AddSelector('.contrib-head, .tester-head')
- .AddProperty(TCSS.BackgroundColorProp(clBtnFace))
- .AddProperty(TCSS.ColorProp(clBtnText))
- .AddProperty(TCSS.FontWeightProp(cfwBold));
end;
procedure TAboutDlg.UpdateTitleCSS(Sender: TObject;
diff --git a/Src/HTML.hrc b/Src/HTML.hrc
index 600d279b8..90e550c11 100644
--- a/Src/HTML.hrc
+++ b/Src/HTML.hrc
@@ -13,7 +13,6 @@
# about box
Res\HTML\dlg-about-head-tplt.html
Res\HTML\dlg-about-program-tplt.html
-Res\HTML\dlg-about-database-tplt.html
# easter egg
Res\HTML\dlg-easter-egg.html
diff --git a/Src/Res/HTML/dlg-about-database-tplt.html b/Src/Res/HTML/dlg-about-database-tplt.html
deleted file mode 100644
index ccc4f9797..000000000
--- a/Src/Res/HTML/dlg-about-database-tplt.html
+++ /dev/null
@@ -1,114 +0,0 @@
-
-
-
-
-
-
-
-
-
- dlg-about-database-tplt.html
-
-
-
-
-
-
- The DelphiDabbler
- Code Snippets Database is a resource containing numerous fragments of useful Object Pascal code. You are using version <%Version%>.
-
- No copyright or licensing information is available.
-
-
-
- The code is used entirely at your own risk.
-
-
-
- Credits
-
-
-
- The following people have contributed code to the database, or have helped to test it:
-
-
-
-
- Contributors
-
-
- <%ContribList%>
-
-
- Testers
-
-
- <%TesterList%>
-
-
-
-
-
-
- Credits, License and Copyright information are not available. The main database may be corrupt. Please use the Database | Install or Update DelphiDabbler Snippets Database menu option to display the Install or Update DelphiDabbler Snippets Database dialogue box and follow the instructions there to get the latest version of the database.
-
-
-
-
-
-
-
- The database is not installed.
-
-
-
- You can install it from the Database | Install or Update DelphiDabbler Snippets Database menu option. Learn more.
-
-
-
-
-
-
-
-
From 0cf77d0eb383e9d42ee29daf7baca24112c1b34c Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 18 Nov 2024 00:01:47 +0000
Subject: [PATCH 103/222] Modify About Box to list collection paths
The Paths & Files tab of the About box was revised to list the paths of
each collection's data instead of the paths to the "user" and "main"
databases.
The new design places the custom group boxes used to display the path
information within a scroll box since the number of collections can't be
predicted and it can't be guaranteed that the path group boxes would not
overflow the availablr screen space.
Moved the buttons used to display the config files from the bottom to
the top of the Paths & Files tab.
Updated commenting to reflect the changes and to fix some typos.
---
Src/FmAboutDlg.dfm | 30 +++++++++--
Src/FmAboutDlg.pas | 127 ++++++++++++++++++++++++++-------------------
2 files changed, 98 insertions(+), 59 deletions(-)
diff --git a/Src/FmAboutDlg.dfm b/Src/FmAboutDlg.dfm
index 6f30713ad..c683d780e 100644
--- a/Src/FmAboutDlg.dfm
+++ b/Src/FmAboutDlg.dfm
@@ -104,24 +104,44 @@ inherited AboutDlg: TAboutDlg
object tsPaths: TTabSheet
Caption = 'Paths && Files'
ImageIndex = 2
+ DesignSize = (
+ 401
+ 190)
object btnViewAppConfig: TButton
Left = 3
- Top = 144
+ Top = 3
Width = 170
Height = 25
Caption = 'View Application Config File...'
- TabOrder = 1
+ TabOrder = 0
OnClick = btnViewAppConfigClick
end
object btnViewUserConfig: TButton
- Left = 192
- Top = 144
+ Left = 228
+ Top = 3
Width = 170
Height = 25
+ Anchors = [akTop, akRight]
Caption = 'View Per-User Config File...'
- TabOrder = 0
+ TabOrder = 1
OnClick = btnViewUserConfigClick
end
+ object sbPaths: TScrollBox
+ Left = 3
+ Top = 34
+ Width = 395
+ Height = 153
+ BevelInner = bvLowered
+ BevelOuter = bvRaised
+ BevelKind = bkFlat
+ BorderStyle = bsNone
+ Padding.Left = 3
+ Padding.Top = 3
+ Padding.Right = 3
+ Padding.Bottom = 3
+ TabOrder = 2
+ TabStop = True
+ end
end
end
object pnlTitle: TPanel
diff --git a/Src/FmAboutDlg.pas b/Src/FmAboutDlg.pas
index 7774645cb..99184be1f 100644
--- a/Src/FmAboutDlg.pas
+++ b/Src/FmAboutDlg.pas
@@ -24,6 +24,7 @@ interface
ExtCtrls,
Classes,
Messages,
+ Generics.Collections,
// Project
Browser.UHTMLEvents,
DB.UCollections,
@@ -77,9 +78,9 @@ TPathInfoBox = class(TCustomGroupBox)
property Path: string read GetPath write SetPath;
end;
- /// Implements program' about dialogue box.
- /// Displays information about the program, the main database and
- /// the program's user and application folders and config files. Also
+ /// Implements program's about dialogue box.
+ /// Displays information about the program, the collections in use
+ /// and the program's user and application folders and config files. Also
/// provides access to the program's easter egg.
TAboutDlg = class(TGenericViewDlg)
bvlSeparator: TBevel;
@@ -95,12 +96,13 @@ TAboutDlg = class(TGenericViewDlg)
cbCollection: TComboBox;
lblCollection: TLabel;
tvCollectionInfo: TTreeView;
+ sbPaths: TScrollBox;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
- /// Handles event triggered when user clicks on one of page
- /// control tabs. Ensures page control has focus.
- /// Without this fix, page control does not always get focus when
- /// a tab is clicked.
+ /// Handles event triggered when user clicks on one of the page
+ /// control tabs. Ensures the page control has focus.
+ /// Without this fix, the page control does not always get focus #
+ /// when a tab is clicked.
procedure pcDetailMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
/// Handles button click event to display application config file.
@@ -109,16 +111,18 @@ TAboutDlg = class(TGenericViewDlg)
/// Handles button click event to display per-user config file.
///
procedure btnViewUserConfigClick(Sender: TObject);
+ /// Handles the change event triggered when the user selects a
+ /// collection in the collections combo box. Updates the display of
+ /// information about the selected collection.
procedure cbCollectionChange(Sender: TObject);
strict private
var
+ /// List of dynamically created path information group boxes.
+ ///
+ fPathInfoBoxes: TList;
+ /// Provides a sorted list of collection names for display in
+ /// the collections combo box.
fCollList: TCollectionListAdapter;
- /// Control that displays main database folder.
- fMainDBPathGp: TPathInfoBox;
- /// Control that displays user database folder.
- fUserDBPathGp: TPathInfoBox;
- /// Control that displays program install path.
- fInstallPathGp: TPathInfoBox;
/// Handles title frame's OnHTMLEvent event. Checks for mouse
/// events relating to display of the easter egg and acts accordingly.
///
@@ -162,7 +166,7 @@ TAboutDlg = class(TGenericViewDlg)
const CSSBuilder: TCSSBuilder);
public
/// Displays dialog box.
- /// TComponent [in] Component that owns this dialogus
+ /// TComponent [in] Component that owns this dialogue
/// box.
class procedure Execute(AOwner: TComponent);
end;
@@ -183,7 +187,6 @@ implementation
FmEasterEgg,
FmPreviewDlg,
UAppInfo,
- UColours,
UConsts,
UCSSUtils,
UCtrlArranger,
@@ -216,7 +219,8 @@ function ExploreFolder(const Folder: string): Boolean;
procedure TAboutDlg.ArrangeForm;
var
- PathTabHeight: Integer;
+ PathInfoBox: TPathInfoBox;
+ NextPathInfoBoxTop: Integer;
begin
// Collections tab
TCtrlArranger.AlignVCentres(8, [lblCollection, cbCollection]);
@@ -224,27 +228,35 @@ procedure TAboutDlg.ArrangeForm;
TCtrlArranger.MoveBelow([lblCollection, cbCollection], tvCollectionInfo, 8);
// Paths tab
- fMainDBPathGp.Top := TCtrlArranger.BottomOf(fInstallPathGp, 8);
- fUserDBPathGp.Top := TCtrlArranger.BottomOf(fMainDBPathGp, 8);
- TCtrlArranger.AlignTops(
- [btnViewAppConfig, btnViewUserConfig],
- TCtrlArranger.BottomOf(fUserDBPathGp, 8)
- );
- PathTabHeight := TCtrlArranger.BottomOf(
- [btnViewUserConfig, btnViewAppConfig]
- );
- TCtrlArranger.AlignLefts([fUserDBPathGp, btnViewAppConfig]);
- TCtrlArranger.AlignRights([fUserDBPathGp, btnViewUserConfig]);
+ TCtrlArranger.AlignTops([btnViewAppConfig, btnViewUserConfig], 8);
+ TCtrlArranger.MoveBelow([btnViewAppConfig, btnViewUserConfig], sbPaths, 8);
+ // stack path group boxes vertically
+ NextPathInfoBoxTop := 8;
+ for PathInfoBox in fPathInfoBoxes do
+ begin
+ PathInfoBox.Top := NextPathInfoBoxTop;
+ Inc(NextPathInfoBoxTop, PathInfoBox.Height + 8);
+ end;
+ // align ctrl left & right sides
+ TCtrlArranger.AlignLefts([sbPaths, btnViewAppConfig]);
+ TCtrlArranger.AlignRights([sbPaths, btnViewUserConfig]);
+
// Set height of title frame and page control
pnlTitle.Height := frmTitle.DocHeight;
- pcDetail.ClientHeight :=
- pcDetail.Height - tsProgram.ClientHeight +
- Max(
- PathTabHeight,
- frmProgram.DocHeight
- ) + 8;
+ pcDetail.ClientHeight := pcDetail.Height - tsProgram.ClientHeight
+ + frmProgram.DocHeight + 8;
pnlBody.ClientHeight := pnlTitle.Height + bvlSeparator.Height +
pcDetail.Height;
+
+ // Set path scroll box height
+ sbPaths.ClientHeight := tsPaths.ClientHeight - sbPaths.Top - 28;
+
+ // Set path controls' widths: must do this after all path box tops are set
+ // and after scroll box height is set so any vertical scroll bar will have
+ // been created.
+ for PathInfoBox in fPathInfoBoxes do
+ PathInfoBox.Width := sbPaths.ClientWidth - 2 * PathInfoBox.Left;
+
inherited;
end;
@@ -273,40 +285,49 @@ procedure TAboutDlg.ConfigForm;
// caption, path and tab order.
function CreatePathInfoBox(const Caption, Path: string;
const TabOrder: Integer): TPathInfoBox;
+ const
+ MarginWidth = 8;
begin
- Result := TPathInfoBox.CreateParented(tsPaths.Handle);
- Result.Parent := tsPaths;
- Result.SetBounds(8, 8, tsPaths.ClientWidth - 16, 0);
+ Result := TPathInfoBox.CreateParented(sbPaths.Handle);
+ Result.Parent := sbPaths;
+ Result.SetBounds(MarginWidth, MarginWidth, sbPaths.ClientWidth - 2 * MarginWidth, 0);
Result.Caption := Caption;
Result.Path := Path;
Result.TabOrder := TabOrder;
end;
+var
+ Collection: TCollection;
+ TabIdx: Integer;
resourcestring
// Captions for custom controls
sInstallPathGpCaption = 'Install Directory';
- sMainDBPathGpCaption = 'Main Database Directory';
- sUserDBPathGpCaption = 'User Database Directory';
+ sCollectionPathGpCaption = '%s Collection Directory';
begin
inherited;
// Creates required custom controls
- fInstallPathGp := CreatePathInfoBox(
- sInstallPathGpCaption, TAppInfo.AppExeDir, 0
- );
- fMainDBPathGp := CreatePathInfoBox(
- sMainDBPathGpCaption, TAppInfo.AppDataDir, 1
- );
- fUserDBPathGp := CreatePathInfoBox(
- sUserDBPathGpCaption, TAppInfo.UserDataDir, 2
+ TabIdx := 0;
+ fPathInfoBoxes.Add(
+ CreatePathInfoBox(sInstallPathGpCaption, TAppInfo.AppExeDir, 1)
);
- btnViewAppConfig.TabOrder := fUserDBPathGp.TabOrder + 1;
- btnViewUserConfig.TabOrder := btnViewAppConfig.TabOrder + 1;
+ for Collection in TCollections.Instance do
+ begin
+ Inc(TabIdx);
+ fPathInfoBoxes.Add(
+ CreatePathInfoBox(
+ Format(sCollectionPathGpCaption, [Collection.Name]),
+ Collection.Location.Directory,
+ TabIdx
+ )
+ );
+ end;
// Load collections into combo box & select default collection
fCollList.ToStrings(cbCollection.Items);
cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
DisplayCollectionInfo(fCollList.Collection(cbCollection.ItemIndex));
- // Set collections treeview background colour
+ // Set collections treeview and paths scrollbox background colours
tvCollectionInfo.Color := ThemeServicesEx.GetTabBodyColour;
+ sbPaths.Color := ThemeServicesEx.GetTabBodyColour;
// Load content into HTML frames
InitHTMLFrames;
end;
@@ -416,6 +437,7 @@ procedure TAboutDlg.FormCreate(Sender: TObject);
begin
inherited;
fCollList := TCollectionListAdapter.Create;
+ fPathInfoBoxes := TList.Create;
frmTitle.OnBuildCSS := UpdateTitleCSS;
frmProgram.OnBuildCSS := UpdateProgramTabCSS;
end;
@@ -423,9 +445,7 @@ procedure TAboutDlg.FormCreate(Sender: TObject);
procedure TAboutDlg.FormDestroy(Sender: TObject);
begin
inherited;
- fInstallPathGp.Free;
- fMainDBPathGp.Free;
- fUserDBPathGp.Free;
+ fPathInfoBoxes.Free;
fCollList.Free;
end;
@@ -524,13 +544,12 @@ procedure TAboutDlg.UpdateProgramTabCSS(Sender: TObject;
end;
// Put border round scroll box
CSSBuilder.AddSelector('.scrollbox')
- .AddProperty(UCSSUtils.TCSS.BorderProp(cssAll, 1, cbsSolid, clBorder));
+ .AddProperty(UCSSUtils.TCSS.BorderProp(cssAll, 1, cbsSolid, clBtnShadow));
end;
procedure TAboutDlg.UpdateTitleCSS(Sender: TObject;
const CSSBuilder: TCSSBuilder);
begin
- // Set body colour, and put border round it
CSSBuilder.Selectors['body']
.AddProperty(TCSS.BackgroundColorProp(clWindow))
.AddProperty(TCSS.PaddingProp(4));
From 75c458bfc39073a0654ed0d4b89ba23bf09c8558 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 18 Nov 2024 09:07:43 +0000
Subject: [PATCH 104/222] Remove TMainDBMetaDataFactory record
Removed TMainDBMetaDataFactory from DBIO.MetaData.DCSC unit.
Replace last remaining call to that record's methods in UDBUpdateMgr
with a direct call to TUpdateDBMetaData's constructor.
---
Src/DBIO.MetaData.DCSC.pas | 29 +----------------------------
Src/UDBUpdateMgr.pas | 2 +-
2 files changed, 2 insertions(+), 29 deletions(-)
diff --git a/Src/DBIO.MetaData.DCSC.pas b/Src/DBIO.MetaData.DCSC.pas
index 205eaa738..b2e07bb17 100644
--- a/Src/DBIO.MetaData.DCSC.pas
+++ b/Src/DBIO.MetaData.DCSC.pas
@@ -417,19 +417,6 @@ TUpdateDBMetaData = class sealed(TAbstractMainDBMetaData, IDBMetaData)
constructor Create(const UpdateDir: string);
end;
- /// Factory that creates instances of objects that provide
- /// information about the main database and database updates.
- TMainDBMetaDataFactory = record
- public
- /// Returns instance of class that provides meta data for the
- /// main database.
- class function MainDBMetaDataInstance: IDBMetaData; static;
- /// Returns instance of class that provides meta data for the
- /// database update stored in the given folder.
- class function UpdateMetaDataInstance(const UpdateDir: string):
- IDBMetaData; static;
- end;
-
implementation
uses
@@ -443,20 +430,6 @@ implementation
UResourceUtils,
UStrUtils;
-{ TMainDBMetaDataFactory }
-
-class function TMainDBMetaDataFactory.MainDBMetaDataInstance:
- IDBMetaData;
-begin
- Result := TMainDBMetaData.Create;
-end;
-
-class function TMainDBMetaDataFactory.UpdateMetaDataInstance(
- const UpdateDir: string): IDBMetaData;
-begin
- Result := TUpdateDBMetaData.Create(UpdateDir);
-end;
-
{ TAbstractMainDBMetaData }
procedure TAbstractMainDBMetaData.AfterConstruction;
@@ -520,7 +493,7 @@ function TAbstractMainDBMetaData.GetVersion: TVersionNumber;
class function TAbstractMainDBMetaData.Instance(
ACollection: DB.UCollections.TCollection): IDBMetaData;
begin
- Result := TMainDBMetaDataFactory.MainDBMetaDataInstance;
+ Result := TMainDBMetaData.Create;
end;
function TAbstractMainDBMetaData.IsCorrupt: Boolean;
diff --git a/Src/UDBUpdateMgr.pas b/Src/UDBUpdateMgr.pas
index f5f23bd4c..4119d9484 100644
--- a/Src/UDBUpdateMgr.pas
+++ b/Src/UDBUpdateMgr.pas
@@ -193,7 +193,7 @@ class procedure TDBUpdateMgr.ValidateUpdate(const UpdateDir: string);
raise EDBUpdateValidationError.CreateFmt(sEmptyDirError, [Dir]);
// Check contents
- MetaData := TMainDBMetaDataFactory.UpdateMetaDataInstance(Dir);
+ MetaData := TUpdateDBMetaData.Create(Dir);
// check if data files are recognised as valid database
if not MetaData.IsRecognised then
From 935fc19d4a1cdb21e7fb1793e7a6843341f4cd2e Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 18 Nov 2024 09:18:19 +0000
Subject: [PATCH 105/222] Remove "user database" checks from UCodeShareMgr
TCodeShareMgr was requiring that snippets were available in the "user
database" before permitting code to be exported. This was changed to a
simple check that the entire database is non-empty.
TCodeShareMgr was also refusing to extract a snippet object from a
snippetview if the snippet didn't come from the "user database". This
check was eliminated.
Code comments referring to the "user database" were edited. All class
and method comments were converted to XMLDoc format.
---
Src/UCodeShareMgr.pas | 67 +++++++++++++++----------------------------
1 file changed, 23 insertions(+), 44 deletions(-)
diff --git a/Src/UCodeShareMgr.pas b/Src/UCodeShareMgr.pas
index 367a02b27..add374d25 100644
--- a/Src/UCodeShareMgr.pas
+++ b/Src/UCodeShareMgr.pas
@@ -6,8 +6,7 @@
* Copyright (C) 2008-2021, Peter Johnson (gravatar.com/delphidabbler).
*
* Implements a static class that manages sharing of user defined snippets.
- * Provides support for exporting snippets, importing snippets and submitting
- * snippets to the online database.
+ * Provides support for exporting and importing snippets.
}
@@ -19,39 +18,37 @@ interface
uses
// Project
- DB.USnippet, UBaseObjects, UView;
+ DB.USnippet,
+ UBaseObjects,
+ UView;
type
- {
- TCodeShareMgr:
- Sealed static class that manages sharing of user defined snippets. Provides
- support for exporting snippets, importing snippets and submitting snippets
- to the online database.
- }
+ /// Manages sharing snippets. Provides support for exporting and
+ /// importing snippets.
TCodeShareMgr = class sealed(TNoConstructObject)
strict private
+ /// Gets reference to any snippet represented by a view item.
+ ///
+ /// IView [in] View item fromm which snippet
+ /// is to be extracted, if present.
+ /// TSnippet. Reference to the required snippet or nil if
+ /// the view item does not represent a snippet.
class function GetSnippetFromView(ViewItem: IView): TSnippet;
- {Gets reference to any user defined snippet represented by a view item.
- @param ViewItem [in] View item for which snippet is required.
- @return Reference to required snippet or nil if view item does not
- represent a snippet or if snippet is not user defined.
- }
public
+ /// Checks if there are any snippets that can be shared (i.e.
+ /// exported).
+ /// Boolean. True if database is not empty,
+ /// False otherwise.
class function CanShare: Boolean;
- {Checks if there are any user defined snippets that can be shared (i.e.
- exported or submitted.
- @return True if user defined snippets exist in database.
- }
+ /// Exports snippets to an export file.
+ /// IView [in] View item that may contain a
+ /// snippet. If so the snippet is included in the export file by default.
+ ///
class procedure ExportCode(ViewItem: IView);
- {Exports user defined code to an export file.
- @param ViewItem [in] View item that may contain a user defined snippet.
- If so the snippet is included in the export file by default.
- }
+ /// Imports snippets from an export file.
class procedure ImportCode;
- {Imports user defined code from an export file.
- }
end;
@@ -72,45 +69,27 @@ implementation
{ TCodeShareMgr }
class function TCodeShareMgr.CanShare: Boolean;
- {Checks if there are any user defined snippets that can be shared (i.e.
- exported or submitted.
- @return True if user defined snippets exist in database.
- }
begin
- Result := not Database.Snippets.IsEmpty(
- TCollectionID.__TMP__UserDBCollectionID
- );
+ Result := not Database.Snippets.IsEmpty;
end;
class procedure TCodeShareMgr.ExportCode(ViewItem: IView);
- {Exports user defined code to an export file.
- @param ViewItem [in] View item that may contain a user defined snippet. If
- so the snippet is included in the export file by default.
- }
begin
TCodeExportDlg.Execute(nil, GetSnippetFromView(ViewItem));
end;
class function TCodeShareMgr.GetSnippetFromView(
ViewItem: IView): TSnippet;
- {Gets reference to any user defined snippet represented by a view item.
- @param ViewItem [in] View item for which snippet is required.
- @return Reference to required snippet or nil if view item does not represent
- a snippet or if snippet is not user defined.
- }
var
SnippetView: ISnippetView; // ViewItem as snippet view if supported
begin
- if Supports(ViewItem, ISnippetView, SnippetView)
- and (SnippetView.Snippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID) then
+ if Supports(ViewItem, ISnippetView, SnippetView) then
Result := SnippetView.Snippet
else
Result := nil;
end;
class procedure TCodeShareMgr.ImportCode;
- {Imports user defined code from an export file.
- }
var
ImportMgr: TCodeImportMgr; // manages import of code
begin
From 56fd7b84a86d1e4cef457a4e07542d31bda68988 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 18 Nov 2024 15:18:17 +0000
Subject: [PATCH 106/222] Add hashers and comparers to TSnippet & TSnippetID
Added new Hash method to TSnippetID and new CompareTo and Hash methods
to TSnippet.
Redefined TSnippet.IsEqual in terms of TSnippet.CompareTo.
Added new TComparer nested classes to both TSnippetID and TSnippet.
Changed TSnippetList and TSnippetIDList to use the new TComparer classes
when creating their privte TList<> object, instead of using a
TDelegatedComparer class and defining the comparison explicitly.
---
Src/DB.USnippet.pas | 72 +++++++++++++++++++++++++++++++++++----------
Src/USnippetIDs.pas | 57 ++++++++++++++++++++++++++++-------
2 files changed, 104 insertions(+), 25 deletions(-)
diff --git a/Src/DB.USnippet.pas b/Src/DB.USnippet.pas
index 573955009..21fe6c33d 100644
--- a/Src/DB.USnippet.pas
+++ b/Src/DB.USnippet.pas
@@ -107,13 +107,24 @@ TSnippetList = class;
TSnippet = class(TObject)
public
/// Comparer for snippets by display name.
- type TDisplayNameComparer = class(TComparer)
- public
- /// Compares snippets Left and Right. Returns -ve if Left's
- /// display name sorts before Right's, 0 if the same or +ve if Left's
- /// display name is greater than Right's.
- function Compare(const Left, Right: TSnippet): Integer; override;
- end;
+ type
+ TComparer = class(TInterfacedObject,
+ IComparer, IEqualityComparer
+ )
+ public
+ function Compare(const Left, Right: TSnippet): Integer;
+ function Equals(const Left, Right: TSnippet): Boolean;
+ reintroduce;
+ function GetHashCode(const Value: TSnippet): Integer;
+ reintroduce;
+ end;
+ TDisplayNameComparer = class(TComparer)
+ public
+ /// Compares snippets Left and Right. Returns -ve if Left's
+ /// display name sorts before Right's, 0 if the same or +ve if Left's
+ /// display name is greater than Right's.
+ function Compare(const Left, Right: TSnippet): Integer; override;
+ end;
strict private
fKind: TSnippetKind; // Kind of snippet this is
fCategory: string; // Name of snippet's category
@@ -165,6 +176,13 @@ type TDisplayNameComparer = class(TComparer)
destructor Destroy; override;
{Destructor. Tears down object.
}
+ /// Compares this snippet with another.
+ /// TSnippet [in] Snippet to compare with.
+ ///
+ /// Integer. 0 if the snippets are the same, -ve if
+ /// this snippet is less than Snippets or +ve if this snippet is
+ /// greater than Snippet.
+ function CompareTo(const Snippet: TSnippet): Integer;
function IsEqual(const Snippet: TSnippet): Boolean;
{Checks if this snippet is same as another snippet. Snippets are
considered equal if they have the same key and come from the same
@@ -176,6 +194,8 @@ type TDisplayNameComparer = class(TComparer)
{Checks if snippet can be compiled.
@return True if compilation supported and False if not.
}
+ /// Returns the snippets hash code.
+ function Hash: Integer;
property Kind: TSnippetKind read fKind;
{Kind of snippet represented by this object}
property ID: TSnippetID read GetID;
@@ -415,6 +435,11 @@ function TSnippet.CanCompile: Boolean;
Result := Kind <> skFreeform;
end;
+function TSnippet.CompareTo(const Snippet: TSnippet): Integer;
+begin
+ Result := Self.ID.CompareTo(Snippet.ID);
+end;
+
constructor TSnippet.Create(const AKey: string;
const ACollectionID: TCollectionID; const Props: TSnippetData);
begin
@@ -468,6 +493,12 @@ function TSnippet.GetID: TSnippetID;
Result := TSnippetID.Create(fKey, fCollectionID);
end;
+function TSnippet.Hash: Integer;
+begin
+ // Snippet's hash code is the same as the snippet ID's hash code
+ Result := GetID.Hash;
+end;
+
function TSnippet.IsEqual(const Snippet: TSnippet): Boolean;
{Checks if this snippet is same as another snippet. Snippets are considered
equal if they have the same key and come from the same collection.
@@ -475,7 +506,7 @@ function TSnippet.IsEqual(const Snippet: TSnippet): Boolean;
@return True if snippets are equal, False if not.
}
begin
- Result := Snippet.ID = Self.ID;
+ Result := CompareTo(Snippet) = 0;
end;
procedure TSnippet.SetKey(const AKey: string);
@@ -500,6 +531,23 @@ procedure TSnippet.SetProps(const Data: TSnippetData);
fTestInfo := Data.TestInfo;
end;
+{ TSnippet.TComparer }
+
+function TSnippet.TComparer.Compare(const Left, Right: TSnippet): Integer;
+begin
+ Result := Left.CompareTo(Right);
+end;
+
+function TSnippet.TComparer.Equals(const Left, Right: TSnippet): Boolean;
+begin
+ Result := Left.IsEqual(Right);
+end;
+
+function TSnippet.TComparer.GetHashCode(const Value: TSnippet): Integer;
+begin
+ Result := Value.Hash;
+end;
+
{ TSnippet.TDisplayNameComparer }
function TSnippet.TDisplayNameComparer.Compare(const Left,
@@ -686,13 +734,7 @@ constructor TSnippetList.Create(const OwnsObjects: Boolean = False);
begin
inherited Create;
fList := TSortedObjectList.Create(
- TDelegatedComparer.Create(
- function (const Left, Right: TSnippet): Integer
- begin
- Result := Left.ID.CompareTo(Right.ID);
- end
- ),
- OwnsObjects
+ TSnippet.TComparer.Create, OwnsObjects
);
fList.PermitDuplicates := False;
end;
diff --git a/Src/USnippetIDs.pas b/Src/USnippetIDs.pas
index 0cad2c12b..adfd71065 100644
--- a/Src/USnippetIDs.pas
+++ b/Src/USnippetIDs.pas
@@ -19,6 +19,7 @@ interface
uses
// Delphi
Generics.Collections,
+ Generics.Defaults,
// Project
IntfCommon,
DB.UCollections;
@@ -37,6 +38,18 @@ TSnippetID = record
procedure SetKey(const AValue: string);
procedure SetCollectionID(const AValue: TCollectionID);
public
+ type
+ TComparer = class(TInterfacedObject,
+ IComparer, IEqualityComparer
+ )
+ public
+ function Compare(const Left, Right: TSnippetID): Integer;
+ function Equals(const Left, Right: TSnippetID): Boolean;
+ reintroduce;
+ function GetHashCode(const Value: TSnippetID): Integer;
+ reintroduce;
+ end;
+
/// Snippet's key.
property Key: string read fKey write SetKey;
@@ -59,6 +72,9 @@ TSnippetID = record
/// SID or +ve if this record greater than SID.
function CompareTo(const SID: TSnippetID): Integer;
+ /// Returns the snippet ID's hash code.
+ function Hash: Integer;
+
/// Compares two snippet keys.
/// string [in] First key.
/// string [in] Second key.
@@ -154,7 +170,7 @@ implementation
uses
// Delphi
- SysUtils, Generics.Defaults,
+ SysUtils,
// Project
UStrUtils;
@@ -175,7 +191,6 @@ function TSnippetID.CompareTo(const SID: TSnippetID): Integer;
begin
Result := CompareKeys(Key, SID.Key);
if Result = 0 then
- // TODO -cNote: New comparison changes ordering (no problem tho!)
Result := TCollectionID.Compare(CollectionID, SID.CollectionID);
end;
@@ -191,6 +206,18 @@ constructor TSnippetID.Create(const AKey: string;
Result := SID1.CompareTo(SID2) = 0;
end;
+function TSnippetID.Hash: Integer;
+var
+ PartialHash: Integer;
+ KeyBytes: TBytes;
+begin
+ // Hash is created from hash of CollectionID property combined with hash of
+ // Key property after converting to a byte array in UTF8 format.
+ PartialHash := fCollectionID.Hash;
+ KeyBytes := TEncoding.UTF8.GetBytes(fKey);
+ Result := BobJenkinsHash(KeyBytes[0], Length(KeyBytes), PartialHash);
+end;
+
class operator TSnippetID.NotEqual(const SID1, SID2: TSnippetID): Boolean;
begin
Result := not (SID1 = SID2);
@@ -208,6 +235,23 @@ procedure TSnippetID.SetKey(const AValue: string);
Assert(fKey <> '', 'TSnippetID.SetKey: Value is whitespace or empty');
end;
+{ TSnippetID.TComparer }
+
+function TSnippetID.TComparer.Compare(const Left, Right: TSnippetID): Integer;
+begin
+ Result := Left.CompareTo(Right);
+end;
+
+function TSnippetID.TComparer.Equals(const Left, Right: TSnippetID): Boolean;
+begin
+ Result := Left = Right;
+end;
+
+function TSnippetID.TComparer.GetHashCode(const Value: TSnippetID): Integer;
+begin
+ Result := Value.Hash;
+end;
+
{ TSnippetIDList }
function TSnippetIDList.Add(const SnippetID: TSnippetID): Integer;
@@ -244,14 +288,7 @@ function TSnippetIDList.Count: Integer;
constructor TSnippetIDList.Create;
begin
inherited;
- fList := TList.Create(
- TDelegatedComparer.Create(
- function(const Left, Right: TSnippetID): Integer
- begin
- Result := Left.CompareTo(Right);
- end
- )
- );
+ fList := TList.Create(TSnippetID.TComparer.Create);
end;
destructor TSnippetIDList.Destroy;
From 805a6a78cf896f9e7c9cce9fb0baa2346e714a19 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 18 Nov 2024 16:46:20 +0000
Subject: [PATCH 107/222] Update code importer snippet dependency rules.
Previously UCodeImportMgr checked whether any snippets in an imported
snippet's depends list were in either the user or main databases and
deleted them if not found in either.
The importer now requires that imported snippets can only list snippets
in their depends list if those snippets are also in the import. Any
snippets that are not in the import are removed from depends lists.
This was required to remove code that required the DCS collection to be
present, which can no longer be guaranteed. Additionally, it's
dangerous to assume that any snippet outside the import whose key is
referenced from the import is the same snippet as was intended.
All imported snippets are now given a new key within the chosen
collection.
UCodeImportMgr had to be heavily overhauled to get this new system to
work. In particular the use of new keys meant that the depends lists
needed to be fixed up with new keys.
---
Src/UCodeImportMgr.pas | 137 ++++++++++++++++++++++++++++-------------
1 file changed, 93 insertions(+), 44 deletions(-)
diff --git a/Src/UCodeImportMgr.pas b/Src/UCodeImportMgr.pas
index 1a5ff89b6..775d9f28f 100644
--- a/Src/UCodeImportMgr.pas
+++ b/Src/UCodeImportMgr.pas
@@ -36,14 +36,18 @@ TImportInfo = record
strict private
// Property values
fOrigKey: string;
+ fNewKey: string;
fDisplayName: string;
fSkip: Boolean;
public
/// Initialises properties to given values.
- constructor Create(const AOrigKey, ADisplayName: string;
+ constructor Create(const AOrigKey, ANewKey, ADisplayName: string;
const ASkip: Boolean = False);
/// Snippet key per import file.
property OrigKey: string read fOrigKey;
+ /// New, unique snippet key under which the snippet will be
+ /// imported.
+ property NewKey: string read fNewKey;
/// Snippet's display name.
property DisplayName: string read fDisplayName;
/// Flag indicating if snippet is to be skipped (ignored) when
@@ -120,9 +124,12 @@ TCodeImportMgr = class sealed(TObject)
/// customisation.
procedure Import(const FileName: string);
/// Updates database based on imported snippets and customisation
- /// described by ImportInfo property.
- /// Any existing snippets with same name as imported snippets are
- /// overwritten.
+ /// described by ImportInfo property, using collection specified in
+ /// RequestCollectionCallback.
+ /// Any snippets referenced in the an imported snippet's
+ /// Depends or XRefs property must also be included in the
+ /// import otherwise the snippet is stripped from the dependency list.
+ ///
procedure UpdateDatabase;
/// List of information describing if and how to import snippets
/// in import file. Permits customisation of import.
@@ -153,6 +160,7 @@ implementation
ActiveText.UMain,
DB.UMain,
DB.USnippet,
+ IntfCommon,
UIOUtils,
USnippetIDs,
UStrUtils;
@@ -207,6 +215,9 @@ procedure TCodeImportMgr.InitImportInfoList;
fImportInfoList.Add(
TImportInfo.Create(
SnippetInfo.Key,
+ (Database as IDatabaseEdit).GetUniqueSnippetKey(
+ RequestCollectionCallback
+ ),
StrIf(
SnippetInfo.Data.Props.DisplayName = '',
SnippetInfo.Key,
@@ -219,70 +230,108 @@ procedure TCodeImportMgr.InitImportInfoList;
procedure TCodeImportMgr.UpdateDatabase;
- // Adjusts a snippet's dependency list so that main database is searched for a
- // required snippet if it is not in the user database.
- procedure AdjustDependsList(const Depends: ISnippetIDList);
+ // Adjusts a snippet's references list to exclude snippets not included in the
+ // import.
+ function AdjustRefsList(const ARefs: ISnippetIDList): ISnippetIDList;
var
- Idx: Integer; // loops through dependencies
SnippetID: TSnippetID; // each snippet ID in dependency list
- CollectionID: TCollectionID;
+ Info: TImportInfo;
begin
- // NOTE: The data file format does not record which database a required
- // snippet belongs to, so we first look in the user database and if it's
- // not there, we assume the main database
- for Idx := 0 to Pred(Depends.Count) do
+ // We only include snippets in depends list if it is included in the import
+ Result := TSnippetIDList.Create;
+ for SnippetID in ARefs do
begin
- SnippetID := Depends[Idx];
- CollectionID := TCollectionID.__TMP__UserDBCollectionID;
- if Database.Snippets.Find(SnippetID.Key, CollectionID) = nil then
- CollectionID := TCollectionID.__TMP__MainDBCollectionID;
- SnippetID.CollectionID := CollectionID;
- Depends[Idx] := SnippetID;
+ if fImportInfoList.FindByKey(SnippetID.Key, Info) and not Info.Skip then
+ Result.Add(TSnippetID.Create(Info.NewKey, SnippetID.CollectionID));
end;
end;
+type
+ // Record used to save a snippet's references
+ TSavedReferences = record
+ Snippet: TSnippet;
+ Data: TSnippetEditData;
+ end;
+
var
- Editor: IDatabaseEdit; // object used to update user database
- Snippet: TSnippet; // reference any existing snippet to overwrite
- SnippetInfo: TSnippetInfo; // info about each snippet from import file
- ImportInfo: TImportInfo; // info about how / whether to import a snippet
- CollectionID: TCollectionID;
- SnippetKey: string;
+ Editor: IDatabaseEdit; // object used to update user database
+ SnippetInfo: TSnippetInfo; // info about each snippet from import file
+ ImportInfo: TImportInfo; // info about how / whether to import a snippet
+ CollectionID: TCollectionID; // collection into which we're importing
+ SavedRefs: TList; // preserved references for each snippet
+ SavedRef: TSavedReferences; // each record in Refs list
+ SnippetDataNoRefs: TSnippetEditData; // snippet data with references cleared
resourcestring
// Error message
sBadNameError = 'Can''t find snippet with key "%s" in import data';
begin
+ {TODO -cRefactor: Tidy up messy use of both fSnippetInfoList and
+ fImportInfoList: include all required info in fImportInfoList?
+ }
+
Editor := Database as IDatabaseEdit;
CollectionID := RequestCollectionCallback();
- for SnippetInfo in fSnippetInfoList do
- begin
- if not fImportInfoList.FindByKey(SnippetInfo.Key, ImportInfo) then
- raise EBug.CreateFmt(sBadNameError, [SnippetInfo.Key]);
- if ImportInfo.Skip then
- Continue;
+ SavedRefs := TList.Create(
+ TDelegatedComparer.Create(
+ function (const Left, Right: TSavedReferences): Integer
+ begin
+ Result := Left.Snippet.CompareTo(Right.Snippet);
+ end
+ )
+ );
+ try
+ for SnippetInfo in fSnippetInfoList do
+ begin
+ if not fImportInfoList.FindByKey(SnippetInfo.Key, ImportInfo) then
+ raise EBug.CreateFmt(sBadNameError, [SnippetInfo.Key]);
+
+ if ImportInfo.Skip then
+ Continue;
+
+ // Exclude snippet from depends list if snippet not included in import.
+ (SnippetInfo.Data.Refs.Depends as IAssignable).Assign(
+ AdjustRefsList(SnippetInfo.Data.Refs.Depends)
+ );
+
+ // store snippet data with references
+ SavedRef.Data.Assign(SnippetInfo.Data);
+
+ // clear references before adding snippet: it will probably delete most
+ // anyway if reference is to a snippet after this one in the import list
+ SnippetDataNoRefs.Assign(SnippetInfo.Data);
+ // .. XRef should be clear regardless, because XRefs not included in
+ // export files.
+ SnippetDataNoRefs.Refs.XRef.Clear;
+ SnippetDataNoRefs.Refs.Depends.Clear;
+
+ // add snippet without any dependency
+ SavedRef.Snippet := Editor.AddSnippet(
+ ImportInfo.NewKey, CollectionID, SnippetDataNoRefs
+ );
+
+ // save snippet with its dependencies
+ SavedRefs.Add(SavedRef);
+ end;
- AdjustDependsList(SnippetInfo.Data.Refs.Depends);
+ // Add back the saved snippet references
+ for SavedRef in SavedRefs do
+ if SavedRef.Data.Refs.Depends.Count > 0 then
+ Editor.UpdateSnippet(SavedRef.Snippet, SavedRef.Data);
- Snippet := Database.Snippets.Find(ImportInfo.OrigKey, CollectionID);
- if Assigned(Snippet) then
- SnippetKey := (Database as IDatabaseEdit).GetUniqueSnippetKey(
- CollectionID
- )
- else
- SnippetKey := ImportInfo.OrigKey;
- Editor.AddSnippet(SnippetKey, CollectionID, SnippetInfo.Data);
- {TODO -cVault: Reintroduce the option to overwrite a snippet with matching
- ID, but allow user to select whether this can happen.}
+ finally
+ SavedRefs.Free;
end;
+
end;
{ TImportInfo }
-constructor TImportInfo.Create(const AOrigKey, ADisplayName: string;
+constructor TImportInfo.Create(const AOrigKey, ANewKey, ADisplayName: string;
const ASkip: Boolean = False);
begin
fOrigKey := AOrigKey;
+ fNewKey := ANewKey;
fSkip := ASkip;
fDisplayName := ADisplayName;
end;
@@ -315,7 +364,7 @@ function TImportInfoList.FindByKey(const Key: string;
function TImportInfoList.IndexOfKey(const Key: string): Integer;
begin
- Result := IndexOf(TImportInfo.Create(Key, ''));
+ Result := IndexOf(TImportInfo.Create(Key, '', ''));
end;
procedure TImportInfoList.SetSkip(const AKey: string; const AFlag: Boolean);
From 48bd621f9098c14dd5c47db24914612d54a43ba4 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 18 Nov 2024 17:04:30 +0000
Subject: [PATCH 108/222] Revise snippet exporter re changes in importer
TCodeExporter was modified to not include the keys of snippets in
depends lists for snippets not themselved included in the export.
Also fixed an error where the old snippet ID for snippets included in
the export was being used in depend lists. This meant that no snippet
depends lists were ever imported.
TCodeExporter was modified to ensure that exported dependency lists use
the same key as the changed snippet key.
---
Src/UCodeImportExport.pas | 44 ++++++++++++++++++++++++++-------------
1 file changed, 30 insertions(+), 14 deletions(-)
diff --git a/Src/UCodeImportExport.pas b/Src/UCodeImportExport.pas
index c90d10d7d..44047f7e5 100644
--- a/Src/UCodeImportExport.pas
+++ b/Src/UCodeImportExport.pas
@@ -20,12 +20,14 @@ interface
SysUtils,
Classes,
XMLIntf,
+ Generics.Collections,
// Project
DB.UCategory,
DB.USnippet,
UBaseObjects,
UEncodings,
UIStringList,
+ USnippetIDs,
UXMLDocHelper,
UXMLDocumentEx;
@@ -103,6 +105,7 @@ ECodeImporter = class(ECodeSnipXML);
TCodeExporter = class(TNoPublicConstructObject)
strict private
var
+ fSnippetKeyMap: TDictionary;
/// List of snippets to be exported.
fSnippets: TSnippetList;
/// Extended XML document object.
@@ -112,8 +115,11 @@ TCodeExporter = class(TNoPublicConstructObject)
///
/// An exception is always raised.
procedure HandleException(const EObj: TObject);
- /// Returns a list of snippet names from snippets list.
- function SnippetNames(const SnipList: TSnippetList): IStringList;
+ /// Returns a list of snippet keys for each snippet in
+ /// SnipList. Returned keys are found by looking up the new key
+ /// corresponding to the snippet's original key in fSnippetKeyMap.
+ ///
+ function SnippetKeys(const SnipList: TSnippetList): IStringList;
/// Writes a XML node that contains a list of pascal names.
///
/// IXMLNode [in] Node under which this name list
@@ -180,7 +186,6 @@ implementation
DB.USnippetKind,
UAppInfo,
USnippetExtraHelper,
- USnippetIDs,
UStructs,
UStrUtils,
UXMLDocConsts;
@@ -198,6 +203,7 @@ implementation
destructor TCodeExporter.Destroy;
begin
+ fSnippetKeyMap.Free;
fXMLDoc := nil;
inherited;
end;
@@ -254,19 +260,30 @@ procedure TCodeExporter.HandleException(const EObj: TObject);
end;
constructor TCodeExporter.InternalCreate(const SnipList: TSnippetList);
+var
+ Snippet: TSnippet;
begin
inherited InternalCreate;
fSnippets := SnipList;
+ fSnippetKeyMap := TDictionary.Create(
+ TSnippetID.TComparer.Create
+ );
+ // Create map of actual snippet ID to new unique key with default collection
+ for Snippet in SnipList do
+ fSnippetKeyMap.Add(
+ Snippet.ID,
+ (Database as IDatabaseEdit).GetUniqueSnippetKey(TCollectionID.Default)
+ );
end;
-function TCodeExporter.SnippetNames(
- const SnipList: TSnippetList): IStringList;
+function TCodeExporter.SnippetKeys(const SnipList: TSnippetList): IStringList;
var
Snippet: TSnippet; // references each snippet in list
begin
Result := TIStringList.Create;
for Snippet in SnipList do
- Result.Add(Snippet.Key);
+ if fSnippetKeyMap.ContainsKey(Snippet.ID) then
+ Result.Add(fSnippetKeyMap[Snippet.ID]);
end;
procedure TCodeExporter.WriteProgInfo(const ParentNode: IXMLNode);
@@ -293,14 +310,13 @@ procedure TCodeExporter.WriteSnippet(const ParentNode: IXMLNode;
var
SnippetNode: IXMLNode; // new snippet node
begin
- // Create snippet node with attribute that specifies snippet key
+ // Create snippet node with attribute that specifies snippet key.
+ // Snippet is exported under a new, unique key within the Default collection.
+ // Since no collection information is saved, we need choose one collection in
+ // order to generate the key, and the Default collection is the only one
+ // guaranteed to be present.
SnippetNode := fXMLDoc.CreateElement(ParentNode, cSnippetNode);
- // Export snippet under a new unique key within the default collection
- // we use default collection because code importer assumes snippet id from
- // that collection. We create new unique key because more than one snippet
- // could be exported that have the same key but are in different collections.
- SnippetNode.Attributes[cSnippetNameAttr] :=
- (Database as IDatabaseEdit).GetUniqueSnippetKey(TCollectionID.Default);
+ SnippetNode.Attributes[cSnippetNameAttr] := fSnippetKeyMap[Snippet.ID];
// Add nodes for properties: (ignore category and xrefs)
// description node is written even if empty (which it shouldn't be)
fXMLDoc.CreateElement(
@@ -335,7 +351,7 @@ procedure TCodeExporter.WriteSnippet(const ParentNode: IXMLNode;
);
// depends and units lists
WriteReferenceList(
- SnippetNode, cDependsNode, SnippetNames(Snippet.Depends)
+ SnippetNode, cDependsNode, SnippetKeys(Snippet.Depends)
);
WriteReferenceList(
SnippetNode, cUnitsNode, TIStringList.Create(Snippet.Units)
From ddb1f74e79cd28919202d1fabcf930dcc7986582 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 18 Nov 2024 17:31:16 +0000
Subject: [PATCH 109/222] Simplify CSS class names in Details pane
Replaced the three separate CSS classes used to colour the heading in
the Details pane, depending on whether the view being displayed was a
group or a snippet. Inter-alia removed check for main and user database
to determine CSS class name. A single, hard coded class name is now used
and FrDetailView now determines the correct colour for the class,
depending on the view.
Removed related <% %> templates from .html template files and removed
associated template resolution code from UDetailPageHTML.
---
Src/FrDetailView.pas | 9 ++-------
Src/Res/HTML/info-empty-selection-tplt.html | 2 +-
Src/Res/HTML/info-snippet-list-tplt.html | 2 +-
Src/Res/HTML/info-snippet-tplt.html | 2 +-
Src/UDetailPageHTML.pas | 15 ---------------
5 files changed, 5 insertions(+), 25 deletions(-)
diff --git a/Src/FrDetailView.pas b/Src/FrDetailView.pas
index e8e8cbff5..74a90931a 100644
--- a/Src/FrDetailView.pas
+++ b/Src/FrDetailView.pas
@@ -235,13 +235,8 @@ procedure TDetailViewFrame.BuildCSS(const CSSBuilder: TCSSBuilder);
CSSBuilder.AddSelector('.optionbox')
.AddProperty(TCSS.BorderProp(cssAll, 1, cbsSolid, clBorder));
- // Heading colours for user & main databases
- {TODO -vault: replace all following classes with single ".heading" class}
- CSSBuilder.AddSelector('.userdb')
- .AddProperty(TCSS.ColorProp(fHeadingColour));
- CSSBuilder.AddSelector('.maindb')
- .AddProperty(TCSS.ColorProp(fHeadingColour));
- CSSBuilder.AddSelector('.group-heading')
+ // Heading colour
+ CSSBuilder.AddSelector('.heading')
.AddProperty(TCSS.ColorProp(fHeadingColour));
// Sets CSS for style of New Tab text
diff --git a/Src/Res/HTML/info-empty-selection-tplt.html b/Src/Res/HTML/info-empty-selection-tplt.html
index dd2b9fdd3..208243076 100644
--- a/Src/Res/HTML/info-empty-selection-tplt.html
+++ b/Src/Res/HTML/info-empty-selection-tplt.html
@@ -23,7 +23,7 @@
-
diff --git a/Src/UDetailPageHTML.pas b/Src/UDetailPageHTML.pas
index 78727dab8..39bfc4bc0 100644
--- a/Src/UDetailPageHTML.pas
+++ b/Src/UDetailPageHTML.pas
@@ -238,11 +238,6 @@ TSnippetListPageHTML = class abstract(TDetailPageTpltHTML)
/// snippets to be displayed.
function IsSnippetRequired(const Snippet: TSnippet): Boolean; virtual;
abstract;
- /// Returns name of CSS class to be used for page heading.
- ///
- /// Provides default class name. Descendant classes should
- /// override as necessary.
- function GetH1ClassName: string; virtual;
/// Returns page's heading text.
/// Returns view's description by default. Descendants can
/// override if different behaviour is required.
@@ -517,10 +512,6 @@ procedure TSnippetInfoPageHTML.ResolvePlaceholders(const Tplt: THTMLTemplate);
'overflowXFixScript',
'window.onload = null;'
);
- if GetSnippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID then
- Tplt.ResolvePlaceholderHTML('SnippetCSSClass', 'userdb')
- else
- Tplt.ResolvePlaceholderHTML('SnippetCSSClass', 'maindb');
Tplt.ResolvePlaceholderHTML(
'TestingInfo', TCSS.BlockDisplayProp(GetSnippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID)
);
@@ -576,11 +567,6 @@ destructor TSnippetListPageHTML.Destroy;
inherited;
end;
-function TSnippetListPageHTML.GetH1ClassName: string;
-begin
- Result := 'group-heading';
-end;
-
function TSnippetListPageHTML.GetHeading: string;
begin
Result := View.Description;
@@ -602,7 +588,6 @@ function TSnippetListPageHTML.HaveSnippets: Boolean;
procedure TSnippetListPageHTML.ResolvePlaceholders(const Tplt: THTMLTemplate);
begin
inherited;
- Tplt.ResolvePlaceholderHTML('H1Class', GetH1ClassName);
Tplt.ResolvePlaceholderText('Heading', GetHeading);
if HaveSnippets then
begin
From 1982c43d7b350241952cdce9fe823c387c1a2091 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 18 Nov 2024 19:32:15 +0000
Subject: [PATCH 110/222] Restyle snippet details pane
The snippets details pane used to appear differently depending on
whether the snippet came from the "user" or "main" databases. The former
displayed an "Edit Snippet" link while the latter displayed a test info
glyph in the same place.
Now all snippets display both pieces of information. The test info glyph
now appears after the snippet display name and an edit snippet clickable
glyph remains on the right of the heading line, but without the "Edit
Snippet" text.
Implementing this change required some changes to the
info-snippet-tplt.html template file and the CSS in detail.css.
Some other CSS was moved from the HTML file into details.css.
---
Src/Res/CSS/detail.css | 11 +++++++++--
Src/Res/HTML/info-snippet-tplt.html | 19 +++----------------
Src/UDetailPageHTML.pas | 9 +--------
3 files changed, 13 insertions(+), 26 deletions(-)
diff --git a/Src/Res/CSS/detail.css b/Src/Res/CSS/detail.css
index 47e097417..1df9e3dd8 100644
--- a/Src/Res/CSS/detail.css
+++ b/Src/Res/CSS/detail.css
@@ -170,10 +170,17 @@ pre {
}
.testing-img {
- float: right;
width: 16px;
height: 16px;
padding: 0;
- margin: 2px 0 0 8px;
+ margin: 0 0 0 8px;
+ vertical-align: middle;
}
+#editlink {
+ padding-top: 2px;
+ margin: 0;
+ float: right;
+ vertical-align: baseline;
+ text-align: right;
+}
diff --git a/Src/Res/HTML/info-snippet-tplt.html b/Src/Res/HTML/info-snippet-tplt.html
index 82eebbeaf..1d44327f4 100644
--- a/Src/Res/HTML/info-snippet-tplt.html
+++ b/Src/Res/HTML/info-snippet-tplt.html
@@ -34,15 +34,9 @@
diff --git a/Src/UDetailPageHTML.pas b/Src/UDetailPageHTML.pas
index 39bfc4bc0..1f7905dac 100644
--- a/Src/UDetailPageHTML.pas
+++ b/Src/UDetailPageHTML.pas
@@ -512,12 +512,6 @@ procedure TSnippetInfoPageHTML.ResolvePlaceholders(const Tplt: THTMLTemplate);
'overflowXFixScript',
'window.onload = null;'
);
- Tplt.ResolvePlaceholderHTML(
- 'TestingInfo', TCSS.BlockDisplayProp(GetSnippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID)
- );
- Tplt.ResolvePlaceholderHTML(
- 'EditLink', TCSS.BlockDisplayProp(GetSnippet.CollectionID <> TCollectionID.__TMP__MainDBCollectionID)
- );
Tplt.ResolvePlaceholderText(
'EditEventHandler',
TJavaScript.LiteralFunc(
@@ -526,8 +520,7 @@ procedure TSnippetInfoPageHTML.ResolvePlaceholders(const Tplt: THTMLTemplate);
);
SnippetHTML := TSnippetHTML.Create(GetSnippet);
try
- if GetSnippet.CollectionID = TCollectionID.__TMP__MainDBCollectionID then
- Tplt.ResolvePlaceholderHTML('TestingInfoImg', SnippetHTML.TestingImage);
+ Tplt.ResolvePlaceholderHTML('TestingInfoImg', SnippetHTML.TestingImage);
Tplt.ResolvePlaceholderHTML('SnippetName', SnippetHTML.SnippetName);
finally
SnippetHTML.Free;
From 5d313fda819fb24b3d5fa6d0cb2002ba57744d96 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 18 Nov 2024 19:43:01 +0000
Subject: [PATCH 111/222] Replace update action testing for nonempty user db
The ActNonEmptyUserDBUpdate action update event handler that tested for
a non-empty user database was removed and calls to it were replaced by
calls to ActNonEmptyDBUpdate that makes no such tests.
NOTE: menu actions that used this event handler to enable/disable them
are still "User Database" specific and need to be removed or replaced.
---
Src/FmMain.dfm | 6 +++---
Src/FmMain.pas | 8 --------
2 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/Src/FmMain.dfm b/Src/FmMain.dfm
index 902e71720..038f30d30 100644
--- a/Src/FmMain.dfm
+++ b/Src/FmMain.dfm
@@ -619,7 +619,7 @@ inherited MainForm: TMainForm
Hint = 'Backup user database|Backup the user-defined snippet database'
ImageIndex = 33
OnExecute = actBackupDatabaseExecute
- OnUpdate = ActNonEmptyUserDBUpdate
+ OnUpdate = ActNonEmptyDBUpdate
end
object actRestoreDatabase: TAction
Category = 'Database'
@@ -850,7 +850,7 @@ inherited MainForm: TMainForm
'Move user database|Move the user-defined snippet database to a n' +
'ew directory'
OnExecute = actMoveUserDatabaseExecute
- OnUpdate = ActNonEmptyUserDBUpdate
+ OnUpdate = ActNonEmptyDBUpdate
end
object actSWAGImport: TAction
Category = 'Snippets'
@@ -875,7 +875,7 @@ inherited MainForm: TMainForm
'Delete User Database|Deletes the user'#39's snippets database - USE ' +
'WITH CAUTION'
OnExecute = actDeleteUserDatabaseExecute
- OnUpdate = ActNonEmptyUserDBUpdate
+ OnUpdate = ActNonEmptyDBUpdate
end
end
object mnuMain: TMainMenu
diff --git a/Src/FmMain.pas b/Src/FmMain.pas
index 25e81385b..0d9c56435 100644
--- a/Src/FmMain.pas
+++ b/Src/FmMain.pas
@@ -500,7 +500,6 @@ TMainForm = class(THelpAwareForm)
/// position is permitted and blocks the move if not.
procedure splitVertCanResize(Sender: TObject; var NewSize: Integer;
var Accept: Boolean);
- procedure ActNonEmptyUserDBUpdate(Sender: TObject);
strict private
var
/// Object that notifies user-initiated events by triggering
@@ -941,13 +940,6 @@ procedure TMainForm.ActNonEmptyDBUpdate(Sender: TObject);
(Sender as TAction).Enabled := not Database.Snippets.IsEmpty;
end;
-procedure TMainForm.ActNonEmptyUserDBUpdate(Sender: TObject);
-begin
- (Sender as TAction).Enabled := not Database.Snippets.IsEmpty(
- TCollectionID.__TMP__UserDBCollectionID
- );
-end;
-
procedure TMainForm.ActOverviewTabExecute(Sender: TObject);
begin
// Action's Tag property specifies index of tab being selected
From 41902456fc7cc5c3ea9ed9304a08424a3e7188f1 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 18 Nov 2024 23:37:33 +0000
Subject: [PATCH 112/222] Change Database move code to move any collection
The code in UUserDBMove was modified to move any collection's data files
instead of only the "user database".
FmUserDataPathDlg was also modified to work with the revised
UUserDBMove. In addition, the facility to restore the "user database" to
its default location was removed since there is no concept as a default
location for collections.
Text in FmUserDataPathDlg and UUserDBMove was changed to refer to
collections instead of databases. Comments in both units were similarly
updated.
Text and hints in the relevant menu item in FmMain was changed to refer
to collection instead of user database.
---
Src/FmMain.dfm | 6 +-
Src/FmUserDataPathDlg.dfm | 219 +++++++++++++++-----------------------
Src/FmUserDataPathDlg.pas | 191 ++++++++++++++++++---------------
Src/UUserDBMove.pas | 63 +++++------
4 files changed, 231 insertions(+), 248 deletions(-)
diff --git a/Src/FmMain.dfm b/Src/FmMain.dfm
index 038f30d30..e8cf1d1b8 100644
--- a/Src/FmMain.dfm
+++ b/Src/FmMain.dfm
@@ -845,10 +845,10 @@ inherited MainForm: TMainForm
end
object actMoveUserDatabase: TAction
Category = 'Database'
- Caption = 'Move User Database...'
+ Caption = 'Move Collection Data Files...'
Hint =
- 'Move user database|Move the user-defined snippet database to a n' +
- 'ew directory'
+ 'Move a collection|Move a collection'#39's data files to a new direct' +
+ 'ory'
OnExecute = actMoveUserDatabaseExecute
OnUpdate = ActNonEmptyDBUpdate
end
diff --git a/Src/FmUserDataPathDlg.dfm b/Src/FmUserDataPathDlg.dfm
index 014df9466..450a69321 100644
--- a/Src/FmUserDataPathDlg.dfm
+++ b/Src/FmUserDataPathDlg.dfm
@@ -1,5 +1,5 @@
inherited UserDataPathDlg: TUserDataPathDlg
- Caption = 'Move User Database'
+ Caption = 'Move Collection Data'
ExplicitWidth = 474
ExplicitHeight = 375
PixelsPerInch = 96
@@ -16,20 +16,20 @@ inherited UserDataPathDlg: TUserDataPathDlg
Height = 25
AutoSize = False
Caption =
- 'Use this dialogue box to move the user database to a new directo' +
- 'ry or to restore the directory to its default location. Choose t' +
- 'he appropriate option below.'
+ 'Use this dialogue box to move a collection'#39's data to a new direc' +
+ 'tory.'#13#10'Choose the collection whose data you wish to move then en' +
+ 'ter the directory you wish to move the data to.'
WordWrap = True
end
object lblWarning: TLabel
Left = 0
- Top = 32
+ Top = 31
Width = 377
- Height = 20
+ Height = 34
AutoSize = False
Caption =
- 'You are strongly advised to make a backup of the database before' +
- ' continuing.'
+ 'You are strongly advised to make a backup of the collection befo' +
+ 're continuing.'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
@@ -38,137 +38,45 @@ inherited UserDataPathDlg: TUserDataPathDlg
ParentFont = False
WordWrap = True
end
- object gbMove: TGroupBox
+ object lblPath: TLabel
Left = 0
- Top = 59
- Width = 377
- Height = 140
- Caption = 'Move database to new directory'
+ Top = 125
+ Width = 217
+ Height = 13
+ Caption = 'Enter the full path of the new data &directory:'
+ FocusControl = edPath
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
- Font.Style = [fsBold]
+ Font.Style = []
ParentFont = False
- TabOrder = 0
- object lblPath: TLabel
- Left = 8
- Top = 20
- Width = 240
- Height = 13
- Caption = 'Enter the full path to the new database &directory:'
- FocusControl = edPath
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clWindowText
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- ParentFont = False
- end
- object lblExplainMove: TLabel
- Left = 8
- Top = 66
- Width = 361
- Height = 34
- AutoSize = False
- Caption =
- 'The directory must be empty and must not be a sub-directory of t' +
- 'he current database directory. If the directory does not exist a' +
- ' new one will be created.'
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clWindowText
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- ParentFont = False
- WordWrap = True
- end
- object edPath: TEdit
- Left = 8
- Top = 39
- Width = 325
- Height = 21
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clWindowText
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- ParentFont = False
- TabOrder = 0
- end
- object btnBrowse: TButton
- Left = 341
- Top = 39
- Width = 27
- Height = 21
- Action = actBrowse
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clWindowText
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- ParentFont = False
- TabOrder = 1
- end
- object btnMove: TButton
- Left = 112
- Top = 86
- Width = 153
- Height = 41
- Action = actMove
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clWindowText
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- ParentFont = False
- TabOrder = 2
- end
end
- object gbRestore: TGroupBox
+ object lblExplainMove: TLabel
Left = 0
- Top = 208
- Width = 377
- Height = 112
- Caption = 'Restore database to default directory'
+ Top = 171
+ Width = 361
+ Height = 62
+ AutoSize = False
+ Caption =
+ 'The directory must be empty and must not be a sub-directory of t' +
+ 'he current collection'#39's data directory. If the directory does no' +
+ 't exist a new one will be created.'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
- Font.Style = [fsBold]
+ Font.Style = []
ParentFont = False
- TabOrder = 1
- object lblExplainDefaultPath: TLabel
- Left = 8
- Top = 20
- Width = 361
- Height = 34
- AutoSize = False
- Caption =
- 'Use this button to restore the database to its default directory' +
- '. This option is only available if the database has been moved.'
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clWindowText
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- ParentFont = False
- WordWrap = True
- end
- object btnDefaultPath: TButton
- Left = 112
- Top = 61
- Width = 153
- Height = 41
- Action = actDefaultPath
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clWindowText
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- ParentFont = False
- TabOrder = 0
- end
+ WordWrap = True
+ end
+ object lblCollection: TLabel
+ Left = 0
+ Top = 71
+ Width = 122
+ Height = 13
+ Caption = 'Select &collection to move:'
+ FocusControl = cbCollection
end
inline frmProgress: TProgressFrame
Left = 57
@@ -176,14 +84,66 @@ inherited UserDataPathDlg: TUserDataPathDlg
Width = 320
Height = 82
ParentBackground = False
- TabOrder = 2
+ TabOrder = 4
Visible = False
ExplicitLeft = 57
ExplicitHeight = 82
inherited pnlBody: TPanel
Height = 82
+ ExplicitLeft = 55
+ ExplicitTop = 72
+ ExplicitHeight = 82
end
end
+ object btnMove: TButton
+ Left = 87
+ Top = 199
+ Width = 153
+ Height = 41
+ Action = actMove
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ TabOrder = 3
+ end
+ object edPath: TEdit
+ Left = 0
+ Top = 144
+ Width = 325
+ Height = 21
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ TabOrder = 1
+ end
+ object btnBrowse: TButton
+ Left = 331
+ Top = 144
+ Width = 27
+ Height = 21
+ Action = actBrowse
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ TabOrder = 2
+ end
+ object cbCollection: TComboBox
+ Left = 0
+ Top = 88
+ Width = 358
+ Height = 21
+ Style = csDropDownList
+ TabOrder = 0
+ end
end
object alDlg: TActionList
Left = 152
@@ -192,11 +152,6 @@ inherited UserDataPathDlg: TUserDataPathDlg
Caption = '...'
OnExecute = actBrowseExecute
end
- object actDefaultPath: TAction
- Caption = '&Restore Default Path'
- OnExecute = actDefaultPathExecute
- OnUpdate = actDefaultPathUpdate
- end
object actMove: TAction
Caption = '&Move'
OnExecute = actMoveExecute
diff --git a/Src/FmUserDataPathDlg.pas b/Src/FmUserDataPathDlg.pas
index 9c6bbbbbe..314057ac8 100644
--- a/Src/FmUserDataPathDlg.pas
+++ b/Src/FmUserDataPathDlg.pas
@@ -5,7 +5,7 @@
*
* Copyright (C) 2013-2023, Peter Johnson (gravatar.com/delphidabbler).
*
- * Implements a dialogue box that can be used to move the user database to a
+ * Implements a dialogue box that can be used to move collection data to a
* different directory.
}
@@ -18,66 +18,67 @@ interface
uses
// Delphi
- SysUtils, Forms, Classes, ActnList, StdCtrls, Controls, ExtCtrls,
+ SysUtils,
+ Forms,
+ Classes,
+ ActnList,
+ StdCtrls,
+ Controls,
+ ExtCtrls,
// Project
- FmGenericViewDlg, FrProgress, UBaseObjects,
- UControlStateMgr, UUserDBMove;
+ FmGenericViewDlg,
+ FrProgress,
+ UBaseObjects,
+ UCollectionListAdapter,
+ UControlStateMgr,
+ UUserDBMove;
type
- /// Dialogue box that is used to move the user database to a new
- /// directory or to restore a previously moved database to its default
+ /// Dialogue box that is used to move the collection data to a new
/// directory.
/// IMPORTANT: This dialogue box is for use only with the standard
/// edition of CodeSnip. It MUST NOT be displayed from the portable edition.
///
TUserDataPathDlg = class(TGenericViewDlg, INoPublicConstruct)
actBrowse: TAction;
- actDefaultPath: TAction;
actMove: TAction;
alDlg: TActionList;
- btnBrowse: TButton;
- btnDefaultPath: TButton;
- btnMove: TButton;
- gbMove: TGroupBox;
- gbRestore: TGroupBox;
- lblExplainDefaultPath: TLabel;
- lblExplainMove: TLabel;
lblInstructions: TLabel;
- lblPath: TLabel;
lblWarning: TLabel;
- edPath: TEdit;
frmProgress: TProgressFrame;
+ lblPath: TLabel;
+ lblExplainMove: TLabel;
+ btnMove: TButton;
+ edPath: TEdit;
+ btnBrowse: TButton;
+ lblCollection: TLabel;
+ cbCollection: TComboBox;
/// Dispays Browse For Folder dialogue box and copies any chosen
/// folder to the edPath edit control.
procedure actBrowseExecute(Sender: TObject);
- /// Moves user database back to default directory and records the
- /// changed path.
- /// Raises exception if default path can't be used for any
- /// reason or if there was an error copying the database.
- procedure actDefaultPathExecute(Sender: TObject);
- /// Enables / disables Default Path action according to whether
- /// database is already in default path.
- procedure actDefaultPathUpdate(Sender: TObject);
- /// Moves user database to path entered by user and records the
- /// changed path.
- /// Raises exception given path can't be used for any reason or
- /// if there was an error copying the database.
+ /// Moves the chosen collection to the path entered by the user
+ /// and records the changed path.
+ /// Raises exception if the given path can't be used for any
+ /// reason or if there was an error copying the collection.
procedure actMoveExecute(Sender: TObject);
/// Enables / disables Move action according to whether a suitable
/// path has been entered by user.
procedure actMoveUpdate(Sender: TObject);
- /// Constructs and initialises form's owned object.
+ /// Constructs and initialises form's owned objects.
procedure FormCreate(Sender: TObject);
/// Destroys form's owned objects.
procedure FormDestroy(Sender: TObject);
strict private
var
- /// Object that moves the user database to a new location.
+ /// Object that moves a collection's data to a new location.
///
fMover: TUserDBMove;
/// Object used to disable and enable all controls on the form.
///
fControlStateMgr: TControlStateMgr;
+ /// Object used to provide and interogate a sorted list of
+ /// collection names displated in cbCollection.
+ fCollList: TCollectionListAdapter;
/// Sets visibility of all child controls of a parent control.
///
/// TWinControl [in] Parent of affected controls.
@@ -85,31 +86,33 @@ TUserDataPathDlg = class(TGenericViewDlg, INoPublicConstruct)
/// Boolean [in] Flag indicating required visibility.
/// Pass True to show the controls and False to hide them.
procedure SetVisibility(const ParentCtrl: TWinControl; const Show: Boolean);
- /// Performs the database move to the directory given by NewDir,
- /// displaying a progress base located over the given host window.
- ///
+ /// Move the chosen collection data to the directory given by
+ /// NewDir, displaying a progress base located over the given host
+ /// window.
/// The new directory is checked to be empty and the user is asked
/// for confirmation.
procedure DoMove(const NewDir: string; const ProgressHostCtrl: TWinControl);
- /// Handles the database mover object's OnCopyFile event by
- /// updating the progress frame.
+ /// Handles the collection data mover object's OnCopyFile
+ /// event by updating the progress frame.
procedure CopyFileHandler(Sender: TObject; const Percent: Byte);
- /// Handles the database mover object's OnDeleteFile event by
- /// updating the progress frame.
+ /// Handles the collectio data mover object's OnDeleteFile
+ /// event by updating the progress frame.
procedure DeleteFileHandler(Sender: TObject; const Percent: Byte);
- /// Gets directory entered in edPath edit control.
- /// Edit control contents are trimmed of spaces and any trailing
- /// path delimiter.
+ /// Gets the directory entered in the edPath edit control.
+ ///
+ /// The edit control contents are trimmed of spaces and any
+ /// trailing path delimiter.
function NewDirFromEditCtrl: string;
- /// Handles given exception, converting expected exceptions into
- /// ECodeSnip and re-raising all other unchanged.
+ /// Handles the given exception E, converting expected
+ /// exceptions into ECodeSnip exceptions and re-raising all other
+ /// exceptions unchanged.
/// Always raises a new exception.
/// This method is designed to handle exceptions raised when the
- /// user database is moved.
+ /// collection data is moved.
procedure HandleException(const E: Exception);
strict protected
- /// Sets controls with ParentFont=False to use system default
- /// fonts, preserving font styles for those fonts that need them.
+ /// Initialises the form's controls and associated objects.
+ ///
procedure ConfigForm; override;
/// Arranges form's controls and sizes the dialogue box to fit.
///
@@ -117,8 +120,8 @@ TUserDataPathDlg = class(TGenericViewDlg, INoPublicConstruct)
public
/// Displays the dialogue box aligned over the given owner
/// control.
- /// Raises EBug if called by the portable edition of CodeSnip.
- ///
+ /// Raises EBug if called from the portable edition of
+ /// CodeSnip.
class procedure Execute(AOwner: TComponent);
end;
@@ -128,10 +131,17 @@ implementation
uses
// Delphi
- IOUtils,
+ IOUtils,
// Project
- UAppInfo, UBrowseForFolderDlg, UCtrlArranger, UExceptions, UFontHelper,
- UMessageBox, UStrUtils, UStructs;
+ DB.UCollections,
+ UAppInfo,
+ UBrowseForFolderDlg,
+ UCtrlArranger,
+ UExceptions,
+ UFontHelper,
+ UMessageBox,
+ UStrUtils,
+ UStructs;
{$R *.dfm}
@@ -141,7 +151,7 @@ procedure TUserDataPathDlg.actBrowseExecute(Sender: TObject);
var
Dlg: TBrowseForFolderDlg; // browse for folder standard dialogue box
resourcestring
- sDlgTitle = 'Choose Database Directory';
+ sDlgTitle = 'Choose Collection Data Directory';
sDlgHeading = 'Choose an empty directory or create a new one';
begin
Dlg := TBrowseForFolderDlg.Create(nil);
@@ -156,27 +166,18 @@ procedure TUserDataPathDlg.actBrowseExecute(Sender: TObject);
end;
end;
-procedure TUserDataPathDlg.actDefaultPathExecute(Sender: TObject);
-begin
- DoMove(TAppInfo.DefaultUserDataDir, gbRestore);
-end;
-
-procedure TUserDataPathDlg.actDefaultPathUpdate(Sender: TObject);
-begin
- actDefaultPath.Enabled :=
- not StrSameText(TAppInfo.UserDataDir, TAppInfo.DefaultUserDataDir)
- and Self.Enabled;
-end;
-
procedure TUserDataPathDlg.actMoveExecute(Sender: TObject);
begin
- DoMove(NewDirFromEditCtrl, gbMove);
+ DoMove(NewDirFromEditCtrl, Self);
end;
procedure TUserDataPathDlg.actMoveUpdate(Sender: TObject);
begin
actMove.Enabled := (NewDirFromEditCtrl <> '')
- and not StrSameText(NewDirFromEditCtrl, TAppInfo.UserDataDir)
+ and not StrSameText(
+ NewDirFromEditCtrl,
+ fCollList.Collection(cbCollection.ItemIndex).Location.Directory
+ )
and Self.Enabled;
end;
@@ -186,37 +187,56 @@ procedure TUserDataPathDlg.ArrangeForm;
pnlBody.ClientWidth := TCtrlArranger.TotalControlWidth(pnlBody);
- TCtrlArranger.AlignVCentres(
- TCtrlArranger.BottomOf(lblPath, 4), [edPath, btnBrowse]
+ TCtrlArranger.AlignLefts(
+ [
+ lblInstructions, lblWarning, lblCollection, cbCollection, lblPath, edPath,
+ lblExplainMove
+ ],
+ 0
);
- TCtrlArranger.MoveBelow([edPath, btnBrowse], lblExplainMove, 8);
- TCtrlArranger.MoveBelow(lblExplainMove, btnMove, 8);
- gbMove.ClientHeight := TCtrlArranger.TotalControlHeight(gbMove) + 8;
-
- TCtrlArranger.MoveBelow(lblExplainDefaultPath, btnDefaultPath, 12);
- gbRestore.ClientHeight := TCtrlArranger.TotalControlHeight(gbRestore) + 12;
-
+ // Row 1
+ lblInstructions.Top := 0;
+ lblInstructions.Width := pnlBody.ClientWidth;
+ // Row 2
TCtrlArranger.MoveBelow(lblInstructions, lblWarning, 8);
- TCtrlArranger.MoveBelow(lblWarning, gbMove, 12);
- TCtrlArranger.MoveBelow(gbMove, gbRestore, 12);
+ lblWarning.Width := pnlBody.ClientWidth;
+ // Row 3
+ TCtrlArranger.MoveBelow(lblWarning, lblCollection, 12);
+ // Row 4
+ TCtrlArranger.MoveBelow(lblCollection, cbCollection, 6);
+ cbCollection.Width := pnlBody.ClientWidth;
+ // Row 5
+ TCtrlArranger.MoveBelow(cbCollection, lblPath, 12);
+ // Row 6
+ TCtrlArranger.AlignRights([btnBrowse], pnlBody.ClientWidth);
+ edPath.Width := btnBrowse.Left - 6 - edPath.Left;
+ TCtrlArranger.AlignVCentres(
+ TCtrlArranger.BottomOf(lblPath, 6), [edPath, btnBrowse]
+ );
+ // Row 7
+ TCtrlArranger.MoveBelow([edPath, btnBrowse], lblExplainMove, 12);
+ lblExplainMove.Width := pnlBody.ClientWidth;
+ // Row 8
+ TCtrlArranger.MoveBelow(lblExplainMove, btnMove, 12);
+ btnMove.Left := (pnlBody.Width - btnMove.Width) div 2;
pnlBody.ClientHeight := TCtrlArranger.TotalControlHeight(pnlBody) + 8;
+
inherited;
end;
procedure TUserDataPathDlg.ConfigForm;
begin
inherited;
- TFontHelper.SetDefaultBaseFonts([
- gbMove.Font, gbRestore.Font, lblWarning.Font]
- );
+ TFontHelper.SetDefaultBaseFonts([lblWarning.Font]);
TFontHelper.SetDefaultFonts([
lblPath.Font, edPath.Font, lblExplainMove.Font,
- btnBrowse.Font, btnMove.Font, lblExplainDefaultPath.Font,
- btnDefaultPath.Font
+ btnBrowse.Font, btnMove.Font
]);
frmProgress.Visible := False;
frmProgress.Range := TRange.Create(0, 100);
+ fCollList.ToStrings(cbCollection.Items);
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
end;
procedure TUserDataPathDlg.CopyFileHandler(Sender: TObject;
@@ -245,7 +265,7 @@ procedure TUserDataPathDlg.DoMove(const NewDir: string;
const ProgressHostCtrl: TWinControl);
resourcestring
sNonEmptyDir = 'The specified directory is not empty.';
- sConfirmMsg = 'Are you sure you want to move the database?';
+ sConfirmMsg = 'Are you sure you want to move the collection data?';
begin
if TDirectory.Exists(NewDir)
and not TDirectory.IsEmpty(NewDir) then
@@ -258,7 +278,9 @@ procedure TUserDataPathDlg.DoMove(const NewDir: string;
SetVisibility(ProgressHostCtrl, False);
frmProgress.Show(ProgressHostCtrl);
try
- fMover.MoveTo(NewDir);
+ fMover.MoveTo(
+ fCollList.Collection(cbCollection.ItemIndex), NewDir
+ );
except
on E: Exception do
HandleException(E);
@@ -278,6 +300,7 @@ class procedure TUserDataPathDlg.Execute(AOwner: TComponent);
{$ENDIF}
begin
{$IFDEF PORTABLE}
+ {TODO -cVault: Permit this, but restrict to sub-dirs of install dir}
raise EBug.Create(ClassName + '.Execute: Call forbidden in portable edition');
{$ELSE}
Dlg := InternalCreate(AOwner);
@@ -296,10 +319,12 @@ procedure TUserDataPathDlg.FormCreate(Sender: TObject);
fMover.OnCopyFile := CopyFileHandler;
fMover.OnDeleteFile := DeleteFileHandler;
fControlStateMgr := TControlStateMgr.Create(Self);
+ fCollList := TCollectionListAdapter.Create;
end;
procedure TUserDataPathDlg.FormDestroy(Sender: TObject);
begin
+ fCollList.Free;
fControlStateMgr.Free;
fMover.Free;
inherited;
diff --git a/Src/UUserDBMove.pas b/Src/UUserDBMove.pas
index 946062070..98f3a6fb0 100644
--- a/Src/UUserDBMove.pas
+++ b/Src/UUserDBMove.pas
@@ -5,7 +5,7 @@
*
* Copyright (C) 2013-2021, Peter Johnson (gravatar.com/delphidabbler).
*
- * Implements a class that moves the user defined database to a new location.
+ * Implements a class that moves a collection's data to a new location.
}
@@ -17,17 +17,18 @@ interface
uses
// Project
+ DB.UCollections,
UDirectoryCopier;
type
- /// Class that moves the user defined database to a new location.
+ /// Class that moves a collection's data to a new location.
///
TUserDBMove = class(TObject)
public
type
- /// Type of event triggered by TUserDBMove to report progress
- /// when moving the database files.
+ /// Type of event triggered to report progress when moving a
+ /// collection's data files.
/// TObject [in] TUserDBMove instance that triggered
/// the event.
/// Byte [in] Percentage of operation that has been
@@ -40,39 +41,42 @@ TUserDBMove = class(TObject)
fOnCopyFile: TProgress;
/// Reference to event handler for OnDeleteFile event.
fOnDeleteFile: TProgress;
- /// Directory of existing user database.
+ /// Directory containg existing collection data.
fSourceDir: string;
- /// Required new database directory.
+ /// Required new collection data directory.
fDestDir: string;
+ /// Collection to be moved.
+ fCollection: TCollection;
/// Instance of class used to perform directory move.
fDirCopier: TDirectoryCopier;
/// Validates source and destination directories.
/// Raises EInOutError exception if either directory is not
/// valid.
procedure ValidateDirectories;
- /// Handles TDirectoryCopier.OnAfterCopyDir event to update user
- /// database location.
- /// Database location is updated once the database has been copied
- /// but before old database directory is deleted.
+ /// Handles TDirectoryCopier.OnAfterCopyDir event to update the
+ /// collection data directory.
+ /// Collection data location is updated once the collection's data
+ /// has been copied but before the old collection data directory is
+ /// deleted.
procedure SetNewDBDirectory(Sender: TObject);
/// Handles TDirectoryCopier.OnCopyFileProgress event and passes
- /// the given progress percentage on to this class' similar OnCopyFile
+ /// the given progress percentage on to this class' similar OnCopyFile
/// event.
procedure ReportCopyProgress(Sender: TObject; const Percent: Single);
/// Handles TDirectoryCopier.OnDeleteFileProgress event and passes
- /// the given progress percentage on to this class' similar
- /// OnDeleteFile event.
+ /// the given progress percentage on to this class' similar OnDeleteFile
+ /// event.
procedure ReportDeleteProgress(Sender: TObject; const Percent: Single);
public
/// Constructs and initialises new object instance.
constructor Create;
/// Destroys current object instance.
destructor Destroy; override;
- /// Moves user database from its current directory to the given
+ /// Moves collection data from its current directory to the given
/// new directory.
/// Raises EInOutError exceptions if an error occurs.
///
- procedure MoveTo(const ADirectory: string);
+ procedure MoveTo(const ACollection: TCollection; const ADirectory: string);
/// Event triggered just before file copying begins and once for
/// each file copied. Reports progress towards completion of copy
/// operation.
@@ -91,7 +95,6 @@ implementation
// Delphi
SysUtils, IOUtils,
// Project
- DB.UCollections,
UAppInfo,
UStrUtils;
@@ -113,9 +116,11 @@ destructor TUserDBMove.Destroy;
inherited;
end;
-procedure TUserDBMove.MoveTo(const ADirectory: string);
+procedure TUserDBMove.MoveTo(const ACollection: TCollection;
+ const ADirectory: string);
begin
- fSourceDir := ExcludeTrailingPathDelimiter(TAppInfo.UserDataDir);
+ fCollection := ACollection;
+ fSourceDir := ExcludeTrailingPathDelimiter(ACollection.Location.Directory);
fDestDir := ExcludeTrailingPathDelimiter(ADirectory);
ValidateDirectories;
fDirCopier.Move(fSourceDir, fDestDir);
@@ -137,14 +142,12 @@ procedure TUserDBMove.ReportDeleteProgress(Sender: TObject;
procedure TUserDBMove.SetNewDBDirectory(Sender: TObject);
var
- Collection: TCollection;
Collections: TCollections;
begin
- // record new location BEFORE deleting old directory
Collections := TCollections.Instance;
- Collection := Collections.GetCollection(TCollectionID.__TMP__UserDBCollectionID);
- Collection.Location.Directory := fDestDir;
- Collections.Update(Collection);
+ // record new location BEFORE deleting old directory
+ fCollection.Location.Directory := fDestDir;
+ Collections.Update(fCollection);
// Persist collections immediately to save new directory ASAP to prevent
// directory change being lost following a program crash.
Collections.Save;
@@ -152,14 +155,14 @@ procedure TUserDBMove.SetNewDBDirectory(Sender: TObject);
procedure TUserDBMove.ValidateDirectories;
resourcestring
- sSameNames = 'The new database directory is the same as the current '
+ sSameNames = 'The new collection data directory is the same as the current '
+ 'directory.';
- sSourceMissing = 'No user database found';
- sCantMoveToSubDir = 'Can''t move database into a sub-directory of the '
- + 'existing database directory';
- sDestMustBeRooted = 'A full path to the new database directory must be '
+ sSourceMissing = 'No collection data found';
+ sCantMoveToSubDir = 'Can''t move the collection into a sub-directory of the '
+ + 'its existing data directory';
+ sDestMustBeRooted = 'A full path to the new collectio data directory must be '
+ 'provided.';
- sDestMustBeEmpty = 'The new database directory must be empty';
+ sDestMustBeEmpty = 'The new collection data directory must be empty';
begin
if not TPath.IsPathRooted(fDestDir) then
raise EInOutError.Create(sDestMustBeRooted);
@@ -174,7 +177,7 @@ procedure TUserDBMove.ValidateDirectories;
raise EInOutError.Create(sSameNames);
if StrStartsText(
- IncludeTrailingPathDelimiter(TAppInfo.UserDataDir), fDestDir
+ IncludeTrailingPathDelimiter(fCollection.Location.Directory), fDestDir
) then
raise EInOutError.Create(sCantMoveToSubDir);
end;
From 978c3e2665851b69be17bb24d3907df8af09a35d Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 19 Nov 2024 13:59:55 +0000
Subject: [PATCH 113/222] Add new v5 folder backup file format & make default
A new v5 folder backup file format was added. This new format adds a
custom field to the file header. This is a variable length array of
bytes preceeded by a 16 bit byte count. The custom header field can be
from 0 to High(Int16) bytes long. The FileID from previous formats was
retained.
The v5 file format is now the default file used for writing backup
files. Ability to read formats v1 to v4 in addition to v5 has been
retained.
The idea of the new custom header is to allow a byte array
representation of a collection ID to be stored in the file header thus
enabling a check to be made that a backup file contains a specific
collection's data files.
---
Src/UFolderBackup.pas | 208 +++++++++++++++++++++++++++++++-----------
1 file changed, 157 insertions(+), 51 deletions(-)
diff --git a/Src/UFolderBackup.pas b/Src/UFolderBackup.pas
index f4ca63668..2ed119b70 100644
--- a/Src/UFolderBackup.pas
+++ b/Src/UFolderBackup.pas
@@ -17,6 +17,13 @@
interface
+uses
+ // Delphi
+ SysUtils,
+ // Project
+ UExceptions;
+
+
type
///
@@ -28,47 +35,71 @@ TFolderBackup = class(TObject)
var fSrcFolder: string; // Folder to be backed up or restored
var fBakFile: string; // Full path to backup file
var fFileID: SmallInt; // Identifies the type of file
+ var fCustomHeader: TBytes;
public
- ///
- /// Creates object for a specific folder and backup file type.
+ /// Creates object for a specific folder and backup file type.
///
- /// Folder containing files to be backed up.
- /// Sub-directories are ignored.
- /// Name of backup file.
- /// Backup file type identifier. Specified backup file
- /// must have this identifier.
+ /// string [in] Folder containing files to
+ /// be backed up. Sub-directories are ignored.
+ /// string [in] Name of backup file.
+ /// SmallInt [in] Backup file type identifier.
+ ///
+ /// When restoring a folder BakFile must have the file ID
+ /// specified by FileID and no custom header.
constructor Create(const SrcFolder, BakFile: string;
- const FileID: SmallInt);
- ///
- /// Backs up the files from the source folder passed to constructor into a
- /// single backup file.
- ///
+ const FileID: SmallInt); overload;
+
+ /// Creates object for a specific folder, backup file type and
+ /// custom header.
+ /// string [in] Folder containing files to
+ /// be backed up. Sub-directories are ignored.
+ /// string [in] Name of backup file.
+ /// SmallInt [in] Backup file type identifier.
+ ///
+ /// TBytes [in] Backup file's custom
+ /// header. Can contain zero to High(SmallInt) bytes.
///
- /// Backup file is marked with the file ID passed to constructor.
+ /// When restoring a folder BakFile must have the file ID
+ /// specified by FileID and the custom header specified by
+ /// CustomHeader.
+ /// This constructor can only be used with file format v5 or later,
+ /// unless CustomHeader has length 0.
///
+ constructor Create(const SrcFolder, BakFile: string;
+ const FileID: SmallInt; const CustomHeader: TBytes); overload;
+
+ /// Backs up the files from the source folder passed to
+ /// constructor into a single file.
+ /// Backup file is marked with the file ID and any custom header
+ /// passed to constructor.
procedure Backup;
- ///
- /// Restores files from backup file into source folder passed to
- /// constructor
- ///
- ///
- /// An exception is raised if file type id is not the one passed to the
- /// constructor or if any checksum errors are detected.
- ///
+ /// Restores files from backup file into source folder passed to
+ /// constructor.
+ /// An exception is raised if file type id or any optional custom
+ /// header are not the sames as those passed to the constructor, or if any
+ /// checksum errors are detected.
procedure Restore;
end;
+ /// Type of exception raised by backup file loader objects.
+ EBackupFileLoader = class(ECodeSnip);
+
implementation
uses
// Delphi
- SysUtils, Classes, Generics.Collections,
+ Classes,
+ Generics.Collections,
// DelphiDabbler library
PJMD5,
// Project
- UBaseObjects, UDataStreamIO, UDOSDateTime, UEncodings, UExceptions, UIOUtils,
+ UBaseObjects,
+ UDataStreamIO,
+ UDOSDateTime,
+ UEncodings,
+ UIOUtils,
UUtils;
@@ -91,18 +122,20 @@ TBackupFileInfo = class(TNoConstructObject)
/// Class that writes files to a backup file using the latest file format.
TBackupFileWriter = class(TObject)
strict private
- var fFiles: TStrings; // Files to be backed up
- var fStream: TStream; // Stream to receive backed up files
- var fFileID: SmallInt; // ID of backup file
+ var
+ fFiles: TStrings; // Files to be backed up
+ fStream: TStream; // Stream to receive backed up files
+ fFileID: SmallInt; // ID of backup file
+ fCustomHeader: TBytes; // Bytes of optional custom header
/// Writes file header
procedure WriteHeader;
/// Writes meta information and contents of a specified file.
procedure WriteFileInfo(const FileName: string);
public
/// Sets up object to write specified files to a given stream marked with
- /// given file ID.
+ /// given file ID and optional custom header.
constructor Create(const Files: TStrings; const Stream: TStream;
- const FileID: SmallInt);
+ const FileID: SmallInt; const CustomHeader: TBytes); overload;
/// Generates backup file and writes it to stream passed to constructor.
procedure Generate;
end;
@@ -122,6 +155,7 @@ TFileInfo = record
const NulFileID = 0; // Used for File ID is formats that don't support it
strict private
var fFileID: SmallInt; // Value of FileID property
+ var fCustomHeader: TBytes;
var fFiles: TList; // List of file info records
var fEncoding: TEncoding; // Text encoding used in backup file
var fStream: TStream; // Stream containing backup data being read
@@ -138,7 +172,8 @@ TFileInfo = record
/// Skips over watermark at start of file.
procedure SkipWatermark;
/// Reads header information from the backup file.
- procedure ReadHeader(out FileID, FileCount: SmallInt); virtual; abstract;
+ procedure ReadHeader(out FileID: SmallInt; out CustomHeader: TBytes;
+ out FileCount: SmallInt); virtual; abstract;
/// Reads information about a file to be restored from the backup file.
procedure ReadFileInfo(out FileInfo: TFileInfo); virtual; abstract;
/// Reference to encoding used to read text from the backup file stream.
@@ -155,6 +190,9 @@ TFileInfo = record
procedure Load;
/// Backup file identifier.
property FileID: SmallInt read fFileID;
+
+ property CustomHeader: TBytes read fCustomHeader;
+
/// Gets enumerator for file list.
function GetEnumerator: TEnumerator;
/// Gets file's unique watermark
@@ -184,7 +222,8 @@ TV1BackupFileLoader = class(TTextBackupFileLoader)
/// Returns the backup file's text encoding
function GetFileEncoding: TEncoding; override;
/// Reads header information from the backup file.
- procedure ReadHeader(out FileID, FileCount: SmallInt); override;
+ procedure ReadHeader(out FileID: SmallInt; out CustomHeader: TBytes;
+ out FileCount: SmallInt); override;
/// Reads information about a file to be restored from the backup file.
procedure ReadFileInfo(out FileInfo: TBackupFileLoader.TFileInfo); override;
/// Returns the watermark that identifies the file format. In the v1 file
@@ -199,7 +238,8 @@ TV2BackupFileLoader = class(TTextBackupFileLoader)
/// Returns the backup file's text encoding
function GetFileEncoding: TEncoding; override;
/// Reads header information from the backup file.
- procedure ReadHeader(out FileID, FileCount: SmallInt); override;
+ procedure ReadHeader(out FileID: SmallInt; out CustomHeader: TBytes;
+ out FileCount: SmallInt); override;
/// Reads information about a file to be restored from the backup file.
procedure ReadFileInfo(out FileInfo: TBackupFileLoader.TFileInfo); override;
/// Returns the watermark that identifies the file format.
@@ -213,7 +253,8 @@ TV3BackupFileLoader = class(TTextBackupFileLoader)
/// Returns the backup file's text encoding
function GetFileEncoding: TEncoding; override;
/// Reads header information from the backup file.
- procedure ReadHeader(out FileID, FileCount: SmallInt); override;
+ procedure ReadHeader(out FileID: SmallInt; out CustomHeader: TBytes;
+ out FileCount: SmallInt); override;
/// Reads information about a file to be restored from the backup file.
procedure ReadFileInfo(out FileInfo: TBackupFileLoader.TFileInfo); override;
/// Returns the watermark that identifies the file format.
@@ -227,7 +268,23 @@ TV4BackupFileLoader = class(TBinaryBackupFileLoader)
/// Returns the backup file's text encoding
function GetFileEncoding: TEncoding; override;
/// Reads header information from the backup file.
- procedure ReadHeader(out FileID, FileCount: SmallInt); override;
+ procedure ReadHeader(out FileID: SmallInt; out CustomHeader: TBytes;
+ out FileCount: SmallInt); override;
+ /// Reads information about a file to be restored from the backup file.
+ procedure ReadFileInfo(out FileInfo: TBackupFileLoader.TFileInfo); override;
+ /// Returns the watermark that identifies the file format.
+ class function GetWatermark: TBytes; override;
+ end;
+
+ /// Loads and provides access to data from a backup file that has
+ /// the version 5 file format.
+ TV5BackupFileLoader = class(TBinaryBackupFileLoader)
+ strict protected
+ /// Returns the backup file's text encoding
+ function GetFileEncoding: TEncoding; override;
+ /// Reads header information from the backup file.
+ procedure ReadHeader(out FileID: SmallInt; out CustomHeader: TBytes;
+ out FileCount: SmallInt); override;
/// Reads information about a file to be restored from the backup file.
procedure ReadFileInfo(out FileInfo: TBackupFileLoader.TFileInfo); override;
/// Returns the watermark that identifies the file format.
@@ -254,9 +311,6 @@ TBackupFileLoaderFactory = class sealed(TNoConstructObject)
class function Create(const Stream: TStream): TBackupFileLoader;
end;
- /// Type of exception raised by backup file loader objects.
- EBackupFileLoader = class(ECodeSnip);
-
{ TFolderBackup }
procedure TFolderBackup.Backup;
@@ -270,7 +324,9 @@ procedure TFolderBackup.Backup;
ListFiles(fSrcFolder, '*.*', Files, False);
FS := TFileStream.Create(fBakFile, fmCreate);
try
- FileWriter := TBackupFileWriter.Create(Files, FS, fFileID);
+ FileWriter := TBackupFileWriter.Create(
+ Files, FS, fFileID, fCustomHeader
+ );
try
FileWriter.Generate;
finally
@@ -291,18 +347,27 @@ constructor TFolderBackup.Create(const SrcFolder, BakFile: string;
fSrcFolder := ExcludeTrailingPathDelimiter(SrcFolder);
fBakFile := BakFile;
fFileID := FileID;
+ SetLength(fCustomHeader, 0);
+end;
+
+constructor TFolderBackup.Create(const SrcFolder, BakFile: string;
+ const FileID: SmallInt; const CustomHeader: TBytes);
+begin
+ Create(SrcFolder, BakFile, FileID);
+ fCustomHeader := Copy(CustomHeader);
end;
procedure TFolderBackup.Restore;
var
BakFileStream: TStream; // stream onto backup file
BakFileLoader: TBackupFileLoader; // loads & analyses backup file
- FileSpec: string; // name & path of each file to restore
+ RestoreFileSpec: string; // name & path of each file to restore
DOSDateTime: IDOSDateTime; // date stamp of each file to restore
FileInfo: TBackupFileLoader.TFileInfo; // info about each file to restore
resourcestring
// Error message
sBadFileID = 'Invalid file ID for file "%s"';
+ sBadCustomHeader = 'Invalid custom header for file "%s"';
begin
// Make sure restore folder exists
EnsureFolders(fSrcFolder);
@@ -315,16 +380,19 @@ procedure TFolderBackup.Restore;
// Test for correct file ID if present (NulFileID indicates not present)
if (BakFileLoader.FileID <> TBackupFileLoader.NulFileID)
and (BakFileLoader.FileID <> fFileID) then
- raise EBackupFileLoader.CreateFmt(sBadFileID, [FileSpec]);
+ raise EBackupFileLoader.CreateFmt(sBadFileID, [fBakFile]);
+ if not IsEqualBytes(BakFileLoader.CustomHeader, fCustomHeader) then
+ raise EBackupFileLoader.CreateFmt(sBadCustomHeader, [fBakFile]);
// Restore each file
for FileInfo in BakFileLoader do
begin
- FileSpec := IncludeTrailingPathDelimiter(fSrcFolder) + FileInfo.Name;
+ RestoreFileSpec := IncludeTrailingPathDelimiter(fSrcFolder)
+ + FileInfo.Name;
DOSDateTime := TDOSDateTimeFactory.CreateFromDOSTimeStamp(
FileInfo.TimeStamp
);
- TFileIO.WriteAllBytes(FileSpec, FileInfo.Content);
- DOSDateTime.ApplyToFile(FileSpec);
+ TFileIO.WriteAllBytes(RestoreFileSpec, FileInfo.Content);
+ DOSDateTime.ApplyToFile(RestoreFileSpec);
end;
finally
BakFileLoader.Free;
@@ -367,7 +435,7 @@ procedure TBackupFileLoader.Load;
begin
try
SkipWatermark;
- ReadHeader(fFileID, FileCount);
+ ReadHeader(fFileID, fCustomHeader, FileCount);
for I := 1 to FileCount do
begin
ReadFileInfo(FI);
@@ -435,9 +503,11 @@ procedure TV1BackupFileLoader.ReadFileInfo(
FileInfo.Content := Reader.ReadSizedRawData16;
end;
-procedure TV1BackupFileLoader.ReadHeader(out FileID, FileCount: SmallInt);
+procedure TV1BackupFileLoader.ReadHeader(out FileID: SmallInt;
+ out CustomHeader: TBytes; out FileCount: SmallInt);
begin
FileID := NulFileID;
+ SetLength(CustomHeader, 0);
FileCount := Reader.ReadInt16;
end;
@@ -464,9 +534,11 @@ procedure TV2BackupFileLoader.ReadFileInfo(
FileInfo.Content := Reader.ReadSizedRawData32;
end;
-procedure TV2BackupFileLoader.ReadHeader(out FileID, FileCount: SmallInt);
+procedure TV2BackupFileLoader.ReadHeader(out FileID: SmallInt;
+ out CustomHeader: TBytes; out FileCount: SmallInt);
begin
FileID := NulFileID;
+ SetLength(CustomHeader, 0);
FileCount := Reader.ReadInt16;
end;
@@ -497,9 +569,11 @@ procedure TV3BackupFileLoader.ReadFileInfo(
FileInfo.Content := Reader.ReadSizedRawData32;
end;
-procedure TV3BackupFileLoader.ReadHeader(out FileID, FileCount: SmallInt);
+procedure TV3BackupFileLoader.ReadHeader(out FileID: SmallInt;
+ out CustomHeader: TBytes; out FileCount: SmallInt);
begin
FileID := Reader.ReadInt16;
+ SetLength(CustomHeader, 0);
FileCount := Reader.ReadInt16;
end;
@@ -524,21 +598,51 @@ procedure TV4BackupFileLoader.ReadFileInfo(
FileInfo.Content := Reader.ReadSizedRawData32;
end;
-procedure TV4BackupFileLoader.ReadHeader(out FileID, FileCount: SmallInt);
+procedure TV4BackupFileLoader.ReadHeader(out FileID: SmallInt;
+ out CustomHeader: TBytes; out FileCount: SmallInt);
begin
FileID := Reader.ReadInt16;
+ SetLength(CustomHeader, 0);
FileCount := Reader.ReadInt16;
end;
-{ TBackupFileWriter }
+{ TV5BackupFileLoader }
+
+function TV5BackupFileLoader.GetFileEncoding: TEncoding;
+begin
+ Result := TEncoding.UTF8;
+end;
+
+class function TV5BackupFileLoader.GetWatermark: TBytes;
+begin
+ Result := TBackupFileInfo.WatermarkBytes('FFFF000500000000');
+end;
+
+procedure TV5BackupFileLoader.ReadFileInfo(
+ out FileInfo: TBackupFileLoader.TFileInfo);
+begin
+ FileInfo.Name := Reader.ReadSizedString16;
+ FileInfo.TimeStamp := Reader.ReadInt32;
+ FileInfo.Checksum := Reader.ReadBytes(SizeOf(FileInfo.Checksum));
+ FileInfo.Content := Reader.ReadSizedRawData32;
+end;
+
+procedure TV5BackupFileLoader.ReadHeader(out FileID: SmallInt;
+ out CustomHeader: TBytes; out FileCount: SmallInt);
+begin
+ FileID := Reader.ReadInt16;
+ CustomHeader := Reader.ReadSizedBytes16;
+ FileCount := Reader.ReadInt16;
+end;
constructor TBackupFileWriter.Create(const Files: TStrings;
- const Stream: TStream; const FileID: SmallInt);
+ const Stream: TStream; const FileID: SmallInt; const CustomHeader: TBytes);
begin
inherited Create;
fFiles := Files;
fStream := Stream;
fFileID := FileID;
+ fCustomHeader := Copy(CustomHeader);
end;
procedure TBackupFileWriter.Generate;
@@ -581,6 +685,7 @@ procedure TBackupFileWriter.WriteHeader;
TBackupFileInfo.CurrentLoader.GetWatermark
);
BinWriter.WriteInt16(fFileID);
+ BinWriter.WriteSizedBytes16(fCustomHeader);
BinWriter.WriteInt16(fFiles.Count);
finally
BinWriter.Free;
@@ -616,7 +721,8 @@ class function TBackupFileLoaderFactory.Create(
begin
fClassList := TArray.Create(
TV1BackupFileLoader, TV2BackupFileLoader,
- TV3BackupFileLoader, TV4BackupFileLoader
+ TV3BackupFileLoader, TV4BackupFileLoader,
+ TV5BackupFileLoader
);
end;
@@ -694,7 +800,7 @@ class function TBackupFileLoaderFactory.GetLoaderClass(
class function TBackupFileInfo.CurrentLoader: TBackupFileLoaderClass;
begin
- Result := TV4BackupFileLoader;
+ Result := TV5BackupFileLoader;
end;
class function TBackupFileInfo.WatermarkBytes(const Watermark: string):
From 23116cc46aa3ec626c0efec4ca0169beb0ab47cd Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 19 Nov 2024 14:13:16 +0000
Subject: [PATCH 114/222] Change Database backup code to backup any collection
The code in UUserDBBackup and UUserDBMgr was modified to backup and
restore a specified collection's data files. Before only the "user
database" was handled.
A new FmCollectionBackup dialogue box was added to the project. This is
used when backing up and restoring to get the collection to be backed up
/ restored and the name of the backup file.
The backup and restore menu items and hints were updated to refer to
collections instead of the user database.
Many comments and method names still refer to the "user" database and
need to be updated.
---
Src/CodeSnip.dpr | 3 +-
Src/CodeSnip.dproj | 3 +
Src/FmCollectionBackup.dfm | 70 +++++++++++++++
Src/FmCollectionBackup.pas | 152 +++++++++++++++++++++++++++++++
Src/FmMain.dfm | 10 +--
Src/UUserDBBackup.pas | 29 +++++-
Src/UUserDBMgr.pas | 180 +++++++++++++++----------------------
7 files changed, 330 insertions(+), 117 deletions(-)
create mode 100644 Src/FmCollectionBackup.dfm
create mode 100644 Src/FmCollectionBackup.pas
diff --git a/Src/CodeSnip.dpr b/Src/CodeSnip.dpr
index 73f6da5c6..1d97e2f80 100644
--- a/Src/CodeSnip.dpr
+++ b/Src/CodeSnip.dpr
@@ -378,7 +378,8 @@ uses
UTabSeparatedFileIO in 'UTabSeparatedFileIO.pas',
DBIO.UCategoryIO in 'DBIO.UCategoryIO.pas',
UCollectionListAdapter in 'UCollectionListAdapter.pas',
- DBIO.MetaData.DCSC in 'DBIO.MetaData.DCSC.pas';
+ DBIO.MetaData.DCSC in 'DBIO.MetaData.DCSC.pas',
+ FmCollectionBackup in 'FmCollectionBackup.pas' {CollectionBackupDlg};
// Include resources
{$Resource ExternalObj.tlb} // Type library file
diff --git a/Src/CodeSnip.dproj b/Src/CodeSnip.dproj
index d5132b5a5..3c4760e24 100644
--- a/Src/CodeSnip.dproj
+++ b/Src/CodeSnip.dproj
@@ -585,6 +585,9 @@
+
+
+ Base
diff --git a/Src/FmCollectionBackup.dfm b/Src/FmCollectionBackup.dfm
new file mode 100644
index 000000000..86282bbfa
--- /dev/null
+++ b/Src/FmCollectionBackup.dfm
@@ -0,0 +1,70 @@
+inherited CollectionBackupDlg: TCollectionBackupDlg
+ Caption = 'Choose Collection & Backup File'
+ ExplicitWidth = 474
+ ExplicitHeight = 375
+ PixelsPerInch = 96
+ TextHeight = 13
+ inherited pnlBody: TPanel
+ object lblCollection: TLabel
+ Left = 0
+ Top = 7
+ Width = 80
+ Height = 13
+ Caption = 'Select &collection:'
+ FocusControl = cbCollection
+ end
+ object lblPath: TLabel
+ Left = 0
+ Top = 61
+ Width = 180
+ Height = 13
+ Caption = 'Enter the full path of the back up &file:'
+ FocusControl = edPath
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ end
+ object cbCollection: TComboBox
+ Left = 0
+ Top = 24
+ Width = 358
+ Height = 21
+ Style = csDropDownList
+ TabOrder = 0
+ end
+ object edPath: TEdit
+ Left = 0
+ Top = 80
+ Width = 325
+ Height = 21
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ TabOrder = 1
+ end
+ object btnBrowse: TButton
+ Left = 331
+ Top = 80
+ Width = 27
+ Height = 21
+ Caption = '...'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ TabOrder = 2
+ OnClick = btnBrowseClick
+ end
+ end
+ inherited btnOK: TButton
+ OnClick = btnOKClick
+ end
+end
diff --git a/Src/FmCollectionBackup.pas b/Src/FmCollectionBackup.pas
new file mode 100644
index 000000000..d39d4aa33
--- /dev/null
+++ b/Src/FmCollectionBackup.pas
@@ -0,0 +1,152 @@
+{
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/
+ *
+ * Copyright (C) 2024, Peter Johnson (gravatar.com/delphidabbler).
+ *
+ * Implements a dialogue box that enables the user to choose a collection to
+ * backup or restore along with the directory to backup to or restore from.
+}
+
+
+unit FmCollectionBackup;
+
+interface
+
+uses
+ // Delphi
+ Classes,
+ Controls,
+ StdCtrls,
+ ExtCtrls,
+ // Project
+ DB.UCollections,
+ FmGenericOKDlg,
+ UCollectionListAdapter;
+
+type
+ TCollectionBackupDlg = class(TGenericOKDlg)
+ lblCollection: TLabel;
+ cbCollection: TComboBox;
+ lblPath: TLabel;
+ edPath: TEdit;
+ btnBrowse: TButton;
+ procedure FormCreate(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure btnBrowseClick(Sender: TObject);
+ procedure btnOKClick(Sender: TObject);
+ strict private
+ var
+ fFileName: string;
+ fCollection: TCollection;
+ fCollList: TCollectionListAdapter;
+ function GetFilePathFromEditCtrl: string;
+ strict protected
+ procedure ConfigForm; override;
+ procedure ArrangeForm; override;
+ public
+ class function Execute(AOwner: TComponent;
+ out AFileName: string; out ACollection: TCollection): Boolean;
+ end;
+
+implementation
+
+{$R *.dfm}
+
+uses
+ // Delphi
+ IOUtils,
+ Dialogs,
+ // Project
+ UCtrlArranger,
+ UMessageBox,
+ UOpenDialogHelper,
+ USaveDialogEx,
+ UStrUtils;
+
+procedure TCollectionBackupDlg.ArrangeForm;
+begin
+ TCtrlArranger.AlignLefts([lblCollection, cbCollection, lblPath, edPath], 0);
+ // row 1
+ lblCollection.Top := 0;
+ // row 2
+ TCtrlArranger.MoveBelow(lblCollection, cbCollection, 6);
+ // row 3
+ TCtrlArranger.MoveBelow(cbCollection, lblPath, 12);
+ // row 4
+ TCtrlArranger.MoveToRightOf(edPath, btnBrowse, 6);
+ TCtrlArranger.AlignVCentres(
+ TCtrlArranger.BottomOf(lblPath, 6), [edPath, btnBrowse]
+ );
+ pnlBody.ClientWidth := TCtrlArranger.TotalControlWidth(pnlBody);
+ pnlBody.ClientHeight := TCtrlArranger.TotalControlHeight(pnlBody) + 8;
+ inherited;
+end;
+
+procedure TCollectionBackupDlg.btnBrowseClick(Sender: TObject);
+var
+ SaveDlg: TSaveDialogEx; // save dialog box used to name backup file
+resourcestring
+ // Dialog box caption
+ sCaption = 'Save Backup';
+begin
+ // Get backup file name from user via standard save dialog box
+ SaveDlg := TSaveDialogEx.Create(nil);
+ try
+ SaveDlg.Title := sCaption;
+ SaveDlg.Options := [ofShowHelp, ofExtensionDifferent, ofPathMustExist,
+ ofNoTestFileCreate, ofEnableSizing];
+ SaveDlg.HelpKeyword := 'SaveBackupDlg';
+ if SaveDlg.Execute then
+ edPath.Text := SaveDlg.FileName;
+ finally
+ SaveDlg.Free;
+ end;
+end;
+
+procedure TCollectionBackupDlg.btnOKClick(Sender: TObject);
+begin
+ fFileName := GetFilePathFromEditCtrl;
+ fCollection := fCollList.Collection(cbCollection.ItemIndex);
+end;
+
+procedure TCollectionBackupDlg.ConfigForm;
+begin
+ inherited;
+ fCollList.ToStrings(cbCollection.Items);
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
+end;
+
+class function TCollectionBackupDlg.Execute(AOwner: TComponent;
+ out AFileName: string; out ACollection: TCollection): Boolean;
+var
+ Dlg: TCollectionBackupDlg;
+begin
+ Dlg := TCollectionBackupDlg.Create(AOwner);
+ Result := Dlg.ShowModal = mrOK;
+ if Result then
+ begin
+ AFileName := Dlg.fFileName;
+ ACollection := Dlg.fCollection;
+ end;
+end;
+
+procedure TCollectionBackupDlg.FormCreate(Sender: TObject);
+begin
+ inherited;
+ fCollList := TCollectionListAdapter.Create;
+end;
+
+procedure TCollectionBackupDlg.FormDestroy(Sender: TObject);
+begin
+ fCollList.Free;
+ inherited;
+end;
+
+function TCollectionBackupDlg.GetFilePathFromEditCtrl: string;
+begin
+ Result := StrTrim(edPath.Text);
+end;
+
+end.
diff --git a/Src/FmMain.dfm b/Src/FmMain.dfm
index e8cf1d1b8..5193d9d86 100644
--- a/Src/FmMain.dfm
+++ b/Src/FmMain.dfm
@@ -615,18 +615,18 @@ inherited MainForm: TMainForm
end
object actBackupDatabase: TAction
Category = 'Database'
- Caption = 'Backup User Database...'
- Hint = 'Backup user database|Backup the user-defined snippet database'
+ Caption = 'Backup Collection Data...'
+ Hint = 'Backup a collection|Backup a collection'#39's data files'
ImageIndex = 33
OnExecute = actBackupDatabaseExecute
OnUpdate = ActNonEmptyDBUpdate
end
object actRestoreDatabase: TAction
Category = 'Database'
- Caption = 'Restore User Database...'
+ Caption = 'Restore Collection Data...'
Hint =
- 'Restore user database|Restore the user-defined snippet database ' +
- 'from a backup'
+ 'Restore a collection|Restore a collection'#39's data files from a ba' +
+ 'ckup'
ImageIndex = 32
OnExecute = actRestoreDatabaseExecute
end
diff --git a/Src/UUserDBBackup.pas b/Src/UUserDBBackup.pas
index 7c50ff22c..dd063eda2 100644
--- a/Src/UUserDBBackup.pas
+++ b/Src/UUserDBBackup.pas
@@ -12,11 +12,15 @@
unit UUserDBBackup;
+{TODO -cRefactoring: Rename this unit/classes/methods: the names refer to the
+ CodeSnip 4 database structure but the code now works with collections}
+
interface
uses
// Project
+ DB.UCollections,
UFolderBackup;
@@ -29,9 +33,10 @@ interface
}
TUserDBBackup = class sealed(TFolderBackup)
strict private
- const cFileID = SmallInt($DBAC); // User database backup file ID
+ class function MakeFileID(const ACollection: TCollection): SmallInt;
public
- constructor Create(const BackupFile: string);
+ constructor Create(const BackupFile: string;
+ const ACollection: TCollection);
{Class constructor. Sets up object to backup user database to a specified
file.
@param BackupFile [in] Name of backup file.
@@ -43,19 +48,35 @@ implementation
uses
+ // Delphi
+ SysUtils,
// Project
UAppInfo;
{ TUserDBBackup }
-constructor TUserDBBackup.Create(const BackupFile: string);
+constructor TUserDBBackup.Create(const BackupFile: string;
+ const ACollection: TCollection);
{Class constructor. Sets up object to backup user database to a specified
file.
@param BackupFile [in] Name of backup file.
}
begin
- inherited Create(TAppInfo.UserDataDir, BackupFile, cFileID);
+ inherited Create(
+ ACollection.Location.Directory,
+ BackupFile,
+ MakeFileID(ACollection),
+ ACollection.UID.ToArray
+ );
+end;
+
+class function TUserDBBackup.MakeFileID(const ACollection: TCollection):
+ SmallInt;
+begin
+ // Backup file ID is $Fxxx where xxx is ordinal value of format kind.
+ // The $F indicates that the file is a backup of a collection data format.
+ Result := SmallInt($F000 or UInt16(Ord(ACollection.CollectionFormatKind)));
end;
end.
diff --git a/Src/UUserDBMgr.pas b/Src/UUserDBMgr.pas
index a02e62759..beed308e2 100644
--- a/Src/UUserDBMgr.pas
+++ b/Src/UUserDBMgr.pas
@@ -14,6 +14,8 @@
interface
+{TODO -cRefactoring: Rename this unit/classes/methods: the names refer to the
+ CodeSnip 4 database structure but the code now works with collections}
uses
// Delphi
@@ -30,21 +32,6 @@ interface
/// Static class that manages user's interaction with user database
/// and performs move and backup operations on it.
TUserDBMgr = class(TNoConstructObject)
- strict private
- /// OnClose event handler for open dialogue box. Checks if
- /// dialogue box can close.
- /// TObject [in] Reference to dialogue box in
- /// question.
- /// Boolean [in/out] Set to True to permit dialogue
- /// to close or False to inhibit closure.
- class procedure CanOpenDialogClose(Sender: TObject; var CanClose: Boolean);
- /// OnClose event handler for save dialogue box. Checks if
- /// dialogue box can close.
- /// TObject [in] Reference to dialogue box in
- /// question.
- /// Boolean [in/out] Set to True to permit dialogue
- /// to close or False to inhibit closure.
- class procedure CanSaveDialogClose(Sender: TObject; var CanClose: Boolean);
public
/// Enables user to adds a new user defined snippet to the
/// database using the snippets editor.
@@ -101,19 +88,32 @@ implementation
uses
// Delphi
- SysUtils, Dialogs, Windows {for inlining}, IOUtils,
+ SysUtils,
+ Dialogs,
+ Windows {for inlining},
+ IOUtils,
// Project
- DB.UCollections, DB.UMain, DB.USnippet,
- FmAddCategoryDlg, FmDeleteCategoryDlg, FmDuplicateSnippetDlg,
- FmRenameCategoryDlg, FmSnippetsEditorDlg,
+ DB.UCollections,
+ DB.UMain,
+ DB.USnippet,
+ FmAddCategoryDlg,
+ FmCollectionBackup,
+ FmDeleteCategoryDlg,
+ FmDeleteUserDBDlg,
+ FmDuplicateSnippetDlg,
+ FmRenameCategoryDlg,
+ FmSnippetsEditorDlg,
{$IFNDEF PORTABLE}
FmUserDataPathDlg,
{$ENDIF}
- FmDeleteUserDBDlg, FmWaitDlg,
+ FmWaitDlg,
UAppInfo,
- UConsts, UExceptions, UIStringList, UMessageBox, UOpenDialogEx,
- UOpenDialogHelper, USaveDialogEx,
- UUserDBBackup, UWaitForThreadUI;
+ UConsts,
+ UExceptions,
+ UIStringList,
+ UMessageBox,
+ UUserDBBackup,
+ UWaitForThreadUI;
type
/// Base class for classes that execute a user database management
@@ -177,13 +177,16 @@ TRestoreThread = class(TThread)
var
/// Name of backup file to be restored.
fBakFileName: string;
+
+ fCollection: TCollection;
strict protected
/// Restores the user database from a backup.
procedure Execute; override;
public
/// Constructs a new, suspended, thread that can restore the
/// database from the given backup file.
- constructor Create(const BakFileName: string);
+ constructor Create(const BakFileName: string;
+ const ACollection: TCollection);
end;
public
/// Performs a user database restoration operation from in a
@@ -194,7 +197,8 @@ TRestoreThread = class(TThread)
/// box, over which it is aligned.
/// string [in] Name of backup file to be
/// restored.
- class procedure Execute(AOwner: TComponent; const BakFileName: string);
+ class procedure Execute(AOwner: TComponent; const BakFileName: string;
+ const ACollection: TCollection);
end;
type
@@ -209,13 +213,16 @@ TBackupThread = class(TThread)
var
/// Name of backup file to be created.
fBakFileName: string;
+
+ fCollection: TCollection;
strict protected
/// Backs up the user database.
procedure Execute; override;
public
/// Constructs a new, suspended, thread that can backup the
/// database to the given backup file.
- constructor Create(const BakFileName: string);
+ constructor Create(const BakFileName: string;
+ const ACollection: TCollection);
end;
public
/// Performs a user database backup operation from in a background
@@ -225,7 +232,8 @@ TBackupThread = class(TThread)
/// box, over which it is aligned.
/// string [in] Name of backup file to be
/// created.
- class procedure Execute(AOwner: TComponent; const BakFileName: string);
+ class procedure Execute(AOwner: TComponent; const BakFileName: string;
+ const ACollection: TCollection);
end;
{ TUserDBMgr }
@@ -244,24 +252,19 @@ class procedure TUserDBMgr.AddSnippet;
class procedure TUserDBMgr.BackupDatabase(ParentCtrl: TComponent);
var
- SaveDlg: TSaveDialogEx; // save dialog box used to name backup file
+ FileName: string;
+ Collection: TCollection;
resourcestring
- // Dialog box caption
- sCaption = 'Save Backup';
+ sOverwritePrompt = '"%s" already exists. OK to overwrite?';
begin
- // Get backup file name from user via standard save dialog box
- SaveDlg := TSaveDialogEx.Create(nil);
- try
- SaveDlg.OnCanClose := CanSaveDialogClose;
- SaveDlg.Title := sCaption;
- SaveDlg.Options := [ofShowHelp, ofExtensionDifferent, ofPathMustExist,
- ofNoTestFileCreate, ofEnableSizing];
- SaveDlg.HelpKeyword := 'SaveBackupDlg';
- if SaveDlg.Execute then
- // Perform backup
- TUserDBBackupUI.Execute(ParentCtrl, SaveDlg.FileName);
- finally
- SaveDlg.Free;
+ if TCollectionBackupDlg.Execute(ParentCtrl, FileName, Collection) then
+ begin
+ if TFile.Exists(FileName)
+ and not TMessageBox.Confirm(
+ ParentCtrl, Format(sOverwritePrompt, [FileName])
+ ) then
+ Exit;
+ TUserDBBackupUI.Execute(ParentCtrl, FileName, Collection);
end;
end;
@@ -286,29 +289,6 @@ class function TUserDBMgr.CanEdit(ViewItem: IView): Boolean;
Result := Supports(ViewItem, ISnippetView);
end;
-class procedure TUserDBMgr.CanOpenDialogClose(Sender: TObject;
- var CanClose: Boolean);
-var
- FileName: string; // name of file entered in dialog box
-resourcestring
- // Error message
- sFileDoesNotExist = '"%s" does not exist.';
-begin
- CanClose := False;
- FileName := FileOpenEditedFileName(Sender as TOpenDialogEx);
- if not FileExists(FileName) then
- begin
- // Specified file doesn't exist: inhibit closure
- TMessageBox.Error(
- Sender as TOpenDialogEx,
- Format(sFileDoesNotExist, [FileName])
- );
- Exit;
- end;
- // All OK: allow closure
- CanClose := True;
-end;
-
class function TUserDBMgr.CanRenameACategory: Boolean;
begin
Result := True;
@@ -320,23 +300,6 @@ class function TUserDBMgr.CanSave: Boolean;
Result := (Database as IDatabaseEdit).Updated;
end;
-class procedure TUserDBMgr.CanSaveDialogClose(Sender: TObject;
- var CanClose: Boolean);
-var
- FileName: string; // name of file entered in dialog box
-resourcestring
- // Error message
- sOverwritePrompt = '"%s" already exists. OK to overwrite?';
-begin
- FileName := FileOpenEditedFileName(Sender as TSaveDialogEx);
- if FileExists(FileName) then
- // File exists: allow closure if user permits file to be overwritten
- CanClose := TMessageBox.Confirm(
- Sender as TSaveDialogEx,
- Format(sOverwritePrompt, [FileName])
- );
-end;
-
class procedure TUserDBMgr.DeleteACategory;
var
CatList: TCategoryList; // list of deletable categories
@@ -471,24 +434,23 @@ class procedure TUserDBMgr.RenameACategory;
class function TUserDBMgr.RestoreDatabase(ParentCtrl: TComponent): Boolean;
var
- Dlg: TOpenDialogEx; // open dialog box used to select backup file
+ FileName: string;
+ Collection: TCollection;
resourcestring
- sCaption = 'Open Backup File'; // dialog box caption
+ sFileDoesNotExist = '"%s" does not exist.';
begin
- // Get name of backup file from user via standard open dialog box
- Dlg := TOpenDialogEx.Create(nil);
- try
- Dlg.OnCanClose := CanOpenDialogClose;
- Dlg.Title := sCaption;
- Dlg.Options := [ofShowHelp, ofPathMustExist, ofHideReadOnly,
- ofEnableSizing];
- Dlg.HelpKeyword := 'RestoreBackupDlg';
- Result := Dlg.Execute;
- if Result then
- // Perform restoration
- TUserDBRestoreUI.Execute(ParentCtrl, Dlg.FileName);
- finally
- Dlg.Free;
+ Result := TCollectionBackupDlg.Execute(ParentCtrl, FileName, Collection);
+ if Result then
+ begin
+ if not TFile.Exists(FileName) then
+ begin
+ // Specified file doesn't exist: inhibit closure
+ TMessageBox.Error(
+ ParentCtrl, Format(sFileDoesNotExist, [FileName])
+ );
+ Exit;
+ end;
+ TUserDBRestoreUI.Execute(ParentCtrl, FileName, Collection);
end;
end;
@@ -546,14 +508,14 @@ procedure TUserDBSaveUI.TSaveThread.Execute;
{ TUserDBRestoreUI }
class procedure TUserDBRestoreUI.Execute(AOwner: TComponent;
- const BakFileName: string);
+ const BakFileName: string; const ACollection: TCollection);
resourcestring
// Caption for wait dialog
sWaitCaption = 'Restoring database files...';
var
Thread: TRestoreThread; // thread that performs restore operation
begin
- Thread := TRestoreThread.Create(BakFileName);
+ Thread := TRestoreThread.Create(BakFileName, ACollection);
try
RunThreadWithWaitDlg(Thread, AOwner, sWaitCaption);
finally
@@ -563,17 +525,19 @@ class procedure TUserDBRestoreUI.Execute(AOwner: TComponent;
{ TUserDBRestoreUI.TRestoreThread }
-constructor TUserDBRestoreUI.TRestoreThread.Create(const BakFileName: string);
+constructor TUserDBRestoreUI.TRestoreThread.Create(const BakFileName: string;
+ const ACollection: TCollection);
begin
inherited Create(True);
fBakFileName := BakFileName;
+ fCollection := ACollection;
end;
procedure TUserDBRestoreUI.TRestoreThread.Execute;
var
UserDBBackup: TUserDBBackup;
begin
- UserDBBackup := TUserDBBackup.Create(fBakFileName);
+ UserDBBackup := TUserDBBackup.Create(fBakFileName, fCollection);
try
UserDBBackup.Restore;
finally
@@ -584,14 +548,14 @@ procedure TUserDBRestoreUI.TRestoreThread.Execute;
{ TUserDBBackupUI }
class procedure TUserDBBackupUI.Execute(AOwner: TComponent;
- const BakFileName: string);
+ const BakFileName: string; const ACollection: TCollection);
resourcestring
// Caption for wait dialog
sWaitCaption = 'Backing up database...';
var
Thread: TBackupThread; // thread that performs restore operation
begin
- Thread := TBackupThread.Create(BakFileName);
+ Thread := TBackupThread.Create(BakFileName, ACollection);
try
RunThreadWithWaitDlg(Thread, AOwner, sWaitCaption);
finally
@@ -601,10 +565,12 @@ class procedure TUserDBBackupUI.Execute(AOwner: TComponent;
{ TUserDBBackupUI.TBackupThread }
-constructor TUserDBBackupUI.TBackupThread.Create(const BakFileName: string);
+constructor TUserDBBackupUI.TBackupThread.Create(const BakFileName: string;
+ const ACollection: TCollection);
begin
inherited Create(True);
fBakFileName := BakFileName;
+ fCollection := ACollection;
end;
procedure TUserDBBackupUI.TBackupThread.Execute;
@@ -614,7 +580,7 @@ procedure TUserDBBackupUI.TBackupThread.Execute;
// Dialog box caption
sCaption = 'Save Backup';
begin
- UserDBBackup := TUserDBBackup.Create(fBakFileName);
+ UserDBBackup := TUserDBBackup.Create(fBakFileName, fCollection);
try
UserDBBackup.Backup;
finally
From 72550dc0210a4e1f776d6589f49e18fa57b71d0f Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 19 Nov 2024 14:21:45 +0000
Subject: [PATCH 115/222] Update DCSCv2 saver to use new v5 backup file format
The code that saves the DelphiDabbler Code Snippets Collection's content
to storage backs up the collection before saving so that it can be
restored should anything go wrong. This backup / restore code was
modified to call TUserDBBackup instead of directly calling TFolderBackup
so that the correct FileID and Custom header for this file format
backups are written to the backup file.
---
Src/DB.UDatabaseIO.pas | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index d265d42cb..09efcb63f 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -138,9 +138,9 @@ implementation
DBIO.UXMLDataIO,
UAppInfo,
UConsts,
- UFolderBackup,
UIStringList,
- USnippetIDs;
+ USnippetIDs,
+ UUserDBBackup;
type
@@ -347,8 +347,6 @@ TDCSCV2FormatSaver = class(TFormatSaver,
IDataFormatSaver
)
strict private
- const
- BakFileID = SmallInt($DC52);
var
fBakFile: string; // Backup file used in case of failure
@@ -800,11 +798,9 @@ procedure TFormatSaver.WriteSnippets;
procedure TDCSCV2FormatSaver.Backup;
var
- FB: TFolderBackup;
+ FB: TUserDBBackup; // TODO -cRefactoring: this is correct class (will change)
begin
- FB := TFolderBackup.Create(
- Collection.Location.Directory, fBakFile, BakFileID
- );
+ FB := TUserDBBackup.Create(fBakFile, Collection);
try
FB.Backup;
finally
@@ -830,11 +826,9 @@ function TDCSCV2FormatSaver.CreateWriter: IDataWriter;
procedure TDCSCV2FormatSaver.Restore;
var
- FB: TFolderBackup;
+ FB: TUserDBBackup;
begin
- FB := TFolderBackup.Create(
- Collection.Location.Directory, fBakFile, BakFileID
- );
+ FB := TUserDBBackup.Create(fBakFile, Collection);
try
FB.Restore;
finally
From a45f38d5a09a18929bbe31db56bc97d5425be49c Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 19 Nov 2024 16:41:09 +0000
Subject: [PATCH 116/222] Change database delete code to work with collections
The code in UUserDBMgr was changed to delete all snippets in a given
collection rather than to delete just the "user database".
The FmDeleteUserDBDlg was modified to not only get permission to delete
the collection but also to get the user to select collection whose
data is to be deleted.
The delete database menu item and hints were updated to refer to
collections instead of the user database.
The explanatory HTML that appears in FmDeleteUserDBDlg was modified re
the change to deleting a selected collection.
---
Src/FmDeleteUserDBDlg.dfm | 37 +++++++++++++----
Src/FmDeleteUserDBDlg.pas | 72 ++++++++++++++++++++++++++++------
Src/FmMain.dfm | 6 +--
Src/Res/HTML/dlg-dbdelete.html | 8 ++--
Src/UUserDBMgr.pas | 13 ++++--
5 files changed, 105 insertions(+), 31 deletions(-)
diff --git a/Src/FmDeleteUserDBDlg.dfm b/Src/FmDeleteUserDBDlg.dfm
index 1bd52b82a..d915e4668 100644
--- a/Src/FmDeleteUserDBDlg.dfm
+++ b/Src/FmDeleteUserDBDlg.dfm
@@ -1,16 +1,32 @@
inherited DeleteUserDBDlg: TDeleteUserDBDlg
- Caption = 'Delete User Database'
+ Caption = 'Delete All Snippets From Collection'
ExplicitWidth = 474
ExplicitHeight = 375
PixelsPerInch = 96
TextHeight = 13
inherited pnlBody: TPanel
- object edConfirm: TEdit
+ object lblConfirm: TLabel
+ Left = 0
+ Top = 256
+ Width = 82
+ Height = 13
+ Caption = 'Confirm &deletion:'
+ FocusControl = edConfirm
+ end
+ object lblCollection: TLabel
Left = 0
- Top = 216
- Width = 201
+ Top = 224
+ Width = 87
+ Height = 13
+ Caption = 'Choose &collection:'
+ FocusControl = cbCollection
+ end
+ object edConfirm: TEdit
+ Left = 120
+ Top = 248
+ Width = 249
Height = 21
- TabOrder = 0
+ TabOrder = 2
end
inline frmWarning: TFixedHTMLDlgFrame
Left = 0
@@ -18,8 +34,7 @@ inherited DeleteUserDBDlg: TDeleteUserDBDlg
Width = 369
Height = 210
Align = alTop
- TabOrder = 1
- TabStop = True
+ TabOrder = 0
ExplicitWidth = 369
ExplicitHeight = 210
inherited pnlBrowser: TPanel
@@ -41,6 +56,14 @@ inherited DeleteUserDBDlg: TDeleteUserDBDlg
end
end
end
+ object cbCollection: TComboBox
+ Left = 120
+ Top = 221
+ Width = 249
+ Height = 21
+ Style = csDropDownList
+ TabOrder = 1
+ end
end
inherited btnOK: TButton
OnClick = btnOKClick
diff --git a/Src/FmDeleteUserDBDlg.pas b/Src/FmDeleteUserDBDlg.pas
index d51be0681..b98b722c8 100644
--- a/Src/FmDeleteUserDBDlg.pas
+++ b/Src/FmDeleteUserDBDlg.pas
@@ -5,8 +5,8 @@
*
* Copyright (C) 2022-2023, Peter Johnson (gravatar.com/delphidabbler).
*
- * Implements a dialogue box that asks user to confirm deletion of user-defined
- * snippets database.
+ * Implements a dialogue box that enables the user to choose a collection from
+ * which to delete all snippets.
}
@@ -16,30 +16,46 @@ interface
uses
// Delphi
- Forms, StdCtrls, Controls, ExtCtrls, Classes,
+ Forms,
+ StdCtrls,
+ Controls,
+ ExtCtrls,
+ Classes,
// Project
+ DB.UCollections,
FmGenericOKDlg,
- FrBrowserBase, FrHTMLDlg, FrFixedHTMLDlg,
- UBaseObjects;
+ FrBrowserBase,
+ FrHTMLDlg,
+ FrFixedHTMLDlg,
+ UBaseObjects,
+ UCollectionListAdapter;
type
TDeleteUserDBDlg = class(TGenericOKDlg, INoPublicConstruct)
edConfirm: TEdit;
frmWarning: TFixedHTMLDlgFrame;
+ lblConfirm: TLabel;
+ lblCollection: TLabel;
+ cbCollection: TComboBox;
procedure btnOKClick(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
strict private
const
cConfirmText = 'DELETE MY SNIPPETS';
var
fPermissionGranted: Boolean;
+ fCollection: TCollection;
+ fCollList: TCollectionListAdapter;
+ function SelectedCollection: TCollection;
+ function IsValidPassword: Boolean;
strict protected
/// Protected constructor that sets up form.
constructor InternalCreate(AOwner: TComponent); override;
procedure ConfigForm; override;
procedure ArrangeForm; override;
- function IsValidPassword: Boolean;
public
- class function Execute(AOwner: TComponent): Boolean;
+ class function Execute(AOwner: TComponent; out ACollection: TCollection): Boolean;
end;
implementation
@@ -48,16 +64,24 @@ implementation
// Delphi
SysUtils,
// Project
- UCtrlArranger, UMessageBox;
+ UCtrlArranger,
+ UMessageBox;
{$R *.dfm}
procedure TDeleteUserDBDlg.ArrangeForm;
begin
frmWarning.Height := frmWarning.DocHeight;
- edConfirm.Left := 0;
- TCtrlArranger.MoveBelow(frmWarning, edConfirm, 12);
- TCtrlArranger.AlignHCentresTo([frmWarning], [edConfirm]);
+ TCtrlArranger.AlignLefts([frmWarning, lblConfirm, lblCollection], 0);
+ TCtrlArranger.AlignRights([frmWarning, cbCollection, edConfirm]);
+ TCtrlArranger.AlignVCentres(
+ TCtrlArranger.BottomOf(frmWarning, 12),
+ [lblCollection, cbCollection]
+ );
+ TCtrlArranger.AlignVCentres(
+ TCtrlArranger.BottomOf([lblCollection, cbCollection], 12),
+ [lblConfirm, edConfirm]
+ );
pnlBody.ClientHeight := TCtrlArranger.TotalControlHeight(pnlBody) + 8;
inherited;
end;
@@ -68,6 +92,7 @@ procedure TDeleteUserDBDlg.btnOKClick(Sender: TObject);
begin
inherited;
fPermissionGranted := IsValidPassword;
+ fCollection := SelectedCollection;
if not fPermissionGranted then
begin
TMessageBox.Error(Self, sBadPassword);
@@ -79,11 +104,13 @@ procedure TDeleteUserDBDlg.btnOKClick(Sender: TObject);
procedure TDeleteUserDBDlg.ConfigForm;
begin
inherited;
-// frmWarning.OnBuildCSS := BuildCSS;
frmWarning.Initialise('dlg-dbdelete.html');
+ fCollList.ToStrings(cbCollection.Items);
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
end;
-class function TDeleteUserDBDlg.Execute(AOwner: TComponent): Boolean;
+class function TDeleteUserDBDlg.Execute(AOwner: TComponent;
+ out ACollection: TCollection): Boolean;
var
Dlg: TDeleteUserDBDlg;
begin
@@ -91,11 +118,25 @@ class function TDeleteUserDBDlg.Execute(AOwner: TComponent): Boolean;
try
Dlg.ShowModal;
Result := Dlg.fPermissionGranted;
+ if Result then
+ ACollection := Dlg.fCollection;
finally
Dlg.Free;
end;
end;
+procedure TDeleteUserDBDlg.FormCreate(Sender: TObject);
+begin
+ inherited;
+ fCollList := TCollectionListAdapter.Create;
+end;
+
+procedure TDeleteUserDBDlg.FormDestroy(Sender: TObject);
+begin
+ fCollList.Free;
+ inherited;
+end;
+
constructor TDeleteUserDBDlg.InternalCreate(AOwner: TComponent);
begin
Assert(Supports(Self, INoPublicConstruct), ClassName + '.InternalCreate: '
@@ -108,4 +149,9 @@ function TDeleteUserDBDlg.IsValidPassword: Boolean;
Result := edConfirm.Text = cConfirmText;
end;
+function TDeleteUserDBDlg.SelectedCollection: TCollection;
+begin
+ Result := fCollList.Collection(cbCollection.ItemIndex);
+end;
+
end.
diff --git a/Src/FmMain.dfm b/Src/FmMain.dfm
index 5193d9d86..319c83542 100644
--- a/Src/FmMain.dfm
+++ b/Src/FmMain.dfm
@@ -870,10 +870,10 @@ inherited MainForm: TMainForm
end
object actDeleteUserDatabase: TAction
Category = 'Database'
- Caption = 'Delete User Database...'
+ Caption = 'Delete All Snippets From Collection'
Hint =
- 'Delete User Database|Deletes the user'#39's snippets database - USE ' +
- 'WITH CAUTION'
+ 'Delete All Snippets From A Collection|Deletes all the snippets f' +
+ 'rom a selected collection - USE WITH CAUTION'
OnExecute = actDeleteUserDatabaseExecute
OnUpdate = ActNonEmptyDBUpdate
end
diff --git a/Src/Res/HTML/dlg-dbdelete.html b/Src/Res/HTML/dlg-dbdelete.html
index b21cfb4c7..4272c61ef 100644
--- a/Src/Res/HTML/dlg-dbdelete.html
+++ b/Src/Res/HTML/dlg-dbdelete.html
@@ -28,19 +28,19 @@
- Before going any further you are strongly advised to take a backup of your snippets database. Use the Database | Backup User Database menu option to do this.
+ This action cannot be undone. You will loose all the snippets in the collection. The collection itself will remain but will be empty.
- This action cannot be undone: you will loose all your user-defined snippets.
+ Before going any further you are strongly advised to take a backup of the collection you are planning to delete. Use the Database | Backup Collection Data menu option to do this.
- To confirm enter DELETEMYSNIPPETS (in capital letters) in the box below, then click OK.
+ To proceed, first choose the collection you want to delete from the Choose collection drop down list. Then confirm the action by entering DELETEMYSNIPPETS (in capital letters) in the Confirm deletion edit box.
- There will be no further chances to change your mind.
+ When you click OK there will be no further chances to change your mind.
diff --git a/Src/UUserDBMgr.pas b/Src/UUserDBMgr.pas
index beed308e2..ce6b9222b 100644
--- a/Src/UUserDBMgr.pas
+++ b/Src/UUserDBMgr.pas
@@ -78,7 +78,10 @@ TUserDBMgr = class(TNoConstructObject)
/// Moves the user database to a new location specified by the
/// user.
class procedure MoveDatabase;
- /// Deletes the user database, with permission.
+ /// Deletes all the snippets in a collection specified by the
+ /// user.
+ /// Boolean. True if the collection's data was
+ /// deleted, False otherwise.
class function DeleteDatabase: Boolean;
end;
@@ -318,12 +321,14 @@ class procedure TUserDBMgr.DeleteACategory;
end;
class function TUserDBMgr.DeleteDatabase: Boolean;
+var
+ CollectionToDelete: TCollection;
begin
- if not TDeleteUserDBDlg.Execute(nil) then
+ if not TDeleteUserDBDlg.Execute(nil, CollectionToDelete) then
Exit(False);
- if not TDirectory.Exists(TAppInfo.UserDataDir) then
+ if not TDirectory.Exists(CollectionToDelete.Location.Directory) then
Exit(False);
- TDirectory.Delete(TAppInfo.UserDataDir, True);
+ TDirectory.Delete(CollectionToDelete.Location.Directory, True);
Result := True;
end;
From aa33488cc41f3ab6ee0091079b6eb638a9631080 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 19 Nov 2024 17:04:07 +0000
Subject: [PATCH 117/222] Remove redundant TAppInfo.UserDataDir method
This method returned the location of the "user database". All code that
used it has now been changed to work with all collections, so there is
no further use for this method.
---
Src/UAppInfo.pas | 25 -------------------------
1 file changed, 25 deletions(-)
diff --git a/Src/UAppInfo.pas b/Src/UAppInfo.pas
index aad6fdcf5..1a033a289 100644
--- a/Src/UAppInfo.pas
+++ b/Src/UAppInfo.pas
@@ -55,10 +55,6 @@ TAppInfo = class(TNoConstructObject)
{Returns the directory where CodeSnip stores the "database" files.
@return Full path to database sub directory.
}
- class function UserDataDir: string;
- {Returns the directory where CodeSnip stores the user's "database" files.
- @return Full path to database sub directory.
- }
class function DefaultUserDataDir: string;
{Returns the default directory where CodeSnip stores the uer's "database"
files.
@@ -257,27 +253,6 @@ class function TAppInfo.UserConfigFileName: string;
Result := UserAppDir + '\User.config';
end;
-class function TAppInfo.UserDataDir: string;
- {Returns the directory where CodeSnip stores the user's "database" files.
- @return Full path to database sub directory.
- }
-{$IFNDEF PORTABLE}
-var
- Collections: TCollections;
- Collection: TCollection;
-{$ENDIF}
-begin
- {$IFNDEF PORTABLE}
- Collections := TCollections.Instance;
- Collection := Collections.GetCollection(TCollectionID.__TMP__UserDBCollectionID);
- Result := Collection.Location.Directory;
- if Result = '' then
- Result := DefaultUserDataDir;
- {$ELSE}
- Result := DefaultUserDataDir;
- {$ENDIF}
-end;
-
class function TAppInfo.UserFavouritesFileName: string;
begin
Result := UserAppDir + '\Favourites';
From b78f631d7b39993e47cca38e6f1a7634f0aada14 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 19 Nov 2024 17:23:23 +0000
Subject: [PATCH 118/222] Prevent default collection linking to DCSC snippets
TNativeV4FormatLoader was setting snippets dependency and xref
properties to include snippets in the "main database" (now DelphiDabbler
Code Snippets Collection - DCSC). While this was OK when there were just
the "main" and "user" databases, it is not permitted with collections:
we can't assumed anything special about the DCSC, which may not even be
installed.
Therefore snippets in collections loaded by TNativeV4FormatLoader will
have any links to the old "main" database ignored.
This change meant that TNativeV4FormatLoader.FindSnippet was now
implemented identically to TDCSCV2FormatLoader.FindSnippet, so the
implementation was pushed up into the base class and the methods were
removed.
---
Src/DB.UDatabaseIO.pas | 57 ++++++------------------------------------
1 file changed, 7 insertions(+), 50 deletions(-)
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index 09efcb63f..2fd8f31f9 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -184,7 +184,7 @@ TDatabaseLoader = class(TInterfacedObject, IDataFormatLoader)
@return Reader object instance.
}
function FindSnippet(const SnippetKey: string;
- const SnipList: TSnippetList): TSnippet; virtual; abstract;
+ const SnipList: TSnippetList): TSnippet; virtual;
{Finds the snippet object with a specified key.
@param SnippetKey [in] Key of required snippet.
@param SnipList [in] List of snippets to search.
@@ -240,15 +240,6 @@ TDCSCV2FormatLoader = class(TDatabaseLoader, IDataFormatLoader)
created.
@return Reader object instance.
}
- function FindSnippet(const SnippetKey: string;
- const SnipList: TSnippetList): TSnippet; override;
- {Finds the snippet object with a specified key in the main database.
- @param SnippetKey [in] Key of required snippet.
- @param SnipList [in] List of snippets to search.
- @return Reference to required snippet object or nil if snippet is not
- found.
- }
-
function ErrorMessageHeading: string; override;
{Returns heading to use in error messages. Identifies main database.
@return Required heading.
@@ -266,16 +257,6 @@ TNativeV4FormatLoader = class(TDatabaseLoader, IDataFormatLoader)
created.
@return Reader object instance.
}
- function FindSnippet(const SnippetKey: string;
- const SnipList: TSnippetList): TSnippet; override;
- {Finds the snippet object with a specified key. If snippet is not in this
- (user) database the main database is searched.
- @param SnippetKey [in] Key of required snippet.
- @param SnipList [in] List of snippets to search.
- @return Reference to required snippet object or nil if snippet is not
- found.
- }
-
function ErrorMessageHeading: string; override;
{Returns heading to use in error messages. Identifies main database.
@return Required heading.
@@ -493,6 +474,12 @@ procedure TDatabaseLoader.CreateCategory(const CatID: string;
fCategories.Add(fFactory.CreateCategory(CatID, CatData));
end;
+function TDatabaseLoader.FindSnippet(const SnippetKey: string;
+ const SnipList: TSnippetList): TSnippet;
+begin
+ Result := SnipList.Find(SnippetKey, Collection.UID);
+end;
+
procedure TDatabaseLoader.HandleException(const E: Exception);
{Handles exceptions generated by loader and converts ECodeSnip and descendant
exceptions into EDatabaseLoader exceptions.
@@ -668,18 +655,6 @@ function TDCSCV2FormatLoader.ErrorMessageHeading: string;
Result := sError;
end;
-function TDCSCV2FormatLoader.FindSnippet(const SnippetKey: string;
- const SnipList: TSnippetList): TSnippet;
- {Finds the snippet object with a specified key in the main database.
- @param SnippetKey [in] Key of required snippet.
- @param SnipList [in] List of snippets to search.
- @return Reference to required snippet object or nil if snippet is not found.
- }
-begin
- // We only search main database
- Result := SnipList.Find(SnippetKey, Collection.UID);
-end;
-
{ TNativeV4FormatLoader }
function TNativeV4FormatLoader.CreateReader: IDataReader;
@@ -703,24 +678,6 @@ function TNativeV4FormatLoader.ErrorMessageHeading: string;
Result := sError;
end;
-function TNativeV4FormatLoader.FindSnippet(const SnippetKey: string;
- const SnipList: TSnippetList): TSnippet;
- {Finds the snippet object with a specified key. If snippet is not in this
- (user) database the main database is searched.
- @param SnippetKey [in] Key of required snippet.
- @param SnipList [in] List of snippets to search.
- @return Reference to required snippet object or nil if snippet is not found.
- }
-begin
- // Search in user database
- Result := SnipList.Find(SnippetKey, Collection.UID);
- {TODO -cVault: Delete the following - only allow references in same collection
- }
- if not Assigned(Result) then
- // Not in user database: try main database
- Result := SnipList.Find(SnippetKey, TCollectionID.__TMP__MainDBCollectionID);
-end;
-
{ TFormatSaver }
constructor TFormatSaver.Create(const ACollection: TCollection);
From 1a56dc5285e6ea23990e4442444ec1be4f5a3652 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 19 Nov 2024 23:04:09 +0000
Subject: [PATCH 119/222] Change database load/save to cycle thru collections
TDatabase's Load and Save methods previously had the "user" and "main"
databases (later DCSC and Default collections) loaded/saved explicitly.
This was changed so that the methods loop through all available
collections, loading and saving them. This means that the methods will
now load and save whatever collections are available.
---
Src/DB.UMain.pas | 92 +++++++++++++-----------------------------------
1 file changed, 25 insertions(+), 67 deletions(-)
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index 2ca5089c8..b8e73511f 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -478,9 +478,10 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
{Gets list of all snippets in database.
@return Required list.
}
+
+ /// Load database from all available collections.
procedure Load;
- {Loads object's data from main and user defined databases.
- }
+
procedure Clear;
{Clears the object's data.
}
@@ -623,9 +624,11 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
{Checks if user database has been updated since last save.
@return True if database has been updated, False otherwise.
}
+
+ /// Saves snippets from database to their respective collections.
+ ///
procedure Save;
- {Saves user defined snippets and all categories to user database.
- }
+
end;
/// Class that provides data about the categories and snippets in
@@ -1072,54 +1075,32 @@ procedure TDatabase.Load;
{Loads object's data from main and user defined databases.
}
var
- Factory: IDBDataItemFactory; // object reader uses to create snippets objects
- MainCollectionIdx: Integer;
- Loader: IDataFormatLoader;
- Collections: TCollections;
+ DataItemFactory: IDBDataItemFactory;
+ CollectionLoader: IDataFormatLoader;
Collection: TCollection;
CatLoader: IGlobalCategoryLoader;
begin
+ // Clear the database
Clear;
-
// Create factory that reader calls into to create category and snippet
// objects. This is done to keep updating of snippet and categories private
// to this unit
- Factory := TDBDataItemFactory.Create;
-
- Collections := TCollections.Instance;
-
- {TODO: -cVault: The following code is a kludge to maintain compatibility with
- CodeSnip 4. In CodeSnip Vault we should iterate over all collections
- creating a loader for each one. }
-
+ DataItemFactory := TDBDataItemFactory.Create;
try
- MainCollectionIdx := TCollections.Instance.IndexOfID(
- TCollectionID.__TMP__MainDBCollectionID
- );
- if MainCollectionIdx >= 0 then
+ // Load all collections
+ for Collection in TCollections.Instance do
begin
- Collection := Collections[MainCollectionIdx];
- Loader := TDatabaseIOFactory.CreateDBLoader(Collection);
- if Assigned(Loader) then
- Loader.Load(fSnippets, fCategories, Factory);
+ CollectionLoader := TDatabaseIOFactory.CreateDBLoader(Collection);
+ if Assigned(CollectionLoader) then
+ CollectionLoader.Load(fSnippets, fCategories, DataItemFactory);
end;
-
- // Load default collection
- Collection := Collections.Default;
- Loader := TDatabaseIOFactory.CreateDBLoader(Collection);
- Assert(Assigned(Loader),
- ClassName + '.Load: No loader for default collection');
- Loader.Load(fSnippets, fCategories, Factory);
-
// Read categories from categories file to get any empty categories not
// created by format loaders
CatLoader := TDatabaseIOFactory.CreateGlobalCategoryLoader;
- CatLoader.Load(fCategories, Factory);
-
+ CatLoader.Load(fCategories, DataItemFactory);
// Ensure that the default category is present, if it's not already loaded
if not Assigned(fCategories.Find(TCategory.DefaultID)) then
fCategories.Add(TCategoryEx.CreateDefault);
-
fUpdated := False;
except
// If an exception occurs clear the database
@@ -1140,47 +1121,24 @@ procedure TDatabase.Save;
{Saves user defined snippets and all categories to user database.
}
var
- MainProvider, DefaultProvider: IDBDataProvider;
- MainCollectionIdx: Integer;
- Saver: IDataFormatSaver;
- Collections: TCollections;
+ Provider: IDBDataProvider;
+ CollectionSaver: IDataFormatSaver;
Collection: TCollection;
CatSaver: IGlobalCategorySaver;
begin
// Save categories
CatSaver := TDatabaseIOFactory.CreateGlobalCategorySaver;
CatSaver.Save(fCategories);
-
- Collections := TCollections.Instance;
-
- {TODO: -cVault: The following code is a kludge to maintain compatibility with
- CodeSnip 4. In CodeSnip Vault we should iterate over all collections
- creating a writer for each one. }
-
- // *** The following code is a stub for later versions.
- MainCollectionIdx := TCollections.Instance.IndexOfID(
- TCollectionID.__TMP__MainDBCollectionID
- );
- if MainCollectionIdx >= 0 then
+ // Save all collections
+ for Collection in TCollections.Instance do
begin
- Collection := Collections[MainCollectionIdx];
- MainProvider := TCollectionDataProvider.Create(
+ Provider := TCollectionDataProvider.Create(
Collection.UID, fSnippets, fCategories
);
- Saver := TDatabaseIOFactory.CreateDBSaver(Collection);
- if Assigned(Saver) then
- Saver.Save(fSnippets, fCategories, MainProvider);
+ CollectionSaver := TDatabaseIOFactory.CreateDBSaver(Collection);
+ if Assigned(CollectionSaver) then
+ CollectionSaver.Save(fSnippets, fCategories, Provider);
end;
-
- Collection := Collections.Default;
- DefaultProvider := TCollectionDataProvider.Create(
- Collection.UID, fSnippets, fCategories
- );
- Saver := TDatabaseIOFactory.CreateDBSaver(Collection);
- Assert(Assigned(Saver),
- ClassName + '.Save: No saver for default collection');
- Saver.Save(fSnippets, fCategories, DefaultProvider);
-
fUpdated := False;
end;
From 2bb2a5f70c82dc18058c0575e4d2313bb864c47c Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 19 Nov 2024 23:14:06 +0000
Subject: [PATCH 120/222] Remove explicit creation of main database collection
The "main" database, aka the DCSC collection, is no longer explicit
created when TCollections initialises if it has not already been read
from the config file.
TCollections only ensures that the Default collection is available.
---
Src/DB.UCollections.pas | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
index f12ae768f..84516c8a7 100644
--- a/Src/DB.UCollections.pas
+++ b/Src/DB.UCollections.pas
@@ -472,19 +472,6 @@ procedure TCollections.Initialize;
TCollectionFormatKind.Native_v4
)
);
- { TODO -cCollections: following line is for v4 main database compatibility
- Remove when reduce to only one compulsory collection }
- if not ContainsID(TCollectionID.__TMP__MainDBCollectionID) then
- Add(
- TCollection.Create(
- TCollectionID.__TMP__MainDBCollectionID,
- { TODO -cVault: change name - this text matches name used in CodeSnip
- v4}
- 'DelphiDabbler Code Snippets Database',
- TCollectionLocation.Create(TAppInfo.AppDataDir),
- TCollectionFormatKind.DCSC_v2
- )
- );
end;
procedure TCollections.Save;
From d31ccb2ba97d372bc3c365951acc263e1101c9c0 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 19 Nov 2024 23:23:42 +0000
Subject: [PATCH 121/222] Removed temporary methods etc from DB.UCollections
The __TMP__ methods that were used to explicitly refer to the former
"user" and "main" databases are now redundant and have been removed.
The DCSC_v2_ID and SWAG_v1_ID explicitly specified collection IDs were
also removed as redundant.
---
Src/DB.UCollections.pas | 20 +-------------------
1 file changed, 1 insertion(+), 19 deletions(-)
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
index 84516c8a7..e94e89ff0 100644
--- a/Src/DB.UCollections.pas
+++ b/Src/DB.UCollections.pas
@@ -93,11 +93,6 @@ TComparer = class(TInterfacedObject,
function GetHashCode(const Value: TCollectionID): Integer;
reintroduce;
end;
- const
- {TODO -cCollections: remove DCSC_v2_ID and SWAG_v1_ID once there are no
- built-in collections except Default}
- DCSC_v2_ID: TGUID = '{9F3A4A8A-0A2B-4088-B7C9-AE1D32D3FF9A}';
- SWAG_v1_ID: TGUID = '{ADA985E0-0929-4986-A3FE-B2C981D430F1}';
constructor Create(const ABytes: TBytes); overload;
constructor Create(const AStr: string); overload;
constructor Create(const AGUID: TGUID); overload;
@@ -113,9 +108,6 @@ TComparer = class(TInterfacedObject,
class function Compare(Left, Right: TCollectionID): Integer; static;
class operator Equal(Left, Right: TCollectionID): Boolean;
class operator NotEqual(Left, Right: TCollectionID): Boolean;
- {TODO -c__TMP__: remove following __TMP__*** methods}
- class function __TMP__MainDBCollectionID: TCollectionID; static;
- class function __TMP__UserDBCollectionID: TCollectionID; static;
end;
ECollectionID = class(ECodeSnip);
@@ -272,7 +264,7 @@ implementation
IOUtils,
Math,
// Project
- UAppInfo, // TODO -cVault: needed only for v4 emulation
+ UAppInfo,
UStrUtils,
UUtils;
@@ -590,16 +582,6 @@ function TCollectionID.ToHexString: string;
Result := BytesToHexString(fID);
end;
-class function TCollectionID.__TMP__MainDBCollectionID: TCollectionID;
-begin
- Result := TCollectionID.Create(DCSC_v2_ID);
-end;
-
-class function TCollectionID.__TMP__UserDBCollectionID: TCollectionID;
-begin
- Result := TCollectionID.Default;
-end;
-
{ TCollectionID.TComparer }
function TCollectionID.TComparer.Compare(const Left,
From b8e64b7f405520187ba884301ce269e6e1a40073 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Wed, 20 Nov 2024 00:28:53 +0000
Subject: [PATCH 122/222] Update TAppInfo with collection related directories
Added per-user directories TAppInfo.UserCollectionsDir and
TAppInfo.UserDefaultCollectionDir. The former is the parent directory
under which it is recommended that collections are stored. The latter is
the directory where CodeSnip will initially create the Default
collection, which is a sub-directory of TAppInfo.UserCollectionsDir.
TCollections.Initialize was modified to create the Default directory,
when necessary, in TAppInfo.UserDefaultCollectionDir instead of
TAppInfo.DefaultUserDataDir.
TAppInfo.DefaultUserDataDir was removed as it is now redundant.
---
Src/DB.UCollections.pas | 4 +++-
Src/UAppInfo.pas | 51 ++++++++++++++++++++++++++---------------
2 files changed, 36 insertions(+), 19 deletions(-)
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
index e94e89ff0..c0fcff1db 100644
--- a/Src/DB.UCollections.pas
+++ b/Src/DB.UCollections.pas
@@ -460,7 +460,9 @@ procedure TCollections.Initialize;
TCollection.Create(
TCollectionID.Default,
'Default',
- TCollectionLocation.Create(TAppInfo.DefaultUserDataDir, '', etUTF8),
+ TCollectionLocation.Create(
+ TAppInfo.UserDefaultCollectionDir, '', etUTF8
+ ),
TCollectionFormatKind.Native_v4
)
);
diff --git a/Src/UAppInfo.pas b/Src/UAppInfo.pas
index 1a033a289..8a51d0666 100644
--- a/Src/UAppInfo.pas
+++ b/Src/UAppInfo.pas
@@ -41,6 +41,7 @@ TAppInfo = class(TNoConstructObject)
const ProgramID = 'codesnip';
{TODO -cVault: Remove unused ProgramID const}
{Machine readable identifier of program}
+ public
class function UserAppDir: string;
{Gets the CodeSnip data directory stored within the user's application
data directory.
@@ -52,14 +53,31 @@ TAppInfo = class(TNoConstructObject)
@return Full path to common application data directory.
}
class function AppDataDir: string;
+ {TODO -cCollections: Remove AppDataDir method: used for "main" database}
{Returns the directory where CodeSnip stores the "database" files.
@return Full path to database sub directory.
}
- class function DefaultUserDataDir: string;
- {Returns the default directory where CodeSnip stores the uer's "database"
- files.
- @return Full path to required directory.
- }
+
+ /// Returns the path where collections are recommended to be
+ /// stored for the current user.
+ ///
+ /// Collections each have their own sub-directory of this directory.
+ ///
+ /// The user may ignore this recommendation and install collections
+ /// anywhere they choose.
+ ///
+ class function UserCollectionsDir: string;
+
+ /// Returns the path where the Default collection is recommended
+ /// to be stored for the current user.
+ ///
+ /// If the Default collection is not present then CodeSnip will
+ /// automatically create it in this directory.
+ /// The user may move the Default collection anywhere they choose.
+ ///
+ ///
+ class function UserDefaultCollectionDir: string;
+
class function AppExeFilePath: string;
{Returns fully specified name of program's executable file.
@return Name of file.
@@ -169,19 +187,6 @@ class function TAppInfo.CommonAppDir: string;
{$ENDIF}
end;
-class function TAppInfo.DefaultUserDataDir: string;
- {Returns the default directory where CodeSnip stores the uer's "database"
- files.
- @return Full path to required directory.
- }
-begin
- {$IFNDEF PORTABLE}
- Result := UserAppDir + '\UserDatabase';
- {$ELSE}
- Result := UserAppDir + '\UserDB';
- {$ENDIF}
-end;
-
class function TAppInfo.HelpFileName: string;
{Returns fully specified name of CodeSnip's help file.
@return Name of help file.
@@ -248,11 +253,21 @@ class function TAppInfo.UserCategoriesFileName: string;
Result := UserAppDir + '\Categories';
end;
+class function TAppInfo.UserCollectionsDir: string;
+begin
+ Result := UserAppDir + '\Collections';
+end;
+
class function TAppInfo.UserConfigFileName: string;
begin
Result := UserAppDir + '\User.config';
end;
+class function TAppInfo.UserDefaultCollectionDir: string;
+begin
+ Result := UserCollectionsDir + '\Default';
+end;
+
class function TAppInfo.UserFavouritesFileName: string;
begin
Result := UserAppDir + '\Favourites';
From 94fa9f495acc15858521c2bf234265c8ab6a62c3 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Wed, 20 Nov 2024 00:47:13 +0000
Subject: [PATCH 123/222] Fix bug in TMainDBMetaData not finding moved DCSC
When the DelphiDabbler Code Snippets Database is moved from the location
specified by TAppInfo.AppDataDir (which was compulosory in CodeSnip 4),
TMainDBMetaData could no longer read meta data because it was always
looking for it in TAppInfo.AppDataDir.
TMainDBMetaData was changed to look for the data in the location
specified by a TCollection instance passed to to the constructor.
---
Src/DBIO.MetaData.DCSC.pas | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/Src/DBIO.MetaData.DCSC.pas b/Src/DBIO.MetaData.DCSC.pas
index b2e07bb17..f4b3d2286 100644
--- a/Src/DBIO.MetaData.DCSC.pas
+++ b/Src/DBIO.MetaData.DCSC.pas
@@ -401,8 +401,13 @@ TAbstractMainDBMetaData = class abstract(TRegisterableMetaData)
/// Class that provides meta data for the main database.
TMainDBMetaData = class sealed(TAbstractMainDBMetaData, IDBMetaData)
+ strict private
+ var
+ fCollection: TCollection;
strict protected
function GetDBDir: string; override;
+ public
+ constructor Create(const ACollection: TCollection);
end;
/// Class that provides meta data for update database directories.
@@ -424,7 +429,6 @@ implementation
Classes,
IOUtils,
// VCL
- UAppInfo,
UEncodings,
UIOUtils,
UResourceUtils,
@@ -493,7 +497,7 @@ function TAbstractMainDBMetaData.GetVersion: TVersionNumber;
class function TAbstractMainDBMetaData.Instance(
ACollection: DB.UCollections.TCollection): IDBMetaData;
begin
- Result := TMainDBMetaData.Create;
+ Result := TMainDBMetaData.Create(ACollection);
end;
function TAbstractMainDBMetaData.IsCorrupt: Boolean;
@@ -557,9 +561,16 @@ procedure TAbstractMainDBMetaData.Refresh;
{ TMainDBMetaData }
+constructor TMainDBMetaData.Create(
+ const ACollection: DB.UCollections.TCollection);
+begin
+ inherited Create;
+ fCollection := ACollection;
+end;
+
function TMainDBMetaData.GetDBDir: string;
begin
- Result := TAppInfo.AppDataDir;
+ Result := fCollection.Location.Directory;
end;
{ TUpdateDBMetaData }
From 6980a51b09f75ab73fe5b8fedf4253b82191ab1d Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Wed, 20 Nov 2024 01:02:42 +0000
Subject: [PATCH 124/222] Fix bug reading tab separated files with no data
A bug in TTabSeparatedReader was raising an exception for tabbed
separated text files with a valid watermark but no tabbed separated data
lines, which is a valid state.
---
Src/UTabSeparatedFileIO.pas | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Src/UTabSeparatedFileIO.pas b/Src/UTabSeparatedFileIO.pas
index 0c411c570..7028a3797 100644
--- a/Src/UTabSeparatedFileIO.pas
+++ b/Src/UTabSeparatedFileIO.pas
@@ -189,7 +189,7 @@ procedure TTabSeparatedReader.Parse(const ALineCallback: TLineCallback);
Idx: Integer;
begin
// check for watermark in 1st line
- if (fLines.Count <= 1) or (fLines[0] <> fWatermark) then
+ if (fLines.Count < 1) or (fLines[0] <> fWatermark) then
raise ETabSeparatedReader.Create(sBadFileFormat);
// delete watermark line
fLines.Delete(0);
From 7ddb3719aa7fcaa7afbe96a09629749c501825fa Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 26 Nov 2024 01:41:20 +0000
Subject: [PATCH 125/222] Add means to get metadata caps via class method
Added TRegisterableMetaData.Capabilities abstract class method that
provides a means of getting a data format's meta data capabilities
without having to create an instance of the class. Added an
implementation of the method to TAbstractMainDBMetaData.
Added implementation of IDBMetaData.GetCapabilities to
TRegisterableMetaData that simply calls the new class method.
IDBMetaData.GetCapabilities remains necessary because it provides a
means of getting capabilities from an IDBMetaData instance. Removed the
IDBMetaData.GetCapabilities implementation from TAbstractMainDBMetaData
in favour of the implementation TRegisterableMetaData.
Added new TMetaDataFactory.CapabilitiesOf class method that gets the
meta data capabilities for a given data format. This method calls the
TRegisterableMetaData.Capabilities class method of relevant data format
class.
---
Src/DB.UMetaData.pas | 43 ++++++++++++++++++++++++++++++++++++--
Src/DBIO.MetaData.DCSC.pas | 20 +++++++++++-------
2 files changed, 53 insertions(+), 10 deletions(-)
diff --git a/Src/DB.UMetaData.pas b/Src/DB.UMetaData.pas
index af4eefb8f..88f83d657 100644
--- a/Src/DB.UMetaData.pas
+++ b/Src/DB.UMetaData.pas
@@ -152,6 +152,19 @@ TRegisterableMetaData = class abstract(TInterfacedObject)
/// IDBMetaData. Required meta data object.
class function Instance(ACollection: TCollection): IDBMetaData;
virtual; abstract;
+ /// Gets the meta data capabilities for the collection data
+ /// format.
+ /// TMetaDataCapabilities. Required meta data capabilities.
+ ///
+ /// This method enables meta data capabilities to be obtained
+ /// without creating an instance of the object.
+ class function Capabilities: TMetaDataCapabilities; virtual; abstract;
+ /// Returns information about what, if any, meta data is supported
+ /// by a collection.
+ /// This method provides a means of accessing the data returned by
+ /// the Capabilities class method from IDBMetaData instances.
+ ///
+ function GetCapabilities: TMetaDataCapabilities; virtual;
end;
TRegisterableMetaDataClass = class of TRegisterableMetaData;
@@ -161,8 +174,10 @@ TRegisterableMetaDataClass = class of TRegisterableMetaData;
TMetaDataFactory = record
strict private
class var
- /// Map of collection format kinds to functions that create
- /// meta data objects of the required type.
+ {TODO -Refactor: rename fCallbackMap since it does not contain callback,
+ but does contain class types.}
+ /// Map of collection format kinds to classes that implement the
+ /// format's meta data.
fCallbackMap: TDictionary<
TCollectionFormatKind, TRegisterableMetaDataClass
>;
@@ -186,6 +201,14 @@ TMetaDataFactory = record
/// ACollection.
class function CreateInstance(const ACollection: TCollection):
IDBMetaData; static;
+ /// Gets the meta data capabilities for a collection data format.
+ ///
+ /// TCollectionFormatKind [in] Collection data
+ /// format for which meta data capabilities are required.
+ /// TMetaDataCapabilities. Required meta data capabilities.
+ ///
+ class function CapabilitiesOf(const AFormat: TCollectionFormatKind):
+ TMetaDataCapabilities; static;
end;
implementation
@@ -294,8 +317,24 @@ function TDBCopyrightInfo.ToString: string;
Result := sCopyright + ' ' + Result;
end;
+{ TRegisterableMetaData }
+
+function TRegisterableMetaData.GetCapabilities: TMetaDataCapabilities;
+begin
+ Result := Capabilities;
+end;
+
{ TMetaDataFactory }
+class function TMetaDataFactory.CapabilitiesOf(
+ const AFormat: TCollectionFormatKind): TMetaDataCapabilities;
+begin
+ if fCallbackMap.ContainsKey(AFormat) then
+ Result := fCallbackMap[AFormat].Capabilities
+ else
+ Result := [];
+end;
+
class constructor TMetaDataFactory.Create;
begin
fCallbackMap := TDictionary<
diff --git a/Src/DBIO.MetaData.DCSC.pas b/Src/DBIO.MetaData.DCSC.pas
index f4b3d2286..d1db872bd 100644
--- a/Src/DBIO.MetaData.DCSC.pas
+++ b/Src/DBIO.MetaData.DCSC.pas
@@ -336,11 +336,15 @@ TAbstractMainDBMetaData = class abstract(TRegisterableMetaData)
/// collection's format.
/// Must be called from a concrete descendant class.
class function Instance(ACollection: TCollection): IDBMetaData; override;
+ /// Gets the meta data capabilities for the collection data
+ /// format.
+ /// TMetaDataCapabilities. Required meta data capabilities.
+ ///
+ /// This method enables meta data capabilities to be obtained
+ /// without creating an instance of the object.
+ class function Capabilities: TMetaDataCapabilities; override;
procedure AfterConstruction; override;
destructor Destroy; override;
- /// Returns information about what, if any, meta data is supported
- /// by a collection.
- function GetCapabilities: TMetaDataCapabilities;
/// Returns database version number.
///
/// A null version number is returned if the meta data does not come
@@ -442,15 +446,15 @@ procedure TAbstractMainDBMetaData.AfterConstruction;
Refresh;
end;
-destructor TAbstractMainDBMetaData.Destroy;
+class function TAbstractMainDBMetaData.Capabilities: TMetaDataCapabilities;
begin
- fMetaFiles.Free;
- inherited;
+ Result := [mdcVersion, mdcLicense, mdcCopyright, mdcContributors, mdcTesters];
end;
-function TAbstractMainDBMetaData.GetCapabilities: TMetaDataCapabilities;
+destructor TAbstractMainDBMetaData.Destroy;
begin
- Result := [mdcVersion, mdcLicense, mdcCopyright, mdcContributors, mdcTesters];
+ fMetaFiles.Free;
+ inherited;
end;
function TAbstractMainDBMetaData.GetContributors: IStringList;
From ae4be0b32d734c14b36b978dacdf6fd22eea0d1d Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 26 Nov 2024 01:58:59 +0000
Subject: [PATCH 126/222] Updated TCollectionFormatInfo
Added new GetSupportedFormats method and DefaultFormat public constant
to TCollectionFormatInfo.
Also revised the names of the supported formats and re-ordered the
lookup table so the the default format is listed first.
---
Src/DB.UCollections.pas | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
index c0fcff1db..64f621f9c 100644
--- a/Src/DB.UCollections.pas
+++ b/Src/DB.UCollections.pas
@@ -62,17 +62,26 @@ TMapRecord = record
// There are so few entries in this table it's not worth the overhead
// of using a dicitionary for the lookup.
LookupTable: array[0..1] of TMapRecord = (
- (Kind: TCollectionFormatKind.DCSC_v2;
- Name: 'DelphiDabbler Code Snippets Collection format v2'),
(Kind: TCollectionFormatKind.Native_v4;
- Name: 'CodeSnip v4 native snippet collection format')
+ Name: 'CodeSnip Native Snippet Collection v4'),
+ (Kind: TCollectionFormatKind.DCSC_v2;
+ Name: 'DelphiDabbler Code Snippets Collection v2')
);
class function IndexOf(const AKind: TCollectionFormatKind): Integer; static;
+ public
+ const
+ /// Specifies the data format used for the default collection.
+ ///
+ DefaultFormat = TCollectionFormatKind.Native_v4;
public
/// Gets the name of the data format specified by
/// AKind. Returns an empty string if no name is associated with
/// AKind.
class function GetName(const AKind: TCollectionFormatKind): string; static;
+ /// Returns an array of all supported data formats.
+ /// TArray<TCollectionFormatKind>. Array of values
+ /// that identify the supported data formats.
+ class function GetSupportedFormats: TArray; static;
end;
type
@@ -697,6 +706,21 @@ class function TCollectionFormatInfo.GetName(
Result := LookupTable[Idx].Name;
end;
+class function TCollectionFormatInfo.GetSupportedFormats:
+ TArray;
+var
+ Idx: Integer;
+ Item: TMapRecord;
+begin
+ SetLength(Result, Length(LookupTable));
+ Idx := 0;
+ for Item in LookupTable do
+ begin
+ Result[Idx] := Item.Kind;
+ Inc(Idx);
+ end;
+end;
+
class function TCollectionFormatInfo.IndexOf(
const AKind: TCollectionFormatKind): Integer;
var
From 739fac4c79cee1fde43b7063cd20f965b361aac8 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 26 Nov 2024 11:42:45 +0000
Subject: [PATCH 127/222] Move collection data format code to new unit
Added new DB.DataFormats unit to project
Removed TCollectionFormatKind enumerated type and TCollectionFormatInfo
record with methods from DB.UCollections into DB.DataFormats and renamed
them as TDataFormatKind and TDataFormatInfo respectively.
Updated all units affected by the change of unit and name changes.
---
Src/CodeSnip.dpr | 3 +-
Src/CodeSnip.dproj | 1 +
Src/DB.DataFormats.pas | 103 +++++++++++++++++++++++++++++++
Src/DB.UCollections.pas | 122 ++++---------------------------------
Src/DB.UDatabaseIO.pas | 9 +--
Src/DB.UMetaData.pas | 15 +++--
Src/DBIO.MetaData.DCSC.pas | 7 ++-
7 files changed, 134 insertions(+), 126 deletions(-)
create mode 100644 Src/DB.DataFormats.pas
diff --git a/Src/CodeSnip.dpr b/Src/CodeSnip.dpr
index 1d97e2f80..f9d75bbb9 100644
--- a/Src/CodeSnip.dpr
+++ b/Src/CodeSnip.dpr
@@ -379,7 +379,8 @@ uses
DBIO.UCategoryIO in 'DBIO.UCategoryIO.pas',
UCollectionListAdapter in 'UCollectionListAdapter.pas',
DBIO.MetaData.DCSC in 'DBIO.MetaData.DCSC.pas',
- FmCollectionBackup in 'FmCollectionBackup.pas' {CollectionBackupDlg};
+ FmCollectionBackup in 'FmCollectionBackup.pas' {CollectionBackupDlg},
+ DB.DataFormats in 'DB.DataFormats.pas';
// Include resources
{$Resource ExternalObj.tlb} // Type library file
diff --git a/Src/CodeSnip.dproj b/Src/CodeSnip.dproj
index 3c4760e24..d0995c58d 100644
--- a/Src/CodeSnip.dproj
+++ b/Src/CodeSnip.dproj
@@ -588,6 +588,7 @@
+ Base
diff --git a/Src/DB.DataFormats.pas b/Src/DB.DataFormats.pas
new file mode 100644
index 000000000..519c409f4
--- /dev/null
+++ b/Src/DB.DataFormats.pas
@@ -0,0 +1,103 @@
+unit DB.DataFormats;
+
+interface
+
+type
+
+ /// Enumeration of the kinds of supported snippet collection data
+ /// formats.
+ ///
+ /// Error -- Invalid format. Used to indicate an unknown format
+ /// or other error.
+ /// DCSC_v2 -- Format used by the DelphiDabbler Code Snippets
+ /// Collection v2.
+ /// Native_v4 -- Native format used by CodeSnip v4 to store user
+ /// snippets.
+ ///
+ TDataFormatKind = (
+ // NEVER specify a literal ordinal value in this enumeration.
+ // NEVER delete or re-order the enumeration items: the ordinal values may
+ // be written to a config file and changing the ordinal value here can
+ // cause hard to trace bugs. If an item goes out of use then leave it
+ // in place & possibly rename the item to indicate its redundancy.
+ // NEVER associate error with a format loader or saver class.
+ Error,
+ DCSC_v2,
+ Native_v4
+ );
+
+
+ TDataFormatInfo = record
+ strict private
+ type
+ TMapRecord = record
+ /// Collection data format kind.
+ Kind: TDataFormatKind;
+ /// Collection data format name.
+ Name: string;
+ end;
+ const
+ // There are so few entries in this table it's not worth the overhead
+ // of using a dicitionary for the lookup.
+ LookupTable: array[0..1] of TMapRecord = (
+ (Kind: TDataFormatKind.Native_v4;
+ Name: 'CodeSnip Native Snippet Collection v4'),
+ (Kind: TDataFormatKind.DCSC_v2;
+ Name: 'DelphiDabbler Code Snippets Collection v2')
+ );
+ class function IndexOf(const AKind: TDataFormatKind): Integer; static;
+ public
+ const
+ /// Specifies the data format used for the default collection.
+ ///
+ DefaultFormat = TDataFormatKind.Native_v4;
+ public
+ /// Gets the name of the data format specified by
+ /// AKind. Returns an empty string if no name is associated with
+ /// AKind.
+ class function GetName(const AKind: TDataFormatKind): string; static;
+ /// Returns an array of all supported data formats.
+ /// TArray<TDataFormatKind>. Array of values
+ /// that identify the supported data formats.
+ class function GetSupportedFormats: TArray; static;
+ end;
+
+implementation
+
+{ TDataFormatInfo }
+
+class function TDataFormatInfo.GetName(const AKind: TDataFormatKind): string;
+var
+ Idx: Integer;
+begin
+ Idx := IndexOf(AKind);
+ if Idx < 0 then
+ Exit('');
+ Result := LookupTable[Idx].Name;
+end;
+
+class function TDataFormatInfo.GetSupportedFormats: TArray;
+var
+ Idx: Integer;
+ Item: TMapRecord;
+begin
+ SetLength(Result, Length(LookupTable));
+ Idx := 0;
+ for Item in LookupTable do
+ begin
+ Result[Idx] := Item.Kind;
+ Inc(Idx);
+ end;
+end;
+
+class function TDataFormatInfo.IndexOf(const AKind: TDataFormatKind): Integer;
+var
+ Idx: Integer;
+begin
+ Result := -1;
+ for Idx := Low(LookupTable) to High(LookupTable) do
+ if LookupTable[Idx].Kind = AKind then
+ Exit(Idx);
+end;
+
+end.
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
index 64f621f9c..0764fe91d 100644
--- a/Src/DB.UCollections.pas
+++ b/Src/DB.UCollections.pas
@@ -19,71 +19,13 @@ interface
SysUtils,
Generics.Collections,
Generics.Defaults,
+
+ DB.DataFormats,
UEncodings,
UExceptions,
USettings,
USingleton;
-type
-
- /// Enumeration of the kinds of supported snippet collection data
- /// formats.
- ///
- /// Error -- Invalid format. Used to indicate an unknown format
- /// or other error.
- /// DCSC_v2 -- Format used by the DelphiDabbler Code Snippets
- /// Collection v2.
- /// Native_v4 -- Native format used by CodeSnip v4 to store user
- /// snippets.
- ///
- TCollectionFormatKind = ( // TODO: move to more appropriate unit
- // NEVER specify a literal ordinal value in this enumeration.
- // NEVER delete or re-order the enumeration items: the ordinal values may
- // be written to a config file and changing the ordinal value here can
- // cause hard to trace bugs. If an item goes out of use then leave it
- // in place & possibly rename the item to indicate its redundancy.
- // NEVER associate error with a format loader or saver class.
- Error,
- DCSC_v2,
- Native_v4
- );
-
-
- TCollectionFormatInfo = record // TODO: move to more appropriate unit
- strict private
- type
- TMapRecord = record
- /// Collection data format kind.
- Kind: TCollectionFormatKind;
- /// Collection data format name.
- Name: string;
- end;
- const
- // There are so few entries in this table it's not worth the overhead
- // of using a dicitionary for the lookup.
- LookupTable: array[0..1] of TMapRecord = (
- (Kind: TCollectionFormatKind.Native_v4;
- Name: 'CodeSnip Native Snippet Collection v4'),
- (Kind: TCollectionFormatKind.DCSC_v2;
- Name: 'DelphiDabbler Code Snippets Collection v2')
- );
- class function IndexOf(const AKind: TCollectionFormatKind): Integer; static;
- public
- const
- /// Specifies the data format used for the default collection.
- ///
- DefaultFormat = TCollectionFormatKind.Native_v4;
- public
- /// Gets the name of the data format specified by
- /// AKind. Returns an empty string if no name is associated with
- /// AKind.
- class function GetName(const AKind: TCollectionFormatKind): string; static;
- /// Returns an array of all supported data formats.
- /// TArray<TCollectionFormatKind>. Array of values
- /// that identify the supported data formats.
- class function GetSupportedFormats: TArray; static;
- end;
-
type
TCollectionID = record
@@ -177,7 +119,7 @@ TCollection = record
fUID: TCollectionID;
fName: string;
fLocation: TCollectionLocation;
- fCollectionFormatKind: TCollectionFormatKind;
+ fCollectionFormatKind: TDataFormatKind;
public
type
TComparer = class(TInterfacedObject,
@@ -197,7 +139,7 @@ TComparer = class(TInterfacedObject,
/// unique. Must not be empty or only whitespace.
constructor Create(const AUID: TCollectionID; const AName: string;
const ALocation: TCollectionLocation;
- const ACollectionFormatKind: TCollectionFormatKind);
+ const ACollectionFormatKind: TDataFormatKind);
/// Collection identifier. Must be unique.
property UID: TCollectionID
read fUID;
@@ -209,8 +151,7 @@ TComparer = class(TInterfacedObject,
read fLocation;
/// Kind of collection format used for to store data for this
/// collection.
- property CollectionFormatKind: TCollectionFormatKind
- read fCollectionFormatKind;
+ property CollectionFormatKind: TDataFormatKind read fCollectionFormatKind;
/// Checks if this record's fields are valid.
function IsValid: Boolean;
/// Checks if this record is the default collection.
@@ -314,7 +255,7 @@ procedure TCollectionLocation.SetDirectory(const ANewDirectory: string);
constructor TCollection.Create(const AUID: TCollectionID;
const AName: string; const ALocation: TCollectionLocation;
- const ACollectionFormatKind: TCollectionFormatKind);
+ const ACollectionFormatKind: TDataFormatKind);
var
TrimmedName: string;
begin
@@ -323,7 +264,7 @@ constructor TCollection.Create(const AUID: TCollectionID;
Assert(TrimmedName <> '',
'TCollection.Create: AName is empty or only whitespace');
Assert(ALocation.IsValid, 'TCollection.Create: ALocation is not valid');
- Assert(ACollectionFormatKind <> TCollectionFormatKind.Error,
+ Assert(ACollectionFormatKind <> TDataFormatKind.Error,
'TCollection.Create: ACollectionFormatKind = TCollectionFormatKind.Error');
fUID := AUID.Clone;
fName := TrimmedName;
@@ -343,7 +284,7 @@ function TCollection.IsValid: Boolean;
Result := not fUID.IsNull
and (fName <> '')
and fLocation.IsValid
- and (fCollectionFormatKind <> TCollectionFormatKind.Error);
+ and (fCollectionFormatKind <> TDataFormatKind.Error);
end;
{ TCollections }
@@ -472,7 +413,7 @@ procedure TCollections.Initialize;
TCollectionLocation.Create(
TAppInfo.UserDefaultCollectionDir, '', etUTF8
),
- TCollectionFormatKind.Native_v4
+ TDataFormatKind.Native_v4
)
);
end;
@@ -636,7 +577,7 @@ class procedure TCollectionsPersist.LoadCollection(const AOrdinal: Cardinal;
UID: TCollectionID;
Name: string;
Collection: TCollection;
- DataFormat: TCollectionFormatKind;
+ DataFormat: TDataFormatKind;
begin
Storage := Settings.ReadSection(ssCollection, IntToStr(AOrdinal));
UID := TCollectionID.Create(Storage.GetBytes(UIDKey));
@@ -653,8 +594,8 @@ class procedure TCollectionsPersist.LoadCollection(const AOrdinal: Cardinal;
)
)
);
- DataFormat := TCollectionFormatKind(
- Storage.GetInteger(DataFormatKey, Ord(TCollectionFormatKind.Error))
+ DataFormat := TDataFormatKind(
+ Storage.GetInteger(DataFormatKey, Ord(TDataFormatKind.Error))
);
Collection := TCollection.Create(UID, Name, Location, DataFormat);
ACollections.Add(Collection);
@@ -693,45 +634,6 @@ class procedure TCollectionsPersist.SaveCollection(const AOrdinal: Cardinal;
Storage.Save;
end;
-{ TCollectionFormatInfo }
-
-class function TCollectionFormatInfo.GetName(
- const AKind: TCollectionFormatKind): string;
-var
- Idx: Integer;
-begin
- Idx := IndexOf(AKind);
- if Idx < 0 then
- Exit('');
- Result := LookupTable[Idx].Name;
-end;
-
-class function TCollectionFormatInfo.GetSupportedFormats:
- TArray;
-var
- Idx: Integer;
- Item: TMapRecord;
-begin
- SetLength(Result, Length(LookupTable));
- Idx := 0;
- for Item in LookupTable do
- begin
- Result[Idx] := Item.Kind;
- Inc(Idx);
- end;
-end;
-
-class function TCollectionFormatInfo.IndexOf(
- const AKind: TCollectionFormatKind): Integer;
-var
- Idx: Integer;
-begin
- Result := -1;
- for Idx := Low(LookupTable) to High(LookupTable) do
- if LookupTable[Idx].Kind = AKind then
- Exit(Idx);
-end;
-
{ TCollection.TComparer }
function TCollection.TComparer.Compare(const Left, Right: TCollection): Integer;
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index 2fd8f31f9..565b7e8bd 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -131,6 +131,7 @@ implementation
Generics.Collections,
IOUtils,
// Project
+ DB.DataFormats,
DBIO.UCategoryIO,
DBIO.UFileIOIntf,
DBIO.UIniData,
@@ -422,9 +423,9 @@ class function TDatabaseIOFactory.CreateDBLoader(const Collection: TCollection):
{TODO -cUDatabaseIO: Revise database loaders to get file path and other
info from collection instead of hard wiring it.}
case Collection.CollectionFormatKind of
- TCollectionFormatKind.DCSC_v2:
+ TDataFormatKind.DCSC_v2:
Result := TDCSCV2FormatLoader.Create(Collection);
- TCollectionFormatKind.Native_v4:
+ TDataFormatKind.Native_v4:
Result := TNativeV4FormatLoader.Create(Collection);
else
Result := nil;
@@ -435,9 +436,9 @@ class function TDatabaseIOFactory.CreateDBSaver(
const Collection: TCollection): IDataFormatSaver;
begin
case Collection.CollectionFormatKind of
- TCollectionFormatKind.DCSC_v2:
+ TDataFormatKind.DCSC_v2:
Result := TDCSCV2FormatSaver.Create(Collection);
- TCollectionFormatKind.Native_v4:
+ TDataFormatKind.Native_v4:
Result := TNativeV4FormatSaver.Create(Collection);
else
Result := nil;
diff --git a/Src/DB.UMetaData.pas b/Src/DB.UMetaData.pas
index 88f83d657..442630bc0 100644
--- a/Src/DB.UMetaData.pas
+++ b/Src/DB.UMetaData.pas
@@ -21,6 +21,7 @@ interface
Generics.Collections,
// Project
DB.UCollections,
+ DB.DataFormats,
UIStringList,
UVersionInfo;
@@ -178,9 +179,7 @@ TMetaDataFactory = record
but does contain class types.}
/// Map of collection format kinds to classes that implement the
/// format's meta data.
- fCallbackMap: TDictionary<
- TCollectionFormatKind, TRegisterableMetaDataClass
- >;
+ fCallbackMap: TDictionary;
public
class constructor Create;
class destructor Destroy;
@@ -190,7 +189,7 @@ TMetaDataFactory = record
/// format for which the meta data class is being registered.
/// TRegisterableMetaDataClass [in] Type of
/// class to create.
- class procedure RegisterCreator(AFormat: TCollectionFormatKind;
+ class procedure RegisterCreator(AFormat: TDataFormatKind;
AClass: TRegisterableMetaDataClass); static;
/// Creates a meta data object instance that can read a given
/// collection data format.
@@ -207,7 +206,7 @@ TMetaDataFactory = record
/// format for which meta data capabilities are required.
/// TMetaDataCapabilities. Required meta data capabilities.
///
- class function CapabilitiesOf(const AFormat: TCollectionFormatKind):
+ class function CapabilitiesOf(const AFormat: TDataFormatKind):
TMetaDataCapabilities; static;
end;
@@ -327,7 +326,7 @@ function TRegisterableMetaData.GetCapabilities: TMetaDataCapabilities;
{ TMetaDataFactory }
class function TMetaDataFactory.CapabilitiesOf(
- const AFormat: TCollectionFormatKind): TMetaDataCapabilities;
+ const AFormat: TDataFormatKind): TMetaDataCapabilities;
begin
if fCallbackMap.ContainsKey(AFormat) then
Result := fCallbackMap[AFormat].Capabilities
@@ -338,7 +337,7 @@ class function TMetaDataFactory.CapabilitiesOf(
class constructor TMetaDataFactory.Create;
begin
fCallbackMap := TDictionary<
- TCollectionFormatKind, TRegisterableMetaDataClass
+ TDataFormatKind, TRegisterableMetaDataClass
>.Create;
end;
@@ -359,7 +358,7 @@ class function TMetaDataFactory.CreateInstance(const ACollection: TCollection):
end;
class procedure TMetaDataFactory.RegisterCreator(
- AFormat: TCollectionFormatKind; AClass: TRegisterableMetaDataClass);
+ AFormat: TDataFormatKind; AClass: TRegisterableMetaDataClass);
begin
fCallbackMap.AddOrSetValue(AFormat, AClass);
end;
diff --git a/Src/DBIO.MetaData.DCSC.pas b/Src/DBIO.MetaData.DCSC.pas
index d1db872bd..5c1c3444e 100644
--- a/Src/DBIO.MetaData.DCSC.pas
+++ b/Src/DBIO.MetaData.DCSC.pas
@@ -429,10 +429,11 @@ TUpdateDBMetaData = class sealed(TAbstractMainDBMetaData, IDBMetaData)
implementation
uses
- // Project
+ // Delphi
Classes,
IOUtils,
- // VCL
+ // Project
+ DB.DataFormats,
UEncodings,
UIOUtils,
UResourceUtils,
@@ -839,7 +840,7 @@ class function TDBMetaFilesFactory.GetInstance(const DBDir: string):
initialization
TMetaDataFactory.RegisterCreator(
- TCollectionFormatKind.DCSC_v2, TMainDBMetaData
+ TDataFormatKind.DCSC_v2, TMainDBMetaData
);
end.
From b4ca46c2c870cc4e4109a629bc32f020d12510f2 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 26 Nov 2024 11:48:13 +0000
Subject: [PATCH 128/222] Refactor creation of default collection
The code that creates the Default collection now gets the data format
from the TDataFormatInfo.DefaultFormat constant instead of hard-wiring
TDataFormatKind.Native_v4. This protects against a possible bug if the
default data format is changed.
---
Src/DB.UCollections.pas | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
index 0764fe91d..06ea12b5d 100644
--- a/Src/DB.UCollections.pas
+++ b/Src/DB.UCollections.pas
@@ -413,7 +413,7 @@ procedure TCollections.Initialize;
TCollectionLocation.Create(
TAppInfo.UserDefaultCollectionDir, '', etUTF8
),
- TDataFormatKind.Native_v4
+ TDataFormatInfo.DefaultFormat
)
);
end;
From 9e698e4d60079c2b38611a7b055b7ddbc34c8b73 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 26 Nov 2024 19:43:59 +0000
Subject: [PATCH 129/222] Revise how TCollection handles data storage info
TCollection previously and a Location of type TCollectionLocation
property that stored the directory in which the collection is stored
along with a CollectionFormatKind property to store the collection's
data format. TCollectionLocation also had some other properties that
have never found a used.
A new record, TDataStorageDetails, was added to DB.DataFormats that
records both the data format kind and the directory used to store the
collection.
TCollection replaced its Location and CollectionFormatKind properties
with a single Storage property of type TDataStorageDetails.
The key/value pairs in the [Collection:X] config file sections were
revised to store the new TCollection property values and not to store
the removed property values.
Calling code was modified as necessary re these changes.
The redundant TCollectionLocation record was deleted.
---
Src/DB.DataFormats.pas | 39 +++++++-
Src/DB.UCollections.pas | 188 +++++++++----------------------------
Src/DB.UDatabaseIO.pas | 12 +--
Src/DB.UMetaData.pas | 16 ++--
Src/DBIO.MetaData.DCSC.pas | 21 ++---
Src/FmAboutDlg.pas | 5 +-
Src/FmUserDataPathDlg.pas | 2 +-
Src/USaveUnitMgr.pas | 3 +-
Src/USnippetDoc.pas | 3 +-
Src/USnippetSourceGen.pas | 3 +-
Src/UUserDBBackup.pas | 4 +-
Src/UUserDBMgr.pas | 4 +-
Src/UUserDBMove.pas | 6 +-
13 files changed, 121 insertions(+), 185 deletions(-)
diff --git a/Src/DB.DataFormats.pas b/Src/DB.DataFormats.pas
index 519c409f4..8207c0940 100644
--- a/Src/DB.DataFormats.pas
+++ b/Src/DB.DataFormats.pas
@@ -26,14 +26,35 @@ interface
Native_v4
);
+ /// Record containing details of the data format and location in
+ /// which a collection is stored.
+ TDataStorageDetails = record
+ strict private
+ var
+ /// Value of the Directory property.
+ fDirectory: string;
+ /// Value of the Format property.
+ fFormat: TDataFormatKind;
+ /// Write access method for Directory property.
+ procedure SetDirectory(const AValue: string);
+ public
+ /// Constructs a new record instance with the given property
+ /// values.
+ constructor Create(const AFormat: TDataFormatKind;
+ const ADirectory: string);
+ /// The format in which the data is stored.
+ property Format: TDataFormatKind read fFormat;
+ /// The directory in which the data is stored.
+ property Directory: string read fDirectory write SetDirectory;
+ end;
TDataFormatInfo = record
strict private
type
TMapRecord = record
- /// Collection data format kind.
+ /// Data format kind.
Kind: TDataFormatKind;
- /// Collection data format name.
+ /// Data format name.
Name: string;
end;
const
@@ -100,4 +121,18 @@ class function TDataFormatInfo.IndexOf(const AKind: TDataFormatKind): Integer;
Exit(Idx);
end;
+{ TDataStorageDetails }
+
+constructor TDataStorageDetails.Create(const AFormat: TDataFormatKind;
+ const ADirectory: string);
+begin
+ fFormat := AFormat;
+ fDirectory := ADirectory;
+end;
+
+procedure TDataStorageDetails.SetDirectory(const AValue: string);
+begin
+ fDirectory := AValue;
+end;
+
end.
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
index 06ea12b5d..b1d7e9800 100644
--- a/Src/DB.UCollections.pas
+++ b/Src/DB.UCollections.pas
@@ -63,63 +63,12 @@ TComparer = class(TInterfacedObject,
ECollectionID = class(ECodeSnip);
- TCollectionLocation = record
- strict private
- var
- fDirectory: string;
- fMetaDataFile: string;
- fEncodingHint: TEncodingType;
- procedure SetDirectory(const ANewDirectory: string);
- public
-
- /// Instantiates a record with given values.
- /// string [in] File system directory
- /// containing the collection data. Must be non-empty and a valid directory
- /// name.
- /// string [in] Path to the collection's
- /// meta data file, if any. May be empty if collection has no meta data
- /// file or if the meta data file name is fixed. If non-empty the path must
- /// be relative to ADirectory. Optional: default is empty string.
- ///
- /// TEncodingType [in] Hints at the
- /// encoding used by text files in ADirectory. Only required if the
- /// text files are not used in the collection or if the collection format
- /// specifies the text format. Optional: default is system default
- /// encoding.
- constructor Create(const ADirectory: string;
- const AMetaDataFile: string = '';
- const AEncodingHint: TEncodingType = TEncodingType.etSysDefault);
-
- /// File system directory containing the collection data.
- ///
- /// Must be a valid directory name and must exist.
- property Directory: string read fDirectory write SetDirectory;
-
- /// Name of any meta data file, relative to Directory.
- ///
- /// May be empty string. If non-empty must be a valid path name
- /// and the file must exist.
- property MetaDataFile: string read fMetaDataFile;
-
- /// Hints at the type of encoding used by the text files in
- /// Directory.
- /// EncodingHint should only be used where the I/O code has
- /// no knowledge of the expected text file encoding AND the where the files
- /// do not contain preamble bytes that specify the encoding.
- property EncodingHint: TEncodingType read fEncodingHint;
-
- /// Checks if the record instance has valid fields.
- function IsValid: Boolean;
-
- end;
-
TCollection = record
strict private
var
fUID: TCollectionID;
fName: string;
- fLocation: TCollectionLocation;
- fCollectionFormatKind: TDataFormatKind;
+ fStorage: TDataStorageDetails;
public
type
TComparer = class(TInterfacedObject,
@@ -138,20 +87,16 @@ TComparer = class(TInterfacedObject,
/// string [in] Name of collection. Should be
/// unique. Must not be empty or only whitespace.
constructor Create(const AUID: TCollectionID; const AName: string;
- const ALocation: TCollectionLocation;
- const ACollectionFormatKind: TDataFormatKind);
+ const AStorage: TDataStorageDetails);
/// Collection identifier. Must be unique.
property UID: TCollectionID
read fUID;
/// Collection name. Must be unique.
property Name: string read
fName;
- /// Collection location information.
- property Location: TCollectionLocation
- read fLocation;
- /// Kind of collection format used for to store data for this
- /// collection.
- property CollectionFormatKind: TDataFormatKind read fCollectionFormatKind;
+ /// Collection storage information.
+ property Storage: TDataStorageDetails
+ read fStorage;
/// Checks if this record's fields are valid.
function IsValid: Boolean;
/// Checks if this record is the default collection.
@@ -193,10 +138,8 @@ TCollectionsPersist = record
CountKey = 'Count';
UIDKey = 'UID';
NameKey = 'Name';
- LocationDirectoryKey = 'Location.Directory';
- LocationMetaDataFileKey = 'Location.MetaDataFile';
- LocationEncodingHintKey = 'Location.EncodingHint';
- DataFormatKey = 'DataFormat';
+ StorageFormatKey = 'Storage.Format';
+ StorageDirectoryKey = 'Storage.Directory';
class procedure SaveCollection(const AOrdinal: Cardinal;
const ACollection: TCollection); static;
class procedure LoadCollection(const AOrdinal: Cardinal;
@@ -221,41 +164,10 @@ implementation
resourcestring
SBadHexString = 'Invalid Hex String.';
-{ TCollectionLocation }
-
-constructor TCollectionLocation.Create(const ADirectory,
- AMetaDataFile: string; const AEncodingHint: TEncodingType);
-begin
- fDirectory := StrTrim(ADirectory);
- fMetaDataFile := StrTrim(AMetaDataFile);
- fEncodingHint := AEncodingHint;
- Assert(IsValid, 'TCollectionLocation.Create: invalid parameter(s)');
-end;
-
-function TCollectionLocation.IsValid: Boolean;
-begin
- Result := True;
- if fDirectory = '' then
- Exit(False);
- if not TPath.HasValidPathChars(fDirectory, False) then
- Exit(False);
- if (fMetaDataFile <> '') then
- begin
- if not TPath.IsRelativePath(fMetaDataFile) then
- Exit(False);
- end;
-end;
-
-procedure TCollectionLocation.SetDirectory(const ANewDirectory: string);
-begin
- fDirectory := ANewDirectory;
-end;
-
{ TCollection }
-constructor TCollection.Create(const AUID: TCollectionID;
- const AName: string; const ALocation: TCollectionLocation;
- const ACollectionFormatKind: TDataFormatKind);
+constructor TCollection.Create(const AUID: TCollectionID; const AName: string;
+ const AStorage: TDataStorageDetails);
var
TrimmedName: string;
begin
@@ -263,13 +175,12 @@ constructor TCollection.Create(const AUID: TCollectionID;
Assert(not AUID.IsNull, 'TCollection.Create: AUID is null');
Assert(TrimmedName <> '',
'TCollection.Create: AName is empty or only whitespace');
- Assert(ALocation.IsValid, 'TCollection.Create: ALocation is not valid');
- Assert(ACollectionFormatKind <> TDataFormatKind.Error,
- 'TCollection.Create: ACollectionFormatKind = TCollectionFormatKind.Error');
+ {TODO -cRefactor: move following into IsValid method of TDataDetails}
+ Assert(AStorage.Format <> TDataFormatKind.Error,
+ 'TCollection.Create: ADataDetails.Kind = TCollectionFormatKind.Error');
fUID := AUID.Clone;
fName := TrimmedName;
- fLocation := ALocation;
- fCollectionFormatKind := ACollectionFormatKind;
+ fStorage := AStorage;
end;
function TCollection.IsDefault: Boolean;
@@ -283,8 +194,7 @@ function TCollection.IsValid: Boolean;
may not be needed.}
Result := not fUID.IsNull
and (fName <> '')
- and fLocation.IsValid
- and (fCollectionFormatKind <> TDataFormatKind.Error);
+ and (fStorage.Format <> TDataFormatKind.Error);
end;
{ TCollections }
@@ -410,10 +320,10 @@ procedure TCollections.Initialize;
TCollection.Create(
TCollectionID.Default,
'Default',
- TCollectionLocation.Create(
- TAppInfo.UserDefaultCollectionDir, '', etUTF8
- ),
- TDataFormatInfo.DefaultFormat
+ TDataStorageDetails.Create(
+ TDataFormatInfo.DefaultFormat,
+ TAppInfo.UserDefaultCollectionDir
+ )
)
);
end;
@@ -559,12 +469,12 @@ function TCollectionID.TComparer.GetHashCode(
class procedure TCollectionsPersist.Load(
const ACollections: TCollections);
var
- Storage: ISettingsSection;
+ ConfigSection: ISettingsSection;
Count: Integer;
Idx: Integer;
begin
- Storage := Settings.ReadSection(ssCollections);
- Count := Storage.GetInteger(CountKey, 0);
+ ConfigSection := Settings.ReadSection(ssCollections);
+ Count := ConfigSection.GetInteger(CountKey, 0);
for Idx := 0 to Pred(Count) do
LoadCollection(Idx, ACollections);
end;
@@ -572,45 +482,39 @@ class procedure TCollectionsPersist.Load(
class procedure TCollectionsPersist.LoadCollection(const AOrdinal: Cardinal;
const ACollections: TCollections);
var
- Storage: ISettingsSection;
- Location: TCollectionLocation;
+ ConfigSection: ISettingsSection;
UID: TCollectionID;
Name: string;
Collection: TCollection;
- DataFormat: TDataFormatKind;
+ StorageDetails: TDataStorageDetails;
begin
- Storage := Settings.ReadSection(ssCollection, IntToStr(AOrdinal));
- UID := TCollectionID.Create(Storage.GetBytes(UIDKey));
+ ConfigSection := Settings.ReadSection(ssCollection, IntToStr(AOrdinal));
+ UID := TCollectionID.Create(ConfigSection.GetBytes(UIDKey));
if ACollections.ContainsID(UID) then
// Don't load a duplicate collection
Exit;
- Name := Storage.GetString(NameKey, '');
- Location := TCollectionLocation.Create(
- Storage.GetString(LocationDirectoryKey, ''),
- Storage.GetString(LocationMetaDataFileKey, ''),
- TEncodingType(
- Storage.GetInteger(
- LocationEncodingHintKey, Ord(TEncodingType.etSysDefault)
- )
- )
- );
- DataFormat := TDataFormatKind(
- Storage.GetInteger(DataFormatKey, Ord(TDataFormatKind.Error))
+ Name := ConfigSection.GetString(NameKey, '');
+
+ StorageDetails := TDataStorageDetails.Create(
+ TDataFormatKind(
+ ConfigSection.GetInteger(StorageFormatKey, Ord(TDataFormatKind.Error))
+ ),
+ ConfigSection.GetString(StorageDirectoryKey, '')
);
- Collection := TCollection.Create(UID, Name, Location, DataFormat);
+ Collection := TCollection.Create(UID, Name, StorageDetails);
ACollections.Add(Collection);
end;
class procedure TCollectionsPersist.Save(const
ACollections: TCollections);
var
- Storage: ISettingsSection;
+ ConfigSection: ISettingsSection;
Idx: Integer;
begin
// Save number of collections
- Storage := Settings.EmptySection(ssCollections);
- Storage.SetInteger(CountKey, ACollections.Count);
- Storage.Save;
+ ConfigSection := Settings.EmptySection(ssCollections);
+ ConfigSection.SetInteger(CountKey, ACollections.Count);
+ ConfigSection.Save;
// Save each collection's properties in its own section
for Idx := 0 to Pred(ACollections.Count) do
SaveCollection(Idx, ACollections[Idx]);
@@ -619,19 +523,15 @@ class procedure TCollectionsPersist.Save(const
class procedure TCollectionsPersist.SaveCollection(const AOrdinal: Cardinal;
const ACollection: TCollection);
var
- Storage: ISettingsSection;
+ ConfigSection: ISettingsSection;
begin
// Save info about collection format in its own section
- Storage := Settings.EmptySection(ssCollection, IntToStr(AOrdinal));
- Storage.SetBytes(UIDKey, ACollection.UID.ToArray);
- Storage.SetString(NameKey, ACollection.Name);
- Storage.SetString(LocationDirectoryKey, ACollection.Location.Directory);
- Storage.SetString(LocationMetaDataFileKey, ACollection.Location.MetaDataFile);
- Storage.SetInteger(
- LocationEncodingHintKey, Ord(ACollection.Location.EncodingHint)
- );
- Storage.SetInteger(DataFormatKey, Ord(ACollection.CollectionFormatKind));
- Storage.Save;
+ ConfigSection := Settings.EmptySection(ssCollection, IntToStr(AOrdinal));
+ ConfigSection.SetBytes(UIDKey, ACollection.UID.ToArray);
+ ConfigSection.SetString(NameKey, ACollection.Name);
+ ConfigSection.SetInteger(StorageFormatKey, Ord(ACollection.Storage.Format));
+ ConfigSection.SetString(StorageDirectoryKey, ACollection.Storage.Directory);
+ ConfigSection.Save;
end;
{ TCollection.TComparer }
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index 565b7e8bd..6fa7eab71 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -422,7 +422,7 @@ class function TDatabaseIOFactory.CreateDBLoader(const Collection: TCollection):
begin
{TODO -cUDatabaseIO: Revise database loaders to get file path and other
info from collection instead of hard wiring it.}
- case Collection.CollectionFormatKind of
+ case Collection.Storage.Format of
TDataFormatKind.DCSC_v2:
Result := TDCSCV2FormatLoader.Create(Collection);
TDataFormatKind.Native_v4:
@@ -435,7 +435,7 @@ class function TDatabaseIOFactory.CreateDBLoader(const Collection: TCollection):
class function TDatabaseIOFactory.CreateDBSaver(
const Collection: TCollection): IDataFormatSaver;
begin
- case Collection.CollectionFormatKind of
+ case Collection.Storage.Format of
TDataFormatKind.DCSC_v2:
Result := TDCSCV2FormatSaver.Create(Collection);
TDataFormatKind.Native_v4:
@@ -641,7 +641,7 @@ function TDCSCV2FormatLoader.CreateReader: IDataReader;
@return Reader object instance.
}
begin
- Result := TIniDataReader.Create(Collection.Location.Directory);
+ Result := TIniDataReader.Create(Collection.Storage.Directory);
if not Result.DatabaseExists then
Result := TNulDataReader.Create;
end;
@@ -664,7 +664,7 @@ function TNativeV4FormatLoader.CreateReader: IDataReader;
@return Reader object instance.
}
begin
- Result := TXMLDataReader.Create(Collection.Location.Directory);
+ Result := TXMLDataReader.Create(Collection.Storage.Directory);
if not Result.DatabaseExists then
Result := TNulDataReader.Create;
end;
@@ -779,7 +779,7 @@ constructor TDCSCV2FormatSaver.Create(const ACollection: TCollection);
function TDCSCV2FormatSaver.CreateWriter: IDataWriter;
begin
- Result := TIniDataWriter.Create(Collection.Location.Directory);
+ Result := TIniDataWriter.Create(Collection.Storage.Directory);
end;
procedure TDCSCV2FormatSaver.Restore;
@@ -814,7 +814,7 @@ procedure TDCSCV2FormatSaver.Save(const SnipList: TSnippetList;
function TNativeV4FormatSaver.CreateWriter: IDataWriter;
begin
- Result := TXMLDataWriter.Create(Collection.Location.Directory);
+ Result := TXMLDataWriter.Create(Collection.Storage.Directory);
end;
procedure TNativeV4FormatSaver.Save(const SnipList: TSnippetList;
diff --git a/Src/DB.UMetaData.pas b/Src/DB.UMetaData.pas
index 442630bc0..93171ebb4 100644
--- a/Src/DB.UMetaData.pas
+++ b/Src/DB.UMetaData.pas
@@ -20,7 +20,6 @@ interface
// Delphi
Generics.Collections,
// Project
- DB.UCollections,
DB.DataFormats,
UIStringList,
UVersionInfo;
@@ -151,7 +150,8 @@ TRegisterableMetaData = class abstract(TInterfacedObject)
/// TCollection [in] Collection associated
/// with the meta data being created.
/// IDBMetaData. Required meta data object.
- class function Instance(ACollection: TCollection): IDBMetaData;
+ class function Instance(const AStorageDetails: TDataStorageDetails):
+ IDBMetaData;
virtual; abstract;
/// Gets the meta data capabilities for the collection data
/// format.
@@ -198,7 +198,7 @@ TMetaDataFactory = record
/// IDBMetaData. Requested object. May be a null object if
/// no meta data class was registered for the data format associated with
/// ACollection.
- class function CreateInstance(const ACollection: TCollection):
+ class function CreateInstance(const AStorageDetails: TDataStorageDetails):
IDBMetaData; static;
/// Gets the meta data capabilities for a collection data format.
///
@@ -341,13 +341,11 @@ class function TMetaDataFactory.CapabilitiesOf(
>.Create;
end;
-class function TMetaDataFactory.CreateInstance(const ACollection: TCollection):
- IDBMetaData;
+class function TMetaDataFactory.CreateInstance(
+ const AStorageDetails: TDataStorageDetails): IDBMetaData;
begin
- if fCallbackMap.ContainsKey(ACollection.CollectionFormatKind) then
- Result := fCallbackMap[ACollection.CollectionFormatKind].Instance(
- ACollection
- )
+ if fCallbackMap.ContainsKey(AStorageDetails.Format) then
+ Result := fCallbackMap[AStorageDetails.Format].Instance(AStorageDetails)
else
Result := TNullMetaData.Create;
end;
diff --git a/Src/DBIO.MetaData.DCSC.pas b/Src/DBIO.MetaData.DCSC.pas
index 5c1c3444e..85052f55b 100644
--- a/Src/DBIO.MetaData.DCSC.pas
+++ b/Src/DBIO.MetaData.DCSC.pas
@@ -98,7 +98,7 @@ interface
SysUtils,
Types,
// VCL
- DB.UCollections,
+ DB.DataFormats,
DB.UMetaData,
UIStringList,
UStructs,
@@ -335,7 +335,8 @@ TAbstractMainDBMetaData = class abstract(TRegisterableMetaData)
/// Creates an instance of meta data object that can read this
/// collection's format.
/// Must be called from a concrete descendant class.
- class function Instance(ACollection: TCollection): IDBMetaData; override;
+ class function Instance(const AStorageDetails: TDataStorageDetails):
+ IDBMetaData; override;
/// Gets the meta data capabilities for the collection data
/// format.
/// TMetaDataCapabilities. Required meta data capabilities.
@@ -407,11 +408,11 @@ TAbstractMainDBMetaData = class abstract(TRegisterableMetaData)
TMainDBMetaData = class sealed(TAbstractMainDBMetaData, IDBMetaData)
strict private
var
- fCollection: TCollection;
+ fDirectory: string;
strict protected
function GetDBDir: string; override;
public
- constructor Create(const ACollection: TCollection);
+ constructor Create(const ADirectory: string);
end;
/// Class that provides meta data for update database directories.
@@ -433,7 +434,6 @@ implementation
Classes,
IOUtils,
// Project
- DB.DataFormats,
UEncodings,
UIOUtils,
UResourceUtils,
@@ -500,9 +500,9 @@ function TAbstractMainDBMetaData.GetVersion: TVersionNumber;
end;
class function TAbstractMainDBMetaData.Instance(
- ACollection: DB.UCollections.TCollection): IDBMetaData;
+ const AStorageDetails: TDataStorageDetails): IDBMetaData;
begin
- Result := TMainDBMetaData.Create(ACollection);
+ Result := TMainDBMetaData.Create(AStorageDetails.Directory);
end;
function TAbstractMainDBMetaData.IsCorrupt: Boolean;
@@ -566,16 +566,15 @@ procedure TAbstractMainDBMetaData.Refresh;
{ TMainDBMetaData }
-constructor TMainDBMetaData.Create(
- const ACollection: DB.UCollections.TCollection);
+constructor TMainDBMetaData.Create(const ADirectory: string);
begin
inherited Create;
- fCollection := ACollection;
+ fDirectory := ADirectory;
end;
function TMainDBMetaData.GetDBDir: string;
begin
- Result := fCollection.Location.Directory;
+ Result := fDirectory;
end;
{ TUpdateDBMetaData }
diff --git a/Src/FmAboutDlg.pas b/Src/FmAboutDlg.pas
index 99184be1f..b470aecc3 100644
--- a/Src/FmAboutDlg.pas
+++ b/Src/FmAboutDlg.pas
@@ -184,6 +184,7 @@ implementation
ShellAPI,
IOUtils,
// Project
+ DB.DataFormats,
FmEasterEgg,
FmPreviewDlg,
UAppInfo,
@@ -316,7 +317,7 @@ procedure TAboutDlg.ConfigForm;
fPathInfoBoxes.Add(
CreatePathInfoBox(
Format(sCollectionPathGpCaption, [Collection.Name]),
- Collection.Location.Directory,
+ Collection.Storage.Directory,
TabIdx
)
);
@@ -377,7 +378,7 @@ procedure TAboutDlg.DisplayCollectionInfo(ACollection: TCollection);
tvCollectionInfo.Items.BeginUpdate;
try
tvCollectionInfo.Items.Clear;
- MetaData := TMetaDataFactory.CreateInstance(ACollection);
+ MetaData := TMetaDataFactory.CreateInstance(ACollection.Storage);
Capabilities := MetaData.GetCapabilities;
if Capabilities <> [] then
begin
diff --git a/Src/FmUserDataPathDlg.pas b/Src/FmUserDataPathDlg.pas
index 314057ac8..74215c0b8 100644
--- a/Src/FmUserDataPathDlg.pas
+++ b/Src/FmUserDataPathDlg.pas
@@ -176,7 +176,7 @@ procedure TUserDataPathDlg.actMoveUpdate(Sender: TObject);
actMove.Enabled := (NewDirFromEditCtrl <> '')
and not StrSameText(
NewDirFromEditCtrl,
- fCollList.Collection(cbCollection.ItemIndex).Location.Directory
+ fCollList.Collection(cbCollection.ItemIndex).Storage.Directory
)
and Self.Enabled;
end;
diff --git a/Src/USaveUnitMgr.pas b/Src/USaveUnitMgr.pas
index 6b13e0d50..dd9ba3b7d 100644
--- a/Src/USaveUnitMgr.pas
+++ b/Src/USaveUnitMgr.pas
@@ -103,6 +103,7 @@ implementation
// Delphi
SysUtils,
// Project
+ DB.DataFormats,
DB.UMetaData,
UAppInfo,
UUtils;
@@ -153,7 +154,7 @@ function TSaveUnitMgr.CreateHeaderComments: IStringList;
var
DBMetaData: IDBMetaData;
begin
- DBMetaData := TMetaDataFactory.CreateInstance(ACollection);
+ DBMetaData := TMetaDataFactory.CreateInstance(ACollection.Storage);
Result := '';
if mdcLicense in DBMetaData.GetCapabilities then
begin
diff --git a/Src/USnippetDoc.pas b/Src/USnippetDoc.pas
index 765543073..83b6a8640 100644
--- a/Src/USnippetDoc.pas
+++ b/Src/USnippetDoc.pas
@@ -119,6 +119,7 @@ implementation
Generics.Collections,
// Project
Compilers.UCompilers,
+ DB.DataFormats,
DB.UMain,
DB.UMetaData,
DB.USnippetKind,
@@ -138,7 +139,7 @@ function TSnippetDoc.CollectionInfo(const ACollectionID: TCollectionID): string;
begin
Collection := TCollections.Instance.GetCollection(ACollectionID);
Result := Format(sCollectionInfo, [Collection.Name]);
- MetaData := TMetaDataFactory.CreateInstance(Collection);
+ MetaData := TMetaDataFactory.CreateInstance(Collection.Storage);
if mdcLicense in MetaData.GetCapabilities then
begin
Result := Result + ' ' + MetaData.GetLicenseInfo.NameWithURL + '.';
diff --git a/Src/USnippetSourceGen.pas b/Src/USnippetSourceGen.pas
index b30a35883..388cac79e 100644
--- a/Src/USnippetSourceGen.pas
+++ b/Src/USnippetSourceGen.pas
@@ -94,6 +94,7 @@ implementation
// Delphi
SysUtils,
// Project
+ DB.DataFormats,
DB.USnippet,
DB.USnippetKind,
DBIO.MetaData.DCSC,
@@ -123,7 +124,7 @@ function TSnippetSourceGen.BuildHeaderComments: IStringList;
function CreditsLine(const ACollection: TCollection): string;
begin
- DBMetaData := TMetaDataFactory.CreateInstance(ACollection);
+ DBMetaData := TMetaDataFactory.CreateInstance(ACollection.Storage);
Result := '';
if mdcLicense in DBMetaData.GetCapabilities then
begin
diff --git a/Src/UUserDBBackup.pas b/Src/UUserDBBackup.pas
index dd063eda2..c6a1a8323 100644
--- a/Src/UUserDBBackup.pas
+++ b/Src/UUserDBBackup.pas
@@ -64,7 +64,7 @@ constructor TUserDBBackup.Create(const BackupFile: string;
}
begin
inherited Create(
- ACollection.Location.Directory,
+ ACollection.Storage.Directory,
BackupFile,
MakeFileID(ACollection),
ACollection.UID.ToArray
@@ -76,7 +76,7 @@ class function TUserDBBackup.MakeFileID(const ACollection: TCollection):
begin
// Backup file ID is $Fxxx where xxx is ordinal value of format kind.
// The $F indicates that the file is a backup of a collection data format.
- Result := SmallInt($F000 or UInt16(Ord(ACollection.CollectionFormatKind)));
+ Result := SmallInt($F000 or UInt16(Ord(ACollection.Storage.Format)));
end;
end.
diff --git a/Src/UUserDBMgr.pas b/Src/UUserDBMgr.pas
index ce6b9222b..56dc38823 100644
--- a/Src/UUserDBMgr.pas
+++ b/Src/UUserDBMgr.pas
@@ -326,9 +326,9 @@ class function TUserDBMgr.DeleteDatabase: Boolean;
begin
if not TDeleteUserDBDlg.Execute(nil, CollectionToDelete) then
Exit(False);
- if not TDirectory.Exists(CollectionToDelete.Location.Directory) then
+ if not TDirectory.Exists(CollectionToDelete.Storage.Directory) then
Exit(False);
- TDirectory.Delete(CollectionToDelete.Location.Directory, True);
+ TDirectory.Delete(CollectionToDelete.Storage.Directory, True);
Result := True;
end;
diff --git a/Src/UUserDBMove.pas b/Src/UUserDBMove.pas
index 98f3a6fb0..6e5959adb 100644
--- a/Src/UUserDBMove.pas
+++ b/Src/UUserDBMove.pas
@@ -120,7 +120,7 @@ procedure TUserDBMove.MoveTo(const ACollection: TCollection;
const ADirectory: string);
begin
fCollection := ACollection;
- fSourceDir := ExcludeTrailingPathDelimiter(ACollection.Location.Directory);
+ fSourceDir := ExcludeTrailingPathDelimiter(ACollection.Storage.Directory);
fDestDir := ExcludeTrailingPathDelimiter(ADirectory);
ValidateDirectories;
fDirCopier.Move(fSourceDir, fDestDir);
@@ -146,7 +146,7 @@ procedure TUserDBMove.SetNewDBDirectory(Sender: TObject);
begin
Collections := TCollections.Instance;
// record new location BEFORE deleting old directory
- fCollection.Location.Directory := fDestDir;
+ fCollection.Storage.Directory := fDestDir;
Collections.Update(fCollection);
// Persist collections immediately to save new directory ASAP to prevent
// directory change being lost following a program crash.
@@ -177,7 +177,7 @@ procedure TUserDBMove.ValidateDirectories;
raise EInOutError.Create(sSameNames);
if StrStartsText(
- IncludeTrailingPathDelimiter(fCollection.Location.Directory), fDestDir
+ IncludeTrailingPathDelimiter(fCollection.Storage.Directory), fDestDir
) then
raise EInOutError.Create(sCantMoveToSubDir);
end;
From 02d5a3f391f7a880af4b24c309b06805c7028f30 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Tue, 10 Dec 2024 09:56:18 +0000
Subject: [PATCH 130/222] Extend TSnippetTestInfo enumeration
Added new stiUnitTests and stiDemoCode values to the TSnippetTestInfo
enumeration.
Updated calling code in DBIO.UIniData and USnippetHTML units just to
allow to compile, but didn't implement any code relating to the new
values.
---
Src/DB.USnippet.pas | 4 +++-
Src/DBIO.UIniData.pas | 11 ++++++++---
Src/USnippetHTML.pas | 10 ++++++++--
3 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/Src/DB.USnippet.pas b/Src/DB.USnippet.pas
index 21fe6c33d..e54da8c1b 100644
--- a/Src/DB.USnippet.pas
+++ b/Src/DB.USnippet.pas
@@ -36,7 +36,9 @@ interface
TSnippetTestInfo = (
stiNone, // snippet has not been tested
stiBasic, // snippet has had some basic testing
- stiAdvanced // snippet has had advanced (unit) testing
+ stiAdvanced, // snippet has had unspecified advanced testing
+ stiUnitTests, // snippet has unit tests
+ stiDemoCode // snippet has a demo program
);
type
diff --git a/Src/DBIO.UIniData.pas b/Src/DBIO.UIniData.pas
index e54c5c20a..7039883b7 100644
--- a/Src/DBIO.UIniData.pas
+++ b/Src/DBIO.UIniData.pas
@@ -942,9 +942,14 @@ procedure TIniDataWriter.WriteSnippetProps(const SnippetKey: string;
'Q' // crQuery
);
TestInfo: array[TSnippetTestInfo] of string = (
- 'none', // stiNone
- 'basic', // stiBasic
- 'advanced' // stiAdvanced
+ {TODO -cVault: New empty entries added because new entries have been added
+ to TSnippetTestInfo. Need to update code to support new Advanced.XXX
+ entries in DCSC v2.2}
+ 'none', // stiNone
+ 'basic', // stiBasic
+ 'advanced', // stiAdvanced
+ '', // stiUnitTests
+ '' // stiDemoCode
);
var
SourceFileName: string;
diff --git a/Src/USnippetHTML.pas b/Src/USnippetHTML.pas
index 3d4a6fbc5..e5783b245 100644
--- a/Src/USnippetHTML.pas
+++ b/Src/USnippetHTML.pas
@@ -250,7 +250,9 @@ function TSnippetHTML.TestingImage: string;
resourcestring
sTestingNone = 'Untested'#13#10'Use with care';
sTestingBasic = 'Passed simple tests';
- sTestingAdvanced = 'Passed advanced / unit testing';
+ sTestingAdvanced = 'Passed unspecified advanced testing';
+ sTestingUnitTests = 'Has unit tests';
+ sTestingDemo = 'Has demo program';
const
ImgWidth = 16;
ImgHeight = 16;
@@ -260,7 +262,11 @@ function TSnippetHTML.TestingImage: string;
end =(
(ResName: 'testing-none.png'; Title: sTestingNone),
(ResName: 'testing-basic.png'; Title: sTestingBasic),
- (ResName: 'testing-advanced.png'; Title: sTestingAdvanced)
+ (ResName: 'testing-advanced.png'; Title: sTestingAdvanced),
+ {TODO -cVault: Add new icons below for unit tests and demo code test info
+ to replace testing-advanced.png}
+ (ResName: 'testing-advanced.png'; Title: sTestingUnitTests),
+ (ResName: 'testing-advanced.png'; Title: sTestingDemo)
);
var
Attrs: IHTMLAttributes; // image's attributes
From 2156e10b9126f23eda0708e57f8f83d9fb956719 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Thu, 12 Dec 2024 17:53:27 +0000
Subject: [PATCH 131/222] Add new StrReplaceChar function to UStrUtils
---
Src/UStrUtils.pas | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/Src/UStrUtils.pas b/Src/UStrUtils.pas
index b56d8005c..1c27f35ab 100644
--- a/Src/UStrUtils.pas
+++ b/Src/UStrUtils.pas
@@ -21,6 +21,7 @@ interface
uses
// Delphi
+ SysUtils,
Classes,
// Project
UConsts;
@@ -117,6 +118,12 @@ function StrStartsText(const SubStr, Str: UnicodeString): Boolean;
function StrReplace(const Str, FindStr, ReplaceStr: UnicodeString):
UnicodeString;
+/// Replaces all occurences in Str of characters for which
+/// predicate Condition returns True with character
+/// ReplaceCh and returns the modified string.
+function StrReplaceChar(const Str: string; const Condition: TPredicate;
+ const ReplaceCh: Char): string;
+
/// Trims leading and trailing white space characters from a string.
///
/// White space is considered to be any character from #0..#32.
@@ -333,7 +340,8 @@ implementation
uses
// Delphi
- SysUtils, StrUtils, Character;
+ StrUtils,
+ Character;
{ Internal helper routines }
@@ -659,6 +667,19 @@ function StrReplace(const Str, FindStr, ReplaceStr: UnicodeString):
Result := StrUtils.AnsiReplaceStr(Str, FindStr, ReplaceStr);
end;
+function StrReplaceChar(const Str: string; const Condition: TPredicate;
+ const ReplaceCh: Char): string;
+var
+ Idx: Integer;
+begin
+ SetLength(Result, Length(Str));
+ for Idx := 1 to Length(Str) do
+ if Condition(Str[Idx]) then
+ Result[Idx] := ReplaceCh
+ else
+ Result[Idx] := Str[Idx];
+end;
+
function StrSameStr(const Left, Right: UnicodeString): Boolean;
begin
Result := SysUtils.AnsiSameStr(Left, Right);
From 88f38fa7f262c8cb5e75c8dc39a829e92f9988e8 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Thu, 12 Dec 2024 17:55:24 +0000
Subject: [PATCH 132/222] Modify some TIStringList methods re nil string lists
The implementation of the TIStringList constructor and .Add methods that
accept either IStringList or TStrings parameters were modified to permit
nil to be passed as a parameter. In such cases .Add methods become noops
and the constructors construct an empty IStringList object.
Documentation was modified accordingly.
---
Src/UIStringList.pas | 71 ++++++++++++++++++++++++--------------------
1 file changed, 39 insertions(+), 32 deletions(-)
diff --git a/Src/UIStringList.pas b/Src/UIStringList.pas
index 90a630931..4a0239917 100644
--- a/Src/UIStringList.pas
+++ b/Src/UIStringList.pas
@@ -170,15 +170,19 @@ TIStringList = class(TInterfacedObject,
constructor Create; overload;
{Class constructor. Creates new empty list.
}
+
+ /// Create a new list containing all the strings contained in a
+ /// given string list.
+ /// TStrings [in] List of strings to add. An
+ /// empty list is created if Strs is empty or nil.
constructor Create(const Strs: TStrings); overload;
- {Class constructor. Creates new list containing specified strings.
- @param Strs [in] List of strings to be stored in list.
- }
+
+ /// Create a new list containing all the strings contained in a
+ /// given string list.
+ /// IStringList [in] List of strings to add. An
+ /// empty list is created if Strs is empty or nil.
constructor Create(const Strs: IStringList); overload;
- {Class constructor. Creates new list containing strings from another
- IStringList instance.
- @param Strs [in] List of strings to be stored in list.
- }
+
constructor Create(const Str: string); overload;
{Class constructor. Creates new list containing a single string.
@param Str [in] String to be included in list.
@@ -194,10 +198,13 @@ TIStringList = class(TInterfacedObject,
@param Trim [in] Determines whether strings are trimmed of trailing and
leading spaces before adding to list.
}
+
+ /// Create a new list containing all the strings contained in a
+ /// given array.
+ /// array of string [in] List of strings to add.
+ /// An empty list is created if Strs is empty.
constructor Create(const Strs: array of string); overload;
- {Class constructor. Creates new list containing strings from array.
- @param Strs [in] Array of strings to be included in list.
- }
+
destructor Destroy; override;
{Class destructor. Tears down object.
}
@@ -207,18 +214,25 @@ TIStringList = class(TInterfacedObject,
@param Str [in] String to be added to list.
@return Index of new string in list.
}
+
+ /// Adds all strings from a string list to the end of the list.
+ ///
+ /// TStrings [in] List of strings to add. Does
+ /// nothing if Strs is nil or empty.
procedure Add(const Strs: TStrings); overload;
- {Adds all items from a string list to end of list.
- @param Strs [in] String list to be added.
- }
+
+ /// Adds all strings from a string list to the end of the list.
+ ///
+ /// IStringList [in] List of strings to add. Does
+ /// nothing if Strs is nil or empty.
procedure Add(const Strs: IStringList); overload;
- {Adds all items from another IStringList instance to end of list.
- @param Strs [in] String list to be added.
- }
+
+ /// Adds all strings from an array of strings to the end of the
+ /// list.
+ /// array of string [in] Array of strings to add.
+ /// Does nothing if Strs is empty.
procedure Add(const Strs: array of string); overload;
- {Adds all strings from an array to end of list.
- @param Strs [in] Dynamic array of strings to be added.
- }
+
procedure Add(const Str: string; const Delim: string;
const AllowEmpty: Boolean; const Trim: Boolean = False); overload;
{Splits a string at delimiter and adds component parts of string to end of
@@ -345,11 +359,9 @@ implementation
{ TIStringList }
procedure TIStringList.Add(const Strs: TStrings);
- {Adds all items from a string list to end of list.
- @param Strs [in] String list to be added.
- }
begin
- fStrings.AddStrings(Strs);
+ if Assigned(Strs) then
+ fStrings.AddStrings(Strs);
end;
function TIStringList.Add(const Str: string): Integer;
@@ -362,14 +374,12 @@ function TIStringList.Add(const Str: string): Integer;
end;
procedure TIStringList.Add(const Strs: IStringList);
- {Adds all items from another IStringList instance to end of list.
- @param Strs [in] String list to be added.
- }
var
- Idx: Integer; // loops through strings in added list
+ S: string;
begin
- for Idx := 0 to Pred(Strs.Count) do
- Add(Strs[Idx]);
+ if Assigned(Strs) then
+ for S in Strs do
+ Add(S);
end;
procedure TIStringList.Add(const Str: string; const Delim: string;
@@ -398,9 +408,6 @@ procedure TIStringList.Add(const Str: string; const Delim: string;
end;
procedure TIStringList.Add(const Strs: array of string);
- {Adds all strings from an array to end of list.
- @param Strs [in] Dynamic array of strings to be added.
- }
var
Idx: Integer; // loops thru elements of array
begin
From b0edfb3b24d09e466a9d48f9635724849e312ba8 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Fri, 28 Feb 2025 19:18:09 +0000
Subject: [PATCH 133/222] Update TDBLicenseInfo ctr to sanitise parameters
TDBLicenseInfo.Create now replaces any control characters with spaces in
the license name, spdx, url and text parameters and compresses multiple
spaces into single spaces.
---
Src/DB.UMetaData.pas | 39 ++++++++++++++++++++++++++++++++++-----
1 file changed, 34 insertions(+), 5 deletions(-)
diff --git a/Src/DB.UMetaData.pas b/Src/DB.UMetaData.pas
index 93171ebb4..0d0b6be76 100644
--- a/Src/DB.UMetaData.pas
+++ b/Src/DB.UMetaData.pas
@@ -32,7 +32,7 @@ interface
mdcLicense,
mdcCopyright,
mdcContributors,
- mdcTesters
+ mdcTesters {TODO -cView: rename as mdcAcknowledgements}
);
TMetaDataCapabilities = set of TMetaDataCapability;
@@ -49,21 +49,27 @@ TDBLicenseInfo = record
/// Record constructor: sets all fields of record.
/// Any or all parameters may be the empty string
constructor Create(const AName, ASPDX, AURL, AText: string);
+
/// Creates and returns a null record with all fields set to the
/// empty string.
class function CreateNull: TDBLicenseInfo; static;
+
/// Name of license.
property Name: string read fName;
+
/// Open Source Initiative SPDX short idenitifier for licenses.
///
/// If the license is not supported by the Open Source Initiative
/// then this property will be the empty string.
property SPDX: string read fSPDX;
+
/// URL of license online.
/// Optional.
property URL: string read fURL;
+
/// Full text of license.
property Text: string read fText;
+
/// Returns a string containing license name followed by any URL
/// in parentheses.
/// If no URL is available then only the license name is returned.
@@ -212,6 +218,14 @@ TMetaDataFactory = record
implementation
+uses
+ // Delphi
+ SysUtils,
+ Character,
+ // Project
+ UConsts,
+ UStrUtils;
+
type
/// Implements a null, do nothing, meta data object.
/// Instance of this class are used when a collection format does
@@ -260,11 +274,26 @@ TNullMetaData = class(TInterfacedObject, IDBMetaData)
{ TDBLicenseInfo }
constructor TDBLicenseInfo.Create(const AName, ASPDX, AURL, AText: string);
+
+ function StandardiseStr(const AStr: string): string;
+ begin
+ Result := StrCompressWhiteSpace(
+ StrReplaceChar(
+ AStr,
+ function(Ch: Char): Boolean
+ begin
+ Result := TCharacter.IsControl(Ch);
+ end,
+ ' '
+ )
+ );
+ end;
+
begin
- fName := AName;
- fSPDX := ASPDX;
- fURL := AURL;
- fText := AText;
+ fName := StandardiseStr(AName);
+ fSPDX := StandardiseStr(ASPDX);
+ fURL := StandardiseStr(AURL);
+ fText := StandardiseStr(AText);
end;
class function TDBLicenseInfo.CreateNull: TDBLicenseInfo;
From c9dd185b7bc3152ec1a74256fc1d58164a4d5fcf Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Fri, 28 Feb 2025 19:21:52 +0000
Subject: [PATCH 134/222] Add support for CodeSnip Vault native data format
Added new DB.IO.DataFormat.Native unit to the project that reads and
writes a snippet collection in the new CodeSnip Vault native data
format. This is an XML based format.
Modified DB.DataFormats to provide information about the new data
format: added a new value to TDataFormatKind enumeration and added a
description to TDataFormatInfo.
Added support for loading and saving the new Vault format to
DB.UDatabaseIO using new TNativeVaultFormatLoader and
TNativeVaultFormatSaver claases and associated factory class changes.
---
Src/CodeSnip.dpr | 3 +-
Src/CodeSnip.dproj | 1 +
Src/DB.DataFormats.pas | 11 +-
Src/DB.IO.DataFormat.Native.pas | 1216 +++++++++++++++++++++++++++++++
Src/DB.UDatabaseIO.pas | 76 ++
5 files changed, 1303 insertions(+), 4 deletions(-)
create mode 100644 Src/DB.IO.DataFormat.Native.pas
diff --git a/Src/CodeSnip.dpr b/Src/CodeSnip.dpr
index f9d75bbb9..5d592e737 100644
--- a/Src/CodeSnip.dpr
+++ b/Src/CodeSnip.dpr
@@ -380,7 +380,8 @@ uses
UCollectionListAdapter in 'UCollectionListAdapter.pas',
DBIO.MetaData.DCSC in 'DBIO.MetaData.DCSC.pas',
FmCollectionBackup in 'FmCollectionBackup.pas' {CollectionBackupDlg},
- DB.DataFormats in 'DB.DataFormats.pas';
+ DB.DataFormats in 'DB.DataFormats.pas',
+ DB.IO.DataFormat.Native in 'DB.IO.DataFormat.Native.pas';
// Include resources
{$Resource ExternalObj.tlb} // Type library file
diff --git a/Src/CodeSnip.dproj b/Src/CodeSnip.dproj
index d0995c58d..0f4eb32cf 100644
--- a/Src/CodeSnip.dproj
+++ b/Src/CodeSnip.dproj
@@ -589,6 +589,7 @@
+ Base
diff --git a/Src/DB.DataFormats.pas b/Src/DB.DataFormats.pas
index 8207c0940..37394cf98 100644
--- a/Src/DB.DataFormats.pas
+++ b/Src/DB.DataFormats.pas
@@ -13,6 +13,8 @@ interface
/// Collection v2.
/// Native_v4 -- Native format used by CodeSnip v4 to store user
/// snippets.
+ /// Native_Vault -- Native format used by CodeSnip Vault to
+ /// store user snippets.
///
TDataFormatKind = (
// NEVER specify a literal ordinal value in this enumeration.
@@ -23,7 +25,8 @@ interface
// NEVER associate error with a format loader or saver class.
Error,
DCSC_v2,
- Native_v4
+ Native_v4,
+ Native_Vault
);
/// Record containing details of the data format and location in
@@ -60,9 +63,11 @@ TMapRecord = record
const
// There are so few entries in this table it's not worth the overhead
// of using a dicitionary for the lookup.
- LookupTable: array[0..1] of TMapRecord = (
+ LookupTable: array[0..2] of TMapRecord = (
+ (Kind: TDataFormatKind.Native_Vault;
+ Name: 'CodeSnip Vault Native Snippet Collection'),
(Kind: TDataFormatKind.Native_v4;
- Name: 'CodeSnip Native Snippet Collection v4'),
+ Name: 'CodeSnip 4 Native Snippet Collection'),
(Kind: TDataFormatKind.DCSC_v2;
Name: 'DelphiDabbler Code Snippets Collection v2')
);
diff --git a/Src/DB.IO.DataFormat.Native.pas b/Src/DB.IO.DataFormat.Native.pas
new file mode 100644
index 000000000..9ac56a5ba
--- /dev/null
+++ b/Src/DB.IO.DataFormat.Native.pas
@@ -0,0 +1,1216 @@
+{
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/
+ *
+ * Copyright (C) 2025, Peter Johnson (gravatar.com/delphidabbler).
+ *
+ * Implements classes that can read and write collections stored in the CodeSnip
+ * Vault native data format.
+}
+
+
+unit DB.IO.DataFormat.Native;
+
+interface
+
+uses
+ // Delphi
+ XMLIntf,
+ // Project
+ Compilers.UGlobals,
+ DB.UCategory,
+ DB.USnippet,
+ DB.USnippetKind,
+ DBIO.UFileIOIntf,
+ UIStringList,
+ UVersionInfo,
+ UXMLDocumentEx;
+
+type
+
+ /// Base class for classes that read and write collection data in
+ /// the native data format.
+ TNativeDataRW = class abstract(TInterfacedObject)
+ strict private
+ var
+ /// Value of DataDirectory property.
+ fDataDirectory: string;
+ /// Value of XMLDoc property.
+ fXMLDoc: IXMLDocumentEx;
+ strict protected
+ const
+ /// Name of collection's XML file.
+ XMLFileName = 'collection.xml';
+ /// Extension used for source code files.
+ SourceCodeFileExt = '.source';
+ /// Name of collection's license file, if any.
+ LicenseTextFileName = 'license.txt';
+ /// Watermark included in all native data format files.
+ ///
+ Watermark = '882BAD68-8C3E-44E3-BBF4-17E55143DAF8';
+ /// Version number of the earliest supported data file format.
+ ///
+ EarliestFileVersion: TVersionNumber = (V1: 1; V2: 0; V3: 0; V4: 0);
+ /// Version number of the current data file format.
+ CurrentFileVersion: TVersionNumber = (V1: 1; V2: 0; V3: 0; V4: 0);
+
+ // XML node and attribute names
+ RootNodeName = 'collection';
+ RootNodeWatermarkAttr = 'watermark';
+ RootNodeVersionMajorAttr = 'version-major';
+ RootNodeVersionMinorAttr = 'version-minor';
+ CategoriesNodeName = 'categories';
+ CategoryNodeName = 'category';
+ CategoryNodeIdAttr = 'id';
+ CategoryDescriptionNodeName = 'description';
+ CategorySnippetsListNodeName = 'snippet-keys';
+ CategorySnippetsListItemNodeName = 'key';
+ SnippetsNodeName = 'snippets';
+ SnippetNodeName = 'snippet';
+ SnippetNodeKeyAttr = 'key';
+ SnippetNodeCategoryAttr = 'category';
+ SnippetNodeKindAttr = 'kind';
+ SnippetDescriptionNodeName = 'description';
+ SnippetSourceNodeName = 'source-code';
+ SnippetSourceNodeFileAttr = 'file-name';
+ SnippetSourceNodeLanguageAttr = 'language';
+ SnippetDisplayNameNodeName = 'display-name';
+ SnippetNotesNodeName = 'notes';
+ SnippetCompileResultsNodeName = 'compile-results';
+ SnippetCompilerNodeName = 'compiler';
+ SnippetCompilerNodeIdAttr = 'id';
+ SnippetCompilerNodeResultAttr = 'result';
+ SnippetTestInfoNodeName = 'tests';
+ SnippetTestInfoNodeLevelAttr = 'level';
+ SnippetTestInfoNodeUrlAttr = 'url';
+ SnippetUnitsListNodeName = 'required-units';
+ SnippetUnitsListItemNodeName = 'unit';
+ SnippetDependsListNodeName = 'required-snippets';
+ SnippetDependsListItemNodeName = 'key';
+ SnippetXRefsListNodeName = 'xrefs';
+ SnippetXRefsListItemNodeName = 'key';
+ LicenseNodeName = 'license';
+ LicenseNodeSPDXAttr = 'spdx';
+ LicenseNodeNameAttr = 'name';
+ LicenseNodeURLAttr = 'url';
+ LicenseNodeLicenseFileAttr = 'license-file-name';
+ CopyrightNodeName = 'copyright';
+ CopyrightNodeDateAttr = 'date';
+ CopyrightNodeHolderAttr = 'holder';
+ CopyrightNodeURLAttr = 'holder-url';
+ CopyrightContributorsListNodeName = 'contributors';
+ CopyrightContributorsListItemNodeName = 'name';
+ AcknowledgementsListNodeName = 'acknowledgements';
+ AcknowledgementsListItemNodeName = 'name';
+
+ /// Map of snippet kinds to the representative value used in the
+ /// XML file.
+ SnippetKindValues: array[TSnippetKind] of string = (
+ 'freeform', 'routine', 'const', 'type', 'unit', 'class'
+ );
+
+ /// Map of compile result values to the representative value
+ /// used in the XML file.
+ /// crWarning is not supported and maps to the same value
+ /// as crSuccess.
+ CompileResultValues: array[TCompileResult] of Char = ('y', 'y', 'n', 'q');
+
+ /// Map of compiler IDs to the representative value used in the
+ /// XML file.
+ CompilerIDs: array[TCompilerID] of string = (
+ 'd2', 'd3', 'd4', 'd5', 'd6', 'd7',
+ 'd2005', 'd2006', 'd2007', 'd2009', 'd2010',
+ 'dxe', 'dxe2', 'dxe3', 'dxe4', 'dxe5', 'dxe6', 'dxe7', 'dxe8',
+ 'd10.0', 'd10.1', 'd10.2', 'd10.3', 'd10.4', 'd11', 'd12',
+ 'fpc'
+ );
+
+ /// Map of test information to the representative value used in
+ /// the XML file.
+ TestInfoValues: array[TSnippetTestInfo] of string = (
+ 'none', 'basic', 'advanced', 'unit-tests', 'demo-code'
+ );
+
+ strict protected
+
+ /// Directory containing the collection.
+ property DataDirectory: string read fDataDirectory;
+
+ /// XML document object.
+ property XMLDoc: IXMLDocumentEx read fXMLDOc;
+
+ /// Creates and activates a minimal XML document containing a
+ /// processing instruction and a root node with the required attributes.
+ ///
+ /// IXMLNode. Reference to the root node.
+ function InitXMLDocAndRootNode: IXMLNode;
+
+ /// Finds a specified category node.
+ /// string [in] ID of required category.
+ ///
+ /// IXMLNode. Found node or nil if the node was not found.
+ ///
+ function FindCategoryNode(const ACatID: string): IXMLNode;
+
+ /// Finds a specified snippet node.
+ /// string [in] Key of required snippet.
+ ///
+ /// IXMLNode. Found node or nil if the node was not found.
+ ///
+ function FindSnippetNode(const ASnippetKey: string): IXMLNode;
+
+ /// Returns fully specified path of the XML file.
+ function PathToXMLFile: string;
+
+ /// Returns fully specified path of a file within the collection
+ /// directory.
+ function FilePath(const AFileName: string): string;
+
+ public
+
+ /// Object constructor. Creates an XML document to access the
+ /// collection's XML file.
+ /// string [in] Full path to the
+ /// directory that contains the collection's data files.
+ constructor Create(const ADataDirectory: string);
+
+ end;
+
+ /// Class that performs the low level reading of collection data in
+ /// CodeSnip Vault native format from an XML file and linked data files.
+ ///
+ TNativeDataReader = class sealed(TNativeDataRW, IDataReader)
+ strict private
+ var
+ /// Flag that indicates if unit & depends-upon lists are
+ /// permitted.
+ fCanReadRequiredLists: Boolean;
+
+ /// Validates an XML document loaded from storage. Returns
+ /// normally on success or raises exception on error.
+ /// EDataIO raised if there is no valid root node with
+ /// the expected watermark and a valid version number.
+ procedure ValidateDoc;
+
+ /// Reads a list of text nodes that each have the same tag name,
+ /// within an enclosing node.
+ /// IXMLNode [in] Reference to the parent
+ /// node of the node that encloses the list items.
+ /// string [in] Name of the node that
+ /// encloses the list items.
+ /// string [in] Name of each list item
+ /// node.
+ /// IStringList [in] Text value of each list item.
+ ///
+ function GetEnclosedListItems(const AParentNode: IXMLNode;
+ const AListNodeName, AItemNodeName: string): IStringList;
+
+ /// Reads a list of items that are referenced by a given snippet.
+ ///
+ /// string [in] Key of snippet making the
+ /// references.
+ /// string [in] Name of the XML node
+ /// that contains the list items.
+ /// string [in] Name of each list item
+ /// XML node within the list.
+ /// IStringList [in] List of referenced items.
+ function GetSnippetReferences(const ASnippetKey, AListNodeName,
+ AListItemName: string): IStringList;
+
+ /// Handles exceptions raised by converting expected exceptions
+ /// into ECodeSnip derived exceptions.
+ /// TObject [in] Reference to exception object to
+ /// be handled.
+ /// Always raises an exception. Expected exceptions are
+ /// re-raised as EDataIO exceptions. Unexpected exceptions are
+ /// re-raised unchanged.
+ procedure HandleException(const EObj: TObject);
+ public
+
+ /// Object constructor. Loads XML from file if the collection
+ /// exists, otherwise creates a minimal empty document.
+ /// string [in] Full path to the
+ /// directory that contains the collection's data files.
+ constructor Create(const ADirectory: string);
+
+ /// Checks if the collection exists.
+ /// Boolean. Returns True if the collection exists
+ /// or False if not.
+ ///
+ /// This method is always called before any other IDataReader
+ /// methods. If it returns False then no other IDataReader
+ /// methods are called. Therefore other methods can safely assume that the
+ /// collection exists.
+ /// Method of IDataReader.
+ ///
+ function DatabaseExists: Boolean;
+ {TODO -cRefactor: Rename DatabaseExists to CollectionExists.}
+
+ /// Gets the unique IDs of all categories referenced in the
+ /// collection.
+ /// IStringList. List of category IDs.
+ /// Method of IDataReader.
+ function GetAllCatIDs: IStringList;
+
+ /// Gets the properties of a given category.
+ /// string [in] ID of the required category.
+ ///
+ /// TCategoryData [in/out] An empty,
+ /// initialised, properties record is passed in and a record with the
+ /// properties read from the collection data is passed out.
+ /// Method of IDataReader.
+ procedure GetCatProps(const CatID: string; var Props: TCategoryData);
+
+ /// Gets the unique keys of all snippets in a category within the
+ /// collection.
+ /// string [in] ID of the required category.
+ ///
+ /// IStringList. List of snippet keys.
+ /// Method of IDataReader.
+ function GetCatSnippets(const CatID: string): IStringList;
+
+ /// Gets the properties of a given snippet.
+ /// string [in] Key of the required
+ /// snippet.
+ /// TSnippetData [in/out] An empty,
+ /// initialised, properties record is passed in and a record with the
+ /// properties read from the collection data is passed out.
+ /// Method of IDataReader.
+ procedure GetSnippetProps(const SnippetKey: string;
+ var Props: TSnippetData);
+
+ /// Gets a list of the keys of all snippets within the collection
+ /// that are cross-referenced by a given snippet.
+ /// string [in] Key of snippet for which
+ /// cross references are required.
+ /// IStringList. List of keys of cross referenced snippets.
+ ///
+ /// Method of IDataReader.
+ function GetSnippetXRefs(const SnippetKey: string): IStringList;
+
+ /// Gets a list of the keys of all snippets on which a given
+ /// snippet depends in order to compile.
+ /// string [in] Key of snippet for which
+ /// dependencies are required.
+ /// IStringList. List of keys of required snippets.
+ ///
+ /// Method of IDataReader.
+ function GetSnippetDepends(const SnippetKey: string): IStringList;
+
+ /// Gets a list of the keys of all unit which a given snippet
+ /// requires in order to compile.
+ /// string [in] Key of snippet for which
+ /// units are required.
+ /// IStringList. List of required units.
+ ///
+ /// Method of IDataReader.
+ function GetSnippetUnits(const SnippetKey: string): IStringList;
+ end;
+
+ /// Class that performs the low level writing of collection data in
+ /// CodeSnip Vault native format to an XML file and linked data files.
+ ///
+ TNativeDataWriter = class sealed(TNativeDataRW, IDataWriter)
+ strict private
+ var
+ /// Reference to root node.
+ fRootNode: IXMLNode;
+ /// Reference to top-level snippets XML node.
+ fSnippetsNode: IXMLNode;
+ /// Reference to top-level categories XML node.
+ fCategoriesNode: IXMLNode;
+ /// Flag that indicates if unit & depends-upon lists can be
+ /// written.
+ fCanWriteRequiredLists: Boolean;
+
+ /// Handles exceptions raised by converting expected exceptions
+ /// into ECodeSnip derived exceptions.
+ /// TObject [in] Reference to exception object to
+ /// be handled.
+ /// Always raises an exception. Expected exceptions are
+ /// re-raised as EDataIO exceptions. Unexpected exceptions are
+ /// re-raised unchanged.
+ procedure HandleException(const EObj: TObject);
+
+ /// Writes a list of text nodes that each have the same tag name,
+ /// within an enclosing node.
+ /// IXMLNode [in] Reference to the parent node
+ /// of the node that encloses the list items.
+ /// string [in] Name of the node that
+ /// encloses the list items.
+ /// string [in] Name of each list item
+ /// node.
+ /// IStringList [in] Text value of each list
+ /// item.
+ procedure WriteEnclosedList(const AParent: IXMLNode;
+ const AListNodeName, AItemNodeName: string; const AItems: IStringList);
+
+ /// Writes a reference list associated with a snippet to XML.
+ ///
+ /// string [in] Key of snippet.
+ /// string [in] Name of the XML node
+ /// that contains the list item.
+ /// string [in] Name of each list item
+ /// XML node within the list.
+ /// IStringList [in] List of referenced items.
+ ///
+ procedure WriteReferenceList(const ASnippetKey, AListNodeName,
+ AItemNodeName: string; const AItems: IStringList);
+
+ public
+ /// Initialises the collection write.
+ ///
+ /// Always called before all other IDataWriter methods.
+ /// Method of IDataWriter.
+ ///
+ procedure Initialise;
+
+ /// Writes the properties of a given category.
+ /// string [in] ID of category.
+ /// TCategoryData [in] Properties of the
+ /// category.
+ ///
+ /// Always called before WriteCatSnippets for a given
+ /// category, so can be used to perform any per-category initialisation.
+ ///
+ /// Method of IDataWriter.
+ ///
+ procedure WriteCatProps(const CatID: string; const Props: TCategoryData);
+
+ /// Writes a list of keys of snippets belonging to a given
+ /// category.
+ /// string [in] ID of category.
+ /// IStringList [in] List of snippet keys.
+ ///
+ ///
+ /// Always called after WriteCatProps for a given category.
+ ///
+ /// Method of IDataWriter.
+ ///
+ procedure WriteCatSnippets(const CatID: string;
+ const SnipList: IStringList);
+
+ /// Writes the property of a given snippet.
+ /// string [in] Snippet's key.
+ /// TSnippetData [in] Properties of the snippet.
+ ///
+ ///
+ /// Always called after all categories are written and before
+ /// WriteSnippetUnits, so can be used to perform any per-snippet
+ /// intialisation that is required.
+ /// Method of IDataWriter.
+ ///
+ procedure WriteSnippetProps(const SnippetKey: string;
+ const Props: TSnippetData);
+
+ /// Writes a list of units required to compile a snippet.
+ ///
+ /// string [in] Snippet's key.
+ /// IStringList [in] List of unit names.
+ /// Method of IDataWriter.
+ procedure WriteSnippetUnits(const SnippetKey: string;
+ const Units: IStringList);
+
+ /// Writes a list of keys of snippets that a snippet depends on in
+ /// order to compile.
+ /// string [in] Snippet's key.
+ /// IStringList [in] List of keys of required
+ /// snippets.
+ /// Method of IDataWriter.
+ procedure WriteSnippetDepends(const SnippetKey: string;
+ const Depends: IStringList);
+
+ /// Writes a list of keys of snippets that are cross referenced
+ /// by a given snippet.
+ /// string [in] Snippet's key.
+ /// IStringList [in] List of keys of cross
+ /// referenced snippets.
+ /// Method of IDataWriter.
+ procedure WriteSnippetXRefs(const SnippetKey: string;
+ const XRefs: IStringList);
+
+ /// Finalises the collection write.
+ ///
+ /// Always called after all other IDataWriter methods.
+ /// Method of IDataWriter.
+ ///
+ procedure Finalise;
+ end;
+
+implementation
+
+uses
+ // Delphi
+ SysUtils,
+ Classes,
+ IOUtils,
+ ActiveX,
+ XMLDom,
+ // Project
+ ActiveText.UMain,
+ UExceptions,
+ UIOUtils,
+ USnippetExtraHelper,
+ UStrUtils,
+ UUtils,
+ UXMLDocHelper;
+
+resourcestring
+ // TNativeDataRW error message
+ sMissingNode = 'Document has no %s node.';
+ // TNativeDataReader error messages
+ sParseError = 'Error parsing XML file';
+ sBadDataFormat = 'Invalid native collection data format: %s';
+ sNoRootNode = 'Invalid document: no root element present';
+ sBadRootName = 'Invalid document: root element must be named <%s>';
+ sBadWatermark = 'Invalid document: watermark is incorrect';
+ sBadVersion = 'Invalid document: unsupported document version %d.%d';
+ sNoCategoriesNode = 'No categories node in XML file';
+ sCatNotFound = 'Can''t find reference to category "%s" in XML file';
+ sMissingSource = 'Source code file name missing for snippet "%s"';
+ sBadKind = 'Missing or invalid snippet kind for snippet "%s"';
+ sSnippetNotFound = 'Can''t find reference to snippet key "%s" in XML file';
+ sBadTestInfo = 'Invalid test information for snippet "%s"';
+
+{ TNativeDataRW }
+
+constructor TNativeDataRW.Create(const ADataDirectory: string);
+begin
+ inherited Create;
+ fDataDirectory := ADataDirectory;
+ // For some reason we must call OleInitialize here rather than in
+ // initialization section
+ OleInitialize(nil);
+ fXMLDoc := TXMLDocHelper.CreateXMLDoc;
+end;
+
+function TNativeDataRW.FilePath(const AFileName: string): string;
+begin
+ Result := TPath.Combine(DataDirectory, AFileName);
+end;
+
+function TNativeDataRW.FindCategoryNode(const ACatID: string): IXMLNode;
+var
+ CatListNode: IXMLNode; // node that contains category nodes
+begin
+ Result := nil;
+ // Find node
+ CatListNode := XMLDoc.FindNode(RootNodeName + '\' + CategoriesNodeName);
+ if not Assigned(CatListNode) then
+ raise EDataIO.CreateFmt(sMissingNode, [CategoriesNodeName]);
+ // Find required node
+ Result := fXMLDoc.FindFirstChildNode(
+ CatListNode, CategoryNodeName, CategoryNodeIdAttr, ACatID
+ )
+end;
+
+function TNativeDataRW.FindSnippetNode(const ASnippetKey: string): IXMLNode;
+var
+ SnippetListNode: IXMLNode; // list node that contains snippets nodes
+begin
+ Result := nil;
+ // Find snippets node
+ SnippetListNode := XMLDoc.FindNode(RootNodeName + '\' + SnippetsNodeName);
+ if not Assigned(SnippetListNode) then
+ raise EDataIO.CreateFmt(sMissingNode, [SnippetsNodeName]);
+ // Find required snippet node
+ Result := XMLDoc.FindFirstChildNode(
+ SnippetListNode, SnippetNodeName, SnippetNodeKeyAttr, ASnippetKey
+ );
+end;
+
+function TNativeDataRW.InitXMLDocAndRootNode: IXMLNode;
+begin
+ XMLDoc.Active := True;
+ TXMLDocHelper.CreateXMLProcInst(XMLDoc);
+ XMLDoc.Encoding := 'UTF-8';
+ // root node
+ Result := XMLDoc.CreateNode(RootNodeName);
+ Result.SetAttribute(RootNodeWatermarkAttr, Watermark);
+ Result.SetAttribute(RootNodeVersionMajorAttr, CurrentFileVersion.V1);
+ Result.SetAttribute(RootNodeVersionMinorAttr, CurrentFileVersion.V2);
+ XMLDoc.ChildNodes.Add(Result);
+end;
+
+function TNativeDataRW.PathToXMLFile: string;
+begin
+ Result := FilePath(XMLFileName);
+end;
+
+{ TNativeDataReader }
+
+constructor TNativeDataReader.Create(const ADirectory: string);
+var
+ RootNode: IXMLNode; // reference to document's root node
+begin
+ inherited Create(ADirectory);
+ if DatabaseExists then
+ begin
+ // Database exists: load it
+ XMLDoc.LoadFromFile(PathToXMLFile);
+ XMLDoc.Active := True;
+ try
+ ValidateDoc;
+ except
+ HandleException(ExceptObject);
+ end;
+ end
+ else
+ begin
+ // Database doesn't exist: create sufficient nodes for main code to find
+ RootNode := InitXMLDocAndRootNode;
+ XMLDoc.CreateElement(RootNode, CategoriesNodeName);
+ XMLDoc.CreateElement(RootNode, SnippetsNodeName);
+ end;
+end;
+
+function TNativeDataReader.DatabaseExists: Boolean;
+begin
+ Result := TFile.Exists(PathToXMLFile);
+end;
+
+function TNativeDataReader.GetAllCatIDs: IStringList;
+var
+ CatListNode: IXMLNode; // node containing list of categories
+ CatNodes: IXMLSimpleNodeList; // list of all category nodes of categories
+ CatNode: IXMLNode; // a node in CatNodes
+begin
+ try
+ Result := TIStringList.Create;
+ CatListNode := XMLDoc.FindNode(RootNodeName + '\' + CategoriesNodeName);
+ if not Assigned(CatListNode) then
+ raise EDataIO.Create(sNoCategoriesNode);
+ CatNodes := XMLDoc.FindChildNodes(CatListNode, CategoryNodeName);
+ for CatNode in CatNodes do
+ Result.Add(CatNode.Attributes[CategoryNodeIdAttr]);
+ except
+ HandleException(ExceptObject);
+ end;
+end;
+
+procedure TNativeDataReader.GetCatProps(const CatID: string;
+ var Props: TCategoryData);
+var
+ CatNode: IXMLNode; // reference to node for required category
+begin
+ try
+ CatNode := FindCategoryNode(CatID);
+ if not Assigned(CatNode) then
+ // Properties will not be requested for a category that doesn't exist in
+ // this database, so this should never happen
+ raise EDataIO.CreateFmt(sCatNotFound, [CatID]);
+ Props.Desc := TXMLDocHelper.GetSubTagText(
+ XMLDoc, CatNode, CategoryDescriptionNodeName
+ );
+ except
+ HandleException(ExceptObject);
+ end;
+end;
+
+function TNativeDataReader.GetCatSnippets(const CatID: string): IStringList;
+var
+ CatNode: IXMLNode; // reference to required category node
+begin
+ try
+ CatNode := FindCategoryNode(CatID);
+ if not Assigned(CatNode) then
+ {TODO -cVault: Check the following comment and decide if this still
+ applies. Replace Exit with exception if necessary.}
+ // This is not an error since it is possible that a category exists in
+ // another collection and loader will request info from here also
+ Exit(TIStringList.Create);
+ Result := GetEnclosedListItems(
+ CatNode, CategorySnippetsListNodeName, CategorySnippetsListItemNodeName
+ );
+ except
+ HandleException(ExceptObject);
+ end;
+end;
+
+function TNativeDataReader.GetEnclosedListItems(const AParentNode: IXMLNode;
+ const AListNodeName, AItemNodeName: string): IStringList;
+var
+ ListNode: IXMLNode;
+ ItemNode: IXMLNode;
+ NodeList: IXMLSimpleNodeList;
+begin
+ Assert(Assigned(AParentNode),
+ ClassName + '.GetEnclosedListItems: AParentNode is nil');
+ Result := TIStringList.Create;
+ ListNode := XMLDoc.FindFirstChildNode(AParentNode, AListNodeName);
+ if not Assigned(ListNode) then
+ Exit; // it is sometimes permitted for snippet lists to be omitted
+ NodeList := XMLDoc.FindChildNodes(ListNode, AItemNodeName);
+ for ItemNode in NodeList do
+ if ItemNode.IsTextElement then
+ Result.Add(ItemNode.Text);
+end;
+
+function TNativeDataReader.GetSnippetDepends(const SnippetKey: string):
+ IStringList;
+begin
+ if fCanReadRequiredLists then
+ Result := GetSnippetReferences(
+ SnippetKey, SnippetDependsListNodeName, SnippetDependsListItemNodeName
+ )
+ else
+ Result := TIStringList.Create;
+end;
+
+procedure TNativeDataReader.GetSnippetProps(const SnippetKey: string;
+ var Props: TSnippetData);
+var
+ SnippetNode: IXMLNode; // node for required snippet
+
+ // Gets text of a sepecified property that is stored in the named subtag of
+ // the given parent node.
+ function GetPropertyText(const AParentNode: IXMLNode;
+ const ASubTagNodeName: string): string;
+ begin
+ if not Assigned(AParentNode) then
+ Exit('');
+ Result := TXMLDocHelper.GetSubTagText(XMLDoc, AParentNode, ASubTagNodeName);
+ end;
+
+ // Returns a reference to the source code node
+ function SourceCodeNode: IXMLNode;
+ begin
+ Result := XMLDoc.FindFirstChildNode(SnippetNode, SnippetSourceNodeName);
+ end;
+
+ // Returns source code language from source code node attribute
+ function GetSourceCodeLanguage: string;
+ begin
+ Result := SourceCodeNode.Attributes[SnippetSourceNodeLanguageAttr];
+ end;
+
+ // Checks if source code language is Pascal
+ function IsPascalSource: Boolean;
+ begin
+ Result := GetSourceCodeLanguage = 'pascal';
+ end;
+
+ // Gets source code from file referenced in source code node attribute
+ function GetSourceCodePropertyText: string;
+ var
+ DataFileName: string; // name of file containing source code
+ begin
+ DataFileName := SourceCodeNode.Attributes[SnippetSourceNodeFileAttr];
+ if DataFileName = '' then
+ raise EDataIO.CreateFmt(sMissingSource, [SnippetKey]);
+ Result := TFileIO.ReadAllText(
+ FilePath(DataFileName), TEncoding.UTF8, False
+ );
+ end;
+
+ // Gets kind property value from snippet node attribute
+ function GetKindProperty: TSnippetKind;
+
+ // Looks up AKindStr in lookup table and passes out matching TSnippetKind
+ // value, if found. Returns True if found & false if not
+ function TryLookupKind(const AKindStr: string; out AKind: TSnippetKind):
+ Boolean;
+ var
+ K: TSnippetKind;
+ begin
+ Result := False;
+ for K := Low(SnippetKindValues) to High(SnippetKindValues) do
+ begin
+ if StrSameText(SnippetKindValues[K], AKindStr) then
+ begin
+ AKind := K;
+ Exit(True);
+ end;
+ end;
+ end;
+
+ var
+ Value: string; // text value of Kind node
+ begin
+ if not IsPascalSource then
+ // being permissive here: strictly speaking snippet kind attribute must
+ // have value 'freeform'.
+ Exit(skFreeform);
+
+ Value := SnippetNode.Attributes[SnippetNodeKindAttr];
+ if not TryLookupKind(Value, Result) then
+ raise EDataIO.CreateFmt(sBadKind, [SnippetKey]);
+ end;
+
+ // Gets REML from the named child node of the snippet node and parses it as
+ // active text.
+ function GetActiveText(const ANodeName: string): IActiveText;
+ var
+ REML: string;
+ begin
+ REML := GetPropertyText(SnippetNode, ANodeName);
+ if REML <> '' then
+ Result := TSnippetExtraHelper.BuildActiveText(REML)
+ else
+ Result := TActiveTextFactory.CreateActiveText;
+ end;
+
+ // Get compilation results from compile results node and its child nodes
+ function GetCompileResults: TCompileResults;
+
+ // Looks up compiler ID string in lookup table and passes the corresponding
+ // compiler ID in Match if found. Returns True if found, False if not.
+ function TryLookupCompID(IDStr: string; out Match: TCompilerID): Boolean;
+ var
+ CompID: TCompilerID; // loops thru all compiler IDs
+ begin
+ Result := False;
+ for CompID := Low(TCompilerID) to High(TCompilerID) do
+ begin
+ if StrSameText(CompilerIDs[CompID], IDStr) then
+ begin
+ Match := CompID;
+ Exit(True);
+ end;
+ end;
+ end;
+
+ var
+ ListNode: IXMLNode; // node that enclose compiler result nodes
+ ResultsNodes: IXMLSimpleNodeList; // list of compiler-result nodes
+ ResultNode: IXMLNode; // a compiler-result node
+ CompID: TCompilerID; // loops thru compiler IDs
+ CompResultStr: string; // compiler id string from result node
+ begin
+ // Initialise all results to unknown (query)
+ for CompID := Low(TCompilerID) to High(TCompilerID) do
+ Result[CompID] := crQuery;
+
+ // Find enclosing node: valid if this is not present
+ ListNode := XMLDoc.FindFirstChildNode(
+ SnippetNode, SnippetCompileResultsNodeName
+ );
+ if not Assigned(ListNode) then
+ Exit;
+
+ // Get list of compiler-result nodes contained in list and process each one
+ ResultsNodes := XMLDoc.FindChildNodes(ListNode, SnippetCompilerNodeName);
+ for ResultNode in ResultsNodes do
+ begin
+ // get compile result identifier
+ CompResultStr := StrToLower(
+ ResultNode.Attributes[SnippetCompilerNodeResultAttr]
+ );
+ if CompResultStr = '' then
+ CompResultStr := '?';
+ // add specified result function result
+ if TryLookupCompID(
+ ResultNode.Attributes[SnippetCompilerNodeIdAttr], CompID
+ ) then
+ begin
+ case CompResultStr[1] of
+ 'y': Result[CompID] := crSuccess;
+ 'n': Result[CompID] := crError;
+ else Result[CompID] := crQuery;
+ end;
+ end;
+ end;
+ end;
+
+ // Get test info from test node attributes
+ procedure SetTestInfoProperty(var Props: TSnippetData);
+
+ function TryLookupTestLevel(const AIDStr: string;
+ var ALevel: TSnippetTestInfo): Boolean;
+ var
+ TestID: TSnippetTestInfo;
+ begin
+ Result := False;
+ for TestID := Low(TSnippetTestInfo) to High(TSnippetTestInfo) do
+ begin
+ if StrSameText(TestInfoValues[TestID], AIDStr) then
+ begin
+ ALevel := TestID;
+ Exit(True);
+ end;
+ end;
+ end;
+
+ var
+ TestNode: IXMLNode;
+ Level: TSnippetTestInfo;
+ URL: string;
+ begin
+ URL := '';
+ Level := stiNone;
+ TestNode := XMLDoc.FindFirstChildNode(SnippetNode, SnippetTestInfoNodeName);
+ if not Assigned(TestNode) then
+ Exit;
+ if not TryLookupTestLevel(
+ TestNode.Attributes[SnippetTestInfoNodeLevelAttr], Level
+ ) then
+ Exit;
+ URL := TestNode.Attributes[SnippetTestInfoNodeUrlAttr];
+ Props.TestInfo := Level;
+ {TODO -cVault: When Snippet test URL is implemented, add following line}
+ // Props.TestURL := URL;
+ end;
+
+begin
+ try
+ // Find snippet node
+ SnippetNode := FindSnippetNode(SnippetKey);
+ if not Assigned(SnippetNode) then
+ raise EDataIO.CreateFmt(sSnippetNotFound, [SnippetKey]);
+ // Snippet found: read properties
+ Props.Cat := SnippetNode.Attributes[SnippetNodeCategoryAttr];
+ Props.DisplayName := GetPropertyText(
+ SnippetNode, SnippetDisplayNameNodeName
+ );
+ Props.Kind := GetKindProperty;
+ Props.Desc := GetActiveText(SnippetDescriptionNodeName);
+ Props.Extra := GetActiveText(SnippetNotesNodeName);
+ Props.SourceCode := GetSourceCodePropertyText;
+ {TODO -cVault: Replace Props.HiliteSource with Props.SourceCodeLanguage
+ field.}
+ Props.HiliteSource := IsPascalSource;
+ Props.CompilerResults := GetCompileResults;
+ SetTestInfoProperty(Props);
+
+ // Record whether required units / snippets list are permitted
+ {TODO -cVault: Change following line to use Props.SourceLanguage once
+ implemented to check if language is Pascal: can't write the lists
+ if not.}
+ fCanReadRequiredLists := Props.HiliteSource;
+ except
+ HandleException(ExceptObject);
+ end;
+end;
+
+function TNativeDataReader.GetSnippetReferences(const ASnippetKey,
+ AListNodeName, AListItemName: string): IStringList;
+var
+ SnippetNode: IXMLNode;
+begin
+ // Find snippet node
+ SnippetNode := FindSnippetNode(ASnippetKey);
+ if not Assigned(SnippetNode) then
+ raise EDataIO.CreateFmt(sSnippetNotFound, [ASnippetKey]);
+ Result := GetEnclosedListItems(SnippetNode, AListNodeName, AListItemName);
+end;
+
+function TNativeDataReader.GetSnippetUnits(const SnippetKey: string):
+ IStringList;
+begin
+ if fCanReadRequiredLists then
+ Result := GetSnippetReferences(
+ SnippetKey, SnippetUnitsListNodeName, SnippetUnitsListItemNodeName
+ )
+ else
+ Result := TIStringList.Create;
+end;
+
+function TNativeDataReader.GetSnippetXRefs(const SnippetKey: string):
+ IStringList;
+begin
+ Result := GetSnippetReferences(
+ SnippetKey, SnippetXRefsListNodeName, SnippetXRefsListItemNodeName
+ )
+end;
+
+procedure TNativeDataReader.HandleException(const EObj: TObject);
+begin
+ {TODO -cVault: Query whether database files should be deleted on error.
+ This is not being done while debugging}
+// DeleteFiles(DataDir, '*.*');
+ if EObj is EDOMParseError then
+ // Expected DOM parsing error
+ raise EDataIO.CreateFmt(sBadDataFormat, [sParseError]);
+ if (EObj is EDataIO)
+ or (EObj is EXMLDocError)
+ or (EObj is ECodeSnipXML)
+ or (EObj is EFileStreamError)
+ or (EObj is EFOpenError)
+ or (EObj is EActiveTextParserError) then
+ // Expected other error: Raise new exception containing old message
+ raise EDataIO.CreateFmt(sBadDataFormat, [(EObj as Exception).Message])
+ else
+ // Mot an expected error: just re-raise
+ raise EObj;
+end;
+
+procedure TNativeDataReader.ValidateDoc;
+var
+ RootNode: IXMLNode;
+ Version: TVersionNumber;
+begin
+ RootNode := XMLDoc.DocumentElement;
+
+ if not Assigned(RootNode) then
+ raise EDataIO.Create(sNoRootNode);
+
+ if RootNode.NodeName <> RootNodeName then
+ raise EDataIO.CreateFmt(sBadRootName, [RootNodeName]);
+
+ if RootNode.Attributes[RootNodeWatermarkAttr] <> Watermark then
+ raise EDataIO.Create(sBadWatermark);
+
+ Version := TVersionNumber.Nul;
+ Version.V1 := RootNode.Attributes[RootNodeVersionMajorAttr];
+ Version.V2 := RootNode.Attributes[RootNodeVersionMinorAttr];
+ if (Version < EarliestFileVersion) or (Version > CurrentFileVersion) then
+ raise EDataIO.CreateFmt(sBadVersion, [Version.V1, Version.V2]);
+end;
+
+{ TNativeDataWriter }
+
+procedure TNativeDataWriter.Finalise;
+var
+ FS: TFileStream; // stream onto output file
+begin
+ // We use a TFileStream and TXMLDocument.SaveToStream rather than calling
+ // TXMLDocument.SaveToFile so that any problem creating file is reported via
+ // a known Delphi exception that can be handled.
+ EnsureFolders(DataDirectory);
+ try
+ FS := TFileStream.Create(PathToXMLFile, fmCreate);
+ try
+ XMLDoc.Encoding := 'UTF-8';
+ XMLDoc.SaveToStream(FS);
+ finally
+ FreeAndNil(FS);
+ end;
+ except
+ HandleException(ExceptObject);
+ end;
+end;
+
+procedure TNativeDataWriter.HandleException(const EObj: TObject);
+begin
+ if (EObj is EFileStreamError) or (EObj is ECodeSnip) then
+ raise EDataIO.Create(EObj as Exception);
+ raise EObj;
+end;
+
+procedure TNativeDataWriter.Initialise;
+//var
+// RootNode: IXMLNode; // document root node
+begin
+ try
+ // Make sure database folder exists, empty of source code files
+ TDirectory.CreateDirectory(DataDirectory);
+ DeleteFiles(DataDirectory, '*' + SourceCodeFileExt);
+
+ fRootNode := InitXMLDocAndRootNode;
+
+ // create empty categories and snippets nodes
+ fCategoriesNode := XMLDoc.CreateElement(fRootNode, CategoriesNodeName);
+ fSnippetsNode := XMLDoc.CreateElement(fRootNode, SnippetsNodeName);
+ except
+ HandleException(ExceptObject);
+ end;
+end;
+
+procedure TNativeDataWriter.WriteCatProps(const CatID: string;
+ const Props: TCategoryData);
+var
+ CatNode: IXMLNode; // referenced to required category node
+begin
+ try
+ // Create node
+ CatNode := XMLDoc.CreateElement(fCategoriesNode, CategoryNodeName);
+ CatNode.Attributes[CategoryNodeIdAttr] := CatID;
+ XMLDoc.CreateElement(CatNode, CategoryDescriptionNodeName, Props.Desc);
+ except
+ HandleException(ExceptObject);
+ end;
+end;
+
+procedure TNativeDataWriter.WriteCatSnippets(const CatID: string;
+ const SnipList: IStringList);
+var
+ CatNode: IXMLNode; // reference to required category node
+begin
+ try
+ // Don't write list if no snippets
+ if SnipList.Count = 0 then
+ Exit;
+ // Find required category node
+ CatNode := FindCategoryNode(CatID);
+ Assert(Assigned(CatNode),
+ ClassName + '.WriteCatSnippets: Can''t find category node');
+ // Write the list
+ WriteEnclosedList(
+ CatNode,
+ CategorySnippetsListNodeName,
+ CategorySnippetsListItemNodeName,
+ SnipList
+ );
+ except
+ HandleException(ExceptObject);
+ end;
+end;
+
+procedure TNativeDataWriter.WriteEnclosedList(const AParent: IXMLNode;
+ const AListNodeName, AItemNodeName: string; const AItems: IStringList);
+var
+ ListNode: IXMLNode; // reference to enclosing list node
+ Item: string; // a name item in list
+begin
+ ListNode := XMLDoc.CreateElement(AParent, AListNodeName);
+ for Item in AItems do
+ XMLDoc.CreateElement(ListNode, AItemNodeName, Item);
+end;
+
+procedure TNativeDataWriter.WriteReferenceList(const ASnippetKey,
+ AListNodeName, AItemNodeName: string; const AItems: IStringList);
+var
+ SnippetNode: IXMLNode; // reference to snippet's node
+begin
+ try
+ // Don't write list if no items
+ if AItems.Count = 0 then
+ Exit;
+ // Find snippet node
+ SnippetNode := FindSnippetNode(ASnippetKey);
+ Assert(Assigned(SnippetNode),
+ ClassName + '.WriteReferenceList: Can''t find snippet node');
+ // Write the list
+ WriteEnclosedList(SnippetNode, AListNodeName, AItemNodeName, AItems);
+ except
+ HandleException(ExceptObject);
+ end;
+end;
+
+procedure TNativeDataWriter.WriteSnippetDepends(const SnippetKey: string;
+ const Depends: IStringList);
+begin
+ if not fCanWriteRequiredLists then
+ Exit;
+ WriteReferenceList(
+ SnippetKey,
+ SnippetDependsListNodeName,
+ SnippetDependsListItemNodeName,
+ Depends
+ );
+end;
+
+procedure TNativeDataWriter.WriteSnippetProps(const SnippetKey: string;
+ const Props: TSnippetData);
+var
+ SnippetNode: IXMLNode; // snippet's node
+ FileName: string; // name of file where source code stored
+ SourceCodeNode: IXMLNode;
+ CompResultsNode: IXMLNode; // node that stores all compiler results
+ CompResultNode: IXMLNode; // each compiler result node
+ CompID: TCompilerID; // loops thru all supported compilers
+ TestInfoNode: IXMLNode;
+begin
+ try
+ // Record whether required units / snippets list are permitted
+ {TODO -cVault: Change following line to use Props.SourceLanguage once
+ implemented to check if language is Pascal: can't write the lists
+ if not.}
+ fCanWriteRequiredLists := Props.HiliteSource;
+ // Create snippet node
+ SnippetNode := XMLDoc.CreateElement(fSnippetsNode, SnippetNodeName);
+ SnippetNode.Attributes[SnippetNodeKeyAttr] := SnippetKey;
+ SnippetNode.Attributes[SnippetNodeCategoryAttr] := Props.Cat;
+ {TODO -cVault: change following test to test for Language = 'pascal'
+ instead of HiliteSource once Language prop is created}
+ if Props.HiliteSource then
+ SnippetNode.Attributes[SnippetNodeKindAttr] :=
+ SnippetKindValues[Props.Kind]
+ else
+ SnippetNode.Attributes[SnippetNodeKindAttr] :=
+ SnippetKindValues[skFreeform];
+
+ // Add property nodes
+ // display name
+ XMLDoc.CreateElement(
+ SnippetNode, SnippetDisplayNameNodeName, Props.DisplayName
+ );
+ // description node: only written if Desc property has a value
+ if Props.Desc.HasContent then
+ XMLDoc.CreateElement(
+ SnippetNode,
+ SnippetDescriptionNodeName,
+ TSnippetExtraHelper.BuildREMLMarkup(Props.Desc)
+ );
+ // notes node: only written if Extra property has a value
+ if Props.Extra.HasContent then
+ {TODO -cVault: rename Extra snippets property as Notes}
+ XMLDoc.CreateElement(
+ SnippetNode,
+ SnippetNotesNodeName,
+ TSnippetExtraHelper.BuildREMLMarkup(Props.Extra)
+ );
+ // source code node
+ FileName := SnippetKey + SourceCodeFileExt;
+ SourceCodeNode := XMLDoc.CreateElement(SnippetNode, SnippetSourceNodeName);
+ SourceCodeNode.Attributes[SnippetSourceNodeFileAttr] := FileName;
+ {TODO -cVault: change snippet props to have a language field instead of
+ HiliteSource and use it to set the following attribute}
+ SourceCodeNode.Attributes[SnippetSourceNodeLanguageAttr] :=
+ StrIf(Props.HiliteSource, 'pascal', 'text');
+ // source code file: source code is written to a UTF-8 encoded file with no
+ // BOM and filename is stored in XML
+ TFileIO.WriteAllText(
+ FilePath(FileName), Props.SourceCode, TEncoding.UTF8, False
+ );
+ {TODO -cVault: change following test to test for Language = 'pascal'
+ instead of HiliteSource once Language prop is created}
+ if Props.HiliteSource and (Props.Kind <> skFreeform) then
+ begin
+ // compile results list: must be omitted if snippet is not Pascal &
+ // even then, only known compiler results are written
+ CompResultsNode := XMLDoc.CreateElement(
+ SnippetNode, SnippetCompileResultsNodeName
+ );
+ for CompID := Low(TCompilerID) to High(TCompilerID) do
+ begin
+ if Props.CompilerResults[CompID] <> crQuery then
+ begin
+ CompResultNode := XMLDoc.CreateElement(
+ CompResultsNode, SnippetCompilerNodeName
+ );
+ CompResultNode.Attributes[SnippetCompilerNodeIdAttr] :=
+ CompilerIDs[CompID];
+ CompResultNode.Attributes[SnippetCompilerNodeResultAttr] :=
+ CompileResultValues[Props.CompilerResults[CompID]];
+ end;
+ end;
+ end;
+ // test info
+ TestInfoNode := XMLDoc.CreateElement(SnippetNode, SnippetTestInfoNodeName);
+ TestInfoNode.Attributes[SnippetTestInfoNodeLevelAttr] :=
+ TestInfoValues[Props.TestInfo];
+ {TODO -cVault: Change following line that always writes an empty URL once
+ TestURL property added to snippets.}
+ TestInfoNode.Attributes[SnippetTestInfoNodeUrlAttr] := '';
+ except
+ HandleException(ExceptObject);
+ end;
+end;
+
+procedure TNativeDataWriter.WriteSnippetUnits(const SnippetKey: string;
+ const Units: IStringList);
+begin
+ if not fCanWriteRequiredLists then
+ Exit;
+ WriteReferenceList(
+ SnippetKey,
+ SnippetUnitsListNodeName,
+ SnippetUnitsListItemNodeName,
+ Units
+ );
+end;
+
+procedure TNativeDataWriter.WriteSnippetXRefs(const SnippetKey: string;
+ const XRefs: IStringList);
+begin
+ WriteReferenceList(
+ SnippetKey,
+ SnippetXRefsListNodeName,
+ SnippetXRefsListItemNodeName,
+ XRefs
+ );
+end;
+
+end.
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index 6fa7eab71..7293b6c50 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -132,6 +132,7 @@ implementation
IOUtils,
// Project
DB.DataFormats,
+ DB.IO.DataFormat.Native,
DBIO.UCategoryIO,
DBIO.UFileIOIntf,
DBIO.UIniData,
@@ -264,6 +265,19 @@ TNativeV4FormatLoader = class(TDatabaseLoader, IDataFormatLoader)
}
end;
+ TNativeVaultFormatLoader = class(TDatabaseLoader, IDataFormatLoader)
+ strict protected
+ function CreateReader: IDataReader; override;
+ {Creates reader object. If user database doesn't exist a nul reader is
+ created.
+ @return Reader object instance.
+ }
+ function ErrorMessageHeading: string; override;
+ {Returns heading to use in error messages. Identifies main database.
+ @return Required heading.
+ }
+ end;
+
/// Base for classes that save a collection to storage.
TFormatSaver = class abstract (TInterfacedObject,
IDataFormatSaver
@@ -390,6 +404,31 @@ TNativeV4FormatSaver = class(TFormatSaver,
const Provider: IDBDataProvider); override;
end;
+ TNativeVaultFormatSaver = class(TFormatSaver,
+ IDataFormatSaver
+ )
+ strict protected
+
+ /// Creates an object that can write data to storage in
+ /// CodeSnip's native v4 data format.
+ /// IDataWriter. Required writer object.
+ function CreateWriter: IDataWriter; override;
+
+ public
+
+ /// Saves data to storage.
+ /// TSnippetList [in] List of all snippets
+ /// in the database.
+ /// TCategoryList [in] List of all
+ /// categories in the database.
+ /// IDBDataProvider [in] Object used to
+ /// obtain details of the data to be stored.
+ /// Method of IDataFormatSaver.
+ procedure Save(const SnipList: TSnippetList;
+ const Categories: TCategoryList;
+ const Provider: IDBDataProvider); override;
+ end;
+
/// Class used to save global category information, regardless of
/// any categories saved with collections.
TGlobalCategoryLoader = class(TInterfacedObject, IGlobalCategoryLoader)
@@ -427,6 +466,8 @@ class function TDatabaseIOFactory.CreateDBLoader(const Collection: TCollection):
Result := TDCSCV2FormatLoader.Create(Collection);
TDataFormatKind.Native_v4:
Result := TNativeV4FormatLoader.Create(Collection);
+ TDataFormatKind.Native_Vault:
+ Result := TNativeVaultFormatLoader.Create(Collection);
else
Result := nil;
end;
@@ -440,6 +481,8 @@ class function TDatabaseIOFactory.CreateDBSaver(
Result := TDCSCV2FormatSaver.Create(Collection);
TDataFormatKind.Native_v4:
Result := TNativeV4FormatSaver.Create(Collection);
+ TDataFormatKind.Native_Vault:
+ Result := TNativeVaultFormatSaver.Create(Collection);
else
Result := nil;
end;
@@ -679,6 +722,25 @@ function TNativeV4FormatLoader.ErrorMessageHeading: string;
Result := sError;
end;
+{ TNativeVaultFormatLoader }
+
+function TNativeVaultFormatLoader.CreateReader: IDataReader;
+begin
+ Result := TNativeDataReader.Create(Collection.Storage.Directory);
+ if not Result.DatabaseExists then
+ Result := TNulDataReader.Create;
+end;
+
+function TNativeVaultFormatLoader.ErrorMessageHeading: string;
+resourcestring
+ sError = 'Error loading the collection %0:s using the %1:s data format:';
+begin
+ Result := Format(
+ sError,
+ [Collection.Name, TDataFormatInfo.GetName(Collection.Storage.Format)]
+ );
+end;
+
{ TFormatSaver }
constructor TFormatSaver.Create(const ACollection: TCollection);
@@ -819,6 +881,20 @@ function TNativeV4FormatSaver.CreateWriter: IDataWriter;
procedure TNativeV4FormatSaver.Save(const SnipList: TSnippetList;
const Categories: TCategoryList; const Provider: IDBDataProvider);
+begin
+ {TODO -cVault: Backup and restore this collection per the DCSC v2 loader}
+ DoSave(SnipList, Categories, Provider);
+end;
+
+{ TNativeVaultFormatSaver }
+
+function TNativeVaultFormatSaver.CreateWriter: IDataWriter;
+begin
+ Result := TNativeDataWriter.Create(Collection.Storage.Directory);
+end;
+
+procedure TNativeVaultFormatSaver.Save(const SnipList: TSnippetList;
+ const Categories: TCategoryList; const Provider: IDBDataProvider);
begin
DoSave(SnipList, Categories, Provider);
end;
From 198342e0e3d5b837557a94eb6ae2e3c6ba5eeb9d Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Fri, 28 Feb 2025 19:27:01 +0000
Subject: [PATCH 135/222] Document CodeSnip Vault native data format
Added new HTML file format document for the CodeSnip Vault native data
format. This file not only documents the features of the format as
currently implemented but also documents how it is proposed to implement
storage of meta data in future. The proposed features are currently
commented out so they don't appear in the rendered HTML document.
---
.../FileFormats/collections/native.html | 934 ++++++++++++++++++
1 file changed, 934 insertions(+)
create mode 100644 Docs/Design/FileFormats/collections/native.html
diff --git a/Docs/Design/FileFormats/collections/native.html b/Docs/Design/FileFormats/collections/native.html
new file mode 100644
index 000000000..30942b3c0
--- /dev/null
+++ b/Docs/Design/FileFormats/collections/native.html
@@ -0,0 +1,934 @@
+
+
+
+
+
+
+
+ CodeSnip File Format Documentation - Native Collection Format
+
+
+
+
+
+
+
+
+
+ This file format is the default collection data format used by CodeSnip Vault.
+
+
+
+ The format comprises a single XML file along with a number of data files located in the same directory. Each user can have zero or more snippet collections that use this format.
+
+
+
+ The XML file is named collection.xml. It contains all the information about about the collection, except for the source code of each snippet.
+
+
+
+ Snippet source code is stored in separate data files – one per snippet. Each source code file is referenced by the XML file.
+
+
+
+ The format allows for later revisions. Files are versioned and comply with the principles of Semantic Versioning. Details of all the changes between versions are listed in the Change Log at the end of this document.
+
+
+
+
+
+
+
+ Encoding
+
+
+
+ All files are text files that use UTF-8 encoding, without any UTF-8 preamble (BOM). The XML processing instruction of collection.xml has its encoding atrribute set to UTF-8.
+
+
+
+
+
+
+
+ File Format
+
+
+
+ XML File
+
+
+
+ The following information applies to file format v1.0.
+
+
+
+
+ XML processing instruction
+
+
+
+ Attributes:
+
+
+
+ version
+
+
+ Always set to 1.0.
+
+
+ encoding
+
+
+ Character encoding used for file. Always set to UTF-8.
+
+
+
+
+
+ collection
+
+
+
+ Parent node that contains all the collection data.
+
+
+ Attributes:
+
+
+
+ watermark
+
+
+ Identifies the file as the correct type. It is always set to 882BAD68-8C3E-44E3-BBF4-17E55143DAF8, regardless of the file version.
+
+
+ version-major
+
+
+ Identifies the major version of the file format. Must be 1.
+
+
+ version-minor
+
+
+ Identifies the minor version of the file format. Must be 0.
+
+
+
+
+
+ collection/categories
+
+
+
+ Contains a list of all categories used by the collection.
+
+
+
+
+ collection/categories/category
+
+
+
+ Contains information about a single category. There is one node per category.
+
+
+ Attributes:
+
+
+
+ id
+
+
+ Unique id of the category.
+
+
+
+
+
+ collection/categories/category/description
+
+
+
+ Description of the category.
+
+
+
+
+ collection/categories/category/snippet-keys
+
+
+
+ Contains list of the unique keys of all snippets in this category. May be omitted if there are no snippets in the category.
+
+ Key of a snippet within the required snippets list.
+
+
+
+
+ collection/snippets/snippet/xrefs
+
+
+
+ List of cross-referenced snippets.
+
+
+ The node may be omitted if there are no cross referenced snippets.
+
+
+
+
+ collection/snippets/snippet/xrefs/key
+
+
+
+ Key of a snippet within the cross-references list.
+
+
+
+
+
+
+
+
+ Source Code Files
+
+
+
+ Source code is stored separately from the main XML file. The source code of each snippet has its own file. File names relate to the relevant snippet's key and have extension .source.
+
+
+
+ Source code files are referenced by the file-name attribute of a snippet's collection/snippets/snippet/source-code node in the XML file.
+
+
+
+
+
+
+
+
+
+ Change Log
+
+
+
+ This section describes the changes between versions of the file format.
+
+
+
+ Version 1.0
+
+
+
+
+ Introduced with CodeSnip Vault.
+
+
+ Supports Delphi compilers from Delphi 2 to Delphi 12.x, plus Free Pascal.
+
+
+
From a23192b76d33d863c1c979c99ecc162ba91e366b Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 1 Mar 2025 15:32:07 +0000
Subject: [PATCH 136/222] Add new DB.MetaData unit to project
This unit encapsulates meta data. It provides an enumerated type,
TMetaDataCap that enumerate the various meta data capabilities along with
an associated TMetaDataCaps set type. There are 3 records: TLicenseInfo,
TCopyrightInfo and TMetaData. TMetaData contains fields of type
TLicenseInfo and TCopyrightInfo.
TLicenseInfo and TCopyrightInfo are similar to TDBLicenseInfo and
TDBCopyrightInfo in DB.UMetaData while TMetaDataCap / TMetaDataCaps are
similar to TMetaDataCapability and TMetaDataCapabilities in
DB.UMetaData.
Ultimately DB.MetaData will replace DB.UMetaData and related units.
---
Src/CodeSnip.dpr | 3 +-
Src/CodeSnip.dproj | 1 +
Src/DB.MetaData.pas | 346 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 349 insertions(+), 1 deletion(-)
create mode 100644 Src/DB.MetaData.pas
diff --git a/Src/CodeSnip.dpr b/Src/CodeSnip.dpr
index 5d592e737..8bdcb5f3b 100644
--- a/Src/CodeSnip.dpr
+++ b/Src/CodeSnip.dpr
@@ -381,7 +381,8 @@ uses
DBIO.MetaData.DCSC in 'DBIO.MetaData.DCSC.pas',
FmCollectionBackup in 'FmCollectionBackup.pas' {CollectionBackupDlg},
DB.DataFormats in 'DB.DataFormats.pas',
- DB.IO.DataFormat.Native in 'DB.IO.DataFormat.Native.pas';
+ DB.IO.DataFormat.Native in 'DB.IO.DataFormat.Native.pas',
+ DB.MetaData in 'DB.MetaData.pas';
// Include resources
{$Resource ExternalObj.tlb} // Type library file
diff --git a/Src/CodeSnip.dproj b/Src/CodeSnip.dproj
index 0f4eb32cf..0b89e7d51 100644
--- a/Src/CodeSnip.dproj
+++ b/Src/CodeSnip.dproj
@@ -590,6 +590,7 @@
+ Base
diff --git a/Src/DB.MetaData.pas b/Src/DB.MetaData.pas
new file mode 100644
index 000000000..1860ba1ab
--- /dev/null
+++ b/Src/DB.MetaData.pas
@@ -0,0 +1,346 @@
+{
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/
+ *
+ * Copyright (C) 2025, Peter Johnson (gravatar.com/delphidabbler).
+ *
+ * Encapsulates a collection's data format metadata.
+}
+
+
+unit DB.MetaData;
+
+{$ScopedEnums ON}
+
+interface
+
+uses
+ // Project
+ UIStringList,
+ UVersionInfo;
+
+type
+
+ /// Enumeration of the capabilities of a data format.
+ ///
+ /// - Version - supports the collection's data format version
+ /// number.
+ /// - License - supports collection license information.
+ /// - Copyright - supports collection copyright information.
+ ///
+ /// - Acknowledgements - supports acknowledgements for the
+ /// collection.
+ ///
+ TMetaDataCap = (
+ Version,
+ License,
+ Copyright,
+ Acknowledgements
+ );
+
+ /// Set of meta data capabilities applying to a data format.
+ ///
+ TMetaDataCaps = set of TMetaDataCap;
+
+ /// Record providing information about a collection's license.
+ ///
+ TLicenseInfo = record
+ strict private
+ var
+ fName: string;
+ fSPDX: string;
+ fURL: string;
+ fText: string;
+ public
+ /// Record constructor: sets all fields of record.
+ /// Any or all parameters may be the empty string
+ constructor Create(const AName, ASPDX, AURL, AText: string);
+
+ /// Creates and returns a null record with all fields set to the
+ /// empty string.
+ class function CreateNull: TLicenseInfo; static;
+
+ /// Returns a deep copy of this record.
+ function Clone: TLicenseInfo;
+
+ /// Name of license.
+ property Name: string read fName;
+
+ /// Open Source Initiative SPDX short idenitifier for licenses.
+ ///
+ /// If the license is not supported by the Open Source Initiative
+ /// then this property will be the empty string.
+ property SPDX: string read fSPDX;
+
+ /// URL of license online.
+ /// Optional.
+ property URL: string read fURL;
+
+ /// Full text of license.
+ property Text: string read fText;
+
+ /// Returns a string containing license name followed by any URL
+ /// in parentheses.
+ /// If no URL is available then only the license name is returned.
+ ///
+ function NameWithURL: string;
+ end;
+
+ /// Record providing informaton about a collection's copyright.
+ ///
+ TCopyrightInfo = record
+ strict private
+ var
+ fDate: string;
+ fHolder: string;
+ fHolderURL: string;
+ fContributors: IStringList;
+ function GetContributors: IStringList;
+ public
+ /// Record constructor: sets all fields of record.
+ /// Any or all string parameters may be the empty string.
+ /// AContributors may be nil if there are no contributors.
+ ///
+ constructor Create(const ADate, AHolder, AHolderURL: string;
+ AContributors: IStringList);
+
+ /// Creates and returns a null record.
+ /// A null record has all string fields set to the empty string
+ /// and the Contributors property set to an empty list.
+ class function CreateNull: TCopyrightInfo; static;
+
+ /// Returns a deep copy of this record.
+ function Clone: TCopyrightInfo;
+
+ /// Copyright date.
+ /// May be a single year or a range: e.g. 2020 or 2012-2016.
+ ///
+ property Date: string read fDate;
+
+ /// Name of copyright holder.
+ property Holder: string read fHolder;
+
+ /// URL of main copyright holder.
+ /// Optional.
+ property HolderURL: string read fHolderURL;
+
+ /// List of names of contributors who share ownership of the
+ /// copyright.
+ property Contributors: IStringList read GetContributors;
+
+ /// Creates and returns a string representation of all the
+ /// non-empty fields of the record.
+ function ToString: string;
+ end;
+
+ /// Encapsulates a collection's meta data.
+ TMetaData = record
+ strict private
+ var
+ fCapabilities: TMetaDataCaps;
+ fVersion: TVersionNumber;
+ fLicenseInfo: TLicenseInfo;
+ fCopyrightInfo: TCopyrightInfo;
+ fAcknowledgements: IStringList;
+ function GetVersion: TVersionNumber;
+ function GetLicenseInfo: TLicenseInfo;
+ function GetCopyrightInfo: TCopyrightInfo;
+ function GetAcknowledgements: IStringList;
+ public
+ /// Creates a meta data record with specified capabilities.
+ ///
+ /// TMetaDataCaps [in] The required
+ /// capabilities.
+ constructor Create(const ACapabilities: TMetaDataCaps);
+
+ /// Creates a null meta data record with specified capabilities.
+ ///
+ class function CreateNull: TMetaData; static;
+
+ /// Returns a deep copy of this record.
+ function Clone: TMetaData;
+
+ /// The meta data capabilities.
+ property Capabilities: TMetaDataCaps
+ read fCapabilities;
+
+ /// The data format version.
+ property Version: TVersionNumber
+ read GetVersion write fVersion;
+
+ /// Information about the collection license.
+ property LicenseInfo: TLicenseInfo
+ read GetLicenseInfo write fLicenseInfo;
+
+ /// Information about the collection's copyright.
+ property CopyrightInfo: TCopyrightInfo
+ read GetCopyrightInfo write fCopyrightInfo;
+
+ /// List of acknowledgements.
+ property Acknowledgements: IStringList
+ read GetAcknowledgements write fAcknowledgements;
+ end;
+
+implementation
+
+uses
+ // Delphi
+ Character,
+ // Project
+ UStrUtils;
+
+function StandardiseStr(const AStr: string): string;
+begin
+ Result := StrCompressWhiteSpace(
+ StrReplaceChar(
+ AStr,
+ function(Ch: Char): Boolean
+ begin
+ Result := TCharacter.IsControl(Ch);
+ end,
+ ' '
+ )
+ );
+end;
+
+{ TLicenseInfo }
+
+function TLicenseInfo.Clone: TLicenseInfo;
+begin
+ Result.fName := Name;
+ Result.fSPDX := SPDX;
+ Result.fURL := URL;
+ Result.fText := Text;
+end;
+
+constructor TLicenseInfo.Create(const AName, ASPDX, AURL, AText: string);
+begin
+ fName := StandardiseStr(AName);
+ fSPDX := StandardiseStr(ASPDX);
+ fURL := StandardiseStr(AURL);
+ fText := StandardiseStr(AText);
+end;
+
+class function TLicenseInfo.CreateNull: TLicenseInfo;
+begin
+ Result := TLicenseInfo.Create('', '', '', '');
+end;
+
+function TLicenseInfo.NameWithURL: string;
+begin
+ Result := fName;
+ if fURL <> '' then
+ Result := Result + ' (' + fURL + ')';
+end;
+
+{ TCopyrightInfo }
+
+function TCopyrightInfo.Clone: TCopyrightInfo;
+begin
+ Result.fDate := Date;
+ Result.fHolder := Holder;
+ Result.fHolderURL := HolderURL;
+ Result.fContributors := Contributors;
+end;
+
+constructor TCopyrightInfo.Create(const ADate, AHolder, AHolderURL: string;
+ AContributors: IStringList);
+begin
+ fDate := StandardiseStr(ADate);
+ fHolder := StandardiseStr(AHolder);
+ fHolderURL := StandardiseStr(AHolderURL);
+ fContributors := TIStringList.Create(AContributors);
+end;
+
+class function TCopyrightInfo.CreateNull: TCopyrightInfo;
+begin
+ Result := TCopyrightInfo.Create('', '', '', nil);
+end;
+
+function TCopyrightInfo.GetContributors: IStringList;
+begin
+ Result := TIStringList.Create(fContributors);
+end;
+
+function TCopyrightInfo.ToString: string;
+resourcestring
+ sCopyright = 'Copyright';
+begin
+ Result := '';
+ if Date <> '' then
+ Result := Result + '(C) ' + Date;
+ if Holder <> '' then
+ begin
+ if Result <> '' then
+ Result := Result + ', ';
+ Result := Result + Holder;
+ end;
+ if HolderURL <> '' then
+ begin
+ if Result <> '' then
+ Result := Result + ', ';
+ Result := Result + HolderURL;
+ end;
+ if Result <> '' then
+ Result := sCopyright + ' ' + Result;
+end;
+
+{ TMetaData }
+
+function TMetaData.Clone: TMetaData;
+begin
+ Result.fCapabilities := Capabilities;
+ Result.fVersion := GetVersion;
+ Result.fLicenseInfo := GetLicenseInfo;
+ Result.fCopyrightInfo := GetCopyrightInfo;
+ Result.fAcknowledgements := GetAcknowledgements;
+end;
+
+constructor TMetaData.Create(const ACapabilities: TMetaDataCaps);
+begin
+ fCapabilities := ACapabilities;
+ fVersion := TVersionNumber.Nul;
+ fLicenseInfo := TLicenseInfo.CreateNull;
+ fCopyrightInfo := TCopyrightInfo.CreateNull;
+ fAcknowledgements := TIStringList.Create;
+end;
+
+class function TMetaData.CreateNull: TMetaData;
+begin
+ Result := TMetaData.Create([]);
+end;
+
+function TMetaData.GetAcknowledgements: IStringList;
+begin
+ if TMetaDataCap.Acknowledgements in fCapabilities then
+ Result := TIStringList.Create(fAcknowledgements)
+ else
+ Result := TIStringList.Create;
+end;
+
+function TMetaData.GetCopyrightInfo: TCopyrightInfo;
+begin
+ if TMetaDataCap.Copyright in fCapabilities then
+ Result := fCopyrightInfo.Clone
+ else
+ Result := TCopyrightInfo.CreateNull;
+end;
+
+function TMetaData.GetLicenseInfo: TLicenseInfo;
+begin
+ if TMetaDataCap.License in fCapabilities then
+ Result := fLicenseInfo.Clone
+ else
+ Result := TLicenseInfo.CreateNull;
+end;
+
+function TMetaData.GetVersion: TVersionNumber;
+begin
+ if TMetaDataCap.Version in fCapabilities then
+ Result := fVersion
+ else
+ Result := TVersionNumber.Nul;
+end;
+
+end.
From 8413b324137c47d3edbcddd98f4e169d34039a38 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 2 Mar 2025 10:39:14 +0000
Subject: [PATCH 137/222] Add new TCollection.MetaData property
This property added to enable meta data associated with a collection to
be stored with it.
---
Src/DB.UCollections.pas | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
index b1d7e9800..ea1777a8a 100644
--- a/Src/DB.UCollections.pas
+++ b/Src/DB.UCollections.pas
@@ -21,6 +21,7 @@ interface
Generics.Defaults,
DB.DataFormats,
+ DB.MetaData,
UEncodings,
UExceptions,
USettings,
@@ -69,6 +70,8 @@ TCollection = record
fUID: TCollectionID;
fName: string;
fStorage: TDataStorageDetails;
+ fMetaData: TMetaData;
+ procedure SetMetaData(const AValue: TMetaData);
public
type
TComparer = class(TInterfacedObject,
@@ -97,6 +100,11 @@ TComparer = class(TInterfacedObject,
/// Collection storage information.
property Storage: TDataStorageDetails
read fStorage;
+ /// Meta data associated with the collection.
+ /// Meta data is read from and written to the associated storage.
+ ///
+ property MetaData: TMetaData
+ read fMetaData write SetMetaData;
/// Checks if this record's fields are valid.
function IsValid: Boolean;
/// Checks if this record is the default collection.
@@ -197,6 +205,11 @@ function TCollection.IsValid: Boolean;
and (fStorage.Format <> TDataFormatKind.Error);
end;
+procedure TCollection.SetMetaData(const AValue: TMetaData);
+begin
+ fMetaData := AValue.Clone;
+end;
+
{ TCollections }
procedure TCollections.Add(const ACollection: TCollection);
From 5a5b2ebf28dfaedf907ba8c1a53c849fe7198dec Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sat, 1 Mar 2025 17:54:25 +0000
Subject: [PATCH 138/222] Add facility to save metadata to data format writers
Added WriteMetaData method to TFormatSaver class in DB.UDatabaseIO.
Added IDataWriter.WriteMetaData method and implemented it in
TIniDataWriter (writes all kinds of meta data for the DCSC v2 data
format), TXMLDataWriter (writes no meta data for the CodeSnip v4 native
format) and TNativeDataWriter (writes all but version meta data for
CodeSnip Vault native data format).
---
Src/DB.IO.DataFormat.Native.pas | 56 ++++++++++++++++++++++++
Src/DB.UDatabaseIO.pas | 22 ++++++++++
Src/DBIO.UFileIOIntf.pas | 13 +++++-
Src/DBIO.UIniData.pas | 75 ++++++++++++++++++++++++++++++++-
Src/DBIO.UXMLDataIO.pas | 23 +++++++++-
5 files changed, 186 insertions(+), 3 deletions(-)
diff --git a/Src/DB.IO.DataFormat.Native.pas b/Src/DB.IO.DataFormat.Native.pas
index 9ac56a5ba..50e72a423 100644
--- a/Src/DB.IO.DataFormat.Native.pas
+++ b/Src/DB.IO.DataFormat.Native.pas
@@ -19,6 +19,7 @@ interface
XMLIntf,
// Project
Compilers.UGlobals,
+ DB.MetaData,
DB.UCategory,
DB.USnippet,
DB.USnippetKind,
@@ -430,6 +431,12 @@ TNativeDataWriter = class sealed(TNativeDataRW, IDataWriter)
procedure WriteSnippetXRefs(const SnippetKey: string;
const XRefs: IStringList);
+ /// Writes the collection's meta data.
+ /// TMetaData [in] Meta data to be written.
+ ///
+ /// Method of IDataWriter.
+ procedure WriteMetaData(const AMetaData: TMetaData);
+
/// Finalises the collection write.
///
/// Always called after all other IDataWriter methods.
@@ -1058,6 +1065,55 @@ procedure TNativeDataWriter.WriteEnclosedList(const AParent: IXMLNode;
XMLDoc.CreateElement(ListNode, AItemNodeName, Item);
end;
+procedure TNativeDataWriter.WriteMetaData(const AMetaData: TMetaData);
+var
+ LicenseNode: IXMLNode;
+ CopyrightNode: IXMLNode;
+begin
+ // Write license info
+ LicenseNode := XMLDoc.CreateElement(fRootNode, LicenseNodeName);
+ LicenseNode.Attributes[LicenseNodeSPDXAttr] := AMetaData.LicenseInfo.SPDX;
+ LicenseNode.Attributes[LicenseNodeNameAttr] := AMetaData.LicenseInfo.Name;
+ LicenseNode.Attributes[LicenseNodeURLAttr] := AMetaData.LicenseInfo.URL;
+ if StrIsEmpty(AMetaData.LicenseInfo.Text) then
+ LicenseNode.Attributes[LicenseNodeLicenseFileAttr] := ''
+ else
+ begin
+ // license text file: license text is written to a UTF-8 encoded file with
+ // no BOM and filename is stored in XML
+ LicenseNode.Attributes[LicenseNodeLicenseFileAttr] := LicenseTextFileName;
+ TFileIO.WriteAllText(
+ FilePath(LicenseTextFileName),
+ AMetaData.LicenseInfo.Text,
+ TEncoding.UTF8,
+ False
+ );
+ end;
+
+ CopyrightNode := XMLDoc.CreateElement(fRootNode, CopyrightNodeName);
+ CopyrightNode.Attributes[CopyrightNodeDateAttr] :=
+ AMetaData.CopyrightInfo.Date;
+ CopyrightNode.Attributes[CopyrightNodeHolderAttr] :=
+ AMetaData.CopyrightInfo.Holder;
+ CopyrightNode.Attributes[CopyrightNodeURLAttr]
+ := AMetaData.CopyrightInfo.HolderURL;
+ if AMetaData.CopyrightInfo.Contributors.Count > 0 then
+ WriteEnclosedList(
+ CopyrightNode,
+ CopyrightContributorsListNodeName,
+ CopyrightContributorsListItemNodeName,
+ AMetaData.CopyrightInfo.Contributors
+ );
+
+ WriteEnclosedList(
+ fRootNode,
+ AcknowledgementsListNodeName,
+ AcknowledgementsListItemNodeName,
+ AMetaData.Acknowledgements
+ );
+
+end;
+
procedure TNativeDataWriter.WriteReferenceList(const ASnippetKey,
AListNodeName, AItemNodeName: string; const AItems: IStringList);
var
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index 7293b6c50..005ff186c 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -153,6 +153,12 @@ implementation
}
TDatabaseLoaderClass = class of TDatabaseLoader;
+ {TODO -cRefactoring: Would a better method be to have a single TDatabaseLoader
+ class that is passed a reader object in its constructor,
+ rather than have sub-classes that simply create the
+ required reader object?}
+ {TODO -cRefactoring: Rename TDatabaseLoader to TFormatLoader or similar}
+
{
TDatabaseLoader:
Abstract base class for objects that can load data into the Database object
@@ -278,6 +284,13 @@ TNativeVaultFormatLoader = class(TDatabaseLoader, IDataFormatLoader)
}
end;
+ {TODO -cRefactoring: Would a better method be to have a single TFormatSaver
+ class that is passed a writer object in its constructor,
+ rather than have sub-classes that simply create the
+ required writer object?
+ Would need to make sure all .Save methods in sub-classes
+ are identical first. }
+
/// Base for classes that save a collection to storage.
TFormatSaver = class abstract (TInterfacedObject,
IDataFormatSaver
@@ -298,6 +311,9 @@ TFormatSaver = class abstract (TInterfacedObject,
/// collection.
procedure WriteCategories;
+ /// Writes the collection's meta data, if supported.
+ procedure WriteMetaData;
+
strict protected
/// Saves collection to storage.
@@ -759,6 +775,7 @@ procedure TFormatSaver.DoSave(const SnipList: TSnippetList;
fWriter.Initialise;
WriteCategories;
WriteSnippets;
+ WriteMetaData;
fWriter.Finalise;
end;
@@ -781,6 +798,11 @@ procedure TFormatSaver.WriteCategories;
end;
end;
+procedure TFormatSaver.WriteMetaData;
+begin
+ fWriter.WriteMetaData(fCollection.MetaData);
+end;
+
procedure TFormatSaver.WriteSnippets;
// Adds snippet keys from IDList to a string list
diff --git a/Src/DBIO.UFileIOIntf.pas b/Src/DBIO.UFileIOIntf.pas
index d032816b5..6cb46bd33 100644
--- a/Src/DBIO.UFileIOIntf.pas
+++ b/Src/DBIO.UFileIOIntf.pas
@@ -19,7 +19,11 @@ interface
uses
// Project
- DB.UCategory, DB.USnippet, UExceptions, UIStringList;
+ DB.MetaData,
+ DB.UCategory,
+ DB.USnippet,
+ UExceptions,
+ UIStringList;
type
@@ -128,6 +132,13 @@ interface
@param SnippetKey [in] Snippet's key.
@param XRefs [in] List of snippet keys.
}
+
+ /// Write the collection's meta data.
+ /// TMetaData [in] Meta data to be written.
+ ///
+ /// Data formats may support all, some or no metadata.
+ procedure WriteMetaData(const AMetaData: TMetaData);
+
procedure Finalise;
{Finalises the database. Always called after all other methods.
}
diff --git a/Src/DBIO.UIniData.pas b/Src/DBIO.UIniData.pas
index 7039883b7..9310b9f0f 100644
--- a/Src/DBIO.UIniData.pas
+++ b/Src/DBIO.UIniData.pas
@@ -26,6 +26,7 @@ interface
IniFiles,
// Project
ActiveText.UMain,
+ DB.MetaData,
DB.UCategory,
DB.USnippet,
DBIO.UFileIOIntf,
@@ -304,6 +305,11 @@ TUTF8IniFileCache = class(TObject)
/// unformatted, single line, REML string.
function ActiveTextToREML(AActiveText: IActiveText): string;
+ procedure WriteTextFile(const AFileName, AText: string); overload;
+
+ procedure WriteTextFile(const AFileName: string; const ALines: IStringList);
+ overload;
+
public
/// Object constructor.
@@ -377,6 +383,12 @@ TUTF8IniFileCache = class(TObject)
procedure WriteSnippetXRefs(const SnippetKey: string;
const XRefs: IStringList);
+ /// Writes the collection's meta data.
+ /// TMetaData [in] Meta data to be written.
+ ///
+ /// Method of IDataWriter.
+ procedure WriteMetaData(const AMetaData: TMetaData);
+
/// Finalises the output. Always called after all other methods.
///
/// Method of IDataWriter.
@@ -409,6 +421,12 @@ implementation
const
// Name of master file that defines database
cMasterFileName = 'categories.ini';
+ // Names of meta data files
+ VersionFileName = 'VERSION';
+ LicenseFileName = 'LICENSE';
+ LicenseInfoFileName = 'LICENSE-INFO';
+ ContributorsFileName = 'CONTRIBUTORS';
+ AcknowledgementsFileName = 'TESTERS';
// Names of values in categories ini file
cMasterIniName = 'Ini'; // name of category ini file
cMasterDescName = 'Desc'; // category description
@@ -916,6 +934,43 @@ procedure TIniDataWriter.WriteCatSnippets(const CatID: string;
// Do nothing
end;
+procedure TIniDataWriter.WriteMetaData(const AMetaData: TMetaData);
+begin
+ WriteTextFile(
+ VersionFileName,
+ Format(
+ '%0:d.%1:d.%2:d',
+ [AMetaData.Version.V1, AMetaData.Version.V2, AMetaData.Version.V3]
+ )
+ );
+
+ WriteTextFile(LicenseFileName, AMetaData.LicenseInfo.Text);
+
+ WriteTextFile(
+ LicenseInfoFileName,
+ Format(
+ 'LicenseName=%0:s' + EOL +
+ 'LicenseSPDX=%1:s' + EOL +
+ 'LicenseURL=%2:s' + EOL +
+ 'CopyrightDate=%3:s' + EOL +
+ 'CopyrightHolder=%4:s' + EOL +
+ 'CopyrightHolderURL=%5:s' + EOL,
+ [
+ AMetaData.LicenseInfo.Name,
+ AMetaData.LicenseInfo.SPDX,
+ AMetaData.LicenseInfo.URL,
+ AMetaData.CopyrightInfo.Date,
+ AMetaData.CopyrightInfo.Holder,
+ AMetaData.CopyrightInfo.HolderURL
+ ]
+ )
+ );
+
+ WriteTextFile(ContributorsFileName, AMetaData.CopyrightInfo.Contributors);
+
+ WriteTextFile(AcknowledgementsFileName, AMetaData.Acknowledgements);
+end;
+
procedure TIniDataWriter.WriteSnippetDepends(const SnippetKey: string;
const Depends: IStringList);
begin
@@ -1006,7 +1061,9 @@ procedure TIniDataWriter.WriteSnippetProps(const SnippetKey: string;
// test info: only write if not basic
{TODO -cVault: Add support for AdvancedTest .Level & .URL}
if Props.TestInfo <> stiBasic then
- fCurrentCatIni.WriteString(SnippetKey, cTestInfoName, TestInfo[Props.TestInfo]);
+ fCurrentCatIni.WriteString(
+ SnippetKey, cTestInfoName, TestInfo[Props.TestInfo]
+ );
except
@@ -1040,6 +1097,22 @@ procedure TIniDataWriter.WriteSnippetXRefs(const SnippetKey: string;
);
end;
+procedure TIniDataWriter.WriteTextFile(const AFileName, AText: string);
+begin
+ TFileIO.WriteAllText(MakePath(AFileName), AText, TEncoding.UTF8, True);
+end;
+
+procedure TIniDataWriter.WriteTextFile(const AFileName: string;
+ const ALines: IStringList);
+var
+ Content: string;
+begin
+ Content := ALines.GetText(EOL, False);
+ if not StrIsEmpty(Content) then
+ Content := Content + EOL;
+ WriteTextFile(AFileName, Content);
+end;
+
{ TIniDataWriter.TUTF8IniFile }
procedure TIniDataWriter.TUTF8IniFile.Save;
diff --git a/Src/DBIO.UXMLDataIO.pas b/Src/DBIO.UXMLDataIO.pas
index eb0ec1db5..c1ff21f4b 100644
--- a/Src/DBIO.UXMLDataIO.pas
+++ b/Src/DBIO.UXMLDataIO.pas
@@ -20,7 +20,12 @@ interface
// Delphi
XMLIntf,
// Project
- DB.UCategory, DB.USnippet, DBIO.UFileIOIntf, UIStringList, UREMLDataIO,
+ DB.MetaData,
+ DB.UCategory,
+ DB.USnippet,
+ DBIO.UFileIOIntf,
+ UIStringList,
+ UREMLDataIO,
UXMLDocumentEx;
@@ -231,6 +236,17 @@ TXMLDataWriter = class(TXMLDataIO,
@param SnippetKey [in] Snippet's key.
@param XRefs [in] List of snippet keys.
}
+
+ /// Writes the collection's meta data.
+ /// TMetaData [in] Meta data to be written.
+ ///
+ ///
+ /// This data format does not support metadata, so this method does
+ /// nothing.
+ /// Method of IDataWriter.
+ ///
+ procedure WriteMetaData(const AMetaData: TMetaData);
+
procedure Finalise;
{Finalises the database. Always called after all other methods.
}
@@ -858,6 +874,11 @@ procedure TXMLDataWriter.WriteCatSnippets(const CatID: string;
end;
end;
+procedure TXMLDataWriter.WriteMetaData(const AMetaData: TMetaData);
+begin
+ // Do nothing: meta data not supported.
+end;
+
procedure TXMLDataWriter.WriteNameList(const Parent: IXMLNode; const ListName,
ItemName: string; const Items: IStringList);
{Writes a list of names to XML.
From e3551aa77fbe5744f9378fc692728a2d4da625d9 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 2 Mar 2025 10:34:29 +0000
Subject: [PATCH 139/222] Add facility to read metadata from data format
readers
Added IDataReader.GetMetaData method and implemented it in
TIniDataWriter (reads all kinds of meta data for the DCSC v2 data
format), TXMLDataReader (returns null record for the CodeSnip v4 native
format), TNativeDataReader (read all but version meta data for
CodeSnip Vault native data format) and TNulDataReader (retruns null
record).
Updated TDatabaseLoader.Load method in DB.UDatabaseIO to get meta data
and store it in the collection's MetaData property.
---
Src/DB.IO.DataFormat.Native.pas | 64 +++++++++++++++++
Src/DB.UDatabaseIO.pas | 2 +
Src/DBIO.UFileIOIntf.pas | 5 ++
Src/DBIO.UIniData.pas | 121 +++++++++++++++++++++++++++++++-
Src/DBIO.UNulDataReader.pas | 16 ++++-
Src/DBIO.UXMLDataIO.pas | 14 ++++
6 files changed, 219 insertions(+), 3 deletions(-)
diff --git a/Src/DB.IO.DataFormat.Native.pas b/Src/DB.IO.DataFormat.Native.pas
index 50e72a423..064717021 100644
--- a/Src/DB.IO.DataFormat.Native.pas
+++ b/Src/DB.IO.DataFormat.Native.pas
@@ -307,6 +307,12 @@ TNativeDataReader = class sealed(TNativeDataRW, IDataReader)
///
/// Method of IDataReader.
function GetSnippetUnits(const SnippetKey: string): IStringList;
+
+ /// Gets the collection's meta data.
+ /// TMetaData. The required meta data. Will be null if
+ /// is no meta data.
+ /// Method of IDataReader.
+ function GetMetaData: TMetaData;
end;
/// Class that performs the low level writing of collection data in
@@ -479,6 +485,7 @@ implementation
sBadKind = 'Missing or invalid snippet kind for snippet "%s"';
sSnippetNotFound = 'Can''t find reference to snippet key "%s" in XML file';
sBadTestInfo = 'Invalid test information for snippet "%s"';
+ sMissingLicenseText = 'License text file "%s" is missing';
{ TNativeDataRW }
@@ -654,6 +661,63 @@ function TNativeDataReader.GetEnclosedListItems(const AParentNode: IXMLNode;
Result.Add(ItemNode.Text);
end;
+function TNativeDataReader.GetMetaData: TMetaData;
+var
+ RootNode: IXMLNode;
+ LicenseNode: IXMLNode;
+ CopyrightNode: IXMLNode;
+ LicenseTextFileName: string;
+ LicenseText: string;
+begin
+ Result := TMetaData.Create([
+ TMetaDataCap.License, TMetaDataCap.Copyright, TMetaDataCap.Acknowledgements
+ ]);
+
+ LicenseNode := XMLDoc.FindNode(RootNodeName + '\' + LicenseNodeName);
+ if Assigned(LicenseNode) then
+ begin
+ LicenseTextFileName := LicenseNode.Attributes[LicenseNodeLicenseFileAttr];
+ if (LicenseTextFileName <> '') then
+ begin
+ if not TFile.Exists(FilePath(LicenseTextFileName)) then
+ raise EDataIO.CreateFmt(sMissingLicenseText, [LicenseTextFileName]);
+ LicenseText := TFileIO.ReadAllText(
+ FilePath(LicenseTextFileName), TEncoding.UTF8, False
+ );
+ end
+ else
+ LicenseText := '';
+ Result.LicenseInfo := TLicenseInfo.Create(
+ LicenseNode.Attributes[LicenseNodeNameAttr],
+ LicenseNode.Attributes[LicenseNodeSPDXAttr],
+ LicenseNode.Attributes[LicenseNodeURLAttr],
+ LicenseText
+ );
+ end;
+
+ CopyrightNode := XMLDoc.FindNode(RootNodeName + '\' + CopyrightNodeName);
+ if Assigned(CopyrightNode) then
+ begin
+ Result.CopyrightInfo := TCopyrightInfo.Create(
+ CopyrightNode.Attributes[CopyrightNodeDateAttr],
+ CopyrightNode.Attributes[CopyrightNodeHolderAttr],
+ CopyrightNode.Attributes[CopyrightNodeURLAttr],
+ GetEnclosedListItems(
+ CopyrightNode,
+ CopyrightContributorsListNodeName,
+ CopyrightContributorsListItemNodeName
+ )
+ );
+ end;
+
+ RootNode := XMLDoc.FindNode(RootNodeName);
+ if not Assigned(RootNode) then
+ raise EDataIO.Create(sNoRootNode);
+ Result.Acknowledgements := GetEnclosedListItems(
+ RootNode, AcknowledgementsListNodeName, AcknowledgementsListItemNodeName
+ );
+end;
+
function TNativeDataReader.GetSnippetDepends(const SnippetKey: string):
IStringList;
begin
diff --git a/Src/DB.UDatabaseIO.pas b/Src/DB.UDatabaseIO.pas
index 005ff186c..3baacb4f0 100644
--- a/Src/DB.UDatabaseIO.pas
+++ b/Src/DB.UDatabaseIO.pas
@@ -593,6 +593,8 @@ procedure TDatabaseLoader.Load(const SnipList: TSnippetList;
if IsNativeSnippet(Snippet) then
LoadReferences(Snippet);
end;
+ // Get collection's meta data
+ fCollection.MetaData := fReader.GetMetaData;
except
on E: Exception do
HandleException(E);
diff --git a/Src/DBIO.UFileIOIntf.pas b/Src/DBIO.UFileIOIntf.pas
index 6cb46bd33..0adc83a3e 100644
--- a/Src/DBIO.UFileIOIntf.pas
+++ b/Src/DBIO.UFileIOIntf.pas
@@ -78,6 +78,11 @@ interface
@param SnippetKey [in] Snippet's key.
@return List of unit names.
}
+
+ /// Gets the collection's meta data.
+ /// TMetaData. The required meta data. May be null if meta
+ /// data is not supported or not present.
+ function GetMetaData: TMetaData;
end;
{
diff --git a/Src/DBIO.UIniData.pas b/Src/DBIO.UIniData.pas
index 9310b9f0f..60d36c195 100644
--- a/Src/DBIO.UIniData.pas
+++ b/Src/DBIO.UIniData.pas
@@ -20,7 +20,9 @@ interface
uses
// Delphi
+ SysUtils,
Classes,
+ Types,
Generics.Collections,
Generics.Defaults,
IniFiles,
@@ -31,7 +33,8 @@ interface
DB.USnippet,
DBIO.UFileIOIntf,
UIStringList,
- UMainDBFileReader;
+ UMainDBFileReader,
+ UVersionInfo;
type
@@ -118,6 +121,8 @@ TIniFileCache = class(TObject)
///
/// Exception object to be handled.
procedure HandleCorruptDatabase(const EObj: TObject);
+ /// Returns encoding used by given meta file.
+ function GetFileEncoding(const FileName: string): TEncoding;
///
/// Returns name of directory where the database is stored.
///
@@ -126,6 +131,16 @@ TIniFileCache = class(TObject)
/// Returns fully specified path to given file name.
///
function DataFile(const FileName: string): string;
+ /// Checks if a given file exists in collection directory.
+ ///
+ function DataFileExists(const FileName: string): Boolean;
+ /// Reads all lines from given file and returns them as an array.
+ ///
+ /// FileName must contain no path information.
+ function ReadFileLines(const FileName: string): TStringDynArray;
+ /// Reads all text from given file and returns it.
+ /// FileName must contain no path information.
+ function ReadFileText(const FileName: string): string;
///
/// Gets a list from ini file of all of items of a specified kind that are
/// referenced by a snippet.
@@ -206,6 +221,11 @@ TIniFileCache = class(TObject)
/// string [in] Snippet's key.
/// IStringList containing unit names.
function GetSnippetUnits(const SnippetKey: string): IStringList;
+ /// Gets the collection's meta data.
+ /// TMetaData. The required meta data. Will be null if
+ /// is no meta data present.
+ /// Method of IDataReader.
+ function GetMetaData: TMetaData;
end;
/// Write a collection to disk in the DelphiDabbler Code Snippets
@@ -401,13 +421,13 @@ implementation
uses
// Delphi
- SysUtils,
IOUtils,
// Project
Compilers.UGlobals,
DB.USnippetKind,
UComparers,
UConsts,
+ UEncodings,
UExceptions,
UIniDataLoader,
UIOUtils,
@@ -421,12 +441,22 @@ implementation
const
// Name of master file that defines database
cMasterFileName = 'categories.ini';
+
// Names of meta data files
VersionFileName = 'VERSION';
LicenseFileName = 'LICENSE';
LicenseInfoFileName = 'LICENSE-INFO';
ContributorsFileName = 'CONTRIBUTORS';
AcknowledgementsFileName = 'TESTERS';
+
+ // Names of keys in license info file
+ LicenseInfoLicenseNameKey = 'LicenseName';
+ LicenseInfoLicenseSPDXKey = 'LicenseSPDX';
+ LicenseInfoLicenseURLKey = 'LicenseURL';
+ LicenseInfoCopyrightDateKey = 'CopyrightDate';
+ LicenseInfoCopyrightHolderKey = 'CopyrightHolder';
+ LicenseInfoCopyrightHolderURLKey = 'CopyrightHolderURL';
+
// Names of values in categories ini file
cMasterIniName = 'Ini'; // name of category ini file
cMasterDescName = 'Desc'; // category description
@@ -505,6 +535,11 @@ function TIniDataReader.DataFile(const FileName: string): string;
Result := IncludeTrailingPathDelimiter(DataDir) + FileName;
end;
+function TIniDataReader.DataFileExists(const FileName: string): Boolean;
+begin
+ Result := TFile.Exists(DataFile(FileName), False);
+end;
+
destructor TIniDataReader.Destroy;
begin
fFileReader.Free;
@@ -558,6 +593,60 @@ function TIniDataReader.GetCatSnippets(const CatID: string): IStringList;
end;
end;
+function TIniDataReader.GetFileEncoding(const FileName: string): TEncoding;
+begin
+ // Old v1 database meta files may be in the system default encodings, v1 and
+ // all v2 and later use UTF-8 with BOM.
+ if TFileIO.CheckBOM(DataFile(FileName), TEncoding.UTF8) then
+ Result := TEncoding.UTF8
+ else
+ Result := TEncoding.Default;
+end;
+
+function TIniDataReader.GetMetaData: TMetaData;
+var
+ SL: TStringList;
+ LicenseText: string;
+ LicenseFileInfo: TStringDynArray;
+ Contributors: IStringList;
+ VerStr: string;
+ Version: TVersionNumber;
+begin
+ VerStr := StrTrim(ReadFileText(VersionFileName));
+ if not TVersionNumber.TryStrToVersionNumber(VerStr, Version) then
+ Version := TVersionNumber.Nul;
+ LicenseText := StrTrimRight(ReadFileText(LicenseFileName));
+ LicenseFileInfo := ReadFileLines(LicenseInfoFileName);
+ Contributors := TIStringList.Create(ReadFileLines(ContributorsFileName));
+
+ Result := TMetaData.Create([
+ TMetaDataCap.Version, TMetaDataCap.License, TMetaDataCap.Copyright,
+ TMetaDataCap.Acknowledgements
+ ]);
+ Result.Version := Version;
+ SL := TStringList.Create;
+ try
+ StrArrayToStrList(LicenseFileInfo, SL);
+ Result.LicenseInfo := TLicenseInfo.Create(
+ SL.Values[LicenseInfoLicenseNameKey],
+ SL.Values[LicenseInfoLicenseSPDXKey],
+ SL.Values[LicenseInfoLicenseURLKey],
+ LicenseText
+ );
+ Result.CopyrightInfo := TCopyrightInfo.Create(
+ SL.Values[LicenseInfoCopyrightDateKey],
+ SL.Values[LicenseInfoCopyrightHolderKey],
+ SL.Values[LicenseInfoCopyrightHolderURLKey],
+ Contributors
+ );
+ finally
+ SL.Free;
+ end;
+ Result.Acknowledgements := TIStringList.Create(
+ ReadFileLines(AcknowledgementsFileName)
+ );
+end;
+
function TIniDataReader.GetSnippetDepends(const SnippetKey: string):
IStringList;
begin
@@ -799,6 +888,32 @@ function TIniDataReader.MasterFileName: string;
Result := DataFile(cMasterFileName);
end;
+function TIniDataReader.ReadFileLines(const FileName: string): TStringDynArray;
+var
+ Encoding: TEncoding;
+begin
+ if not DataFileExists(FileName) then
+ begin
+ SetLength(Result, 0);
+ Exit;
+ end;
+ Encoding := GetFileEncoding(FileName);
+ try
+ Result := TFileIO.ReadAllLines(DataFile(FileName), Encoding, True);
+ finally
+ TEncodingHelper.FreeEncoding(Encoding);
+ end;
+end;
+
+function TIniDataReader.ReadFileText(const FileName: string): string;
+begin
+ if not DataFileExists(FileName) then
+ Exit('');
+ Result := TFileIO.ReadAllText(
+ DataFile(FileName), GetFileEncoding(FileName), True
+ );
+end;
+
function TIniDataReader.SnippetToCat(const SnippetKey: string): string;
var
CatIdx: Integer; // index of category in category list for this snippet
@@ -888,6 +1003,8 @@ procedure TIniDataWriter.Initialise;
// Delete current ini and data files
// (don't delete special files: CONTRIBUTORS, LICENSE, LICENSE-INFO,
// TESTERS, VERSION).
+ {TODO -cVault: Is it now safe to delete the special files, since we now
+ write these files.}
DeleteFiles(fOutDir, '*.dat');
DeleteFiles(fOutDir, '*.ini');
diff --git a/Src/DBIO.UNulDataReader.pas b/Src/DBIO.UNulDataReader.pas
index fff3aedf5..9f3de1043 100644
--- a/Src/DBIO.UNulDataReader.pas
+++ b/Src/DBIO.UNulDataReader.pas
@@ -17,7 +17,11 @@ interface
uses
// Project
- DB.UCategory, DB.USnippet, DBIO.UFileIOIntf, UIStringList;
+ DB.MetaData,
+ DB.UCategory,
+ DB.USnippet,
+ DBIO.UFileIOIntf,
+ UIStringList;
type
@@ -72,6 +76,11 @@ TNulDataReader = class(TInterfacedObject,
@param SnippetKey [in] Key of required snippet.
@return Empty unit name list.
}
+
+ /// Gets the collection's meta data.
+ /// TMetaData. Null value.
+ /// Method of IDataReader.
+ function GetMetaData: TMetaData;
end;
@@ -116,6 +125,11 @@ function TNulDataReader.GetCatSnippets(const CatID: string): IStringList;
Result := TIStringList.Create;
end;
+function TNulDataReader.GetMetaData: TMetaData;
+begin
+ Result := TMetaData.CreateNull;
+end;
+
function TNulDataReader.GetSnippetDepends(const SnippetKey: string):
IStringList;
{Gets list of all snippets on which a given snippet depends.
diff --git a/Src/DBIO.UXMLDataIO.pas b/Src/DBIO.UXMLDataIO.pas
index c1ff21f4b..88ff92dea 100644
--- a/Src/DBIO.UXMLDataIO.pas
+++ b/Src/DBIO.UXMLDataIO.pas
@@ -155,6 +155,14 @@ TXMLDataReader = class(TXMLDataIO,
@param SnippetKey [in] Key of required snippet.
@return List of unit names.
}
+
+ /// Gets the collection's meta data.
+ /// TMetaData. Null value.
+ ///
+ /// Meta data is not supported by the data format.
+ /// Method of IDataReader.
+ ///
+ function GetMetaData: TMetaData;
end;
{
@@ -512,6 +520,12 @@ function TXMLDataReader.GetCatSnippets(const CatID: string): IStringList;
end;
end;
+function TXMLDataReader.GetMetaData: TMetaData;
+begin
+ // Meta data not supported by this data format
+ Result := TMetaData.CreateNull;
+end;
+
function TXMLDataReader.GetSnippetDepends(const SnippetKey: string):
IStringList;
{Get list of all snippets on which a given snippet depends.
From 3ba15b79fae6d362f36321ce01be9e018c9ac0d6 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 2 Mar 2025 10:58:25 +0000
Subject: [PATCH 140/222] Refactor TIniDataWriter.WriteMetaData
Replaced literal key names used in license info file with the key name
constants that are used when reading the meta data.
Minor mods to other code in the method.
---
Src/DBIO.UIniData.pas | 51 +++++++++++++++++++------------------------
1 file changed, 23 insertions(+), 28 deletions(-)
diff --git a/Src/DBIO.UIniData.pas b/Src/DBIO.UIniData.pas
index 60d36c195..44c30de84 100644
--- a/Src/DBIO.UIniData.pas
+++ b/Src/DBIO.UIniData.pas
@@ -1052,39 +1052,34 @@ procedure TIniDataWriter.WriteCatSnippets(const CatID: string;
end;
procedure TIniDataWriter.WriteMetaData(const AMetaData: TMetaData);
+var
+ VersionStr: string;
+ KVPairs: TStringList;
+ LicenseInfo: IStringList;
begin
- WriteTextFile(
- VersionFileName,
- Format(
- '%0:d.%1:d.%2:d',
- [AMetaData.Version.V1, AMetaData.Version.V2, AMetaData.Version.V3]
- )
+ VersionStr := Format(
+ '%0:d.%1:d.%2:d',
+ [AMetaData.Version.V1, AMetaData.Version.V2, AMetaData.Version.V3]
);
+ KVPairs := TStringList.Create;
+ try
+ KVPairs.Values[LicenseInfoLicenseNameKey] := AMetaData.LicenseInfo.Name;
+ KVPairs.Values[LicenseInfoLicenseSPDXKey] := AMetaData.LicenseInfo.SPDX;
+ KVPairs.Values[LicenseInfoLicenseURLKey] := AMetaData.LicenseInfo.URL;
+ KVPairs.Values[LicenseInfoCopyrightDateKey] := AMetaData.CopyrightInfo.Date;
+ KVPairs.Values[LicenseInfoCopyrightHolderKey] :=
+ AMetaData.CopyrightInfo.Holder;
+ KVPairs.Values[LicenseInfoCopyrightHolderURLKey] :=
+ AMetaData.CopyrightInfo.HolderURL;
+ LicenseInfo := TIStringList.Create(KVPairs);
+ finally
+ KVPairs.Free;
+ end;
+ WriteTextFile(VersionFileName, VersionStr);
WriteTextFile(LicenseFileName, AMetaData.LicenseInfo.Text);
-
- WriteTextFile(
- LicenseInfoFileName,
- Format(
- 'LicenseName=%0:s' + EOL +
- 'LicenseSPDX=%1:s' + EOL +
- 'LicenseURL=%2:s' + EOL +
- 'CopyrightDate=%3:s' + EOL +
- 'CopyrightHolder=%4:s' + EOL +
- 'CopyrightHolderURL=%5:s' + EOL,
- [
- AMetaData.LicenseInfo.Name,
- AMetaData.LicenseInfo.SPDX,
- AMetaData.LicenseInfo.URL,
- AMetaData.CopyrightInfo.Date,
- AMetaData.CopyrightInfo.Holder,
- AMetaData.CopyrightInfo.HolderURL
- ]
- )
- );
-
+ WriteTextFile(LicenseInfoFileName, LicenseInfo);
WriteTextFile(ContributorsFileName, AMetaData.CopyrightInfo.Contributors);
-
WriteTextFile(AcknowledgementsFileName, AMetaData.Acknowledgements);
end;
From 5b4c177dad2a77fda08781f2cb0f597bd66594ed Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 2 Mar 2025 17:40:52 +0000
Subject: [PATCH 141/222] Convert TCollection from record to class
This was done to make it easier to store meta data in the collection
contained in TCollections object when reading meta data from storage.
Updated TCollections to free contained TCollection object when they are
updated in place, deleted and when TCollections itself is finalised.
---
Src/DB.UCollections.pas | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
index ea1777a8a..00f2f9ab1 100644
--- a/Src/DB.UCollections.pas
+++ b/Src/DB.UCollections.pas
@@ -64,7 +64,7 @@ TComparer = class(TInterfacedObject,
ECollectionID = class(ECodeSnip);
- TCollection = record
+ TCollection = class
strict private
var
fUID: TCollectionID;
@@ -116,6 +116,7 @@ TCollections = class sealed(TSingleton)
var
fItems: TList;
function GetItem(const Idx: Integer): TCollection;
+ procedure DoUpdate(const Idx: Integer; const ACollection: TCollection);
class function GetInstance: TCollections; static;
strict protected
procedure Initialize; override;
@@ -226,11 +227,15 @@ procedure TCollections.AddOrUpdate(const ACollection: TCollection);
if Idx < 0 then
fItems.Add(ACollection)
else
- fItems[Idx] := ACollection;
+ DoUpdate(Idx, ACollection);
end;
procedure TCollections.Clear;
+var
+ Idx: Integer;
begin
+ for Idx := Pred(fItems.Count) downto 0 do
+ DoUpdate(Idx, nil); // frees and nils item with given index
fItems.Clear;
end;
@@ -270,12 +275,26 @@ procedure TCollections.Delete(const AUID: TCollectionID);
raise EArgumentException.Create(sCantDelete);
Idx := IndexOfID(AUID);
if Idx >= 0 then
+ begin
+ DoUpdate(Idx, nil); // frees and nils item with given index
fItems.Delete(Idx);
+ end;
+end;
+
+procedure TCollections.DoUpdate(const Idx: Integer;
+ const ACollection: TCollection);
+var
+ OldEntry: TCollection;
+begin
+ OldEntry := fItems[Idx];
+ fItems[Idx] := ACollection;
+ OldEntry.Free;
end;
procedure TCollections.Finalize;
begin
Save;
+ Clear;
fItems.Free;
end;
@@ -357,7 +376,7 @@ procedure TCollections.Update(const ACollection: TCollection);
begin
Idx := IndexOfID(ACollection.UID);
if Idx >= 0 then
- fItems[Idx] := ACollection;
+ DoUpdate(Idx, ACollection);
end;
{ TCollectionID }
From 13129f2cc1f1498edc6eba9f175139859bd849ed Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 2 Mar 2025 17:47:50 +0000
Subject: [PATCH 142/222] Add IsNull methods to TLicenseInfo & TCopyrightInfo
---
Src/DB.MetaData.pas | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/Src/DB.MetaData.pas b/Src/DB.MetaData.pas
index 1860ba1ab..36679cd7d 100644
--- a/Src/DB.MetaData.pas
+++ b/Src/DB.MetaData.pas
@@ -64,6 +64,11 @@ TLicenseInfo = record
/// Returns a deep copy of this record.
function Clone: TLicenseInfo;
+ /// Checks if the record is null.
+ /// A null record is one where Name, SPDX,
+ /// URL and Text properties are all empty strings.
+ function IsNull: Boolean;
+
/// Name of license.
property Name: string read fName;
@@ -113,6 +118,12 @@ TCopyrightInfo = record
/// Returns a deep copy of this record.
function Clone: TCopyrightInfo;
+ /// Checks if the record is null.
+ /// A null record is one where Date, Holder and
+ /// HolderURL properties are empty strings and Contributors
+ /// list is empty.
+ function IsNull: Boolean;
+
/// Copyright date.
/// May be a single year or a range: e.g. 2020 or 2012-2016.
///
@@ -227,6 +238,12 @@ class function TLicenseInfo.CreateNull: TLicenseInfo;
Result := TLicenseInfo.Create('', '', '', '');
end;
+function TLicenseInfo.IsNull: Boolean;
+begin
+ Result := StrIsEmpty(fName) and StrIsEmpty(fSPDX) and StrIsEmpty(fURL)
+ and StrIsEmpty(fText);
+end;
+
function TLicenseInfo.NameWithURL: string;
begin
Result := fName;
@@ -263,6 +280,12 @@ function TCopyrightInfo.GetContributors: IStringList;
Result := TIStringList.Create(fContributors);
end;
+function TCopyrightInfo.IsNull: Boolean;
+begin
+ Result := StrIsEmpty(fDate) and StrIsEmpty(fHolder) and StrIsEmpty(fHolderURL)
+ and (fContributors.Count = 0);
+end;
+
function TCopyrightInfo.ToString: string;
resourcestring
sCopyright = 'Copyright';
From d4c40d560ffc6fd212371776dbca43bb4dc26466 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 2 Mar 2025 17:50:02 +0000
Subject: [PATCH 143/222] Add new ctor to TVersionNumber
This new constructor takes four parameters that are the four parts of
the version number.
---
Src/UVersionInfo.pas | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/Src/UVersionInfo.pas b/Src/UVersionInfo.pas
index c74fbdc01..9e6e33b98 100644
--- a/Src/UVersionInfo.pas
+++ b/Src/UVersionInfo.pas
@@ -49,6 +49,10 @@ TVersionNumber = record
V2: Word; // Minor version number
V3: Word; // Revision version number
V4: Word; // Build number
+
+ /// Creates an instance of the record with the given version
+ /// numbers.
+ constructor Create(const AV1, AV2, AV3, AV4: Word);
/// Checks if this version number is Null.
/// Boolean. True if null, False otherwise.
function IsNull: Boolean;
@@ -277,6 +281,14 @@ class function TVersionInfo.SpecialBuildStr: string;
{ TVersionNumber }
+constructor TVersionNumber.Create(const AV1, AV2, AV3, AV4: Word);
+begin
+ V1 := AV1;
+ V2 := AV2;
+ V3 := AV3;
+ V4 := AV4;
+end;
+
class operator TVersionNumber.Equal(Ver1, Ver2: TVersionNumber): Boolean;
{Operator overload that compares two version numbers to check for equality.
@param Ver1 [in] First version number.
From 55dd0e4475a70dea19007baee2f143f5770f3753 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 2 Mar 2025 18:00:19 +0000
Subject: [PATCH 144/222] Update TIniDataReader to validate version
Changed to read and validate version number in constructor. Can detect
v1 and later formats but only supports v2.x.x
---
Src/DBIO.UIniData.pas | 56 +++++++++++++++++++++++++++++++++++++------
1 file changed, 49 insertions(+), 7 deletions(-)
diff --git a/Src/DBIO.UIniData.pas b/Src/DBIO.UIniData.pas
index 44c30de84..f95a2cdcd 100644
--- a/Src/DBIO.UIniData.pas
+++ b/Src/DBIO.UIniData.pas
@@ -92,10 +92,20 @@ TIniFileCache = class(TObject)
fIniCache: TIniFileCache;
/// Reads DB files using correct encoding.
fFileReader: TMainDBFileReader;
+ /// Data format version number.
+ fVersion: TVersionNumber;
+ const
+ SupportedMajorVersion = 2;
+ strict private
///
/// Returns fully specified name of database master file.
///
function MasterFileName: string;
+ /// Reads data format version from file.
+ /// Stores result in fVersion. Detects DCSC versions 1 and
+ /// later. fVersion is set to null if the version can't be
+ /// determined.
+ procedure ReadVersionNumber;
///
/// Returns ID of category associated with a snippet.
///
@@ -442,13 +452,18 @@ implementation
// Name of master file that defines database
cMasterFileName = 'categories.ini';
- // Names of meta data files
+ // Names of v2 meta data files
VersionFileName = 'VERSION';
LicenseFileName = 'LICENSE';
LicenseInfoFileName = 'LICENSE-INFO';
ContributorsFileName = 'CONTRIBUTORS';
AcknowledgementsFileName = 'TESTERS';
+ // Names of v1 meta data files
+ ContributorsFileNameV1 = 'contrib.txt';
+ AcknowledgementsFileNameV1 = 'testers.txt';
+
+
// Names of keys in license info file
LicenseInfoLicenseNameKey = 'LicenseName';
LicenseInfoLicenseSPDXKey = 'LicenseSPDX';
@@ -500,6 +515,10 @@ class function TIniDataReader.CommaStrToStrings(
end;
constructor TIniDataReader.Create(const DBDir: string);
+resourcestring
+ // Error messages
+ sVersionNotSpecified = 'Format version number not specified';
+ sVersionNotSupported = 'Format version %s is not supported';
begin
inherited Create;
fDBDir := DBDir;
@@ -509,6 +528,11 @@ constructor TIniDataReader.Create(const DBDir: string);
fFileReader := TMainDBFileReader.Create(MasterFileName);
fIniCache := TIniFileCache.Create(fFileReader);
try
+ ReadVersionNumber;
+ if fVersion.IsNull then
+ raise EDataIO.Create(sVersionNotSpecified);
+ if fVersion.V1 <> SupportedMajorVersion then
+ raise EDataIO.CreateFmt(sVersionNotSupported, [string(fVersion)]);
fMasterIni := TDatabaseIniFile.Create(fFileReader, MasterFileName);
fCatIDs := TStringList.Create;
fSnippetCatMap := TSnippetCatMap.Create(TTextEqualityComparer.Create);
@@ -609,12 +633,8 @@ function TIniDataReader.GetMetaData: TMetaData;
LicenseText: string;
LicenseFileInfo: TStringDynArray;
Contributors: IStringList;
- VerStr: string;
- Version: TVersionNumber;
begin
- VerStr := StrTrim(ReadFileText(VersionFileName));
- if not TVersionNumber.TryStrToVersionNumber(VerStr, Version) then
- Version := TVersionNumber.Nul;
+
LicenseText := StrTrimRight(ReadFileText(LicenseFileName));
LicenseFileInfo := ReadFileLines(LicenseInfoFileName);
Contributors := TIStringList.Create(ReadFileLines(ContributorsFileName));
@@ -623,7 +643,7 @@ function TIniDataReader.GetMetaData: TMetaData;
TMetaDataCap.Version, TMetaDataCap.License, TMetaDataCap.Copyright,
TMetaDataCap.Acknowledgements
]);
- Result.Version := Version;
+ Result.Version := fVersion; // this was read in constructor
SL := TStringList.Create;
try
StrArrayToStrList(LicenseFileInfo, SL);
@@ -914,6 +934,28 @@ function TIniDataReader.ReadFileText(const FileName: string): string;
);
end;
+procedure TIniDataReader.ReadVersionNumber;
+var
+ VersionStr: string;
+begin
+ if DataFileExists(VersionFileName) then
+ begin
+ // Version file exists. Read and parse it. Set to null if invalid
+ VersionStr := StrTrim(ReadFileText(VersionFileName));
+ if not TVersionNumber.TryStrToVersionNumber(VersionStr, fVersion) then
+ fVersion := TVersionNumber.Nul;
+ end
+ else
+ begin
+ // No version file. Check if v1 present. Set to null if v1 not detected
+ if DataFileExists(ContributorsFileNameV1)
+ and DataFileExists(AcknowledgementsFileNameV1) then
+ fVersion := TVersionNumber.Create(1, 0, 0, 0)
+ else
+ fVersion := TVersionNumber.Nul;
+ end;
+end;
+
function TIniDataReader.SnippetToCat(const SnippetKey: string): string;
var
CatIdx: Integer; // index of category in category list for this snippet
From b647792caf6398dd49106e60e9110c063fad229a Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 2 Mar 2025 19:15:26 +0000
Subject: [PATCH 145/222] Change how About box displays collection metadata
The about box now gets meta data from a collection's MetaData property
rather than from IDBMetaData read on demand. This removes dependency on
DB.UMetaData and DBIO.MetaData.DCSC units and uses DB.MetaData instead.
Also changed how metadata is formatted for display. The display now
treats missing metadata items more inteligently.
---
Src/FmAboutDlg.pas | 131 ++++++++++++++++++++++++++++-----------------
1 file changed, 81 insertions(+), 50 deletions(-)
diff --git a/Src/FmAboutDlg.pas b/Src/FmAboutDlg.pas
index b470aecc3..e3c2fcee7 100644
--- a/Src/FmAboutDlg.pas
+++ b/Src/FmAboutDlg.pas
@@ -27,8 +27,8 @@ interface
Generics.Collections,
// Project
Browser.UHTMLEvents,
+ DB.MetaData,
DB.UCollections,
- DB.UMetaData,
FmGenericViewDlg,
FrBrowserBase,
FrHTMLDlg,
@@ -334,89 +334,120 @@ procedure TAboutDlg.ConfigForm;
end;
procedure TAboutDlg.DisplayCollectionInfo(ACollection: TCollection);
+var
+ HasEntries: Boolean;
- function AddHeading(const AHeading: string): TTreeNode;
- begin
- Result := tvCollectionInfo.Items.AddChild(nil, AHeading);
- end;
-
- procedure AddChild(const AParentNode: TTreeNode; const AData: string);
- begin
- tvCollectionInfo.Items.AddChild(AParentNode, AData);
- end;
-
- procedure AddItem(const AHeading, AData: string);
- var
- HeadingNode: TTreeNode;
+ function AddChild(const AParentNode: TTreeNode; const AData: string):
+ TTreeNode;
begin
- HeadingNode := AddHeading(AHeading);
- AddChild(HeadingNode, AData);
+ Result := tvCollectionInfo.Items.AddChild(AParentNode, AData);
+ HasEntries := True;
end;
- procedure AddItems(const AHeading: string; const AData: IStringList);
+ procedure AddChildren(const AParentNode: TTreeNode; const AData: IStringList);
var
- HeadingNode: TTreeNode;
DataItem: string;
begin
- HeadingNode := AddHeading(AHeading);
for DataItem in AData do
- AddChild(HeadingNode, DataItem);
+ AddChild(AParentNode, DataItem);
end;
var
- MetaData: IDBMetaData;
- Capabilities: TMetaDataCapabilities;
+ MetaData: TMetaData;
+ Capabilities: TMetaDataCaps;
HeadingNode: TTreeNode;
+ SubheadingNode: TTreeNode;
resourcestring
sVersionHeading = 'Version';
sLicenseHeading = 'License';
sCopyrightHeading = 'Copyright';
sContributorsHeading = 'Contributors';
- sTestersHeading = 'Testers';
+ sAcknowledgementsHeading = 'Acknowledgements';
sNoMetaData = 'No information available for this collection.';
+ sNotAvailable = 'Not specified';
+ sNone = 'None';
begin
tvCollectionInfo.Items.BeginUpdate;
try
tvCollectionInfo.Items.Clear;
- MetaData := TMetaDataFactory.CreateInstance(ACollection.Storage);
- Capabilities := MetaData.GetCapabilities;
+ HasEntries := False;
+ MetaData := ACollection.MetaData;
+ Capabilities := MetaData.Capabilities;
+
if Capabilities <> [] then
begin
- if mdcVersion in Capabilities then
- AddItem(sVersionHeading, MetaData.GetVersion);
- if mdcLicense in Capabilities then
+
+ if TMetaDataCap.Version in Capabilities then
begin
- HeadingNode := AddHeading(sLicenseHeading);
- AddChild(
- HeadingNode,
- StrIf(
- MetaData.GetLicenseInfo.Name <> '',
- MetaData.GetLicenseInfo.Name,
- MetaData.GetLicenseInfo.SPDX
- )
- );
- AddChild(HeadingNode, MetaData.GetLicenseInfo.URL);
+ HeadingNode := AddChild(nil, sVersionHeading);
+ if not MetaData.Version.IsNull then
+ AddChild(HeadingNode, MetaData.Version)
+ else
+ AddChild(HeadingNode, sNotAvailable);
end;
- if mdcCopyright in Capabilities then
+
+ if (TMetaDataCap.License in Capabilities) then
begin
- HeadingNode := AddHeading(sCopyrightHeading);
- AddChild(HeadingNode, MetaData.GetCopyrightInfo.Date);
- AddChild(HeadingNode, MetaData.GetCopyrightInfo.Holder);
- AddChild(HeadingNode, MetaData.GetCopyrightInfo.HolderURL);
+ HeadingNode := AddChild(nil, sLicenseHeading);
+ if not MetaData.LicenseInfo.IsNull then
+ begin
+ if not StrIsEmpty(MetaData.LicenseInfo.Name)
+ and not StrIsEmpty(MetaData.LicenseInfo.SPDX) then
+ AddChild(
+ HeadingNode,
+ StrIf(
+ MetaData.LicenseInfo.Name <> '',
+ MetaData.LicenseInfo.Name,
+ MetaData.LicenseInfo.SPDX
+ )
+ );
+ if not StrIsEmpty(MetaData.LicenseInfo.URL) then
+ AddChild(HeadingNode, MetaData.LicenseInfo.URL);
+ end
+ else
+ AddChild(HeadingNode, sNone);
end;
- if mdcContributors in Capabilities then
+
+ if TMetaDataCap.Copyright in Capabilities then
begin
- AddItems(sContributorsHeading, MetaData.GetContributors);
+ HeadingNode := AddChild(nil, sCopyrightHeading);
+ if not MetaData.CopyrightInfo.IsNull then
+ begin
+ if not StrIsEmpty(MetaData.CopyrightInfo.Date) then
+ AddChild(HeadingNode, MetaData.CopyrightInfo.Date);
+ if not StrIsEmpty(MetaData.CopyrightInfo.Holder) then
+ AddChild(HeadingNode, MetaData.CopyrightInfo.Holder);
+ if not StrIsEmpty(MetaData.CopyrightInfo.HolderURL) then
+ AddChild(HeadingNode, MetaData.CopyrightInfo.HolderURL);
+ if MetaData.CopyrightInfo.Contributors.Count > 0 then
+ begin
+ SubheadingNode := AddChild(HeadingNode, sContributorsHeading);
+ AddChildren(SubheadingNode, MetaData.CopyrightInfo.Contributors);
+ end;
+ end
+ else
+ AddChild(HeadingNode, sNone);
+ end;
+
+ if TMetaDataCap.Acknowledgements in Capabilities then
+ begin
+ HeadingNode := AddChild(nil, sAcknowledgementsHeading);
+ if MetaData.Acknowledgements.Count > 0 then
+ AddChildren(HeadingNode, MetaData.Acknowledgements)
+ else
+ AddChild(HeadingNode, sNone);
end;
- if mdcTesters in Capabilities then
- AddItems(sTestersHeading, MetaData.GetTesters);
end
+
else
+ AddChild(nil, sNoMetaData);
+
+ if HasEntries then
begin
- AddHeading(sNoMetaData);
+ tvCollectionInfo.FullExpand;
+ tvCollectionInfo.Items[0].MakeVisible;
end;
- tvCollectionInfo.FullExpand;
- tvCollectionInfo.Items[0].MakeVisible;
+
finally
tvCollectionInfo.Items.EndUpdate;
end;
From 452881df9b17af641c58a9fe28cade3dfe4c9fe9 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 2 Mar 2025 19:41:09 +0000
Subject: [PATCH 146/222] Change how TDBUpdateMgr validates updated DCSC files
Rather than use IDBMetaData the TDBUpdateMgr.ValidateUpdate now reads
the DCSC collection's VERSION file and uses its contents to validate.
The code now only accepts DCSC v2 files.
This change removes dependency on DB.UMetaData and DBIO.MetaData.DCSC
units.
---
Src/UDBUpdateMgr.pas | 40 ++++++++++++++++++++++++----------------
1 file changed, 24 insertions(+), 16 deletions(-)
diff --git a/Src/UDBUpdateMgr.pas b/Src/UDBUpdateMgr.pas
index 4119d9484..ea323882e 100644
--- a/Src/UDBUpdateMgr.pas
+++ b/Src/UDBUpdateMgr.pas
@@ -99,12 +99,12 @@ implementation
// Delphi
IOUtils,
// Project
- DB.UMetaData,
- DBIO.MetaData.DCSC,
UAppInfo,
UFileUpdater,
+ UIOUtils,
UStrUtils,
- UUtils;
+ UUtils,
+ UVersionInfo;
{ TDBUpdateMgr }
@@ -159,9 +159,14 @@ class procedure TDBUpdateMgr.ValidateUpdate(const UpdateDir: string);
sUnsupportedDatabaseError = 'Database in "%0:s" is version %1:s. This '
+ 'version is not currently supported by CodeSnip.';
sCurruptDatabaseError = 'The update database in "%s" is corrupt';
+const
+ VersionFileName = 'VERSION';
var
Dir: string;
- MetaData: IDBMetaData;
+ VersionFilePath: string;
+ VersionStr: string;
+ Version: TVersionNumber;
+
begin
Assert(UpdateDir <> '',
ClassName + '.ValidateUpdate: UpdateDir cannot be empty string');
@@ -192,23 +197,26 @@ class procedure TDBUpdateMgr.ValidateUpdate(const UpdateDir: string);
if TDirectory.IsEmpty(Dir) then
raise EDBUpdateValidationError.CreateFmt(sEmptyDirError, [Dir]);
- // Check contents
- MetaData := TUpdateDBMetaData.Create(Dir);
+ // Version file must exist
+ VersionFilePath := TPath.Combine(Dir, VersionFileName);
+ if not TFile.Exists(TPath.Combine(Dir, VersionFilePath)) then
+ raise EDBUpdateValidationError.Create(sInvalidDatabaseError);
- // check if data files are recognised as valid database
- if not MetaData.IsRecognised then
- raise EDBUpdateValidationError.CreateFmt(sUnrecognisedDatabaseError, [Dir]);
+ // Version file must contain a valid version string
+ VersionStr := TFileIO.ReadAllText(VersionFilePath, TEncoding.UTF8, True);
+ if not TVersionNumber.TryStrToVersionNumber(VersionStr, Version) then
+ raise EDBUpdateValidationError.CreateFmt(
+ sUnrecognisedDatabaseError, [Dir]
+ );
- // seems to be valid database: check if it's a supported version
- if not MetaData.IsSupportedVersion then
+ // Version must be supported
+ if Version.V1 <> 2 then
raise EDBUpdateValidationError.CreateFmt(
- sUnsupportedDatabaseError, [Dir, string(MetaData.GetVersion)]
+ sUnsupportedDatabaseError, [Dir, string(Version)]
);
- // database version supported: check if required meta data files and master db
- // file are present
- if MetaData.IsCorrupt
- or not TFile.Exists(Dir + PathDelim + 'categories.ini', False) then
+ // Master db file must exist
+ if not TFile.Exists(Dir + PathDelim + 'categories.ini', False) then
raise EDBUpdateValidationError.CreateFmt(sCurruptDatabaseError, [Dir]);
end;
From 1e5456eede6506ef775fbbe7b7a097e0548b20e7 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 2 Mar 2025 20:02:37 +0000
Subject: [PATCH 147/222] Change use of metadata in source code generation
Changed how source code comments are generated in USaveUnitMgr,
USnippetDoc and USnippetSourceGen units.
Rather than use IDBMetaData now gets the relevant metadata from the
appropriate collections' MetaData property.
This change removes dependency on the DB.UMetaData and
DBIO.MetaData.DCSC units in favour of DB.MetaData.
Some minor cosmetic changes were made to the presentation of metadata.
---
Src/USaveUnitMgr.pas | 24 +++++++++++++++---------
Src/USnippetDoc.pas | 19 ++++++++++---------
Src/USnippetSourceGen.pas | 18 ++++++++++--------
3 files changed, 35 insertions(+), 26 deletions(-)
diff --git a/Src/USaveUnitMgr.pas b/Src/USaveUnitMgr.pas
index dd9ba3b7d..92debb94c 100644
--- a/Src/USaveUnitMgr.pas
+++ b/Src/USaveUnitMgr.pas
@@ -104,8 +104,9 @@ implementation
SysUtils,
// Project
DB.DataFormats,
- DB.UMetaData,
+ DB.MetaData,
UAppInfo,
+ UStrUtils,
UUtils;
@@ -125,7 +126,7 @@ implementation
sMainGenerator = 'This unit snippet was generated by %0:s %1:s on %2:s.';
sCollection = 'The code was sourced from the %s collection.';
sCollectionList = 'The code was sourced from the following collections:';
- sCollectionCredit = 'Collection "%0:s" is licensed under the %1:s.';
+ sCollectionCredit = 'Collection "%0:s" is licensed under the %1:s';
// Output document title
sDocTitle = 'Pascal unit generated by %s';
@@ -148,19 +149,24 @@ procedure TSaveUnitMgr.CheckFileName(const FileName: string;
function TSaveUnitMgr.CreateHeaderComments: IStringList;
{TODO -cRefactoring: This code has a lot in common with header comment
- generator code in USnippetSourceGen - extract common code.}
+ generator code in USnippetSourceGen and in TSnippetDoc.CollectionInfo
+ - extract common code.}
function CreditsLine(const ACollection: TCollection): string;
var
- DBMetaData: IDBMetaData;
+ MetaData: TMetaData;
begin
- DBMetaData := TMetaDataFactory.CreateInstance(ACollection.Storage);
+ MetaData := ACollection.MetaData;
Result := '';
- if mdcLicense in DBMetaData.GetCapabilities then
+ if TMetaDataCap.License in MetaData.Capabilities then
begin
- Result := Result + DBMetaData.GetLicenseInfo.NameWithURL + '.';
- if (mdcCopyright in DBMetaData.GetCapabilities) then
- Result := Result + ' ' + DBMetaData.GetCopyrightInfo.ToString + '.';
+ Result := Result + StrMakeSentence(MetaData.LicenseInfo.NameWithURL);
+ end;
+ if TMetaDataCap.Copyright in MetaData.Capabilities then
+ begin
+ if not StrIsEmpty(Result) then
+ Result := Result + ' ';
+ Result := Result + StrMakeSentence(MetaData.CopyrightInfo.ToString);
end;
end;
diff --git a/Src/USnippetDoc.pas b/Src/USnippetDoc.pas
index 83b6a8640..0f19169e0 100644
--- a/Src/USnippetDoc.pas
+++ b/Src/USnippetDoc.pas
@@ -120,10 +120,9 @@ implementation
// Project
Compilers.UCompilers,
DB.DataFormats,
+ DB.MetaData,
DB.UMain,
- DB.UMetaData,
DB.USnippetKind,
- DBIO.MetaData.DCSC,
UStrUtils,
UUrl;
@@ -134,17 +133,19 @@ function TSnippetDoc.CollectionInfo(const ACollectionID: TCollectionID): string;
resourcestring
sCollectionInfo = 'A snippet from the "%s" collection.';
var
- MetaData: IDBMetaData;
+ MetaData: TMetaData;
Collection: TCollection;
begin
Collection := TCollections.Instance.GetCollection(ACollectionID);
- Result := Format(sCollectionInfo, [Collection.Name]);
- MetaData := TMetaDataFactory.CreateInstance(Collection.Storage);
- if mdcLicense in MetaData.GetCapabilities then
+ MetaData := Collection.MetaData;
+ Result := '';
+ if TMetaDataCap.License in MetaData.Capabilities then
+ Result := Result + StrMakeSentence(MetaData.LicenseInfo.NameWithURL);
+ if TMetaDataCap.Copyright in MetaData.Capabilities then
begin
- Result := Result + ' ' + MetaData.GetLicenseInfo.NameWithURL + '.';
- if (mdcCopyright in MetaData.GetCapabilities) then
- Result := Result + ' ' + MetaData.GetCopyrightInfo.ToString + '.';
+ if not StrIsEmpty(Result) then
+ Result := Result + ' ';
+ Result := Result + StrMakeSentence(MetaData.CopyrightInfo.ToString);
end;
end;
diff --git a/Src/USnippetSourceGen.pas b/Src/USnippetSourceGen.pas
index 388cac79e..e4b32be2f 100644
--- a/Src/USnippetSourceGen.pas
+++ b/Src/USnippetSourceGen.pas
@@ -20,8 +20,8 @@ interface
// Delphi
Generics.Collections,
// Project
+ DB.MetaData,
DB.UCollections,
- DB.UMetaData,
UBaseObjects,
UIStringList,
USourceGen,
@@ -97,10 +97,10 @@ implementation
DB.DataFormats,
DB.USnippet,
DB.USnippetKind,
- DBIO.MetaData.DCSC,
UConsts,
UAppInfo,
UQuery,
+ UStrUtils,
UUtils;
@@ -111,7 +111,7 @@ function TSnippetSourceGen.BuildHeaderComments: IStringList;
@return String list containing comments.
}
var
- DBMetaData: IDBMetaData;
+ MetaData: TMetaData;
Collection: TCollection;
Credits: string;
resourcestring
@@ -124,13 +124,15 @@ function TSnippetSourceGen.BuildHeaderComments: IStringList;
function CreditsLine(const ACollection: TCollection): string;
begin
- DBMetaData := TMetaDataFactory.CreateInstance(ACollection.Storage);
+ MetaData := ACollection.MetaData;
Result := '';
- if mdcLicense in DBMetaData.GetCapabilities then
+ if TMetaDataCap.License in MetaData.Capabilities then
+ Result := Result + StrMakeSentence(MetaData.LicenseInfo.NameWithURL);
+ if TMetaDataCap.Copyright in MetaData.Capabilities then
begin
- Result := Result + DBMetaData.GetLicenseInfo.NameWithURL + '.';
- if (mdcCopyright in DBMetaData.GetCapabilities) then
- Result := Result + ' ' + DBMetaData.GetCopyrightInfo.ToString + '.';
+ if not StrIsEmpty(Result) then
+ Result := Result + ' ';
+ Result := Result + StrMakeSentence(MetaData.CopyrightInfo.ToString);
end;
end;
From 9f8a0e6c865151a2998b9a63b7c269408824cec2 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Sun, 2 Mar 2025 20:07:29 +0000
Subject: [PATCH 148/222] Remove unused metadata units from project
The DB.UMetaData and DBIO.MetaData.DCSC units have been rendered
redundant. In most cases they have been replaced by use of the
DB.MetaData unit and the TCollection.MetaData property. In one case the
units were replaced by custom code.
---
Src/CodeSnip.dpr | 2 -
Src/CodeSnip.dproj | 2 -
Src/DB.UMetaData.pas | 447 --------------------
Src/DBIO.MetaData.DCSC.pas | 845 -------------------------------------
4 files changed, 1296 deletions(-)
delete mode 100644 Src/DB.UMetaData.pas
delete mode 100644 Src/DBIO.MetaData.DCSC.pas
diff --git a/Src/CodeSnip.dpr b/Src/CodeSnip.dpr
index 8bdcb5f3b..d179cdb10 100644
--- a/Src/CodeSnip.dpr
+++ b/Src/CodeSnip.dpr
@@ -66,7 +66,6 @@ uses
DB.UCategory in 'DB.UCategory.pas',
DB.UDatabaseIO in 'DB.UDatabaseIO.pas',
DB.UMain in 'DB.UMain.pas',
- DB.UMetaData in 'DB.UMetaData.pas',
DB.USnippet in 'DB.USnippet.pas',
DB.USnippetKind in 'DB.USnippetKind.pas',
DBIO.UFileIOIntf in 'DBIO.UFileIOIntf.pas',
@@ -378,7 +377,6 @@ uses
UTabSeparatedFileIO in 'UTabSeparatedFileIO.pas',
DBIO.UCategoryIO in 'DBIO.UCategoryIO.pas',
UCollectionListAdapter in 'UCollectionListAdapter.pas',
- DBIO.MetaData.DCSC in 'DBIO.MetaData.DCSC.pas',
FmCollectionBackup in 'FmCollectionBackup.pas' {CollectionBackupDlg},
DB.DataFormats in 'DB.DataFormats.pas',
DB.IO.DataFormat.Native in 'DB.IO.DataFormat.Native.pas',
diff --git a/Src/CodeSnip.dproj b/Src/CodeSnip.dproj
index 0b89e7d51..a08de9434 100644
--- a/Src/CodeSnip.dproj
+++ b/Src/CodeSnip.dproj
@@ -69,7 +69,6 @@
-
@@ -584,7 +583,6 @@
-
diff --git a/Src/DB.UMetaData.pas b/Src/DB.UMetaData.pas
deleted file mode 100644
index 0d0b6be76..000000000
--- a/Src/DB.UMetaData.pas
+++ /dev/null
@@ -1,447 +0,0 @@
-{
- * This Source Code Form is subject to the terms of the Mozilla Public License,
- * v. 2.0. If a copy of the MPL was not distributed with this file, You can
- * obtain one at https://mozilla.org/MPL/2.0/
- *
- * Copyright (C) 2020-2021, Peter Johnson (gravatar.com/delphidabbler).
- *
- * Declares interface and defines records required to support collection
- * metadata.
-}
-
-
-unit DB.UMetaData;
-
-
-interface
-
-
-uses
- // Delphi
- Generics.Collections,
- // Project
- DB.DataFormats,
- UIStringList,
- UVersionInfo;
-
-
-type
-
- TMetaDataCapability = (
- mdcVersion,
- mdcLicense,
- mdcCopyright,
- mdcContributors,
- mdcTesters {TODO -cView: rename as mdcAcknowledgements}
- );
-
- TMetaDataCapabilities = set of TMetaDataCapability;
-
- /// Record providing information about a collection's license.
- ///
- TDBLicenseInfo = record
- strict private
- fName: string;
- fSPDX: string;
- fURL: string;
- fText: string;
- public
- /// Record constructor: sets all fields of record.
- /// Any or all parameters may be the empty string
- constructor Create(const AName, ASPDX, AURL, AText: string);
-
- /// Creates and returns a null record with all fields set to the
- /// empty string.
- class function CreateNull: TDBLicenseInfo; static;
-
- /// Name of license.
- property Name: string read fName;
-
- /// Open Source Initiative SPDX short idenitifier for licenses.
- ///
- /// If the license is not supported by the Open Source Initiative
- /// then this property will be the empty string.
- property SPDX: string read fSPDX;
-
- /// URL of license online.
- /// Optional.
- property URL: string read fURL;
-
- /// Full text of license.
- property Text: string read fText;
-
- /// Returns a string containing license name followed by any URL
- /// in parentheses.
- /// If no URL is available then only the license name is returned.
- ///
- function NameWithURL: string;
- end;
-
- /// Record providing informaton about a collection's copyright.
- ///
- TDBCopyrightInfo = record
- strict private
- fDate: string;
- fHolder: string;
- fHolderURL: string;
- public
- /// Record constructor: sets all fields of record.
- /// Any or all parameters may be the empty string
- constructor Create(const ADate, AHolder, AHolderURL: string);
- /// Creates and returns a null record with all fields set to the
- /// empty string.
- class function CreateNull: TDBCopyrightInfo; static;
- /// Copyright date.
- /// May be a single year or a range: e.g. 2020 or 2012-2016.
- ///
- property Date: string read fDate;
- /// Name of copyright holder.
- property Holder: string read fHolder;
- /// URL of main copyright holder.
- /// Optional.
- property HolderURL: string read fHolderURL;
- /// Creates and returns a string representation of all the
- /// non-empty fields of the record.
- function ToString: string;
- end;
-
- /// Interface that provides information about any meta data
- /// supported by a collection.
- IDBMetaData = interface(IInterface)
- /// Returns information about what, if any, meta data is supported
- /// by a collection.
- function GetCapabilities: TMetaDataCapabilities;
- /// Returns the collection's version number.
- /// A null version number is returned if the collection does not
- /// include Version in its capabilities.
- function GetVersion: TVersionNumber;
- /// Returns the collection's license information.
- /// Return value is meaningless if the collection does not include
- /// License in its capabilities.
- function GetLicenseInfo: TDBLicenseInfo;
- /// Returns the collection's copyright informatiom.
- /// Return value is meaningless if the collection does not include
- /// Copyright in its capabilities.
- function GetCopyrightInfo: TDBCopyrightInfo;
- /// Returns a list of contributors to the collection.
- /// Return value is meaningless if the collection does not include
- /// Contributors in its capabilities.
- function GetContributors: IStringList;
- /// Returns a list of testers of the collection.
- /// Return value is meaningless if the collection does not include
- /// Testers in its capabilities.
- function GetTesters: IStringList;
- /// Checks if meta data is recognised as belonging to a valid
- /// collection, whether supported or not.
- function IsRecognised: Boolean;
- /// Checks if meta data is recognised as belonging to a supported
- /// collection version.
- function IsSupportedVersion: Boolean;
- /// Checks if meta data is corrupt.
- /// Should only be called if meta data belongs to a supported
- /// collection. An exception should be raised if called on unsupported
- /// versions.
- function IsCorrupt: Boolean;
- /// Refreshes the meta information by re-reading from collection
- /// meta files.
- procedure Refresh;
- end;
-
- /// Base class for all classes that implement IDBMetaData
- /// and can also be registered with TMetaDataFactory.
- TRegisterableMetaData = class abstract(TInterfacedObject)
- public
- /// Creates an instance of a concrete descendant of this class.
- ///
- /// TCollection [in] Collection associated
- /// with the meta data being created.
- /// IDBMetaData. Required meta data object.
- class function Instance(const AStorageDetails: TDataStorageDetails):
- IDBMetaData;
- virtual; abstract;
- /// Gets the meta data capabilities for the collection data
- /// format.
- /// TMetaDataCapabilities. Required meta data capabilities.
- ///
- /// This method enables meta data capabilities to be obtained
- /// without creating an instance of the object.
- class function Capabilities: TMetaDataCapabilities; virtual; abstract;
- /// Returns information about what, if any, meta data is supported
- /// by a collection.
- /// This method provides a means of accessing the data returned by
- /// the Capabilities class method from IDBMetaData instances.
- ///
- function GetCapabilities: TMetaDataCapabilities; virtual;
- end;
-
- TRegisterableMetaDataClass = class of TRegisterableMetaData;
-
- /// Advanced record manages the registration and creation of meta
- /// data objects for different collection data formats.
- TMetaDataFactory = record
- strict private
- class var
- {TODO -Refactor: rename fCallbackMap since it does not contain callback,
- but does contain class types.}
- /// Map of collection format kinds to classes that implement the
- /// format's meta data.
- fCallbackMap: TDictionary;
- public
- class constructor Create;
- class destructor Destroy;
- /// Registers a class type that can create a meta data object for
- /// a given collection data format kind.
- /// TCollectionFormatKind [in] Collection data
- /// format for which the meta data class is being registered.
- /// TRegisterableMetaDataClass [in] Type of
- /// class to create.
- class procedure RegisterCreator(AFormat: TDataFormatKind;
- AClass: TRegisterableMetaDataClass); static;
- /// Creates a meta data object instance that can read a given
- /// collection data format.
- /// TCollection [in] Collection for which
- /// meta data reader object is required.
- /// IDBMetaData. Requested object. May be a null object if
- /// no meta data class was registered for the data format associated with
- /// ACollection.
- class function CreateInstance(const AStorageDetails: TDataStorageDetails):
- IDBMetaData; static;
- /// Gets the meta data capabilities for a collection data format.
- ///
- /// TCollectionFormatKind [in] Collection data
- /// format for which meta data capabilities are required.
- /// TMetaDataCapabilities. Required meta data capabilities.
- ///
- class function CapabilitiesOf(const AFormat: TDataFormatKind):
- TMetaDataCapabilities; static;
- end;
-
-implementation
-
-uses
- // Delphi
- SysUtils,
- Character,
- // Project
- UConsts,
- UStrUtils;
-
-type
- /// Implements a null, do nothing, meta data object.
- /// Instance of this class are used when a collection format does
- /// not support meta data.
- TNullMetaData = class(TInterfacedObject, IDBMetaData)
- public
- /// Returns information about what, if any, meta data is supported
- /// by a collection.
- function GetCapabilities: TMetaDataCapabilities;
- /// Returns the collection's version number.
- /// A null version number is returned if the collection does not
- /// include Version in its capabilities.
- function GetVersion: TVersionNumber;
- /// Returns the collection's license information.
- /// Return value is meaningless if the collection does not include
- /// License in its capabilities.
- function GetLicenseInfo: TDBLicenseInfo;
- /// Returns the collection's copyright informatiom.
- /// Return value is meaningless if the collection does not include
- /// Copyright in its capabilities.
- function GetCopyrightInfo: TDBCopyrightInfo;
- /// Returns a list of contributors to the collection.
- /// Return value is meaningless if the collection does not include
- /// Contributors in its capabilities.
- function GetContributors: IStringList;
- /// Returns a list of testers of the collection.
- /// Return value is meaningless if the collection does not include
- /// Testers in its capabilities.
- function GetTesters: IStringList;
- /// Checks if meta data is recognised as belonging to a valid
- /// collection, whether supported or not.
- function IsRecognised: Boolean;
- /// Checks if meta data is recognised as belonging to a supported
- /// collection version.
- function IsSupportedVersion: Boolean;
- /// Checks if meta data is corrupt.
- /// Should only be called if meta data belongs to a supported
- /// collection. An exception should be raised if called on unsupported
- /// versions.
- function IsCorrupt: Boolean;
- /// Refreshes the meta information by re-reading from collection
- /// meta files.
- procedure Refresh;
- end;
-
-{ TDBLicenseInfo }
-
-constructor TDBLicenseInfo.Create(const AName, ASPDX, AURL, AText: string);
-
- function StandardiseStr(const AStr: string): string;
- begin
- Result := StrCompressWhiteSpace(
- StrReplaceChar(
- AStr,
- function(Ch: Char): Boolean
- begin
- Result := TCharacter.IsControl(Ch);
- end,
- ' '
- )
- );
- end;
-
-begin
- fName := StandardiseStr(AName);
- fSPDX := StandardiseStr(ASPDX);
- fURL := StandardiseStr(AURL);
- fText := StandardiseStr(AText);
-end;
-
-class function TDBLicenseInfo.CreateNull: TDBLicenseInfo;
-begin
- Result := TDBLicenseInfo.Create('', '', '', '');
-end;
-
-function TDBLicenseInfo.NameWithURL: string;
-begin
- Result := fName;
- if fURL <> '' then
- Result := Result + ' (' + fURL + ')';
-end;
-
-{ TDBCopyrightInfo }
-
-constructor TDBCopyrightInfo.Create(const ADate, AHolder, AHolderURL: string);
-begin
- fDate := ADate;
- fHolder := AHolder;
- fHolderURL := AHolderURL;
-end;
-
-class function TDBCopyrightInfo.CreateNull: TDBCopyrightInfo;
-begin
- Result := TDBCopyrightInfo.Create('', '', '');
-end;
-
-function TDBCopyrightInfo.ToString: string;
-resourcestring
- sCopyright = 'Copyright';
-begin
- Result := '';
- if Date <> '' then
- Result := Result + '(C) ' + Date;
- if Holder <> '' then
- begin
- if Result <> '' then
- Result := Result + ', ';
- Result := Result + Holder;
- end;
- if HolderURL <> '' then
- begin
- if Result <> '' then
- Result := Result + ', ';
- Result := Result + HolderURL;
- end;
- if Result <> '' then
- Result := sCopyright + ' ' + Result;
-end;
-
-{ TRegisterableMetaData }
-
-function TRegisterableMetaData.GetCapabilities: TMetaDataCapabilities;
-begin
- Result := Capabilities;
-end;
-
-{ TMetaDataFactory }
-
-class function TMetaDataFactory.CapabilitiesOf(
- const AFormat: TDataFormatKind): TMetaDataCapabilities;
-begin
- if fCallbackMap.ContainsKey(AFormat) then
- Result := fCallbackMap[AFormat].Capabilities
- else
- Result := [];
-end;
-
-class constructor TMetaDataFactory.Create;
-begin
- fCallbackMap := TDictionary<
- TDataFormatKind, TRegisterableMetaDataClass
- >.Create;
-end;
-
-class function TMetaDataFactory.CreateInstance(
- const AStorageDetails: TDataStorageDetails): IDBMetaData;
-begin
- if fCallbackMap.ContainsKey(AStorageDetails.Format) then
- Result := fCallbackMap[AStorageDetails.Format].Instance(AStorageDetails)
- else
- Result := TNullMetaData.Create;
-end;
-
-class destructor TMetaDataFactory.Destroy;
-begin
- fCallBackMap.Free;
-end;
-
-class procedure TMetaDataFactory.RegisterCreator(
- AFormat: TDataFormatKind; AClass: TRegisterableMetaDataClass);
-begin
- fCallbackMap.AddOrSetValue(AFormat, AClass);
-end;
-
-{ TNullMetaData }
-
-function TNullMetaData.GetCapabilities: TMetaDataCapabilities;
-begin
- Result := [];
-end;
-
-function TNullMetaData.GetContributors: IStringList;
-begin
- Result := TIStringList.Create;
-end;
-
-function TNullMetaData.GetCopyrightInfo: TDBCopyrightInfo;
-begin
- Result := TDBCopyrightInfo.CreateNull;
-end;
-
-function TNullMetaData.GetLicenseInfo: TDBLicenseInfo;
-begin
- Result := TDBLicenseInfo.CreateNull;
-end;
-
-function TNullMetaData.GetTesters: IStringList;
-begin
- Result := TIStringList.Create;
-end;
-
-function TNullMetaData.GetVersion: TVersionNumber;
-begin
- Result := TVersionNumber.Nul;
-end;
-
-function TNullMetaData.IsCorrupt: Boolean;
-resourcestring
- sNotSupportedError = 'Can''t call IDBMetaData.IsCorrupt for null meta data';
-begin
- raise ENotSupportedException.Create(sNotSupportedError);
-end;
-
-function TNullMetaData.IsRecognised: Boolean;
-begin
- Result := False;
-end;
-
-function TNullMetaData.IsSupportedVersion: Boolean;
-begin
- Result := False;
-end;
-
-procedure TNullMetaData.Refresh;
-begin
- // Do nothing
-end;
-
-end.
diff --git a/Src/DBIO.MetaData.DCSC.pas b/Src/DBIO.MetaData.DCSC.pas
deleted file mode 100644
index 85052f55b..000000000
--- a/Src/DBIO.MetaData.DCSC.pas
+++ /dev/null
@@ -1,845 +0,0 @@
-{
- * This Source Code Form is subject to the terms of the Mozilla Public License,
- * v. 2.0. If a copy of the MPL was not distributed with this file, You can
- * obtain one at https://mozilla.org/MPL/2.0/
- *
- * Copyright (C) 2024, Peter Johnson (gravatar.com/delphidabbler).
- *
- * Loads and vaildates meta data supported by the DelphiDabbler Code Snippets
- * Collection.
-}
-
-
-unit DBIO.MetaData.DCSC;
-
-interface
-
-{TODO -cVault: Remove support for main database v1 (and perhaps v>2)}
-
-{
- Notes About Database Versions And Meta Files.
- =============================================
-
- Versions
- --------
-
- v1 of the Code Snippets Database was not considered to have a version number
- until the arrival of v2. Therefore v1 did not have any means of identifying
- its version number. Although the database format changed slightly over time
- there is not enough historical information to identify different minor
- releases, so all are considered to be v1.0.0.0
-
- Database v2 has a VERSION file that specifies the version number as a dotted
- quad, of the form v2.0.0.0.
-
- Note that semantic versioning is now being used so any database with major
- version 2 will be backwards compatible with earlier v2 minor release.
-
- If a breaking change is introduced the major version will be bumped to v3 and
- so on.
-
- Meta Files
- ----------
-
- Database v1 had only two meta files:
- + contrib.txt - lists of contributors to the database, one per line
- + testers.txt - lists of database testers, one per line
- If those two files are present the database is assumed to be v1
-
- Database v2 has the following meta files:
- + VERSION - version number (v2.x.x.x)
- + CONTRIBUTORS - lists of contributors to the database, one per line
- + TESTERS - lists of database testers, one per line
- + LICENSE - full text of the license that applies to the snippets
- + LICENSE-INFO - furter information about the license
-
- For database v1 the license text, license information are hard-wired in the
- absence of meta files. As noted above the version number is deduced.
-
- File encoding
- -------------
-
- All meta files are plain text.
-
- Early v1 database meta files were encoded in the system default encoding.
- Later v1 databases encoded meta files in UTF-8. To distinguish between UTF-8
- and default encoded files the UTF-8 files use the UTF-8 preamble (BOM).
-
- v2 database meta files are all encoded in UTF-8 with preamble (BOM).
-
- Future major versions
- ---------------------
-
- Future major database releases MUST include backwards compatibility with
- earlier versions of CodeSnip in as much as those versions must be able to
- easily detect and reject the format.
-
- To achieve this new major releases MUST include a VERSION file encoded in
- UTF-8 with BOM. Existing code can detect and will reject any unsupported
- version.
-
- CodeSnip support
- ----------------
-
- CodeSnip versions earlier than v4.16 are only ever delivered v1 database files
- via their built in web update code. There is no way for these versions to
- access v2 databases.
-
- CodeSnip from v4.16 get their main snippets database from files downloaded
- manually. All such databases are v2. CodeSnip v4.16 also supports v1 format
- because such a database may be resident on the user's computer at install
- time.
-}
-
-
-
-uses
- // Project
- SysUtils,
- Types,
- // VCL
- DB.DataFormats,
- DB.UMetaData,
- UIStringList,
- UStructs,
- UVersionInfo;
-
-
-const
- DBValidVersions: TRange = (Min: 1; Max: 2);
-
-type
-
- /// Provides names of meta data files supported by various database
- /// versions.
- TDBMetaFileNames = record
- public
- const
- ContributorsV1 = 'contrib.txt';
- TestersV1 = 'testers.txt';
- VersionV2AndLater = 'VERSION';
- LicenseV2 = 'LICENSE';
- LicenseInfoV2 = 'LICENSE-INFO';
- ContributorsV2 = 'CONTRIBUTORS';
- TestersV2 = 'TESTERS';
- end;
-
- /// Abstract base class for classes that access or emulate database
- /// meta data files.
- TDBMetaFiles = class abstract(TObject)
- strict private
- var
- /// Directory of database for which meta data files are being
- /// accessed.
- fDBDir: string;
- /// Returns encoding used by given meta file.
- function GetFileEncoding(const FileName: TFileName): TEncoding;
- strict protected
- /// Makes a fully specified path to a given database file.
- ///
- /// FileName must contain no path information.
- function MakePath(const FileName: string): string;
- /// Checks if a given file exists in database directory.
- function DBFileExists(const FileName: string): Boolean;
- /// Reads all lines from given file and returns them as an array.
- ///
- /// FileName must contain no path information.
- function ReadFileLines(const FileName: TFileName): TStringDynArray;
- /// Reads all text from given file and returns it.
- /// FileName must contain no path information.
- function ReadFileText(const FileName: TFileName): string;
- public
- /// Constructs object that accesses meta data database files in
- /// given directory.
- constructor Create(const DBDir: string);
- /// Returns text of the version file, or surrogate value.
- ///
- function Version: string; virtual; abstract;
- /// Returns content license text file or surrogate value.
- ///
- function LicenseText: string; virtual; abstract;
- /// Returns lines of license information file or surrogate value.
- ///
- function LicenseInfo: TStringDynArray; virtual; abstract;
- /// Returns lines of contributors file or surrogate value.
- ///
- function Contributors: TStringDynArray; virtual; abstract;
- /// Returns lines of testers file or surrogate value.
- function Testers: TStringDynArray; virtual; abstract;
- /// Checks if all the expected meta files are present. Returns
- /// True if so or False if not.
- /// ENotSupportedException must be raised if called on an
- /// unsupported database version.
- function AreAllFilesPresent: Boolean; virtual; abstract;
- end;
-
- /// Class that accesses content of version 1 main database meta data
- /// files.
- /// Not all meta files are present in version main databases so
- /// invariant placeholder content is provided to substitute for missing
- /// files.
- TV1DBMetaFiles = class sealed(TDBMetaFiles)
- strict private
- const
- cContributorsFile = TDBMetaFileNames.ContributorsV1;
- cTestersFile = TDBMetaFileNames.TestersV1;
- public
- /// Returns an surrogate, invariant value of 1 for the version
- /// number.
- /// No version file exists for this database version. The value
- /// returned is deduced using documentation from the current code snippets
- /// database project.
- function Version: string; override;
- /// Returns an surrogate, invariant value for the license text.
- ///
- /// No license text file exists for this database version. The
- /// value returned is based on documentation of the database.
- function LicenseText: string; override;
- /// Returns an surrogate, invariant value for the lines of license
- /// information.
- function LicenseInfo: TStringDynArray; override;
- /// Returns the lines of the contributors file.
- function Contributors: TStringDynArray; override;
- /// Returns the lines of the testers file.
- function Testers: TStringDynArray; override;
- /// Checks if all the expected meta files are present. Returns
- /// True if so or False if not.
- function AreAllFilesPresent: Boolean; override;
- end;
-
- /// Class that accesses content of supported version 2 main database
- /// meta files.
- TV2DBMetaFiles = class sealed(TDBMetaFiles)
- strict private
- const
- cVersionFile = TDBMetaFileNames.VersionV2AndLater;
- cLicenseFile = TDBMetaFileNames.LicenseV2;
- cLicenseInfoFile = TDBMetaFileNames.LicenseInfoV2;
- cContributorsFile = TDBMetaFileNames.ContributorsV2;
- cTestersFile = TDBMetaFileNames.TestersV2;
- public
- /// Returns the contents of the version file.
- function Version: string; override;
- /// Returns the contents of the license text file.
- function LicenseText: string; override;
- /// Returns the lines of the license info file.
- function LicenseInfo: TStringDynArray; override;
- /// Returns the lines of the contributors file.
- function Contributors: TStringDynArray; override;
- /// Returns the lines of the testers file.
- function Testers: TStringDynArray; override;
- /// Checks if all the expected meta files are present. Returns
- /// True if so or False if not.
- function AreAllFilesPresent: Boolean; override;
- end;
-
- /// Class that represents later versions of database meta file
- /// formats.
- /// These formats have a valid version file but the version is not
- /// supported and nothing is known about any other meta data files.
- TLaterDBMetaFiles = class sealed(TDBMetaFiles)
- strict private
- const
- cVersionFile = TDBMetaFileNames.VersionV2AndLater;
- public
- /// Returns the contents of the version file.
- function Version: string; override;
- /// Returns the empty string.
- /// The file format is unknown, so the license text file cannot be
- /// read and there is no information to deduce the value.
- function LicenseText: string; override;
- /// Returns an empty string array.
- /// The file format is unknown, so the license information file
- /// cannot be read and there is no information to deduce the value.
- ///
- function LicenseInfo: TStringDynArray; override;
- /// Returns an empty string array.
- /// The file format is unknown, so the contributors file cannot be
- /// read and there is no information to deduce the value.
- function Contributors: TStringDynArray; override;
- /// Returns an empty string array.
- /// The file format is unknown, so the testers file cannot be read
- /// and there is no information to deduce the value.
- function Testers: TStringDynArray; override;
- /// Checks if all the expected meta files are present only if
- /// the meta files come from a supported database format.
- /// ENotSupportedException always raised since there is no way
- /// of knowing what files should be present in an unsupported database
- /// format.
- function AreAllFilesPresent: Boolean; override;
- end;
-
- /// Class that is present to represent unknown database meta file
- /// formats. Also used when database is not present.
- /// Accesses no files and returns null results for all methods
- /// except IsVersionSupported.
- TUnknownOrMissingMetaFiles = class sealed(TDBMetaFiles)
- public
- /// Returns the empty string.
- /// The file format is unknown, so the version file cannot be read
- /// and there is no information to deduce the value.
- function Version: string; override;
- /// Returns the empty string.
- /// The file format is unknown, so the license text file cannot be
- /// read and there is no information to deduce the value.
- function LicenseText: string; override;
- /// Returns an empty string array.
- /// The file format is unknown, so the license information file
- /// cannot be read and there is no information to deduce the value.
- ///
- function LicenseInfo: TStringDynArray; override;
- /// Returns an empty string array.
- /// The file format is unknown, so the contributors file cannot be
- /// read and there is no information to deduce the value.
- function Contributors: TStringDynArray; override;
- /// Returns an empty string array.
- /// The file format is unknown, so the testers file cannot be read
- /// and there is no information to deduce the value.
- function Testers: TStringDynArray; override;
- /// Checks if all the expected meta files are present only if
- /// the meta files come from a supported database format.
- /// ENotSupportedException always raised since there is no way
- /// of knowing what files should be present in an unrecognised database
- /// format.
- function AreAllFilesPresent: Boolean; override;
- end;
-
- /// Factory to create the correct instance of database meta file
- /// classes that can read the version of a database in a given folder.
- ///
- TDBMetaFilesFactory = record
- public
- class function GetInstance(const DBDir: string): TDBMetaFiles;
- static;
- end;
-
- /// Abstract base class for classes that provide main database meta
- /// data.
- TAbstractMainDBMetaData = class abstract(TRegisterableMetaData)
- strict private
- var
- fMetaFiles: TDBMetaFiles;
- fIsVersionLoaded: Boolean;
- fVersion: TVersionNumber;
- fIsLicenseAndCopyrightInfoLoaded: Boolean;
- fLicenseInfo: TDBLicenseInfo;
- fCopyrightInfo: TDBCopyrightInfo;
- fContributors: IStringList;
- fTesters: IStringList;
-
- procedure LoadLicenseAndCopyrightInfo;
-
- strict protected
- function GetDBDir: string; virtual; abstract;
- public
- /// Creates an instance of meta data object that can read this
- /// collection's format.
- /// Must be called from a concrete descendant class.
- class function Instance(const AStorageDetails: TDataStorageDetails):
- IDBMetaData; override;
- /// Gets the meta data capabilities for the collection data
- /// format.
- /// TMetaDataCapabilities. Required meta data capabilities.
- ///
- /// This method enables meta data capabilities to be obtained
- /// without creating an instance of the object.
- class function Capabilities: TMetaDataCapabilities; override;
- procedure AfterConstruction; override;
- destructor Destroy; override;
- /// Returns database version number.
- ///
- /// A null version number is returned if the meta data does not come
- /// from a recognised database.
- /// Method of IDBMetaData.
- ///
- function GetVersion: TVersionNumber;
- /// Returns database license information.
- ///
- /// Return value is meaningless if the meta data does not come
- /// from a supported database.
- /// Method of IDBMetaData.
- ///
- function GetLicenseInfo: TDBLicenseInfo;
- /// Returns database copyright informatiom.
- ///
- /// Return value is meaningless if the meta data does not come
- /// from a supported database.
- /// Method of IDBMetaData.
- ///
- function GetCopyrightInfo: TDBCopyrightInfo;
- /// Returns list of contributors to database.
- ///
- /// Return value is meaningless if the meta data does not come
- /// from a supported database.
- /// Method of IDBMetaData.
- ///
- function GetContributors: IStringList;
- /// Returns list of testers of database.
- ///
- /// Return value is meaningless if the meta data does not come
- /// from a supported database.
- /// Method of IDBMetaData.
- ///
- function GetTesters: IStringList;
- /// Checks if meta data is recognised as belonging to a valid
- /// database, whether supported or not.
- /// Method of IDBMetaData.
- function IsRecognised: Boolean;
- /// Checks if meta data is recognised as belonging to a supported
- /// database version.
- /// Method of IDBMetaData.
- function IsSupportedVersion: Boolean;
- /// Checks if meta data is corrupt.
- ///
- /// Should only be called if meta data belongs to a supported
- /// database.
- /// Method of IDBMetaData.
- ///
- /// ENotSupportedException raised if called on an unsupported
- /// database.
- function IsCorrupt: Boolean;
- /// Refreshes the meta information by re-reading from database
- /// meta files.
- /// Method of IDBMetaData.
- procedure Refresh;
- end;
-
- /// Class that provides meta data for the main database.
- TMainDBMetaData = class sealed(TAbstractMainDBMetaData, IDBMetaData)
- strict private
- var
- fDirectory: string;
- strict protected
- function GetDBDir: string; override;
- public
- constructor Create(const ADirectory: string);
- end;
-
- /// Class that provides meta data for update database directories.
- ///
- TUpdateDBMetaData = class sealed(TAbstractMainDBMetaData, IDBMetaData)
- strict private
- var
- fUpdateDir: string;
- strict protected
- function GetDBDir: string; override;
- public
- constructor Create(const UpdateDir: string);
- end;
-
-implementation
-
-uses
- // Delphi
- Classes,
- IOUtils,
- // Project
- UEncodings,
- UIOUtils,
- UResourceUtils,
- UStrUtils;
-
-{ TAbstractMainDBMetaData }
-
-procedure TAbstractMainDBMetaData.AfterConstruction;
-begin
- inherited;
- Refresh;
-end;
-
-class function TAbstractMainDBMetaData.Capabilities: TMetaDataCapabilities;
-begin
- Result := [mdcVersion, mdcLicense, mdcCopyright, mdcContributors, mdcTesters];
-end;
-
-destructor TAbstractMainDBMetaData.Destroy;
-begin
- fMetaFiles.Free;
- inherited;
-end;
-
-function TAbstractMainDBMetaData.GetContributors: IStringList;
-begin
- if not Assigned(fContributors) then
- fContributors := TIStringList.Create(fMetaFiles.Contributors);
- Result := fContributors;
-end;
-
-function TAbstractMainDBMetaData.GetCopyrightInfo: TDBCopyrightInfo;
-begin
- if not fIsLicenseAndCopyrightInfoLoaded then
- LoadLicenseAndCopyrightInfo;
- Result := fCopyrightInfo;
-end;
-
-function TAbstractMainDBMetaData.GetLicenseInfo: TDBLicenseInfo;
-begin
- if not fIsLicenseAndCopyrightInfoLoaded then
- LoadLicenseAndCopyrightInfo;
- Result := fLicenseInfo;
-end;
-
-function TAbstractMainDBMetaData.GetTesters: IStringList;
-begin
- if not Assigned(fTesters) then
- fTesters := TIStringList.Create(fMetaFiles.Testers);
- Result := fTesters;
-end;
-
-function TAbstractMainDBMetaData.GetVersion: TVersionNumber;
-begin
- if not fIsVersionLoaded then
- begin
- if not TVersionNumber.TryStrToVersionNumber(
- StrTrim(fMetaFiles.Version), fVersion
- ) then
- fVersion := TVersionNumber.Nul;
- end;
- fIsVersionLoaded := True;
- Result := fVersion;
-end;
-
-class function TAbstractMainDBMetaData.Instance(
- const AStorageDetails: TDataStorageDetails): IDBMetaData;
-begin
- Result := TMainDBMetaData.Create(AStorageDetails.Directory);
-end;
-
-function TAbstractMainDBMetaData.IsCorrupt: Boolean;
-resourcestring
- sNotSupportedError = 'Can''t call IDBMetaData.IsCorrupt for an unsupported '
- + 'database version';
-begin
- if not IsSupportedVersion then
- raise ENotSupportedException.Create(sNotSupportedError);
- Result := not fMetaFiles.AreAllFilesPresent;
-end;
-
-function TAbstractMainDBMetaData.IsRecognised: Boolean;
-begin
- Result := not GetVersion.IsNull;
-end;
-
-function TAbstractMainDBMetaData.IsSupportedVersion: Boolean;
-var
- ThisVersion: TVersionNumber;
-begin
- ThisVersion := GetVersion;
- Result := DBValidVersions.Contains(ThisVersion.V1);
-end;
-
-procedure TAbstractMainDBMetaData.LoadLicenseAndCopyrightInfo;
-var
- SL: TStringList;
-begin
- if fIsLicenseAndCopyrightInfoLoaded then
- Exit;
- SL := TStringList.Create;
- try
- StrArrayToStrList(fMetaFiles.LicenseInfo, SL);
- fLicenseInfo := TDBLicenseInfo.Create(
- SL.Values['LicenseName'],
- SL.Values['LicenseSPDX'],
- SL.Values['LicenseURL'],
- fMetaFiles.LicenseText
- );
- fCopyrightInfo := TDBCopyrightInfo.Create(
- SL.Values['CopyrightDate'],
- SL.Values['CopyrightHolder'],
- SL.Values['CopyrightHolderURL']
- );
- finally
- SL.Free;
- end;
- fIsLicenseAndCopyrightInfoLoaded := True;
-end;
-
-procedure TAbstractMainDBMetaData.Refresh;
-begin
- FreeAndNil(fMetaFiles);
- fMetaFiles := TDBMetaFilesFactory.GetInstance(GetDBDir);
- fIsVersionLoaded := False;
- fIsLicenseAndCopyrightInfoLoaded := False;
- fContributors := nil;
- fTesters := nil;
-end;
-
-{ TMainDBMetaData }
-
-constructor TMainDBMetaData.Create(const ADirectory: string);
-begin
- inherited Create;
- fDirectory := ADirectory;
-end;
-
-function TMainDBMetaData.GetDBDir: string;
-begin
- Result := fDirectory;
-end;
-
-{ TUpdateDBMetaData }
-
-constructor TUpdateDBMetaData.Create(const UpdateDir: string);
-begin
- inherited Create;
- fUpdateDir := ExcludeTrailingPathDelimiter(UpdateDir);
-end;
-
-function TUpdateDBMetaData.GetDBDir: string;
-begin
- Result := fUpdateDir;
-end;
-
-{ TDBMetaFiles }
-
-constructor TDBMetaFiles.Create(const DBDir: string);
-begin
- inherited Create;
- fDBDir := DBDir;
-end;
-
-function TDBMetaFiles.DBFileExists(const FileName: string): Boolean;
-begin
- Result := TFile.Exists(MakePath(FileName), False);
-end;
-
-function TDBMetaFiles.GetFileEncoding(const FileName: TFileName): TEncoding;
-begin
- // Old v1 database meta files may be in the system default encodings, v1 and
- // all v2 and later use UTF-8 with BOM.
- if TFileIO.CheckBOM(MakePath(FileName), TEncoding.UTF8) then
- Result := TEncoding.UTF8
- else
- Result := TEncoding.Default;
-end;
-
-function TDBMetaFiles.MakePath(const FileName: string): string;
-begin
- Assert(not StrContainsStr(PathDelim, FileName),
- ClassName + '.MakePath: FileName must be a base file name.');
- Result := IncludeTrailingPathDelimiter(fDBDir) + FileName;
-end;
-
-function TDBMetaFiles.ReadFileLines(const FileName: TFileName): TStringDynArray;
-var
- Encoding: TEncoding;
-begin
- if not DBFileExists(FileName) then
- begin
- SetLength(Result, 0);
- Exit;
- end;
- Encoding := GetFileEncoding(FileName);
- try
- Result := TFileIO.ReadAllLines(MakePath(FileName), Encoding, True);
- finally
- TEncodingHelper.FreeEncoding(Encoding);
- end;
-end;
-
-function TDBMetaFiles.ReadFileText(const FileName: TFileName): string;
-begin
- if not DBFileExists(FileName) then
- Exit('');
- Result := TFileIO.ReadAllText(
- MakePath(FileName), GetFileEncoding(FileName), True
- );
-end;
-
-{ TV1DBMetaFiles }
-
-function TV1DBMetaFiles.AreAllFilesPresent: Boolean;
-begin
- Result := DBFileExists(cContributorsFile) and DBFileExists(cTestersFile);
-end;
-
-function TV1DBMetaFiles.Contributors: TStringDynArray;
-begin
- Result := ReadFileLines(cContributorsFile)
-end;
-
-function TV1DBMetaFiles.LicenseInfo: TStringDynArray;
-begin
- Result := TStringDynArray.Create(
- 'LicenseName=MIT License',
- 'LicenseSPDX=MIT',
- 'LicenseURL=https://opensource.org/licenses/MIT',
- 'CopyrightDate=2005-2016',
- 'CopyrightHolder=Peter Johnson & Contributors',
- 'CopyrightHolderURL=https://gravatar.com/delphidabbler'
- );
-end;
-
-function TV1DBMetaFiles.LicenseText: string;
-begin
- Result := LoadResourceAsString(HInstance, 'CSDBLICENSE', RT_RCDATA, etUTF8);
-end;
-
-function TV1DBMetaFiles.Testers: TStringDynArray;
-begin
- Result := ReadFileLines(cTestersFile);
-end;
-
-function TV1DBMetaFiles.Version: string;
-begin
- Result := '1';
-end;
-
-{ TV2DBMetaFiles }
-
-function TV2DBMetaFiles.AreAllFilesPresent: Boolean;
-begin
- Result := DBFileExists(cVersionFile)
- and DBFileExists(cLicenseFile)
- and DBFileExists(cLicenseInfoFile)
- and DBFileExists(cContributorsFile)
- and DBFileExists(cTestersFile);
-end;
-
-function TV2DBMetaFiles.Contributors: TStringDynArray;
-begin
- Result := ReadFileLines(cContributorsFile);
-end;
-
-function TV2DBMetaFiles.LicenseInfo: TStringDynArray;
-begin
- Result := ReadFileLines(cLicenseInfoFile);
-end;
-
-function TV2DBMetaFiles.LicenseText: string;
-begin
- Result := StrTrimRight(ReadFileText(cLicenseFile));
-end;
-
-function TV2DBMetaFiles.Testers: TStringDynArray;
-begin
- Result := ReadFileLines(cTestersFile);
-end;
-
-function TV2DBMetaFiles.Version: string;
-begin
- Result := StrTrim(ReadFileText(cVersionFile));
-end;
-
-{ TLaterDBMetaFiles }
-
-function TLaterDBMetaFiles.AreAllFilesPresent: Boolean;
-resourcestring
- sNotSupportedError = 'Calling %s.AreAllFilesPresent is not supported for an '
- + 'unsupported database format';
-begin
- raise ENotSupportedException.CreateFmt(sNotSupportedError, [ClassName]);
-end;
-
-function TLaterDBMetaFiles.Contributors: TStringDynArray;
-begin
- SetLength(Result, 0);
-end;
-
-function TLaterDBMetaFiles.LicenseInfo: TStringDynArray;
-begin
- SetLength(Result, 0);
-end;
-
-function TLaterDBMetaFiles.LicenseText: string;
-begin
- Result := '';
-end;
-
-function TLaterDBMetaFiles.Testers: TStringDynArray;
-begin
- SetLength(Result, 0);
-end;
-
-function TLaterDBMetaFiles.Version: string;
-begin
- Result := StrTrim(ReadFileText(cVersionFile));
-end;
-
-{ TUnknownOrMissingMetaFiles }
-
-function TUnknownOrMissingMetaFiles.AreAllFilesPresent: Boolean;
-resourcestring
- sNotSupportedError = 'Calling %s.AreAllFilesPresent is not supported for an '
- + 'unrecognised database format or missing database';
-begin
- raise ENotSupportedException.CreateFmt(sNotSupportedError, [ClassName]);
-end;
-
-function TUnknownOrMissingMetaFiles.Contributors: TStringDynArray;
-begin
- SetLength(Result, 0);
-end;
-
-function TUnknownOrMissingMetaFiles.LicenseInfo: TStringDynArray;
-begin
- SetLength(Result, 0);
-end;
-
-function TUnknownOrMissingMetaFiles.LicenseText: string;
-begin
- Result := '';
-end;
-
-function TUnknownOrMissingMetaFiles.Testers: TStringDynArray;
-begin
- SetLength(Result, 0);
-end;
-
-function TUnknownOrMissingMetaFiles.Version: string;
-begin
- Result := '';
-end;
-
-{ TDBMetaFilesFactory }
-
-class function TDBMetaFilesFactory.GetInstance(const DBDir: string):
- TDBMetaFiles;
-var
- VersionFile: string;
- VersionStr: string;
- Version: TVersionNumber;
- DBPath: string;
-begin
- if not TDirectory.Exists(ExcludeTrailingPathDelimiter(DBDir)) then
- // Database is not installed
- Exit(TUnknownOrMissingMetaFiles.Create(DBDir));
-
- DBPath := IncludeTrailingPathDelimiter(DBDir);
-
- // Check if VERSION file exists:
- // Yes:
- // either: version is invalid - database format unknown
- // or: version is 2.x.x.x - database format v2 recognised
- // or: version is >2 - database format recognised but not supported
- // No:
- // either: expected v1 meta files exist - database format v1 recognised
- // or: no v1 meta files - database format unknown
- VersionFile := DBPath + TDBMetaFileNames.VersionV2AndLater;
- if TFile.Exists(VersionFile, False) then
- begin
- VersionStr := TFileIO.ReadAllText(VersionFile, TEncoding.UTF8, True);
- if not TVersionNumber.TryStrToVersionNumber(VersionStr, Version) then
- Result := TUnknownOrMissingMetaFiles.Create(DBDir)
- else if Version.V1 = 2 then
- Result := TV2DBMetaFiles.Create(DBDir)
- else
- Result := TLaterDBMetaFiles.Create(DBDir);
- end
- else
- begin
- if TFile.Exists(DBPath + TDBMetaFileNames.ContributorsV1, False)
- and TFile.Exists(DBPath + TDBMetaFileNames.TestersV1, False) then
- Result := TV1DBMetaFiles.Create(DBDir)
- else
- Result := TUnknownOrMissingMetaFiles.Create(DBDir);
- end;
-end;
-
-initialization
-
-TMetaDataFactory.RegisterCreator(
- TDataFormatKind.DCSC_v2, TMainDBMetaData
-);
-
-end.
From cbc4c578e227695556cfedbfb6b00e0e341a5853 Mon Sep 17 00:00:00 2001
From: delphidabbler <5164283+delphidabbler@users.noreply.github.com>
Date: Mon, 3 Mar 2025 08:28:42 +0000
Subject: [PATCH 149/222] Rename TCollectionID as TVaultID
Made minimal changes affected code in order to allow compilation to
succeed.
Updated many comments re those minimal changes.
---
Src/DB.UCollections.pas | 126 ++++++++++++++++----------------
Src/DB.UMain.pas | 101 ++++++++++++-------------
Src/DB.USnippet.pas | 45 ++++++------
Src/Favourites.UPersist.pas | 4 +-
Src/FmAboutDlg.dfm | 12 +++
Src/FmAboutDlg.pas | 2 +-
Src/FmCodeImportDlg.dfm | 16 ++++
Src/FmCodeImportDlg.pas | 12 +--
Src/FmCollectionBackup.pas | 2 +-
Src/FmDeleteUserDBDlg.dfm | 1 +
Src/FmDeleteUserDBDlg.pas | 2 +-
Src/FmDependenciesDlg.dfm | 4 -
Src/FmDependenciesDlg.pas | 21 +++---
Src/FmDuplicateSnippetDlg.pas | 9 +--
Src/FmFavouritesDlg.pas | 2 +-
Src/FmSWAGImportDlg.dfm | 12 +++
Src/FmSWAGImportDlg.pas | 14 ++--
Src/FmSelectionSearchDlg.pas | 8 +-
Src/FmSnippetsEditorDlg.pas | 18 ++---
Src/FmUserDataPathDlg.pas | 2 +-
Src/FrDisplayPrefs.pas | 12 +--
Src/FrOverview.dfm | 4 +-
Src/FrOverview.pas | 11 ++-
Src/FrSelectSnippetsBase.pas | 11 ++-
Src/IntfNotifier.pas | 14 ++--
Src/SWAG.UImporter.pas | 10 ++-
Src/UCodeImportExport.pas | 4 +-
Src/UCodeImportMgr.pas | 17 ++---
Src/UCollectionListAdapter.pas | 7 +-
Src/UNotifier.pas | 16 ++--
Src/UPreferences.pas | 39 +++++-----
Src/URTFSnippetDoc.pas | 8 +-
Src/USnippetAction.pas | 4 +-
Src/USnippetDoc.pas | 14 ++--
Src/USnippetIDListIOHandler.pas | 4 +-
Src/USnippetIDs.pas | 16 ++--
Src/USnippetValidator.pas | 17 +----
Src/USnippetsTVDraw.pas | 9 +--
Src/UTextSnippetDoc.pas | 6 +-
Src/UWBExternal.pas | 4 +-
40 files changed, 327 insertions(+), 313 deletions(-)
diff --git a/Src/DB.UCollections.pas b/Src/DB.UCollections.pas
index 00f2f9ab1..2312f3f26 100644
--- a/Src/DB.UCollections.pas
+++ b/Src/DB.UCollections.pas
@@ -29,37 +29,37 @@ interface
type
- TCollectionID = record
+ TVaultID = record
strict private
var
fID: TBytes;
public
type
TComparer = class(TInterfacedObject,
- IComparer, IEqualityComparer
+ IComparer, IEqualityComparer
)
public
- function Compare(const Left, Right: TCollectionID): Integer;
- function Equals(const Left, Right: TCollectionID): Boolean;
+ function Compare(const Left, Right: TVaultID): Integer;
+ function Equals(const Left, Right: TVaultID): Boolean;
reintroduce;
- function GetHashCode(const Value: TCollectionID): Integer;
+ function GetHashCode(const Value: TVaultID): Integer;
reintroduce;
end;
constructor Create(const ABytes: TBytes); overload;
constructor Create(const AStr: string); overload;
constructor Create(const AGUID: TGUID); overload;
- class function CreateFromHexString(const AHexStr: string): TCollectionID;
+ class function CreateFromHexString(const AHexStr: string): TVaultID;
static;
- class function CreateNull: TCollectionID; static;
- class function Default: TCollectionID; static;
- function Clone: TCollectionID;
+ class function CreateNull: TVaultID; static;
+ class function Default: TVaultID; static;
+ function Clone: TVaultID;
function ToArray: TBytes;
function ToHexString: string;
function IsNull: Boolean;
function Hash: Integer;
- class function Compare(Left, Right: TCollectionID): Integer; static;
- class operator Equal(Left, Right: TCollectionID): Boolean;
- class operator NotEqual(Left, Right: TCollectionID): Boolean;
+ class function Compare(Left, Right: TVaultID): Integer; static;
+ class operator Equal(Left, Right: TVaultID): Boolean;
+ class operator NotEqual(Left, Right: TVaultID): Boolean;
end;
ECollectionID = class(ECodeSnip);
@@ -67,7 +67,7 @@ ECollectionID = class(ECodeSnip);
TCollection = class
strict private
var
- fUID: TCollectionID;
+ fUID: TVaultID;
fName: string;
fStorage: TDataStorageDetails;
fMetaData: TMetaData;
@@ -85,14 +85,14 @@ TComparer = class(TInterfacedObject,
reintroduce;
end;
/// Creates a collection record.
- /// TCollectionID [in] Unique ID of the
+ /// TVaultID [in] Unique ID of the
/// collection. Must not be null.
/// string [in] Name of collection. Should be
/// unique. Must not be empty or only whitespace.
- constructor Create(const AUID: TCollectionID; const AName: string;
+ constructor Create(const AUID: TVaultID; const AName: string;
const AStorage: TDataStorageDetails);
/// Collection identifier. Must be unique.
- property UID: TCollectionID
+ property UID: TVaultID
read fUID;
/// Collection name. Must be unique.
property Name: string read
@@ -124,19 +124,19 @@ TCollections = class sealed(TSingleton)
public
class property Instance: TCollections read GetInstance;
function GetEnumerator: TEnumerator;
- function IndexOfID(const AUID: TCollectionID): Integer;
- function ContainsID(const AUID: TCollectionID): Boolean;
+ function IndexOfID(const AUID: TVaultID): Integer;
+ function ContainsID(const AUID: TVaultID): Boolean;
function ContainsName(const AName: string): Boolean;
- function GetCollection(const AUID: TCollectionID): TCollection;
+ function GetCollection(const AUID: TVaultID): TCollection;
function Default: TCollection;
procedure Add(const ACollection: TCollection);
procedure Update(const ACollection: TCollection);
procedure AddOrUpdate(const ACollection: TCollection);
- procedure Delete(const AUID: TCollectionID);
+ procedure Delete(const AUID: TVaultID);
procedure Clear;
procedure Save;
function ToArray: TArray;
- function GetAllIDs: TArray;
+ function GetAllIDs: TArray;
function Count: Integer;
property Items[const Idx: Integer]: TCollection read GetItem; default;
end;
@@ -175,7 +175,7 @@ implementation
{ TCollection }
-constructor TCollection.Create(const AUID: TCollectionID; const AName: string;
+constructor TCollection.Create(const AUID: TVaultID; const AName: string;
const AStorage: TDataStorageDetails);
var
TrimmedName: string;
@@ -194,7 +194,7 @@ constructor TCollection.Create(const AUID: TCollectionID; const AName: string;
function TCollection.IsDefault: Boolean;
begin
- Result := UID = TCollectionID.Default;
+ Result := UID = TVaultID.Default;
end;
function TCollection.IsValid: Boolean;
@@ -239,7 +239,7 @@ procedure TCollections.Clear;
fItems.Clear;
end;
-function TCollections.ContainsID(const AUID: TCollectionID):
+function TCollections.ContainsID(const AUID: TVaultID):
Boolean;
begin
Result := IndexOfID(AUID) >= 0;
@@ -262,16 +262,16 @@ function TCollections.Count: Integer;
function TCollections.Default: TCollection;
begin
- Result := GetCollection(TCollectionID.Default);
+ Result := GetCollection(TVaultID.Default);
end;
-procedure TCollections.Delete(const AUID: TCollectionID);
+procedure TCollections.Delete(const AUID: TVaultID);
resourcestring
sCantDelete = 'Cannot delete the default collection';
var
Idx: Integer;
begin
- if TCollectionID.Default = AUID then
+ if TVaultID.Default = AUID then
raise EArgumentException.Create(sCantDelete);
Idx := IndexOfID(AUID);
if Idx >= 0 then
@@ -298,7 +298,7 @@ procedure TCollections.Finalize;
fItems.Free;
end;
-function TCollections.GetAllIDs: TArray;
+function TCollections.GetAllIDs: TArray;
var
Idx: Integer;
begin
@@ -307,7 +307,7 @@ function TCollections.GetAllIDs: TArray;
Result[Idx] := fItems[Idx].UID;
end;
-function TCollections.GetCollection(const AUID: TCollectionID): TCollection;
+function TCollections.GetCollection(const AUID: TVaultID): TCollection;
var
Idx: Integer;
begin
@@ -332,7 +332,7 @@ function TCollections.GetItem(const Idx: Integer): TCollection;
Result := fItems[Idx];
end;
-function TCollections.IndexOfID(const AUID: TCollectionID): Integer;
+function TCollections.IndexOfID(const AUID: TVaultID): Integer;
var
Idx: Integer;
begin
@@ -347,10 +347,10 @@ procedure TCollections.Initialize;
fItems := TList.Create;
TCollectionsPersist.Load(Self);
// Ensure there is always at least the default collection present
- if not ContainsID(TCollectionID.Default) then
+ if not ContainsID(TVaultID.Default) then
Add(
TCollection.Create(
- TCollectionID.Default,
+ TVaultID.Default,
'Default',
TDataStorageDetails.Create(
TDataFormatInfo.DefaultFormat,
@@ -379,24 +379,24 @@ procedure TCollections.Update(const ACollection: TCollection);
DoUpdate(Idx, ACollection);
end;
-{ TCollectionID }
+{ TVaultID }
-constructor TCollectionID.Create(const ABytes: TBytes);
+constructor TVaultID.Create(const ABytes: TBytes);
begin
fID := System.Copy(ABytes);
end;
-constructor TCollectionID.Create(const AStr: string);
+constructor TVaultID.Create(const AStr: string);
begin
fID := TEncoding.UTF8.GetBytes(AStr);
end;
-function TCollectionID.Clone: TCollectionID;
+function TVaultID.Clone: TVaultID;
begin
- Result := TCollectionID.Create(fID);
+ Result := TVaultID.Create(fID);
end;
-class function TCollectionID.Compare(Left, Right: TCollectionID): Integer;
+class function TVaultID.Compare(Left, Right: TVaultID): Integer;
var
CompareLength: Integer;
Idx: Integer;
@@ -415,83 +415,83 @@ class function TCollectionID.Compare(Left, Right: TCollectionID): Integer;
Exit(1);
end;
-constructor TCollectionID.Create(const AGUID: TGUID);
+constructor TVaultID.Create(const AGUID: TGUID);
begin
fID := System.Copy(GUIDToBytes(AGUID));
end;
-class function TCollectionID.CreateFromHexString(
- const AHexStr: string): TCollectionID;
+class function TVaultID.CreateFromHexString(
+ const AHexStr: string): TVaultID;
var
ConvertedBytes: TBytes;
begin
if not TryHexStringToBytes(AHexStr, ConvertedBytes) then
raise ECollectionID.Create(SBadHexString);
- Result := TCollectionID.Create(ConvertedBytes);
+ Result := TVaultID.Create(ConvertedBytes);
end;
-class function TCollectionID.CreateNull: TCollectionID;
+class function TVaultID.CreateNull: TVaultID;
var
NullID: TBytes;
begin
SetLength(NullID, 0);
- Result := TCollectionID.Create(NullID);
+ Result := TVaultID.Create(NullID);
end;
-class function TCollectionID.Default: TCollectionID;
+class function TVaultID.Default: TVaultID;
begin
// Default collection is an empty GUID = 16 zero bytes
- Result := TCollectionID.Create(TGUID.Empty);
+ Result := TVaultID.Create(TGUID.Empty);
end;
-class operator TCollectionID.Equal(Left, Right: TCollectionID):
+class operator TVaultID.Equal(Left, Right: TVaultID):
Boolean;
begin
Result := IsEqualBytes(Left.fID, Right.fID);
end;
-function TCollectionID.Hash: Integer;
+function TVaultID.Hash: Integer;
begin
Result := BobJenkinsHash(fID[0], Length(fID), 0);
end;
-function TCollectionID.IsNull: Boolean;
+function TVaultID.IsNull: Boolean;
begin
Result := Length(fID) = 0;
end;
-class operator TCollectionID.NotEqual(Left, Right: TCollectionID):
+class operator TVaultID.NotEqual(Left, Right: TVaultID):
Boolean;
begin
Result := not IsEqualBytes(Left.fID, Right.fID);
end;
-function TCollectionID.ToArray: TBytes;
+function TVaultID.ToArray: TBytes;
begin
Result := System.Copy(fID);
end;
-function TCollectionID.ToHexString: string;
+function TVaultID.ToHexString: string;
begin
Result := BytesToHexString(fID);
end;
-{ TCollectionID.TComparer }
+{ TVaultID.TComparer }
-function TCollectionID.TComparer.Compare(const Left,
- Right: TCollectionID): Integer;
+function TVaultID.TComparer.Compare(const Left,
+ Right: TVaultID): Integer;
begin
- Result := TCollectionID.Compare(Left, Right);
+ Result := TVaultID.Compare(Left, Right);
end;
-function TCollectionID.TComparer.Equals(const Left,
- Right: TCollectionID): Boolean;
+function TVaultID.TComparer.Equals(const Left,
+ Right: TVaultID): Boolean;
begin
Result := Left = Right;
end;
-function TCollectionID.TComparer.GetHashCode(
- const Value: TCollectionID): Integer;
+function TVaultID.TComparer.GetHashCode(
+ const Value: TVaultID): Integer;
begin
Result := Value.Hash;
end;
@@ -515,13 +515,13 @@ class procedure TCollectionsPersist.LoadCollection(const AOrdinal: Cardinal;
const ACollections: TCollections);
var
ConfigSection: ISettingsSection;
- UID: TCollectionID;
+ UID: TVaultID;
Name: string;
Collection: TCollection;
StorageDetails: TDataStorageDetails;
begin
ConfigSection := Settings.ReadSection(ssCollection, IntToStr(AOrdinal));
- UID := TCollectionID.Create(ConfigSection.GetBytes(UIDKey));
+ UID := TVaultID.Create(ConfigSection.GetBytes(UIDKey));
if ACollections.ContainsID(UID) then
// Don't load a duplicate collection
Exit;
@@ -570,7 +570,7 @@ class procedure TCollectionsPersist.SaveCollection(const AOrdinal: Cardinal;
function TCollection.TComparer.Compare(const Left, Right: TCollection): Integer;
begin
- Result := TCollectionID.Compare(Left.UID, Right.UID);
+ Result := TVaultID.Compare(Left.UID, Right.UID);
end;
function TCollection.TComparer.Equals(const Left, Right: TCollection): Boolean;
diff --git a/Src/DB.UMain.pas b/Src/DB.UMain.pas
index b8e73511f..50a0e60b1 100644
--- a/Src/DB.UMain.pas
+++ b/Src/DB.UMain.pas
@@ -129,13 +129,13 @@ interface
/// Creates a new snippet object.
/// string [in] New snippet's key. Must not
/// exist in database
- /// TCollectionID [in] Collection
- /// containing the snippet.
+ /// TVaultID [in] Vault containing the
+ /// snippet.
/// TSnippetData [in] Record describing
/// snippet's properties.
/// Instance of new snippet with no references.
- function CreateSnippet(const Key: string;
- const ACollectionID: TCollectionID; const Props: TSnippetData): TSnippet;
+ function CreateSnippet(const Key: string; const ACollectionID: TVaultID;
+ const Props: TSnippetData): TSnippet;
end;
@@ -183,10 +183,10 @@ interface
/// Creates a new snippet key that is unique within the given
/// collection.
- /// TCollectionID ID of collection that
- /// the new key must be unique within.
+ /// TVaultID ID of vault that the new
+ /// key must be unique within.
/// string containing the key.
- function GetUniqueSnippetKey(const ACollectionID: TCollectionID): string;
+ function GetUniqueSnippetKey(const ACollectionID: TVaultID): string;
function GetEditableSnippetInfo(const Snippet: TSnippet = nil):
TSnippetEditData;
@@ -222,12 +222,12 @@ interface
/// Adds a new snippet to the database.
/// string [in] New snippet's key.
- /// TCollectionID [in] ID of collection
- /// that the new snippet will belong to.
+ /// TVaultID [in] ID of vault that the
+ /// new snippet will belong to.
/// TSnippetEditData [in] Record storing the new
/// snippet's properties and references.
/// TSnippet. Reference to the new snippet.
- function AddSnippet(const AKey: string; const ACollectionID: TCollectionID;
+ function AddSnippet(const AKey: string; const ACollectionID: TVaultID;
const AData: TSnippetEditData): TSnippet;
/// Duplicates a snippet in the database.
@@ -235,8 +235,8 @@ interface
///
/// string [in] Key to be used for duplicated
/// snippet.
- /// TCollectionID [in] ID of
- /// collection the duplicated snippet belongs to.
+ /// TVaultID [in] ID of vault the
+ /// duplicated snippet belongs to.
/// string [in] Display name of the
/// duplicated snippet.
/// string [in] ID of the category to which the
@@ -244,21 +244,21 @@ interface
/// TSnippet. Reference to the duplicated snippet.
///
function DuplicateSnippet(const ASnippet: TSnippet; const ANewKey: string;
- const ANewCollectionID: TCollectionID; const ANewDisplayName: string;
+ const ANewCollectionID: TVaultID; const ANewDisplayName: string;
const ACatID: string): TSnippet;
/// Creates a new temporary snippet without adding it to the
/// database.
/// string [in] The new nippet's key.
- /// TCollectionID [in] ID of the
- /// collection to which the new snippet belongs.
+ /// TVaultID [in] ID of the vault to
+ /// which the new snippet belongs.
/// TSnippetEditData [in] Record storing the new
/// snippet's properties and references.
/// TSnippet Reference to new snippet.
/// The returned snippet must not be added to the database.
///
function CreateTempSnippet(const AKey: string;
- const ACollectionID: TCollectionID; const AData: TSnippetEditData):
+ const ACollectionID: TVaultID; const AData: TSnippetEditData):
TSnippet; overload;
function CreateTempSnippet(const Snippet: TSnippet): TSnippet; overload;
@@ -354,13 +354,13 @@ TDBDataItemFactory = class(TInterfacedObject, IDBDataItemFactory)
/// Creates a new snippet object.
/// string [in] New snippet's key. Must not
/// exist in database
- /// TCollectionID [in] Collection
- /// containing the snippet.
+ /// TVaultID [in] Vault containing the
+ /// snippet.
/// TSnippetData [in] Record describing
/// snippet's properties.
/// Instance of new snippet with no references.
function CreateSnippet(const Key: string;
- const ACollectionID: TCollectionID; const Props: TSnippetData): TSnippet;
+ const ACollectionID: TVaultID; const Props: TSnippetData): TSnippet;
end;
@@ -417,23 +417,17 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
/// Adds a new snippet to the database. Assumes the snippet is
/// not already in the database.
/// string [in] New snippet's key.
- /// TCollectionID [in] ID of collection
- /// that the new snippet will belong to.
+ /// TVaultID [in] ID of vault that the
+ /// new snippet will belong to.
/// TSnippetEditData [in] Record storing the new
/// snippet's properties and references.
/// TSnippet. Reference to the new snippet.
/// ECodeSnip raised if the snippet's category does not
/// exist.
function InternalAddSnippet(const AKey: string;
- const ACollectionID: TCollectionID; const AData: TSnippetEditData):
+ const ACollectionID: TVaultID; const AData: TSnippetEditData):
TSnippet;
- {Adds a new snippet to the user database. Assumes snippet not already in
- user database.
- @param SnippetKey [in] New snippet's key.
- @param Data [in] Properties and references of new snippet.
- @return Reference to new snippet object.
- @except Exception raised if
- }
+
procedure InternalDeleteSnippet(const Snippet: TSnippet);
{Deletes a snippet from the user database.
@param Snippet [in] Snippet to delete from database.
@@ -498,11 +492,11 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
/// Creates a new snippet key that is unique within the given
/// collection.
- /// TCollectionID ID of collection that
- /// the new key must be unique within.
+ /// TVaultID ID of vault that the new
+ /// key must be unique within.
/// string containing the key.
/// Method of IDatabaseEdit.
- function GetUniqueSnippetKey(const ACollectionID: TCollectionID): string;
+ function GetUniqueSnippetKey(const ACollectionID: TVaultID): string;
function GetEditableSnippetInfo(const Snippet: TSnippet = nil):
TSnippetEditData;
@@ -541,13 +535,13 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
/// Adds a new snippet to the database.
/// string [in] New snippet's key.
- /// TCollectionID [in] ID of collection
- /// that the new snippet will belong to.
+ /// TVaultID [in] ID of vault that the
+ /// new snippet will belong to.
/// TSnippetEditData [in] Record storing the new
/// snippet's properties and references.
/// TSnippet. Reference to the new snippet.
/// Method of IDatabaseEdit.
- function AddSnippet(const AKey: string; const ACollectionID: TCollectionID;
+ function AddSnippet(const AKey: string; const ACollectionID: TVaultID;
const AData: TSnippetEditData): TSnippet;
/// Duplicates a snippet in the database.
@@ -555,8 +549,8 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
///
/// string [in] Key to be used for duplicated
/// snippet.
- /// TCollectionID [in] ID of
- /// collection the duplicated snippet belongs to.
+ /// TVaultID [in] ID of the vault the
+ /// duplicated snippet belongs to.
/// string [in] Display name of the
/// duplicated snippet.
/// string [in] ID of the category to which the
@@ -565,14 +559,14 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
///
/// Method of IDatabaseEdit.
function DuplicateSnippet(const ASnippet: TSnippet; const ANewKey: string;
- const ANewCollectionID: TCollectionID; const ANewDisplayName: string;
+ const ANewCollectionID: TVaultID; const ANewDisplayName: string;
const ACatID: string): TSnippet;
/// Creates a new temporary snippet without adding it to the
/// database.
/// string [in] The new nippet's key.
- /// TCollectionID [in] ID of the
- /// collection to which the new snippet belongs.
+ /// TVaultID [in] ID of the vault to
+ /// which the new snippet belongs.
/// TSnippetEditData [in] Record storing the new
/// snippet's properties and references.
/// TSnippet Reference to new snippet.
@@ -581,7 +575,7 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
/// Method of IDatabaseEdit.
///
function CreateTempSnippet(const AKey: string;
- const ACollectionID: TCollectionID; const AData: TSnippetEditData):
+ const ACollectionID: TVaultID; const AData: TSnippetEditData):
TSnippet; overload;
function CreateTempSnippet(const Snippet: TSnippet): TSnippet; overload;
@@ -636,18 +630,18 @@ TEventInfo = class(TInterfacedObject, IDatabaseChangeEventInfo)
TCollectionDataProvider = class(TInterfacedObject, IDBDataProvider)
strict private
var
- fCollectionID: TCollectionID; // Collection on which to operate
+ fCollectionID: TVaultID; // Vault on which to operate
fSnippets: TSnippetList; // All snippets in the whole database
fCategories: TCategoryList; // All categories in the whole database
public
/// Object constructor. Sets up data provider.
- /// TCollectionID [in] Collection for
- /// which to provide data.
+ /// TVaultID [in] Vault for which to
+ /// provide data.
/// TSnippetList [in] List of all snippets
/// in the database.
/// TCategoryList [in] List of all
/// categories in the database.
- constructor Create(const ACollectionID: TCollectionID;
+ constructor Create(const ACollectionID: TVaultID;
const SnipList: TSnippetList;
const Categories: TCategoryList);
@@ -733,8 +727,8 @@ procedure TDatabase.AddChangeEventHandler(const Handler: TNotifyEventInfo);
fChangeEvents.AddHandler(Handler);
end;
-function TDatabase.AddSnippet(const AKey: string;
- const ACollectionID: TCollectionID; const AData: TSnippetEditData): TSnippet;
+function TDatabase.AddSnippet(const AKey: string; const ACollectionID: TVaultID;
+ const AData: TSnippetEditData): TSnippet;
resourcestring
// Error message
sKeyExists = 'Snippet with key "%s" already exists in collection';
@@ -794,7 +788,7 @@ function TDatabase.CreateTempSnippet(const Snippet: TSnippet): TSnippet;
end;
function TDatabase.CreateTempSnippet(const AKey: string;
- const ACollectionID: TCollectionID; const AData: TSnippetEditData): TSnippet;
+ const ACollectionID: TVaultID; const AData: TSnippetEditData): TSnippet;
begin
Result := TTempSnippet.Create(AKey, ACollectionID, AData.Props);
(Result as TTempSnippet).UpdateRefs(AData.Refs, fSnippets);
@@ -871,7 +865,7 @@ destructor TDatabase.Destroy;
end;
function TDatabase.DuplicateSnippet(const ASnippet: TSnippet;
- const ANewKey: string; const ANewCollectionID: TCollectionID;
+ const ANewKey: string; const ANewCollectionID: TVaultID;
const ANewDisplayName: string; const ACatID: string): TSnippet;
var
Data: TSnippetEditData;
@@ -994,8 +988,7 @@ function TDatabase.GetSnippets: TSnippetList;
Result := fSnippets;
end;
-function TDatabase.GetUniqueSnippetKey(
- const ACollectionID: TCollectionID): string;
+function TDatabase.GetUniqueSnippetKey(const ACollectionID: TVaultID): string;
var
SnippetsInCollection: TSnippetList;
Snippet: TSnippet;
@@ -1031,7 +1024,7 @@ function TDatabase.InternalAddCategory(const CatID: string;
end;
function TDatabase.InternalAddSnippet(const AKey: string;
- const ACollectionID: TCollectionID; const AData: TSnippetEditData): TSnippet;
+ const ACollectionID: TVaultID; const AData: TSnippetEditData): TSnippet;
var
Cat: TCategory; // category object containing new snippet
resourcestring
@@ -1297,14 +1290,14 @@ function TDBDataItemFactory.CreateCategory(const CatID: string;
end;
function TDBDataItemFactory.CreateSnippet(const Key: string;
- const ACollectionID: TCollectionID; const Props: TSnippetData): TSnippet;
+ const ACollectionID: TVaultID; const Props: TSnippetData): TSnippet;
begin
Result := TSnippetEx.Create(Key, ACollectionID, Props);
end;
{ TCollectionDataProvider }
-constructor TCollectionDataProvider.Create(const ACollectionID: TCollectionID;
+constructor TCollectionDataProvider.Create(const ACollectionID: TVaultID;
const SnipList: TSnippetList; const Categories: TCategoryList);
begin
inherited Create;
diff --git a/Src/DB.USnippet.pas b/Src/DB.USnippet.pas
index e54da8c1b..0b3ecc82d 100644
--- a/Src/DB.USnippet.pas
+++ b/Src/DB.USnippet.pas
@@ -139,7 +139,7 @@ TDisplayNameComparer = class(TComparer)
fXRef: TSnippetList; // List of cross-referenced snippets
fExtra: IActiveText; // Further information for snippet
fCompatibility: TCompileResults; // Snippet's compiler compatibility
- fCollectionID: TCollectionID; // Snippet's collection ID
+ fCollectionID: TVaultID; // Snippet's vault ID
fHiliteSource: Boolean; // If source is syntax highlighted
fTestInfo: TSnippetTestInfo; // Level of testing of snippet
function GetID: TSnippetID;
@@ -168,11 +168,11 @@ TDisplayNameComparer = class(TComparer)
/// Object constructor. Sets up snippet object with given property
/// values belonging to a specified collection.
/// string [in] Snippet's key.
- /// TCollectionID [in] ID of collection
- /// to which the snippet belongs. ID must not be null.
+ /// TVaultID [in] ID of vault to which
+ /// the snippet belongs. ID must not be null.
/// TSnippetData [in] Values of snippet
/// properties.
- constructor Create(const AKey: string; const ACollectionID: TCollectionID;
+ constructor Create(const AKey: string; const ACollectionID: TVaultID;
const Props: TSnippetData);
destructor Destroy; override;
@@ -226,8 +226,8 @@ TDisplayNameComparer = class(TComparer)
{List of any other snippet in database on which this snippet depends}
property XRef: TSnippetList read fXRef;
{List of cross referenced snippets in database}
- /// ID of collection to which the snippet belongs.
- property CollectionID: TCollectionID read fCollectionID;
+ /// ID of vault to which the snippet belongs.
+ property CollectionID: TVaultID read fCollectionID;
end;
{
@@ -287,13 +287,13 @@ TSnippetList = class(TObject)
/// Finds a snippet in the list with whose key and collection ID
/// match.
/// string [in] Snippet's key.
- /// TCollectionID [in] ID of collection
- /// to which the snippet belongs.
+ /// TVaultID [in] ID of vault to which
+ /// the snippet belongs.
/// Integer. [out] Set to the index of the
/// required snippet in the list. Valid only if the snippet was found.
///
/// Boolean. True if snippet found, False if not.
- function Find(const SnippetKey: string; const ACollectionID: TCollectionID;
+ function Find(const SnippetKey: string; const ACollectionID: TVaultID;
out Index: Integer): Boolean; overload;
strict protected
@@ -332,12 +332,12 @@ TSnippetList = class(TObject)
/// Finds a snippet in the list with whose key and collection ID
/// match.
/// string [in] Snippet's key.
- /// TCollectionID [in] ID of collection
- /// to which the snippet belongs.
+ /// TVaultID [in] ID of vault to which
+ /// the snippet belongs.
/// TSnippet. Reference to the required snippet or nil if
/// not found.
function Find(const SnippetKey: string;
- const ACollectionID: TCollectionID): TSnippet; overload;
+ const ACollectionID: TVaultID): TSnippet; overload;
function Contains(const Snippet: TSnippet): Boolean;
{Checks whether list contains a specified snippet.
@@ -360,10 +360,10 @@ TSnippetList = class(TObject)
/// Counts number of snippets in list that belong to a specified
/// collection.
- /// TCollectionID [in] Required
- /// collection.
+ /// TVaultID [in] Required vault.
+ ///
/// Integer Number of snippets in the collection.
- function Count(const ACollectionID: TCollectionID): Integer; overload;
+ function Count(const ACollectionID: TVaultID): Integer; overload;
function Count: Integer; overload;
{Counts number of snippets in list.
@@ -376,11 +376,10 @@ TSnippetList = class(TObject)
/// Checks if the sub-set of snippets in the list belonging to a
/// specified collection is empty.
- /// TCollectionID [in] ID of collection.
- ///
+ /// TVaultID [in] ID of vault.
/// Boolean True if the subset is empty, False otherwise.
///
- function IsEmpty(const ACollectionID: TCollectionID): Boolean; overload;
+ function IsEmpty(const ACollectionID: TVaultID): Boolean; overload;
property Items[Idx: Integer]: TSnippet read GetItem; default;
{List of snippets}
@@ -443,7 +442,7 @@ function TSnippet.CompareTo(const Snippet: TSnippet): Integer;
end;
constructor TSnippet.Create(const AKey: string;
- const ACollectionID: TCollectionID; const Props: TSnippetData);
+ const ACollectionID: TVaultID; const Props: TSnippetData);
begin
Assert(ClassType <> TSnippet,
ClassName + '.Create: must only be called from descendants.');
@@ -710,7 +709,7 @@ function TSnippetList.ContainsKinds(const Kinds: TSnippetKinds): Boolean;
end;
end;
-function TSnippetList.Count(const ACollectionID: TCollectionID): Integer;
+function TSnippetList.Count(const ACollectionID: TVaultID): Integer;
var
Snippet: TSnippet; // refers to all snippets in list
begin
@@ -750,7 +749,7 @@ destructor TSnippetList.Destroy;
end;
function TSnippetList.Find(const SnippetKey: string;
- const ACollectionID: TCollectionID; out Index: Integer): Boolean;
+ const ACollectionID: TVaultID; out Index: Integer): Boolean;
var
TempSnippet: TSnippet; // temp snippet used to perform search
NullData: TSnippetData; // nul data used to create snippet
@@ -767,7 +766,7 @@ function TSnippetList.Find(const SnippetKey: string;
end;
function TSnippetList.Find(const SnippetKey: string;
- const ACollectionID: TCollectionID): TSnippet;
+ const ACollectionID: TVaultID): TSnippet;
var
Idx: Integer; // index of snippet key in list
begin
@@ -811,7 +810,7 @@ function TSnippetList.IsEmpty: Boolean;
Result := Count = 0;
end;
-function TSnippetList.IsEmpty(const ACollectionID: TCollectionID): Boolean;
+function TSnippetList.IsEmpty(const ACollectionID: TVaultID): Boolean;
begin
Result := Count(ACollectionID) = 0;
end;
diff --git a/Src/Favourites.UPersist.pas b/Src/Favourites.UPersist.pas
index 8de05b152..26bd7613e 100644
--- a/Src/Favourites.UPersist.pas
+++ b/Src/Favourites.UPersist.pas
@@ -99,13 +99,13 @@ class procedure TFavouritesPersist.Load(Favourites: TFavourites);
procedure (AFields: TArray)
var
Key: string;
- CollectionID: TCollectionID;
+ CollectionID: TVaultID;
LastAccess: TDateTime;
begin
if Length(AFields) <> 3 then
raise EFavouritesPersist.Create(sBadFormat);
Key := StrTrim(AFields[0]);
- CollectionID := TCollectionID.CreateFromHexString(
+ CollectionID := TVaultID.CreateFromHexString(
StrTrim(AFields[1])
);
LastAccess := StrToDateTime(StrTrim(AFields[2]), DateFormatSettings);
diff --git a/Src/FmAboutDlg.dfm b/Src/FmAboutDlg.dfm
index c683d780e..478fb6456 100644
--- a/Src/FmAboutDlg.dfm
+++ b/Src/FmAboutDlg.dfm
@@ -33,6 +33,10 @@ inherited AboutDlg: TAboutDlg
OnMouseDown = pcDetailMouseDown
object tsProgram: TTabSheet
Caption = 'About The Program'
+ ExplicitLeft = 0
+ ExplicitTop = 0
+ ExplicitWidth = 0
+ ExplicitHeight = 0
inline frmProgram: THTMLTpltDlgFrame
Left = 0
Top = 0
@@ -66,6 +70,10 @@ inherited AboutDlg: TAboutDlg
object tsCollections: TTabSheet
Caption = 'About Collections'
ImageIndex = 1
+ ExplicitLeft = 0
+ ExplicitTop = 0
+ ExplicitWidth = 0
+ ExplicitHeight = 0
DesignSize = (
401
190)
@@ -104,6 +112,10 @@ inherited AboutDlg: TAboutDlg
object tsPaths: TTabSheet
Caption = 'Paths && Files'
ImageIndex = 2
+ ExplicitLeft = 0
+ ExplicitTop = 0
+ ExplicitWidth = 0
+ ExplicitHeight = 0
DesignSize = (
401
190)
diff --git a/Src/FmAboutDlg.pas b/Src/FmAboutDlg.pas
index e3c2fcee7..efd9a7c99 100644
--- a/Src/FmAboutDlg.pas
+++ b/Src/FmAboutDlg.pas
@@ -324,7 +324,7 @@ procedure TAboutDlg.ConfigForm;
end;
// Load collections into combo box & select default collection
fCollList.ToStrings(cbCollection.Items);
- cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TVaultID.Default);
DisplayCollectionInfo(fCollList.Collection(cbCollection.ItemIndex));
// Set collections treeview and paths scrollbox background colours
tvCollectionInfo.Color := ThemeServicesEx.GetTabBodyColour;
diff --git a/Src/FmCodeImportDlg.dfm b/Src/FmCodeImportDlg.dfm
index 8c3dfde69..7b30eb0c7 100644
--- a/Src/FmCodeImportDlg.dfm
+++ b/Src/FmCodeImportDlg.dfm
@@ -14,6 +14,10 @@ inherited CodeImportDlg: TCodeImportDlg
object tsInfo: TTabSheet
Caption = 'tsInfo'
TabVisible = False
+ ExplicitLeft = 0
+ ExplicitTop = 0
+ ExplicitWidth = 0
+ ExplicitHeight = 0
object lblIntro: TLabel
Left = 0
Top = 8
@@ -30,6 +34,10 @@ inherited CodeImportDlg: TCodeImportDlg
Caption = 'tsFile'
ImageIndex = 1
TabVisible = False
+ ExplicitLeft = 0
+ ExplicitTop = 0
+ ExplicitWidth = 0
+ ExplicitHeight = 0
object lblFile: TLabel
Left = 0
Top = 8
@@ -96,6 +104,10 @@ inherited CodeImportDlg: TCodeImportDlg
Caption = 'tsUpdate'
ImageIndex = 3
TabVisible = False
+ ExplicitLeft = 0
+ ExplicitTop = 0
+ ExplicitWidth = 0
+ ExplicitHeight = 0
object lblImportList: TLabel
Left = 0
Top = 53
@@ -147,6 +159,10 @@ inherited CodeImportDlg: TCodeImportDlg
Caption = 'tsFinish'
ImageIndex = 5
TabVisible = False
+ ExplicitLeft = 0
+ ExplicitTop = 0
+ ExplicitWidth = 0
+ ExplicitHeight = 0
object lblFinish: TLabel
Left = 0
Top = 8
diff --git a/Src/FmCodeImportDlg.pas b/Src/FmCodeImportDlg.pas
index 7b9bfa4f8..6d025f65b 100644
--- a/Src/FmCodeImportDlg.pas
+++ b/Src/FmCodeImportDlg.pas
@@ -117,9 +117,9 @@ TCodeImportDlg = class(TWizardDlg, INoPublicConstruct)
procedure UpdateDatabase;
/// Displays names of imported snippets on finish page.
procedure PresentResults;
- /// Gets the ID of the collection into which all snippets are to
- /// be imported.
- function GetCollectionID: TCollectionID;
+ /// Gets the ID of the vault into which all snippets are to be
+ /// imported.
+ function GetCollectionID: TVaultID;
strict protected
/// Protected constructor that sets up object to use given import
/// manager object.
@@ -305,7 +305,7 @@ procedure TCodeImportDlg.FormDestroy(Sender: TObject);
TObject(lvImports.Items[Idx].Data).Free;
end;
-function TCodeImportDlg.GetCollectionID: TCollectionID;
+function TCodeImportDlg.GetCollectionID: TVaultID;
begin
Assert(cbCollection.ItemIndex >= 0,
ClassName + '.GetCollectionID: no collection selected');
@@ -339,9 +339,9 @@ procedure TCodeImportDlg.InitForm;
begin
fCollList.ToStrings(cbCollection.Items);
Assert(cbCollection.Items.Count > 0, ClassName + '.InitForm: no collections');
- Assert(TCollections.Instance.ContainsID(TCollectionID.Default),
+ Assert(TCollections.Instance.ContainsID(TVaultID.Default),
ClassName + '.InitForm: default collection not found');
- cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TVaultID.Default);
Assert(cbCollection.ItemIndex >= 0,
ClassName + '.InitForm: default collection name not in cbCollection');
diff --git a/Src/FmCollectionBackup.pas b/Src/FmCollectionBackup.pas
index d39d4aa33..e15697ab5 100644
--- a/Src/FmCollectionBackup.pas
+++ b/Src/FmCollectionBackup.pas
@@ -115,7 +115,7 @@ procedure TCollectionBackupDlg.ConfigForm;
begin
inherited;
fCollList.ToStrings(cbCollection.Items);
- cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TVaultID.Default);
end;
class function TCollectionBackupDlg.Execute(AOwner: TComponent;
diff --git a/Src/FmDeleteUserDBDlg.dfm b/Src/FmDeleteUserDBDlg.dfm
index d915e4668..d1e181c91 100644
--- a/Src/FmDeleteUserDBDlg.dfm
+++ b/Src/FmDeleteUserDBDlg.dfm
@@ -35,6 +35,7 @@ inherited DeleteUserDBDlg: TDeleteUserDBDlg
Height = 210
Align = alTop
TabOrder = 0
+ TabStop = True
ExplicitWidth = 369
ExplicitHeight = 210
inherited pnlBrowser: TPanel
diff --git a/Src/FmDeleteUserDBDlg.pas b/Src/FmDeleteUserDBDlg.pas
index b98b722c8..353aff673 100644
--- a/Src/FmDeleteUserDBDlg.pas
+++ b/Src/FmDeleteUserDBDlg.pas
@@ -106,7 +106,7 @@ procedure TDeleteUserDBDlg.ConfigForm;
inherited;
frmWarning.Initialise('dlg-dbdelete.html');
fCollList.ToStrings(cbCollection.Items);
- cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TVaultID.Default);
end;
class function TDeleteUserDBDlg.Execute(AOwner: TComponent;
diff --git a/Src/FmDependenciesDlg.dfm b/Src/FmDependenciesDlg.dfm
index 45f0aa78d..e3d882f53 100644
--- a/Src/FmDependenciesDlg.dfm
+++ b/Src/FmDependenciesDlg.dfm
@@ -52,10 +52,6 @@ inherited DependenciesDlg: TDependenciesDlg
object tsRequiredBy: TTabSheet
Caption = 'Required By'
ImageIndex = 1
- ExplicitLeft = 0
- ExplicitTop = 0
- ExplicitWidth = 0
- ExplicitHeight = 0
object lblNoDependents: TLabel
Left = 8
Top = 8
diff --git a/Src/FmDependenciesDlg.pas b/Src/FmDependenciesDlg.pas
index cc723100b..a7a5e6f8b 100644
--- a/Src/FmDependenciesDlg.pas
+++ b/Src/FmDependenciesDlg.pas
@@ -67,14 +67,13 @@ TTVDraw = class(TSnippetsTVDraw)
fRootID: TSnippetID; // ID of snippet whose dependency nodes displayed
strict protected
- /// Gets the collection ID, if any, associated with a tree
- /// node.
+ /// Gets the vault ID, if any, associated with a tree node.
+ ///
/// TTreeNode [in] Node to be checked.
///
- /// TCollectionID. Associated collection ID. If
- /// Node has no associated collection then a null collection ID
- /// is returned.
- function GetCollectionID(const Node: TTreeNode): TCollectionID;
+ /// TVaultID. Associated vault ID. If Node has
+ /// no associated vault then a null vault ID is returned.
+ function GetCollectionID(const Node: TTreeNode): TVaultID;
override;
function IsErrorNode(const Node: TTreeNode): Boolean;
@@ -410,9 +409,9 @@ procedure TDependenciesDlg.lbDependentsDrawItem(Control: TWinControl;
LB: TListBox;
Canvas: TCanvas;
- function ExtractCollectionItem: TCollectionID;
+ function ExtractCollectionItem: TVaultID;
begin
- Result := (LB.Items.Objects[Index] as TBox).Value;
+ Result := (LB.Items.Objects[Index] as TBox).Value;
end;
begin
@@ -458,7 +457,7 @@ procedure TDependenciesDlg.PopulateRequiredByList;
Assert(Assigned(ASnippet),
ClassName + '.PopulateRequiredByList: Snippet id not found');
lbDependents.Items.AddObject(
- ASnippet.DisplayName, TBox.Create(ASnippet.CollectionID)
+ ASnippet.DisplayName, TBox.Create(ASnippet.CollectionID)
);
end;
end;
@@ -509,10 +508,10 @@ constructor TDependenciesDlg.TTVDraw.Create(
end;
function TDependenciesDlg.TTVDraw.GetCollectionID(
- const Node: TTreeNode): TCollectionID;
+ const Node: TTreeNode): TVaultID;
begin
if not Assigned(Node.Data) then
- Result := TCollectionID.CreateNull
+ Result := TVaultID.CreateNull
else
Result := TSnippet(Node.Data).CollectionID;
end;
diff --git a/Src/FmDuplicateSnippetDlg.pas b/Src/FmDuplicateSnippetDlg.pas
index f874b197a..ab2b45a76 100644
--- a/Src/FmDuplicateSnippetDlg.pas
+++ b/Src/FmDuplicateSnippetDlg.pas
@@ -56,10 +56,9 @@ TPersistentOptions = class(TObject)
fCollList: TCollectionListAdapter;
fOptions: TPersistentOptions;
fSnippetKey: string;
- /// Returns the ID of the collection selected in the collections
- /// drop down list, or the null collection ID if no collection is selected.
- ///
- function SelectedCollectionID: TCollectionID;
+ /// Returns the ID of the vault selected in the collections drop
+ /// down list, or the null vault ID if no vault is selected.
+ function SelectedCollectionID: TVaultID;
function SelectedCategoryID: string;
procedure ValidateData;
procedure HandleException(const E: Exception);
@@ -216,7 +215,7 @@ function TDuplicateSnippetDlg.SelectedCategoryID: string;
Result := fCatList.CatID(cbCategory.ItemIndex);
end;
-function TDuplicateSnippetDlg.SelectedCollectionID: TCollectionID;
+function TDuplicateSnippetDlg.SelectedCollectionID: TVaultID;
begin
Assert(cbCollection.ItemIndex >= 0,
ClassName + '.SelectedCollectionID: no collection selected');
diff --git a/Src/FmFavouritesDlg.pas b/Src/FmFavouritesDlg.pas
index 5148b5252..325ff2d2d 100644
--- a/Src/FmFavouritesDlg.pas
+++ b/Src/FmFavouritesDlg.pas
@@ -580,7 +580,7 @@ class function TFavouritesDlg.IsDisplayed: Boolean;
procedure TFavouritesDlg.LVCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
var
- CollectionID: TCollectionID;
+ CollectionID: TVaultID;
begin
CollectionID := (Item as TFavouriteListItem).Favourite.SnippetID.CollectionID;
fLVFavs.Canvas.Font.Color := Preferences.GetSnippetHeadingColour(
diff --git a/Src/FmSWAGImportDlg.dfm b/Src/FmSWAGImportDlg.dfm
index 027a4b723..96f67658f 100644
--- a/Src/FmSWAGImportDlg.dfm
+++ b/Src/FmSWAGImportDlg.dfm
@@ -25,6 +25,10 @@ inherited SWAGImportDlg: TSWAGImportDlg
object tsIntro: TTabSheet
Caption = 'tsIntro'
TabVisible = False
+ ExplicitLeft = 0
+ ExplicitTop = 0
+ ExplicitWidth = 0
+ ExplicitHeight = 0
inline frmIntro: THTMLTpltDlgFrame
Left = 0
Top = 0
@@ -55,6 +59,10 @@ inherited SWAGImportDlg: TSWAGImportDlg
Caption = 'tsFolder'
ImageIndex = 4
TabVisible = False
+ ExplicitLeft = 0
+ ExplicitTop = 0
+ ExplicitWidth = 0
+ ExplicitHeight = 0
object lblFolder: TLabel
Left = 0
Top = 8
@@ -248,6 +256,10 @@ inherited SWAGImportDlg: TSWAGImportDlg
Caption = 'tsFinish'
ImageIndex = 3
TabVisible = False
+ ExplicitLeft = 0
+ ExplicitTop = 0
+ ExplicitWidth = 0
+ ExplicitHeight = 0
inline frmOutro: THTMLTpltDlgFrame
Left = 0
Top = 0
diff --git a/Src/FmSWAGImportDlg.pas b/Src/FmSWAGImportDlg.pas
index e33029319..0de76a9df 100644
--- a/Src/FmSWAGImportDlg.pas
+++ b/Src/FmSWAGImportDlg.pas
@@ -155,10 +155,10 @@ TSWAGImportDlg = class(TWizardDlg, INoPublicConstruct)
/// Retrieves import directory name from edit control where it is
/// entered.
function GetDirNameFromEditCtrl: string;
- /// Retrieves collection specified by user that applies to
- /// imported snippets.
- /// TCollectionID. The required collection ID.
- function SelectedCollectionID: TCollectionID;
+ /// Retrieves vault specified by user that applies to imported
+ /// snippets.
+ /// TVaultID. The required vault ID.
+ function SelectedCollectionID: TVaultID;
/// Validates entries on the wizard page identified by the given
/// page index.
procedure ValidatePage(const PageIdx: Integer);
@@ -535,9 +535,9 @@ procedure TSWAGImportDlg.ConfigForm;
fCollList.ToStrings(cbCollection.Items);
Assert(cbCollection.Items.Count > 0,
ClassName + '.ConfigForm: no collections');
- Assert(TCollections.Instance.ContainsID(TCollectionID.Default),
+ Assert(TCollections.Instance.ContainsID(TVaultID.Default),
ClassName + '.ConfigForm: default collection not found');
- cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TVaultID.Default);
Assert(cbCollection.ItemIndex >= 0,
ClassName + '.ConfigForm: default collection not in cbCollection');
end;
@@ -871,7 +871,7 @@ procedure TSWAGImportDlg.PreviewSelectedPacket;
);
end;
-function TSWAGImportDlg.SelectedCollectionID: TCollectionID;
+function TSWAGImportDlg.SelectedCollectionID: TVaultID;
begin
Assert(cbCollection.ItemIndex >= 0,
ClassName + '.SelectedCollectionID: no collection selected');
diff --git a/Src/FmSelectionSearchDlg.pas b/Src/FmSelectionSearchDlg.pas
index 37c0eed18..4a756351c 100644
--- a/Src/FmSelectionSearchDlg.pas
+++ b/Src/FmSelectionSearchDlg.pas
@@ -63,9 +63,9 @@ TSelectionSearchDlg = class(TGenericOKDlg, INoPublicConstruct)
}
/// Selects all snippets from the given collection.
- /// TCollectionID ID of the required
- /// collection.
- procedure SelectDB(const ACollectionID: TCollectionID);
+ /// TVaultID ID of the required vault.
+ ///
+ procedure SelectDB(const ACollectionID: TVaultID);
/// Populates collections pop-up menu with menu items.
procedure PopulateCollectionsMenu;
@@ -278,7 +278,7 @@ procedure TSelectionSearchDlg.PopulateCollectionsMenu;
AddMenuItem(Collection);
end;
-procedure TSelectionSearchDlg.SelectDB(const ACollectionID: TCollectionID);
+procedure TSelectionSearchDlg.SelectDB(const ACollectionID: TVaultID);
var
Snippet: TSnippet; // references each snippet in database
SnippetList: TSnippetList; // list of selected snippets
diff --git a/Src/FmSnippetsEditorDlg.pas b/Src/FmSnippetsEditorDlg.pas
index 5c7079dc3..3ccc12a15 100644
--- a/Src/FmSnippetsEditorDlg.pas
+++ b/Src/FmSnippetsEditorDlg.pas
@@ -178,13 +178,13 @@ TSnippetsEditorDlg = class(TGenericOKDlg, INoPublicConstruct)
fMemoCaretPosDisplayMgr: TMemoCaretPosDisplayMgr;
// Manages display of memo caret positions
- /// Returns the ID of the collection that applies to a new or
- /// existing snippet.
- /// TCollectionID. The required collection ID.
- /// For a new snippet the return value is the collection to be
- /// applied to the snippet. For an existing snippet this is collection to
- /// which the snippet already belongs.
- function SelectedCollectionID: TCollectionID;
+ /// Returns the ID of the vault that applies to a new or existing
+ /// snippet.
+ /// TVaultID. The required vault ID.
+ /// For a new snippet the return value is the vault to be applied
+ /// to the snippet. For an existing snippet this is the value to which the
+ /// snippet already belongs.
+ function SelectedCollectionID: TVaultID;
/// Returns a snippet key that is unique with the current
/// snippet collection.
@@ -892,7 +892,7 @@ procedure TSnippetsEditorDlg.InitControls;
cbCategories.ItemIndex := fCatList.IndexOf(TCategory.DefaultID);
if cbCategories.ItemIndex = -1 then
cbCategories.ItemIndex := 0;
- cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TVaultID.Default);
Assert(cbCollection.ItemIndex >= 0,
ClassName + '.InitControls: No default collection in cbCollection');
cbCollection.Visible := True; // can select collection of new snippet
@@ -978,7 +978,7 @@ procedure TSnippetsEditorDlg.PopulateControls;
fCollList.ToStrings(cbCollection.Items);
end;
-function TSnippetsEditorDlg.SelectedCollectionID: TCollectionID;
+function TSnippetsEditorDlg.SelectedCollectionID: TVaultID;
begin
// If editing existing snippet ID then the collection cannot be edited
if Assigned(fSnippet) then
diff --git a/Src/FmUserDataPathDlg.pas b/Src/FmUserDataPathDlg.pas
index 74215c0b8..a5981e27a 100644
--- a/Src/FmUserDataPathDlg.pas
+++ b/Src/FmUserDataPathDlg.pas
@@ -236,7 +236,7 @@ procedure TUserDataPathDlg.ConfigForm;
frmProgress.Visible := False;
frmProgress.Range := TRange.Create(0, 100);
fCollList.ToStrings(cbCollection.Items);
- cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TVaultID.Default);
end;
procedure TUserDataPathDlg.CopyFileHandler(Sender: TObject;
diff --git a/Src/FrDisplayPrefs.pas b/Src/FrDisplayPrefs.pas
index 41c8834d1..ddc7ff5d7 100644
--- a/Src/FrDisplayPrefs.pas
+++ b/Src/FrDisplayPrefs.pas
@@ -61,7 +61,7 @@ TDisplayPrefsFrame = class(TPrefsBaseFrame)
/// Local copy of snippet heading / tree node colour for each
/// collection.
- fSnippetHeadingColours: TDictionary;
+ fSnippetHeadingColours: TDictionary;
fGroupHeadingColourBox: TColorBoxEx;
fGroupHeadingColourDlg: TColorDialogEx;
@@ -88,7 +88,7 @@ TDisplayPrefsFrame = class(TPrefsBaseFrame)
procedure SnippetHeadingColourBoxChange(Sender: TObject);
procedure PopulateFontSizeCombos;
procedure SetTabOrder;
- function SelectedCollectionID: TCollectionID;
+ function SelectedCollectionID: TVaultID;
public
constructor Create(AOwner: TComponent); override;
{Object constructor. Sets up frame and populates controls.
@@ -164,7 +164,7 @@ procedure TDisplayPrefsFrame.Activate(const Prefs: IPreferences;
var
Collection: TCollection;
begin
- cbCollection.ItemIndex := fCollList.IndexOfUID(TCollectionID.Default);
+ cbCollection.ItemIndex := fCollList.IndexOfUID(TVaultID.Default);
Assert(cbCollection.ItemIndex >= 0,
ClassName + '.Activate: no default collection found in cbCollection');
SelectOverviewTreeState(Prefs.OverviewStartState);
@@ -354,8 +354,8 @@ constructor TDisplayPrefsFrame.Create(AOwner: TComponent);
PopulateFontSizeCombos;
- fSnippetHeadingColours := TDictionary.Create(
- TCollectionID.TComparer.Create
+ fSnippetHeadingColours := TDictionary