|
@@ -3,7 +3,7 @@
|
|
-------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------
|
|
Modified version of standard Masks unit
|
|
Modified version of standard Masks unit
|
|
|
|
|
|
- Copyright (C) 2010-2016 Alexander Koblov ([email protected])
|
|
|
|
|
|
+ Copyright (C) 2010-2021 Alexander Koblov ([email protected])
|
|
|
|
|
|
This file is based on masks.pas from the Lazarus Component Library (LCL)
|
|
This file is based on masks.pas from the Lazarus Component Library (LCL)
|
|
|
|
|
|
@@ -26,6 +26,8 @@ uses
|
|
|
|
|
|
type
|
|
type
|
|
TMaskCharType = (mcChar, mcAnyChar, mcAnyText);
|
|
TMaskCharType = (mcChar, mcAnyChar, mcAnyText);
|
|
|
|
+ TMaskOption = (moCaseSensitive, moIgnoreAccents, moWindowsMask, moPinyin);
|
|
|
|
+ TMaskOptions = set of TMaskOption;
|
|
|
|
|
|
TMaskChar = record
|
|
TMaskChar = record
|
|
case CharType: TMaskCharType of
|
|
case CharType: TMaskCharType of
|
|
@@ -44,6 +46,7 @@ type
|
|
private
|
|
private
|
|
FTemplate:string;
|
|
FTemplate:string;
|
|
FMask: TMaskString;
|
|
FMask: TMaskString;
|
|
|
|
+ FUsePinyin: Boolean;
|
|
FCaseSensitive: Boolean;
|
|
FCaseSensitive: Boolean;
|
|
fIgnoreAccents: Boolean;
|
|
fIgnoreAccents: Boolean;
|
|
fWindowsInterpretation: boolean;
|
|
fWindowsInterpretation: boolean;
|
|
@@ -52,10 +55,10 @@ type
|
|
procedure SetTemplate(AValue: String);
|
|
procedure SetTemplate(AValue: String);
|
|
procedure Update;
|
|
procedure Update;
|
|
public
|
|
public
|
|
- constructor Create(const AValue: string; bCaseSensitive: boolean = False; bIgnoreAccents: boolean = False; bWindowsInterpretation: boolean = False);
|
|
|
|
- function Matches(const AFileName: string; usePinyin: boolean = False): boolean;
|
|
|
|
- function LegacyMatches(const AFileName: string; usePinyin: boolean = False): boolean;
|
|
|
|
- function WindowsMatches(const AFileName: string; usePinyin: boolean = False): boolean;
|
|
|
|
|
|
+ constructor Create(const AValue: string; const AOptions: TMaskOptions = []);
|
|
|
|
+ function Matches(const AFileName: string): boolean;
|
|
|
|
+ function LegacyMatches(const AFileName: string): boolean;
|
|
|
|
+ function WindowsMatches(const AFileName: string): boolean;
|
|
property CaseSensitive:boolean read FCaseSensitive write SetCaseSence;
|
|
property CaseSensitive:boolean read FCaseSensitive write SetCaseSence;
|
|
property Template:string read FTemplate write SetTemplate;
|
|
property Template:string read FTemplate write SetTemplate;
|
|
end;
|
|
end;
|
|
@@ -73,18 +76,17 @@ type
|
|
function GetCount: Integer;
|
|
function GetCount: Integer;
|
|
function GetItem(Index: Integer): TMask;
|
|
function GetItem(Index: Integer): TMask;
|
|
public
|
|
public
|
|
- constructor Create(const AValue: string; ASeparatorCharset: string = ';'; bCaseSensitive: boolean = False; bIgnoreAccents: boolean = False; bWindowsInterpretation: boolean = False);
|
|
|
|
|
|
+ constructor Create(const AValue: string; ASeparatorCharset: string = ';'; const AOptions: TMaskOptions = []);
|
|
destructor Destroy; override;
|
|
destructor Destroy; override;
|
|
|
|
|
|
- function Matches(const AFileName: String; usePinyin:boolean=False): Boolean;
|
|
|
|
|
|
+ function Matches(const AFileName: String): Boolean;
|
|
|
|
|
|
property Count: Integer read GetCount;
|
|
property Count: Integer read GetCount;
|
|
property Items[Index: Integer]: TMask read GetItem;
|
|
property Items[Index: Integer]: TMask read GetItem;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function MatchesMask(const FileName, Mask: String; CaseSensitive: Boolean = False; usePinyin:boolean=False): Boolean;
|
|
|
|
-function MatchesMaskList(const FileName, Mask: string; ASeparatorCharset: string = ';'; ACaseSensitive: boolean = False; AIgnoreAccents: boolean = False; AWindowsInterpretation: boolean = False; usePinyin:boolean=False): boolean;
|
|
|
|
-
|
|
|
|
|
|
+function MatchesMask(const FileName, Mask: String; const AOptions: TMaskOptions = []): Boolean;
|
|
|
|
+function MatchesMaskList(const FileName, Mask: string; ASeparatorCharset: string = ';'; const AOptions: TMaskOptions = []): boolean;
|
|
|
|
|
|
implementation
|
|
implementation
|
|
|
|
|
|
@@ -95,17 +97,16 @@ uses
|
|
//DC
|
|
//DC
|
|
uPinyin, uAccentsUtils;
|
|
uPinyin, uAccentsUtils;
|
|
|
|
|
|
-
|
|
|
|
{ MatchesMask }
|
|
{ MatchesMask }
|
|
-function MatchesMask(const FileName, Mask: String; CaseSensitive: Boolean = False; usePinyin:boolean=False ): Boolean;
|
|
|
|
|
|
+function MatchesMask(const FileName, Mask: String; const AOptions: TMaskOptions): Boolean;
|
|
var
|
|
var
|
|
AMask: TMask;
|
|
AMask: TMask;
|
|
begin
|
|
begin
|
|
if Mask <> '' then
|
|
if Mask <> '' then
|
|
begin
|
|
begin
|
|
- AMask := TMask.Create(Mask, CaseSensitive);
|
|
|
|
|
|
+ AMask := TMask.Create(Mask, AOptions);
|
|
try
|
|
try
|
|
- Result := AMask.Matches(FileName, usePinyin);
|
|
|
|
|
|
+ Result := AMask.Matches(FileName);
|
|
finally
|
|
finally
|
|
AMask.Free;
|
|
AMask.Free;
|
|
end;
|
|
end;
|
|
@@ -115,15 +116,15 @@ begin
|
|
end;
|
|
end;
|
|
|
|
|
|
{ MatchesMaskList }
|
|
{ MatchesMaskList }
|
|
-function MatchesMaskList(const FileName, Mask: string; ASeparatorCharset: string; ACaseSensitive: boolean = False; AIgnoreAccents: boolean = False; AWindowsInterpretation: boolean = False; usePinyin:boolean=False): boolean;
|
|
|
|
|
|
+function MatchesMaskList(const FileName, Mask: string; ASeparatorCharset: string; const AOptions: TMaskOptions): boolean;
|
|
var
|
|
var
|
|
AMaskList: TMaskList;
|
|
AMaskList: TMaskList;
|
|
begin
|
|
begin
|
|
if Mask <> '' then
|
|
if Mask <> '' then
|
|
begin
|
|
begin
|
|
- AMaskList := TMaskList.Create(Mask, ASeparatorCharset, ACaseSensitive, AIgnoreAccents, AWindowsInterpretation);
|
|
|
|
|
|
+ AMaskList := TMaskList.Create(Mask, ASeparatorCharset, AOptions);
|
|
try
|
|
try
|
|
- Result := AMaskList.Matches(FileName, usePinyin);
|
|
|
|
|
|
+ Result := AMaskList.Matches(FileName);
|
|
finally
|
|
finally
|
|
AMaskList.Free;
|
|
AMaskList.Free;
|
|
end;
|
|
end;
|
|
@@ -136,14 +137,15 @@ end;
|
|
{ TMask }
|
|
{ TMask }
|
|
|
|
|
|
{ TMask.Create }
|
|
{ TMask.Create }
|
|
-constructor TMask.Create(const AValue: string; bCaseSensitive: boolean = False; bIgnoreAccents: boolean = False; bWindowsInterpretation: boolean = False);
|
|
|
|
|
|
+constructor TMask.Create(const AValue: string; const AOptions: TMaskOptions);
|
|
begin
|
|
begin
|
|
- FTemplate:=AValue;
|
|
|
|
- FCaseSensitive := bCaseSensitive;
|
|
|
|
- fIgnoreAccents := bIgnoreAccents;
|
|
|
|
- fWindowsInterpretation := bWindowsInterpretation;
|
|
|
|
- if bIgnoreAccents then FTemplate := NormalizeAccentedChar(FTemplate); //Let's set the mask early in straight letters if match attempt has to be with accent and ligature removed.
|
|
|
|
- if not bCaseSensitive then FTemplate := UTF8LowerCase(FTemplate); //Let's set the mask early in lowercase if match attempt has to be case insensitive.
|
|
|
|
|
|
+ FTemplate:= AValue;
|
|
|
|
+ FUsePinyin:= moPinyin in AOptions;
|
|
|
|
+ FCaseSensitive := moCaseSensitive in AOptions;
|
|
|
|
+ fIgnoreAccents := moIgnoreAccents in AOptions;
|
|
|
|
+ fWindowsInterpretation := moWindowsMask in AOptions;
|
|
|
|
+ if FIgnoreAccents then FTemplate := NormalizeAccentedChar(FTemplate); //Let's set the mask early in straight letters if match attempt has to be with accent and ligature removed.
|
|
|
|
+ if not FCaseSensitive then FTemplate := UTF8LowerCase(FTemplate); //Let's set the mask early in lowercase if match attempt has to be case insensitive.
|
|
Update;
|
|
Update;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -236,7 +238,7 @@ begin
|
|
end;
|
|
end;
|
|
|
|
|
|
{ TMask.Matches }
|
|
{ TMask.Matches }
|
|
-function TMask.Matches(const AFileName: string; usePinyin: boolean = False): boolean;
|
|
|
|
|
|
+function TMask.Matches(const AFileName: string): boolean;
|
|
var
|
|
var
|
|
sFilename: string;
|
|
sFilename: string;
|
|
begin
|
|
begin
|
|
@@ -251,13 +253,13 @@ begin
|
|
sFilename := UTF8LowerCase(sFilename);
|
|
sFilename := UTF8LowerCase(sFilename);
|
|
|
|
|
|
if not fWindowsInterpretation then
|
|
if not fWindowsInterpretation then
|
|
- Result := LegacyMatches(sFileName, usePinyin)
|
|
|
|
|
|
+ Result := LegacyMatches(sFileName)
|
|
else
|
|
else
|
|
- Result := WindowsMatches(sFileName, usePinyin);
|
|
|
|
|
|
+ Result := WindowsMatches(sFileName);
|
|
end;
|
|
end;
|
|
|
|
|
|
{ TMask.LegacyMatches }
|
|
{ TMask.LegacyMatches }
|
|
-function TMask.LegacyMatches(const AFileName: string; usePinyin: boolean = False): boolean;
|
|
|
|
|
|
+function TMask.LegacyMatches(const AFileName: string): boolean;
|
|
var
|
|
var
|
|
L: Integer;
|
|
L: Integer;
|
|
S: UnicodeString;
|
|
S: UnicodeString;
|
|
@@ -275,7 +277,7 @@ var
|
|
begin
|
|
begin
|
|
if CharIndex > L then Exit;
|
|
if CharIndex > L then Exit;
|
|
//DCDebug('Match ' + S[CharIndex] + '<?>' + FMask.Chars[I].CharValue);
|
|
//DCDebug('Match ' + S[CharIndex] + '<?>' + FMask.Chars[I].CharValue);
|
|
- if usePinyin then
|
|
|
|
|
|
+ if FUsePinyin then
|
|
begin
|
|
begin
|
|
if not PinyinMatch(S[CharIndex], FMask.Chars[I].CharValue) then exit;
|
|
if not PinyinMatch(S[CharIndex], FMask.Chars[I].CharValue) then exit;
|
|
end
|
|
end
|
|
@@ -333,7 +335,7 @@ end;
|
|
// *. -> any file without extension ( .foo is a filename without extension according to Windows)
|
|
// *. -> any file without extension ( .foo is a filename without extension according to Windows)
|
|
// foo. matches only foo but not foo.txt
|
|
// foo. matches only foo but not foo.txt
|
|
// foo.* -> match either foo or foo.*
|
|
// foo.* -> match either foo or foo.*
|
|
-function TMask.WindowsMatches(const AFileName: string; usePinyin: boolean = False): boolean;
|
|
|
|
|
|
+function TMask.WindowsMatches(const AFileName: string): boolean;
|
|
var
|
|
var
|
|
Ext, sInitialTemplate: string;
|
|
Ext, sInitialTemplate: string;
|
|
sInitialMask: UnicodeString;
|
|
sInitialMask: UnicodeString;
|
|
@@ -346,7 +348,7 @@ begin
|
|
sInitialTemplate := FTemplate; //Preserve initial state of FTemplate
|
|
sInitialTemplate := FTemplate; //Preserve initial state of FTemplate
|
|
FTemplate := Copy(sInitialMask, 1, Length(sInitialMask) - 2);
|
|
FTemplate := Copy(sInitialMask, 1, Length(sInitialMask) - 2);
|
|
Update;
|
|
Update;
|
|
- Result := LegacyMatches(AFileName, usePinyin);
|
|
|
|
|
|
+ Result := LegacyMatches(AFileName);
|
|
FTemplate := sInitialTemplate; //Restore initial state of FTemplate
|
|
FTemplate := sInitialTemplate; //Restore initial state of FTemplate
|
|
Update;
|
|
Update;
|
|
end
|
|
end
|
|
@@ -360,7 +362,7 @@ begin
|
|
sInitialTemplate := FTemplate; //Preserve initial state of FTemplate
|
|
sInitialTemplate := FTemplate; //Preserve initial state of FTemplate
|
|
FTemplate := Copy(sInitialMask, 1, Length(sInitialMask) - 1);
|
|
FTemplate := Copy(sInitialMask, 1, Length(sInitialMask) - 1);
|
|
Update;
|
|
Update;
|
|
- Result := LegacyMatches(AFileName, usePinyin);
|
|
|
|
|
|
+ Result := LegacyMatches(AFileName);
|
|
FTemplate := sInitialTemplate; //Restore initial state of FTemplate
|
|
FTemplate := sInitialTemplate; //Restore initial state of FTemplate
|
|
Update;
|
|
Update;
|
|
end
|
|
end
|
|
@@ -373,11 +375,11 @@ begin
|
|
begin
|
|
begin
|
|
//First see if we have 'foo'
|
|
//First see if we have 'foo'
|
|
Result := (AFileName = Copy(sInitialMask, 1, Length(sInitialMask) - 2));
|
|
Result := (AFileName = Copy(sInitialMask, 1, Length(sInitialMask) - 2));
|
|
- if not Result then Result := LegacyMatches(AFileName, usePinyin);
|
|
|
|
|
|
+ if not Result then Result := LegacyMatches(AFileName);
|
|
end
|
|
end
|
|
else
|
|
else
|
|
begin
|
|
begin
|
|
- Result := LegacyMatches(AFileName, usePinyin); //all other cases just call LegacyMatches()
|
|
|
|
|
|
+ Result := LegacyMatches(AFileName); //all other cases just call LegacyMatches()
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -417,7 +419,7 @@ begin
|
|
end;
|
|
end;
|
|
|
|
|
|
{ TMaskList.Create }
|
|
{ TMaskList.Create }
|
|
-constructor TMaskList.Create(const AValue: string; ASeparatorCharset: string; bCaseSensitive: boolean = False; bIgnoreAccents: boolean = False; bWindowsInterpretation: boolean = False);
|
|
|
|
|
|
+constructor TMaskList.Create(const AValue: string; ASeparatorCharset: string; const AOptions: TMaskOptions);
|
|
var
|
|
var
|
|
I: Integer;
|
|
I: Integer;
|
|
S: TParseStringList;
|
|
S: TParseStringList;
|
|
@@ -428,7 +430,7 @@ begin
|
|
S := TParseStringList.Create(AValue, ASeparatorCharset);
|
|
S := TParseStringList.Create(AValue, ASeparatorCharset);
|
|
try
|
|
try
|
|
for I := 0 to S.Count - 1 do
|
|
for I := 0 to S.Count - 1 do
|
|
- FMasks.Add(TMask.Create(S[I], bCaseSensitive, bIgnoreAccents, bWindowsInterpretation));
|
|
|
|
|
|
+ FMasks.Add(TMask.Create(S[I], AOptions));
|
|
finally
|
|
finally
|
|
S.Free;
|
|
S.Free;
|
|
end;
|
|
end;
|
|
@@ -443,7 +445,7 @@ begin
|
|
end;
|
|
end;
|
|
|
|
|
|
{ TMaskList.Matches }
|
|
{ TMaskList.Matches }
|
|
-function TMaskList.Matches(const AFileName: string; usePinyin:boolean=False): boolean;
|
|
|
|
|
|
+function TMaskList.Matches(const AFileName: String): Boolean;
|
|
var
|
|
var
|
|
I: integer;
|
|
I: integer;
|
|
begin
|
|
begin
|
|
@@ -451,7 +453,7 @@ begin
|
|
|
|
|
|
for I := 0 to FMasks.Count - 1 do
|
|
for I := 0 to FMasks.Count - 1 do
|
|
begin
|
|
begin
|
|
- if TMask(FMasks.Items[I]).Matches(AFileName, usePinyin) then
|
|
|
|
|
|
+ if TMask(FMasks.Items[I]).Matches(AFileName) then
|
|
begin
|
|
begin
|
|
Result := True;
|
|
Result := True;
|
|
Exit;
|
|
Exit;
|