Componentes.Terceros.DevExp.../official/x.38/ExpressLibrary/Sources/cxFormats.pas
2008-08-27 11:56:15 +00:00

1256 lines
39 KiB
ObjectPascal

{********************************************************************}
{ }
{ Developer Express Visual Component Library }
{ Express Cross Platform Library classes }
{ }
{ Copyright (c) 2000-2008 Developer Express Inc. }
{ ALL RIGHTS RESERVED }
{ }
{ The entire contents of this file is protected by U.S. and }
{ International Copyright Laws. Unauthorized reproduction, }
{ reverse-engineering, and distribution of all or any portion of }
{ the code contained in this file is strictly prohibited and may }
{ result in severe civil and criminal penalties and will be }
{ prosecuted to the maximum extent possible under the law. }
{ }
{ RESTRICTIONS }
{ }
{ THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES }
{ (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE }
{ SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS }
{ LICENSED TO DISTRIBUTE THE EXPRESSCROSSPLATFORMLIBRARY AND ALL }
{ ACCOMPANYING VCL CONTROLS AS PART OF AN EXECUTABLE PROGRAM }
{ ONLY. }
{ }
{ THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED }
{ FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE }
{ COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE }
{ AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT }
{ AND PERMISSION FROM DEVELOPER EXPRESS INC. }
{ }
{ CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON }
{ ADDITIONAL RESTRICTIONS. }
{ }
{********************************************************************}
unit cxFormats;
{$I cxVer.inc}
interface
uses
Windows, Messages,
Classes, cxDateUtils;
type
IcxFormatControllerListener = interface
['{A7F2F6D3-1A7D-4295-A6E6-9297BD83D0DE}']
procedure FormatChanged;
end;
IcxFormatControllerListener2 = interface
['{5E33A2A7-0C77-415F-A359-112103E54937}']
procedure TimeChanged;
end;
TcxDateTimeEditMaskKind = (dtmkDate, dtmkTime, dtmkDateTime);
TcxDateTimeFormatItemKind = (
dtikString,
dtikYear, // YY YYYY
dtikMonth, // M MM MMM MMMM
dtikDay, // D DD DDD DDDD
dtikHour, // 12H 12HH 24H 24HH
dtikMin, // N NN
dtikSec, // S SS
dtikMSec, // Z ZZ ZZZ
dtikTimeSuffix, // A/P AM/PM AMPM (lower, upper, or mixed case)
dtikDateSeparator,
dtikTimeSeparator
);
TcxTimeSuffixKind = (tskAP, tskAMPM, tskAMPMString);
TcxDateTimeFormatItem = record
Kind: TcxDateTimeFormatItemKind;
Data: string;
end;
TcxDateTimeFormatInfo = record
DefinedItems: array[TcxDateTimeFormatItemKind] of Boolean;
Items: array of TcxDateTimeFormatItem;
end;
TcxDateTimeFormatItemInfo = record
Kind: TcxDateTimeFormatItemKind;
ItemZoneStart, ItemZoneLength: Integer;
TimeSuffixKind: TcxTimeSuffixKind;
end;
{ TcxFormatController }
TcxFormatController = class
private
FAssignedCurrencyFormat: Boolean;
FAssignedRegExprDateEditMask: Boolean;
FAssignedRegExprDateTimeEditMask: Boolean;
FAssignedStandardDateEditMask: Boolean;
FAssignedStandardDateTimeEditMask: Boolean;
FAssignedStartOfWeek: Boolean;
FCurrencyFormat: string;
FDateEditFormat: string;
FDateEditMask: string;
FDateFormatInfo: TcxDateTimeFormatInfo;
FDateTimeFormatInfo: TcxDateTimeFormatInfo;
FFirstWeekOfYear: TcxFirstWeekOfYear;
FList: TList;
FLockCount: Integer;
FMaskedDateEditFormat: string;
FMaskedDateTimeEditFormat: string;
FRegExprDateEditMask: string;
FRegExprDateTimeEditMask: string;
FStandardDateEditMask: string;
FStandardDateTimeEditMask: string;
FStartOfWeek: TDayOfWeek;
FTimeFormatInfo: TcxDateTimeFormatInfo;
FUseDelphiDateTimeFormats: Boolean;
procedure CalculateDateEditMasks(AUseSmartInputWhenRegExpr: Boolean);
function GetCurrencyFormat: string;
function GetDateEditFormat(AIsMasked: Boolean): string;
function GetDateTimeDisplayFormat(AMaskKind: TcxDateTimeEditMaskKind): string;
class function GetDateTimeFormatItemStandardMaskZoneLength(
const AItem: TcxDateTimeFormatItem): Integer;
function GetStartOfWeek: TDayOfWeek;
function InternalGetDateTimeEditRegExprMask(
AFormatInfo: TcxDateTimeFormatInfo;
AMaskKind: TcxDateTimeEditMaskKind): string;
function InternalGetDateTimeEditStandardMask(
AFormatInfo: TcxDateTimeFormatInfo;
AMaskKind: TcxDateTimeEditMaskKind): string;
function InternalGetMaskedDateEditFormat(
AFormatInfo: TcxDateTimeFormatInfo): string;
procedure SetAssignedCurrencyFormat(Value: Boolean);
procedure SetAssignedRegExprDateEditMask(Value: Boolean);
procedure SetAssignedRegExprDateTimeEditMask(Value: Boolean);
procedure SetAssignedStandardDateEditMask(Value: Boolean);
procedure SetAssignedStandardDateTimeEditMask(Value: Boolean);
procedure SetAssignedStartOfWeek(Value: Boolean);
procedure SetCurrencyFormat(const Value: string);
procedure SetFirstWeekOfYear(Value: TcxFirstWeekOfYear);
procedure SetRegExprDateEditMask(const Value: string);
procedure SetRegExprDateTimeEditMask(const Value: string);
procedure SetStandardDateEditMask(const Value: string);
procedure SetStandardDateTimeEditMask(const Value: string);
procedure SetStartOfWeek(Value: TDayOfWeek);
procedure SetUseDelphiDateTimeFormats(Value: Boolean);
protected
FWindow: HWND;
procedure MainWndProc(var Message: TMessage);
procedure WndProc(var Message: TMessage); virtual;
procedure FormatChanged;
procedure TimeChanged;
public
constructor Create;
destructor Destroy; override;
procedure AddListener(AListener: IcxFormatControllerListener); virtual;
procedure BeginUpdate;
procedure EndUpdate;
procedure GetFormats;
class function GetDateTimeFormatItemStandardMaskInfo(
const AFormatInfo: TcxDateTimeFormatInfo; APos: Integer;
out AItemInfo: TcxDateTimeFormatItemInfo): Boolean;
function GetDateTimeStandardMaskStringLength(
const AFormatInfo: TcxDateTimeFormatInfo): Integer;
procedure NotifyListeners;
procedure RemoveListener(AListener: IcxFormatControllerListener); virtual;
property AssignedCurrencyFormat: Boolean read FAssignedCurrencyFormat write SetAssignedCurrencyFormat;
property AssignedRegExprDateEditMask: Boolean read FAssignedRegExprDateEditMask write SetAssignedRegExprDateEditMask;
property AssignedRegExprDateTimeEditMask: Boolean read FAssignedRegExprDateTimeEditMask write SetAssignedRegExprDateTimeEditMask;
property AssignedStandardDateEditMask: Boolean read FAssignedStandardDateEditMask write SetAssignedStandardDateEditMask;
property AssignedStandardDateTimeEditMask: Boolean read FAssignedStandardDateTimeEditMask write SetAssignedStandardDateTimeEditMask;
property AssignedStartOfWeek: Boolean read FAssignedStartOfWeek write SetAssignedStartOfWeek;
property CurrencyFormat: string read FCurrencyFormat write SetCurrencyFormat;
property DateEditFormat: string read FDateEditFormat;
property DateEditMask: string read FDateEditMask;
property DateFormatInfo: TcxDateTimeFormatInfo read FDateFormatInfo;
property DateTimeFormatInfo: TcxDateTimeFormatInfo read FDateTimeFormatInfo;
property FirstWeekOfYear: TcxFirstWeekOfYear read FFirstWeekOfYear write SetFirstWeekOfYear;
property MaskedDateEditFormat: string read FMaskedDateEditFormat;
property MaskedDateTimeEditFormat: string read FMaskedDateTimeEditFormat;
property RegExprDateEditMask: string read FRegExprDateEditMask write SetRegExprDateEditMask;
property RegExprDateTimeEditMask: string read FRegExprDateTimeEditMask write SetRegExprDateTimeEditMask;
property StandardDateEditMask: string read FStandardDateEditMask write SetStandardDateEditMask;
property StandardDateTimeEditMask: string read FStandardDateTimeEditMask write SetStandardDateTimeEditMask;
property StartOfWeek: TDayOfWeek read FStartOfWeek write SetStartOfWeek;
property TimeFormatInfo: TcxDateTimeFormatInfo read FTimeFormatInfo;
property UseDelphiDateTimeFormats: Boolean read FUseDelphiDateTimeFormats write SetUseDelphiDateTimeFormats;
end;
function cxFormatController: TcxFormatController;
function GetCharString(C: Char; ACount: Integer): string;
implementation
uses
SysUtils, Forms, cxClasses;
var
FcxFormatController: TcxFormatController;
function GetCharString(C: Char; ACount: Integer): string;
var
I: Integer;
begin
Result := '';
for I := 1 to ACount do
Result := Result + C;
end;
function CharLength(const S: string; Index: Integer): Integer;
begin
Result := 1;
assert((Index > 0) and (Index <= Length(S)));
if SysLocale.FarEast and (S[Index] in LeadBytes) then
Result := cxStrCharLength(S, Index);
end;
procedure GetDateTimeFormatInfo(const AFormat: string;
var AFormatInfo: TcxDateTimeFormatInfo);
var
A12HourFormat: Boolean;
procedure AddFormatItem(AItemKind: TcxDateTimeFormatItemKind;
const AItemData: string);
begin
if not(AItemKind in [dtikString, dtikDateSeparator, dtikTimeSeparator]) and
AFormatInfo.DefinedItems[AItemKind] then
Exit;
AFormatInfo.DefinedItems[AItemKind] := True;
SetLength(AFormatInfo.Items, Length(AFormatInfo.Items) + 1);
with AFormatInfo.Items[Length(AFormatInfo.Items) - 1] do
begin
Kind := AItemKind;
Data := AItemData;
end;
end;
procedure AppendChars(const S: string; AStartIndex, ACount: Integer);
begin
if (Length(AFormatInfo.Items) = 0) or
(AFormatInfo.Items[Length(AFormatInfo.Items) - 1].Kind <> dtikString) then
AddFormatItem(dtikString, '');
with AFormatInfo.Items[Length(AFormatInfo.Items) - 1] do
Data := Data + Copy(S, AStartIndex, ACount);
end;
function GetCount(const AFormat: string; var AStartIndex: Integer;
AStartSymbol: Char): Integer;
begin
Result := 1;
while (AStartIndex <= Length(AFormat)) and (AFormat[AStartIndex] = AStartSymbol) do
begin
Inc(AStartIndex);
Inc(Result);
end;
end;
function ParseFormat(const AFormat: string; ARecursionDepth: Integer): Boolean;
var
ACount, APrevI, I: Integer;
AFormatItemData: string;
ALastToken, AStartSymbol, AToken: Char;
AThereIsHourItem, AThereIsTimeSuffixItem: Boolean;
begin
Result := True;
if (AFormat = '') or (ARecursionDepth = 2) then
Exit;
Inc(ARecursionDepth);
ALastToken := ' ';
AThereIsHourItem := False;
AThereIsTimeSuffixItem := False;
I := 1;
while I <= Length(AFormat) do
begin
AStartSymbol := AFormat[I];
if AStartSymbol in LeadBytes then
begin
AppendChars(AFormat, I, CharLength(AFormat, I));
Inc(I, CharLength(AFormat, I));
ALastToken := ' ';
Continue;
end;
Inc(I, CharLength(AFormat, I));
AToken := AStartSymbol;
if AToken in ['a'..'z'] then
Dec(AToken, 32);
if AToken in ['A'..'Z'] then
begin
if (AToken = 'M') and (ALastToken = 'H') then
AToken := 'N';
ALastToken := AToken;
end;
case AToken of
'E', 'Y':
begin
ACount := GetCount(AFormat, I, AStartSymbol);
if ACount <= 2 then
AFormatItemData := 'YY'
else
AFormatItemData := 'YYYY';
AddFormatItem(dtikYear, AFormatItemData);
end;
'G':
begin
Result := False;
Break;
end;
'M':
begin
ACount := GetCount(AFormat, I, AStartSymbol);
if ACount > 4 then
ACount := 4;
AddFormatItem(dtikMonth, GetCharString('M', ACount));
end;
'D':
begin
ACount := GetCount(AFormat, I, AStartSymbol);
case ACount of
1..4:
AddFormatItem(dtikDay, GetCharString('D', ACount));
5:
Result := ParseFormat(ShortDateFormat, ARecursionDepth);
else
Result := ParseFormat(LongDateFormat, ARecursionDepth);
end;
if not Result then
Break;
end;
'H':
begin
ACount := GetCount(AFormat, I, AStartSymbol);
if ACount > 2 then
ACount := 2;
AddFormatItem(dtikHour, GetCharString('H', ACount));
AThereIsHourItem := True;
end;
'N':
begin
ACount := GetCount(AFormat, I, AStartSymbol);
if ACount > 2 then
ACount := 2;
AddFormatItem(dtikMin, GetCharString('N', ACount));
end;
'S':
begin
ACount := GetCount(AFormat, I, AStartSymbol);
if ACount > 2 then
ACount := 2;
AddFormatItem(dtikSec, GetCharString('S', ACount));
end;
'T':
begin
ACount := GetCount(AFormat, I, AStartSymbol);
if ACount = 1 then
Result := ParseFormat(ShortTimeFormat, ARecursionDepth)
else
Result := ParseFormat(LongTimeFormat, ARecursionDepth);
if not Result then
Break;
end;
'Z':
begin
ACount := GetCount(AFormat, I, AStartSymbol);
if ACount > 3 then
ACount := 3;
AddFormatItem(dtikMSec, GetCharString('Z', ACount));
end;
'A':
begin
if SameText(Copy(AFormat, I - 1, 5), 'AM/PM') then
begin
AddFormatItem(dtikTimeSuffix, Copy(AFormat, I - 1, 5));
Inc(I, 4);
AThereIsTimeSuffixItem := True;
end
else if SameText(Copy(AFormat, I - 1, 3), 'A/P') then
begin
AddFormatItem(dtikTimeSuffix, Copy(AFormat, I - 1, 3));
Inc(I, 2);
AThereIsTimeSuffixItem := True;
end
else if SameText(Copy(AFormat, I - 1, 4), 'AMPM') then
begin
AddFormatItem(dtikTimeSuffix, 'AMPM');
Inc(I, 3);
AThereIsTimeSuffixItem := True;
end
else if SameText(Copy(AFormat, I - 1, 3), 'AAA') then
begin
if SameText(Copy(AFormat, I - 1, 4), 'AAAA') then
ACount := 4
else
ACount := 3;
AddFormatItem(dtikDay, GetCharString('D', ACount));
Inc(I, ACount - 1);
end
else
AppendChars(AStartSymbol, 1, 1);
end;
'C':
begin
GetCount(AFormat, I, AStartSymbol);
Result := ParseFormat(ShortDateFormat, ARecursionDepth);
if not Result then
Break;
AppendChars(' ', 1, 1);
Result := ParseFormat(LongTimeFormat, ARecursionDepth);
if not Result then
Break;
end;
'/':
AddFormatItem(dtikDateSeparator, '');
':':
AddFormatItem(dtikTimeSeparator, '');
'''', '"':
begin
APrevI := I;
while (I <= Length(AFormat)) and (AFormat[I] <> AStartSymbol) do
if AFormat[I] in LeadBytes then
Inc(I, CharLength(AFormat, I))
else
Inc(I);
AppendChars(AFormat, APrevI, I - APrevI);
if I <= Length(AFormat) then
Inc(I);
end;
else
AppendChars(AStartSymbol, 1, 1);
end;
end;
if AThereIsHourItem then
A12HourFormat := AThereIsTimeSuffixItem;
end;
procedure ClearFormatInfo;
var
AFormatItemKind: TcxDateTimeFormatItemKind;
begin
SetLength(AFormatInfo.Items, 0);
for AFormatItemKind := Low(TcxDateTimeFormatItemKind) to High(TcxDateTimeFormatItemKind) do
AFormatInfo.DefinedItems[AFormatItemKind] := False;
end;
procedure ProcessHourItem;
var
I: Integer;
begin
if AFormatInfo.DefinedItems[dtikHour] then
begin
for I := 0 to Length(AFormatInfo.Items) - 1 do
if AFormatInfo.Items[I].Kind = dtikHour then
with AFormatInfo.Items[I] do
begin
if A12HourFormat then
Data := '12' + Data
else
Data := '24' + Data;
Break;
end;
end
else
if AFormatInfo.DefinedItems[dtikTimeSuffix] then
for I := 0 to Length(AFormatInfo.Items) - 1 do
if AFormatInfo.Items[I].Kind = dtikTimeSuffix then
begin
AFormatInfo.DefinedItems[dtikTimeSuffix] := False;
if I < Length(AFormatInfo.Items) - 1 then
Move(AFormatInfo.Items[I + 1], AFormatInfo.Items[I],
SizeOf(TcxDateTimeFormatItem) * Length(AFormatInfo.Items) - 1 - I);
Break;
end;
end;
var
ARes: Boolean;
begin
ClearFormatInfo;
if AFormat <> '' then
ARes := ParseFormat(AFormat, 0)
else
ARes := ParseFormat('C', 0);
if not ARes then
ClearFormatInfo
else
ProcessHourItem;
end;
{ TcxFormatController }
constructor TcxFormatController.Create;
begin
inherited Create;
FList := TList.Create;
FFirstWeekOfYear := fwySystem;
FUseDelphiDateTimeFormats := False;
GetFormats;
end;
destructor TcxFormatController.Destroy;
begin
FList.Free;
if FWindow <> 0 then
{$IFDEF DELPHI6}
Classes.DeallocateHWnd(FWindow);
{$ELSE}
Forms.DeallocateHWnd(FWindow);
{$ENDIF}
inherited Destroy;
end;
procedure TcxFormatController.CalculateDateEditMasks(
AUseSmartInputWhenRegExpr: Boolean);
begin
GetDateTimeFormatInfo(GetDateTimeDisplayFormat(dtmkDate), FDateFormatInfo);
GetDateTimeFormatInfo(GetDateTimeDisplayFormat(dtmkTime), FTimeFormatInfo);
GetDateTimeFormatInfo(GetDateTimeDisplayFormat(dtmkDateTime),
FDateTimeFormatInfo);
FDateEditMask := InternalGetDateTimeEditStandardMask(FDateFormatInfo,
dtmkDate);
if not FAssignedStandardDateEditMask then
FStandardDateEditMask := FDateEditMask;
if not FAssignedRegExprDateEditMask then
begin
FRegExprDateEditMask := InternalGetDateTimeEditRegExprMask(FDateFormatInfo, dtmkDate);
if AUseSmartInputWhenRegExpr then
AddDateRegExprMaskSmartInput(FRegExprDateEditMask, False);
end;
if not FAssignedRegExprDateTimeEditMask then
begin
FRegExprDateTimeEditMask := InternalGetDateTimeEditRegExprMask(
FDateFormatInfo, dtmkDate);
FRegExprDateTimeEditMask := FRegExprDateTimeEditMask + ' '' ''(' +
InternalGetDateTimeEditRegExprMask(FTimeFormatInfo, dtmkTime) + ')?';
if AUseSmartInputWhenRegExpr then
AddDateRegExprMaskSmartInput(FRegExprDateTimeEditMask, True);
end;
if not FAssignedStandardDateTimeEditMask then
FStandardDateTimeEditMask := InternalGetDateTimeEditStandardMask(
FDateTimeFormatInfo, dtmkDateTime);
FMaskedDateEditFormat := InternalGetMaskedDateEditFormat(FDateFormatInfo);
FMaskedDateTimeEditFormat := InternalGetMaskedDateEditFormat(FDateTimeFormatInfo);
end;
function TcxFormatController.GetCurrencyFormat: string;
function GetPositiveCurrencyFormat(const AFormat, ACurrStr: string): string;
begin
if Length(ACurrStr) > 0 then
case Sysutils.CurrencyFormat of
0: Result := ACurrStr + AFormat; { '$1' }
1: Result := AFormat + ACurrStr; { '1$' }
2: Result := ACurrStr + ' ' + AFormat; { '$ 1' }
3: Result := AFormat + ' ' + ACurrStr; { '1 $' }
end;
end;
function GetNegativeCurrencyFormat(const AFormat, ACurrStr: string): string;
begin
case Sysutils.NegCurrFormat of
0: Result := '(' + ACurrStr + AFormat + ')';
1: Result := '-' + ACurrStr + AFormat;
2: Result := ACurrStr + '-' + AFormat;
3: Result := ACurrStr + AFormat + '-';
4: Result := '(' + AFormat + ACurrStr + ')';
5: Result := '-' + AFormat + ACurrStr;
6: Result := AFormat + '-' + ACurrStr;
7: Result := AFormat + ACurrStr + '-';
8: Result := '-' + AFormat + ' ' + ACurrStr;
9: Result := '-' + ACurrStr + ' ' + AFormat;
10: Result := AFormat + ' ' + ACurrStr + '-';
11: Result := ACurrStr + ' ' + AFormat + '-';
12: Result := ACurrStr + ' ' + '-' + AFormat;
13: Result := AFormat + '-' + ' ' + ACurrStr;
14: Result := '(' + ACurrStr + ' ' + AFormat + ')';
15: Result := '(' + AFormat + ' ' + ACurrStr + ')';
end;
end;
var
ACurrStr: string;
I: Integer;
C: Char;
begin
if CurrencyDecimals > 0 then
Result := GetCharString('0', CurrencyDecimals)
else
Result := '';
Result := ',0.' + Result;
ACurrStr := '';
for I := 1 to Length(CurrencyString) do
begin
C := CurrencyString[I];
if (C = ',') or (C = '.') then
ACurrStr := ACurrStr + '''' + C + ''''
else
ACurrStr := ACurrStr + C;
end;
Result := GetPositiveCurrencyFormat(Result, ACurrStr) + ';' +
GetNegativeCurrencyFormat(Result, ACurrStr);
end;
function TcxFormatController.GetDateEditFormat(AIsMasked: Boolean): string;
procedure CorrectForMaskEdit(var S: string);
var
APos, AStartPos: Integer;
begin
APos := Pos('M', S);
if APos <> 0 then
begin
AStartPos := APos;
while APos <= Length(S) do
if S[APos] = 'M' then
Inc(APos)
else
Break;
if APos - AStartPos > 3 then
Delete(S, AStartPos + 3, APos - AStartPos - 3);
end;
end;
var
Format: string;
I: Integer;
ExistFirst: Boolean;
begin
Format := ShortDateFormat;
Result := '';
for I := 1 to Length(Format) do
begin
if (Format[I] = 'd') then
begin
ExistFirst := True;
if (1 < I) and (Format[I - 1] = 'd') then ExistFirst := False;
if (I < Length(Format)) and (Format[I + 1] = 'd') then ExistFirst := False;
if ExistFirst then Result := Result + 'd';
end;
if (Format[I] = 'M') then
begin
ExistFirst := True;
if (1 < I) and (Format[I - 1] = 'M') then ExistFirst := False;
if (I < Length(Format)) and (Format[I + 1] = 'M') then ExistFirst := False;
if ExistFirst then Result := Result + 'M';
end;
Result := Result + Format[I];
end;
if AIsMasked then CorrectForMaskEdit(Result);
end;
function TcxFormatController.GetDateTimeDisplayFormat(
AMaskKind: TcxDateTimeEditMaskKind): string;
begin
case AMaskKind of
dtmkDate:
Result := ShortDateFormat;
dtmkTime:
Result := LongTimeFormat;
dtmkDateTime:
Result := ShortDateFormat + ' ' + LongTimeFormat;
end;
end;
class function TcxFormatController.GetDateTimeFormatItemStandardMaskZoneLength(
const AItem: TcxDateTimeFormatItem): Integer;
begin
case AItem.Kind of
dtikString:
Result := Length(AItem.Data);
dtikYear:
if Length(AItem.Data) = 2 then
Result := 2
else
Result := 4;
dtikMonth, dtikDay:
if Length(AItem.Data) < 3 then
Result := 2
else
Result := 3;
dtikHour, dtikMin, dtikSec:
Result := 2;
// dtikMSec:
dtikTimeSuffix:
begin
if UpperCase(AItem.Data) = 'A/P' then
Result := 1
else if UpperCase(AItem.Data) = 'AM/PM' then
Result := 2
else
begin
Result := Length(TimeAMString);
if Length(TimePMString) > Result then
Result := Length(TimePMString);
end;
end;
dtikDateSeparator, dtikTimeSeparator:
Result := 1;
else
Result := 0;
end;
end;
function TcxFormatController.GetStartOfWeek: TDayOfWeek;
begin
Result := cxDateUtils.GetStartOfWeek;
end;
function TcxFormatController.InternalGetDateTimeEditRegExprMask(
AFormatInfo: TcxDateTimeFormatInfo;
AMaskKind: TcxDateTimeEditMaskKind): string;
procedure AddChar(var S: string; C: Char);
begin
if C = ' ' then
S := S + ''' '''
else
S := S + '\' + C;
end;
procedure AddString(var ADst: string; const ASrc: string);
begin
ADst := ADst + '''' + ASrc + '''';
end;
procedure ProcessDateItem(var S: string;
const AFormatItem: TcxDateTimeFormatItem);
const
reTwoDigitYearMask = '\d\d';
reFourDigitYearMask = '\d\d\d\d';
reMonthMask = '(0?[1-9]|1[012])';
reDayMask = '([012]?[1-9]|[123]0|31)';
var
AUseLongMonthNames: Boolean;
I: Integer;
begin
with AFormatItem do
case Kind of
dtikString:
AddString(S, Data);
dtikYear:
if Length(Data) = 2 then
Result := S + reTwoDigitYearMask
else
Result := S + reFourDigitYearMask;
dtikMonth:
begin
S := S + '(' + reMonthMask + '|(';
AUseLongMonthNames := Length(Data) = 4;
if AUseLongMonthNames then
AddString(S, LongMonthNames[1])
else
AddString(S, ShortMonthNames[1]);
for I := 2 to 12 do
begin
S := S + '|';
if AUseLongMonthNames then
AddString(S, LongMonthNames[I])
else
AddString(S, ShortMonthNames[I]);
end;
S := S + '))';
end;
dtikDay:
S := S + reDayMask;
dtikDateSeparator:
if DateSeparator <> #0 then
AddChar(S, DateSeparator);
end;
end;
procedure ProcessTimeItem(var S: string;
const AFormatItem: TcxDateTimeFormatItem);
begin
with AFormatItem do
case Kind of
dtikString:
AddString(S, Data);
dtikHour:
begin
if Copy(Data, 1, 2) = '12' then
S := S + '(0?[1-9]|1[012])'
else
S := S + '([01]?\d|2[0-3])';
end;
dtikMin:
S := S + '[0-5]?\d';
dtikSec:
S := S + '[0-5]?\d';
// dtikMSec:
dtikTimeSuffix:
begin
if UpperCase(Data) = 'A/P' then
S := S + '(A|P)?'
else if UpperCase(Data) = 'AM/PM' then
S := S + '(AM|PM)?'
else
if (TimeAMString <> '') or (TimePMString <> '') then
begin
S := S + '(''';
if (TimeAMString <> '') and (TimePMString <> '') then
S := S + TimeAMString + '''|''' + TimePMString
else
if TimeAMString <> '' then
S := S + TimeAMString
else
S := S + TimePMString;
S := S + ''')?';
end;
end;
dtikTimeSeparator:
if TimeSeparator <> #0 then
AddChar(S, TimeSeparator);
end;
end;
var
I: Integer;
begin
Result := '';
if (AMaskKind = dtmkDateTime) or (Length(AFormatInfo.Items) = 0) then
Exit;
for I := 0 to Length(AFormatInfo.Items) - 1 do
if AMaskKind = dtmkDate then
ProcessDateItem(Result, AFormatInfo.Items[I])
else
ProcessTimeItem(Result, AFormatInfo.Items[I]);
end;
function TcxFormatController.InternalGetDateTimeEditStandardMask(
AFormatInfo: TcxDateTimeFormatInfo;
AMaskKind: TcxDateTimeEditMaskKind): string;
procedure AddChar(var S: string; C: Char);
begin
S := S + '\' + C;
end;
var
I, J: Integer;
begin
Result := '';
if Length(AFormatInfo.Items) = 0 then
Exit;
if AMaskKind <> dtmkTime then
Result := '!';
for I := 0 to Length(AFormatInfo.Items) - 1 do
with AFormatInfo.Items[I] do
case Kind of
dtikString:
for J := 1 to Length(Data) do
AddChar(Result, Data[J]);
dtikYear:
if Length(Data) = 2 then
Result := Result + '99'
else
Result := Result + '9999';
dtikMonth:
if Length(Data) < 3 then
Result := Result + '99'
else
Result := Result + 'lll';
dtikDay:
if Length(Data) < 3 then
Result := Result + '99'
else
Result := Result + 'lll';
dtikHour, dtikMin, dtikSec:
if AMaskKind = dtmkTime then
Result := Result + '00'
else
Result := Result + '99';
// dtikMSec:
dtikTimeSuffix:
begin
if UpperCase(Data) = 'A/P' then
Result := Result + 'c'
else if UpperCase(Data) = 'AM/PM' then
Result := Result + 'cc'
else
begin
J := Length(TimeAMString);
if Length(TimePMString) > J then
J := Length(TimePMString);
Result := Result + GetCharString('c', J);
end;
end;
dtikDateSeparator:
Result := Result + '/';
dtikTimeSeparator:
Result := Result + ':';
end;
if AMaskKind = dtmkTime then
Result := Result + ';1;0'
else
Result := Result + ';1; ';
end;
function TcxFormatController.InternalGetMaskedDateEditFormat(
AFormatInfo: TcxDateTimeFormatInfo): string;
var
I: Integer;
begin
Result := '';
for I := 0 to Length(AFormatInfo.Items) - 1 do
with AFormatInfo.Items[I] do
case Kind of
dtikString:
Result := Result + '''' + Data + '''';
dtikYear:
Result := Result + LowerCase(Data);
dtikMonth:
if Length(Data) < 3 then
Result := Result + 'mm'
else
Result := Result + 'mmm';
dtikDay:
if Length(Data) < 3 then
Result := Result + 'dd'
else
Result := Result + 'ddd';
dtikHour:
Result := Result + 'hh';
dtikMin:
Result := Result + 'nn';
dtikSec:
Result := Result + 'ss';
// dtikMSec:
dtikTimeSuffix:
Result := Result + LowerCase(Data);
dtikDateSeparator:
Result := Result + '/';
dtikTimeSeparator:
Result := Result + ':';
end;
end;
procedure TcxFormatController.AddListener(
AListener: IcxFormatControllerListener);
begin
with FList do
if IndexOf(Pointer(AListener)) = -1 then
begin
if Count = 0 then
{$IFDEF DELPHI6}
FWindow := Classes.AllocateHWnd(MainWndProc);
{$ELSE}
FWindow := Forms.AllocateHWnd(MainWndProc);
{$ENDIF}
Add(Pointer(AListener));
end;
end;
procedure TcxFormatController.RemoveListener(
AListener: IcxFormatControllerListener);
begin
FList.Remove(Pointer(AListener));
if FList.Count = 0 then
begin
{$IFDEF DELPHI6}
Classes.DeallocateHWnd(FWindow);
{$ELSE}
Forms.DeallocateHWnd(FWindow);
{$ENDIF}
FWindow := 0;
end;
end;
procedure TcxFormatController.GetFormats;
begin
if FcxFormatController = nil then // to avoid stack overflow
FcxFormatController := Self;
if not FAssignedCurrencyFormat then
FCurrencyFormat := GetCurrencyFormat;
if not FAssignedStartOfWeek then
FStartOfWeek := GetStartOfWeek;
CalculateDateEditMasks(True);
FDateEditFormat := GetDateEditFormat(False);
end;
class function TcxFormatController.GetDateTimeFormatItemStandardMaskInfo(
const AFormatInfo: TcxDateTimeFormatInfo; APos: Integer;
out AItemInfo: TcxDateTimeFormatItemInfo): Boolean;
function GetTimeSuffixKind(const AFormatItemData: string): TcxTimeSuffixKind;
begin
if UpperCase(AFormatItemData) = 'A/P' then
Result := tskAP
else if UpperCase(AFormatItemData) = 'AM/PM' then
Result := tskAMPM
else
Result := tskAMPMString;
end;
var
AItemZoneStart, I: Integer;
AItemZoneStarts: array of Integer;
begin
Result := False;
if (APos < 1) or (Length(AFormatInfo.Items) = 0) then
Exit;
SetLength(AItemZoneStarts, Length(AFormatInfo.Items));
AItemZoneStart := 1;
for I := 0 to Length(AFormatInfo.Items) - 1 do
begin
AItemZoneStarts[I] := AItemZoneStart;
Inc(AItemZoneStart, GetDateTimeFormatItemStandardMaskZoneLength(AFormatInfo.Items[I]));
if APos < AItemZoneStart then
begin
AItemInfo.Kind := AFormatInfo.Items[I].Kind;
AItemInfo.ItemZoneStart := AItemZoneStarts[I];
AItemInfo.ItemZoneLength := AItemZoneStart - AItemZoneStarts[I];
if AItemInfo.Kind = dtikTimeSuffix then
AItemInfo.TimeSuffixKind := GetTimeSuffixKind(AFormatInfo.Items[I].Data);
Result := True;
Break;
end;
end;
end;
function TcxFormatController.GetDateTimeStandardMaskStringLength(
const AFormatInfo: TcxDateTimeFormatInfo): Integer;
var
I: Integer;
begin
Result := 0;
for I := 0 to Length(AFormatInfo.Items) - 1 do
Inc(Result, GetDateTimeFormatItemStandardMaskZoneLength(AFormatInfo.Items[I]));
end;
procedure TcxFormatController.NotifyListeners;
var
I: Integer;
begin
for I := 0 to FList.Count - 1 do
IcxFormatControllerListener(FList[I]).FormatChanged;
end;
procedure TcxFormatController.MainWndProc(var Message: TMessage);
begin
try
WndProc(Message);
except
Application.HandleException(Self);
end;
end;
procedure TcxFormatController.WndProc(var Message: TMessage);
begin
if (Message.Msg = WM_SETTINGCHANGE) and ((Message.WParam = 0) and
(PChar(Message.LParam) = 'intl')) and
Application.UpdateFormatSettings then
begin
SysUtils.GetFormatSettings;
GetFormats;
NotifyListeners;
Message.Result := 0;
Exit;
end;
if Message.Msg = WM_TIMECHANGE then
begin
TimeChanged;
Message.Result := 0;
Exit;
end;
with Message do Result := DefWindowProc(FWindow, Msg, wParam, lParam);
end;
procedure TcxFormatController.BeginUpdate;
begin
Inc(FLockCount);
end;
procedure TcxFormatController.EndUpdate;
begin
Dec(FLockCount);
if FLockCount = 0 then
NotifyListeners;
end;
procedure TcxFormatController.FormatChanged;
begin
if FLockCount = 0 then
begin
GetFormats;
NotifyListeners;
end;
end;
procedure TcxFormatController.TimeChanged;
var
I: Integer;
AIntf: IcxFormatControllerListener2;
begin
for I := 0 to FList.Count - 1 do
if Supports(IcxFormatControllerListener(FList[I]),
IcxFormatControllerListener2, AIntf) then
AIntf.TimeChanged;
end;
function cxFormatController: TcxFormatController;
begin
if FcxFormatController = nil then
FcxFormatController := TcxFormatController.Create;
Result := FcxFormatController;
end;
procedure TcxFormatController.SetAssignedCurrencyFormat(Value: Boolean);
begin
if FAssignedCurrencyFormat <> Value then
begin
FAssignedCurrencyFormat := Value;
FormatChanged;
end;
end;
procedure TcxFormatController.SetAssignedRegExprDateEditMask(Value: Boolean);
begin
if FAssignedRegExprDateEditMask <> Value then
begin
FAssignedRegExprDateEditMask := Value;
FormatChanged;
end;
end;
procedure TcxFormatController.SetAssignedRegExprDateTimeEditMask(Value: Boolean);
begin
if FAssignedRegExprDateTimeEditMask <> Value then
begin
FAssignedRegExprDateTimeEditMask := Value;
FormatChanged;
end;
end;
procedure TcxFormatController.SetAssignedStandardDateEditMask(Value: Boolean);
begin
if FAssignedStandardDateEditMask <> Value then
begin
FAssignedStandardDateEditMask := Value;
FormatChanged;
end;
end;
procedure TcxFormatController.SetAssignedStandardDateTimeEditMask(Value: Boolean);
begin
if FAssignedStandardDateTimeEditMask <> Value then
begin
FAssignedStandardDateTimeEditMask := Value;
FormatChanged;
end;
end;
procedure TcxFormatController.SetAssignedStartOfWeek(Value: Boolean);
begin
if FAssignedStartOfWeek <> Value then
begin
FAssignedStartOfWeek := Value;
FormatChanged;
end;
end;
procedure TcxFormatController.SetCurrencyFormat(const Value: string);
begin
FAssignedCurrencyFormat := True;
if FCurrencyFormat <> Value then
begin
FCurrencyFormat := Value;
FormatChanged;
end;
end;
procedure TcxFormatController.SetFirstWeekOfYear(Value: TcxFirstWeekOfYear);
begin
if Value <> FFirstWeekOfYear then
begin
FFirstWeekOfYear := Value;
FormatChanged;
end;
end;
procedure TcxFormatController.SetRegExprDateEditMask(const Value: string);
begin
FAssignedRegExprDateEditMask := True;
if FRegExprDateEditMask <> Value then
begin
FRegExprDateEditMask := Value;
FormatChanged;
end;
end;
procedure TcxFormatController.SetRegExprDateTimeEditMask(const Value: string);
begin
FAssignedRegExprDateTimeEditMask := True;
if FRegExprDateTimeEditMask <> Value then
begin
FRegExprDateTimeEditMask := Value;
FormatChanged;
end;
end;
procedure TcxFormatController.SetStandardDateEditMask(const Value: string);
begin
FAssignedStandardDateEditMask := True;
if FStandardDateEditMask <> Value then
begin
FStandardDateEditMask := Value;
FormatChanged;
end;
end;
procedure TcxFormatController.SetStandardDateTimeEditMask(const Value: string);
begin
FAssignedStandardDateTimeEditMask := True;
if FStandardDateTimeEditMask <> Value then
begin
FStandardDateTimeEditMask := Value;
FormatChanged;
end;
end;
procedure TcxFormatController.SetStartOfWeek(Value: TDayOfWeek);
begin
FAssignedStartOfWeek := True;
if FStartOfWeek <> Value then
begin
FStartOfWeek := Value;
FormatChanged;
end;
end;
procedure TcxFormatController.SetUseDelphiDateTimeFormats(Value: Boolean);
begin
if FUseDelphiDateTimeFormats <> Value then
begin
FUseDelphiDateTimeFormats := Value;
FormatChanged;
if Value then
MinYear := 1
else
MinYear := 100;
end;
end;
initialization
finalization
FcxFormatController.Free;
FcxFormatController := nil;
end.