{********************************************************************} { } { Developer Express Visual Component Library } { ExpressEditors } { } { Copyright (c) 1998-2007 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 EXPRESSEDITORS 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 cxMaskEdit; {$I cxVer.inc} interface uses {$IFDEF DELPHI6} Variants, {$ENDIF} Windows, Messages, SysUtils, Classes, Controls, StdCtrls, Clipbrd, cxClasses, cxControls, cxContainer, cxDataStorage, cxDataUtils, cxEdit, cxTextEdit, cxEditConsts, cxRegExpr, cxStandardMask, cxFilterControlUtils; type TcxEditMask = type string; TcxEditMaskKind = (emkStandard, emkRegExpr, emkRegExprEx); TcxCustomMaskEdit = class; TcxCustomMaskEditProperties = class; { EcxMaskEditError } EcxMaskEditError = class(EcxEditError); { TcxMaskEditCustomMode } TcxMaskEditCustomMode = class private FCharCase: TEditCharCase; FEchoMode: TcxEditEchoMode; FEditMask: string; FProperties: TcxCustomMaskEditProperties; function GetProperties: TcxCustomMaskEditProperties; protected FClipboardTextLength: Integer; FEdit: TcxCustomMaskEdit; FNeedUpdateEditValue: Boolean; procedure ClearText; function GetMaskKind: TcxEditMaskKind; virtual; function HasEdit: Boolean; property CharCase: TEditCharCase read FCharCase write FCharCase; property EchoMode: TcxEditEchoMode read FEchoMode write FEchoMode; property EditMask: string read FEditMask; property Properties: TcxCustomMaskEditProperties read GetProperties; public constructor Create(AEdit: TcxCustomMaskEdit; AProperties: TcxCustomMaskEditProperties); virtual; procedure AfterPasteFromClipboard; virtual; abstract; procedure BeepOnError; procedure Compile(AMask: string); virtual; abstract; function GetEmptyString: string; virtual; abstract; function GetFormattedText(AText: string; AMatchForBlanksAndLiterals: Boolean = True): string; virtual; abstract; procedure GotoEnd; virtual; abstract; function IsCursorBegin: Boolean; virtual; abstract; function IsCursorEnd: Boolean; virtual; abstract; function IsFullValidText(AText: string): Boolean; virtual; abstract; procedure LMouseDown; virtual; abstract; procedure PrePasteFromClipboard; virtual; abstract; function PressBackSpace: Boolean; virtual; abstract; function PressDelete: Boolean; virtual; abstract; function PressEnd: Boolean; virtual; abstract; function PressHome: Boolean; virtual; abstract; function PressLeft: Boolean; virtual; abstract; function PressRight: Boolean; virtual; abstract; function PressSymbol(var ASymbol: Char): Boolean; virtual; abstract; procedure SetText(AText: string); virtual; abstract; procedure SynchronizeEditValue; virtual; procedure UpdateEditValue; virtual; abstract; function GetUpdatedText(const AText: string; AMatchForBlanksAndLiterals: Boolean = True): string; virtual; abstract; property ClipboardTextLength: Integer read FClipboardTextLength write FClipboardTextLength; end; TcxMaskEditCustomModeClass = class of TcxMaskEditCustomMode; { TcxMaskEditStandardMode } TcxMaskEditStandardMode = class(TcxMaskEditCustomMode) protected FMask: TcxStandardMask; FSelStart: Integer; function GetBlank(APos: Integer): Char; virtual; public constructor Create(AEdit: TcxCustomMaskEdit; AProperties: TcxCustomMaskEditProperties); override; destructor Destroy; override; procedure AfterPasteFromClipboard; override; procedure Compile(AMask: string); override; function GetEmptyString: string; override; function GetFormattedText(AText: string; AMatchForBlanksAndLiterals: Boolean = True): string; override; procedure GotoEnd; override; function IsCursorBegin: Boolean; override; function IsCursorEnd: Boolean; override; function IsFullValidText(AText: string): Boolean; override; procedure LMouseDown; override; procedure PrePasteFromClipboard; override; function PressBackSpace: Boolean; override; function PressDelete: Boolean; override; function PressEnd: Boolean; override; function PressHome: Boolean; override; function PressLeft: Boolean; override; function PressRight: Boolean; override; function PressSymbol(var ASymbol: Char): Boolean; override; procedure SetText(AText: string); override; procedure SynchronizeEditValue; override; procedure UpdateEditValue; override; function GetUpdatedText(const AText: string; AMatchForBlanksAndLiterals: Boolean = True): string; override; end; { TcxMaskEditRegExprMode } TcxMaskEditRegExprMode = class(TcxMaskEditCustomMode) protected FBeginCursor: Boolean; FHead: string; FRegExpr: TcxRegExpr; FSelect: string; FTail: string; FMouseAction: Boolean; procedure ClearTail; function CompileRegExpr(ARegExpr: TcxRegExpr): Boolean; procedure CursorCorrection; procedure DeleteSelection; virtual; function GetMaskKind: TcxEditMaskKind; override; function NextTail: Boolean; procedure RestoreSelection; virtual; public constructor Create(AEdit: TcxCustomMaskEdit; AProperties: TcxCustomMaskEditProperties); override; destructor Destroy; override; procedure AfterPasteFromClipboard; override; procedure Compile(AMask: string); override; function GetEmptyString: string; override; function GetFormattedText(AText: string; AMatchForBlanksAndLiterals: Boolean = True): string; override; procedure GotoEnd; override; function IsCursorBegin: Boolean; override; function IsCursorEnd: Boolean; override; function IsFullValidText(AText: string): Boolean; override; procedure LMouseDown; override; procedure PrePasteFromClipboard; override; function PressBackSpace: Boolean; override; function PressDelete: Boolean; override; function PressEnd: Boolean; override; function PressHome: Boolean; override; function PressLeft: Boolean; override; function PressRight: Boolean; override; function PressSymbol(var ASymbol: Char): Boolean; override; procedure SetText(AText: string); override; procedure SetRegExprCaseInsensitive; procedure SynchronizeEditValue; override; procedure UpdateEditValue; override; function GetUpdatedText(const AText: string; AMatchForBlanksAndLiterals: Boolean = True): string; override; end; { TcxMaskEditRegExprExMode } TcxMaskEditRegExprExMode = class(TcxMaskEditRegExprMode) private FInternalUpdate: string; procedure InternalSymbolUpdate(ASymbol: Char); protected FDeleteNumber: Integer; FNewCursorPos: Integer; FUpdate: string; procedure Clear; procedure CursorCorrection; procedure DeleteSelection; override; function GetMaskKind: TcxEditMaskKind; override; procedure RestoreSelection; override; procedure SymbolDelete; procedure SymbolUpdate(ASymbol: Char); procedure UpdateTail; public constructor Create(AEdit: TcxCustomMaskEdit; AProperties: TcxCustomMaskEditProperties); override; destructor Destroy; override; procedure AfterPasteFromClipboard; override; procedure Compile(AMask: string); override; function GetEmptyString: string; override; function GetFormattedText(AText: string; AMatchForBlanksAndLiterals: Boolean = True): string; override; procedure GotoEnd; override; function IsFullValidText(AText: string): Boolean; override; procedure PrePasteFromClipboard; override; function PressBackSpace: Boolean; override; function PressDelete: Boolean; override; function PressEnd: Boolean; override; function PressHome: Boolean; override; function PressLeft: Boolean; override; function PressRight: Boolean; override; function PressSymbol(var ASymbol: Char): Boolean; override; procedure SetText(AText: string); override; procedure UpdateEditValue; override; end; { TcxCustomMaskEditProperties } TcxCustomMaskEditProperties = class(TcxCustomTextEditProperties) private FAlwaysShowBlanksAndLiterals: Boolean; FCaseInsensitive: Boolean; FEditMask: TcxEditMask; FEmptyString: string; FIgnoreMaskBlank: Boolean; FMaskKind: TcxEditMaskKind; FMaxLengthSetting: Boolean; FTempMode: TcxMaskEditCustomMode; function CreateMode: TcxMaskEditCustomMode; function CreateMode1: TcxMaskEditCustomMode; function GetEditMask: TcxEditMask; function GetIsMasked: Boolean; procedure SetAlwaysShowBlanksAndLiterals(AValue: Boolean); procedure SetCaseInsensitive(AValue: Boolean); procedure SetEditMask(Value: TcxEditMask); procedure SetMaskKind(Value: TcxEditMaskKind); function SpaceToken(AToken: Char): Boolean; function TestTempEditMask: Boolean; function TestTempMaskKind: Boolean; protected function EmptyMask(AMask: string): Boolean; function GetEmptyString: string; procedure SetCharCase(Value: TEditCharCase); override; function GetDisplayFormatOptions: TcxEditDisplayFormatOptions; override; function GetModeClass(AMaskKind: TcxEditMaskKind): TcxMaskEditCustomModeClass; virtual; procedure MaxLengthChanged; override; function UseLookupData: Boolean; override; public constructor Create(AOwner: TPersistent); override; destructor Destroy; override; procedure Assign(Source: TPersistent); override; procedure Changed; override; class function GetContainerClass: TcxContainerClass; override; // function GetEditValueSource(AEditFocused: Boolean): TcxDataEditValueSource; override; function IsEditValueValid(var EditValue: TcxEditValue; AEditFocused: Boolean): Boolean; override; procedure PrepareDisplayValue(const AEditValue: TcxEditValue; var DisplayValue: TcxEditValue; AEditFocused: Boolean); override; procedure ValidateDisplayValue(var ADisplayValue: TcxEditValue; var AErrorText: TCaption; var Error: Boolean; AEdit: TcxCustomEdit); override; public property IsMasked: Boolean read GetIsMasked; // !!! property AlwaysShowBlanksAndLiterals: Boolean read FAlwaysShowBlanksAndLiterals write SetAlwaysShowBlanksAndLiterals default False; property CaseInsensitive: Boolean read FCaseInsensitive write SetCaseInsensitive default True; property EditMask: TcxEditMask read GetEditMask write SetEditMask; property IgnoreMaskBlank: Boolean read FIgnoreMaskBlank write FIgnoreMaskBlank default False; property MaskKind: TcxEditMaskKind read FMaskKind write SetMaskKind default emkStandard; property ValidateOnEnter default True; end; TcxMaskEditProperties = class; { TcxCustomMaskEdit } TcxCustomMaskEdit = class(TcxCustomTextEdit) private FInternalTextSelection: Boolean; FMode: TcxMaskEditCustomMode; FMyMessage: Boolean; FShiftOn: Boolean; FText: string; function GetEditText: TCaption; function GetProperties: TcxCustomMaskEditProperties; function GetActiveProperties: TcxCustomMaskEditProperties; function InternalGetEmptyString: string; procedure InternalSetValue(AValue: string); function IsCursorBegin: Boolean; function IsCursorEnd: Boolean; procedure SetEditText(AValue: TCaption); procedure SetProperties(Value: TcxCustomMaskEditProperties); procedure SendMyKeyDown(Key: Word; Shift: TShiftState); procedure SendMyKeyPress(AKey: Char); protected procedure ChangeHandler(Sender: TObject); override; procedure DblClick; override; procedure DoEnter; override; procedure DoEditKeyDown(var Key: Word; Shift: TShiftState); override; procedure DoEditKeyPress(var Key: Char); override; procedure DoEditKeyUp(var Key: Word; Shift: TShiftState); override; procedure Initialize; override; function InternalGetText: string; override; procedure InternalSetDisplayValue(const Value: TcxEditValue); override; function InternalSetText(const Value: string): Boolean; override; procedure KeyDown(var Key: Word; Shift: TShiftState); override; procedure KeyPress(var Key: Char); override; procedure KeyUp(var Key: Word; Shift: TShiftState); override; procedure Loaded; override; procedure LockInnerEditRepainting; override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure PropertiesChanged(Sender: TObject); override; procedure SelChange(Sender: TObject); override; procedure SetSelText(const Value: TCaption); override; procedure SynchronizeDisplayValue; override; procedure UndoPerformed; override; procedure UnlockInnerEditRepainting; override; function CanSynchronizeModeText: Boolean; virtual; procedure DirectSetSelLength(AValue: Integer); procedure DirectSetSelStart(AValue: Integer); function IsCharValidForPos(var AChar: Char; APos: Integer): Boolean; virtual; procedure UpdateTextFormatting; virtual; property Mode: TcxMaskEditCustomMode read FMode; public {$IFDEF CBUILDER10} constructor Create(AOwner: TComponent); override; {$ENDIF} destructor Destroy; override; procedure CutToClipboard; override; class function GetPropertiesClass: TcxCustomEditPropertiesClass; override; procedure PasteFromClipboard; override; procedure PrepareEditValue(const ADisplayValue: TcxEditValue; out EditValue: TcxEditValue; AEditFocused: Boolean); override; property ActiveProperties: TcxCustomMaskEditProperties read GetActiveProperties; property EditText: TCaption read GetEditText write SetEditText; property Properties: TcxCustomMaskEditProperties read GetProperties write SetProperties; end; { TcxMaskEditProperties } TcxMaskEditProperties = class(TcxCustomMaskEditProperties) published property Alignment; property AlwaysShowBlanksAndLiterals; property AssignedValues; property AutoSelect; property BeepOnError; property CaseInsensitive; property CharCase; property ClearKey; property EchoMode; property HideSelection; property IgnoreMaskBlank; property ImeMode; property ImeName; property IncrementalSearch; property LookupItems; property LookupItemsSorted; property MaskKind; property EditMask; property MaxLength; property OEMConvert; property PasswordChar; property ReadOnly; property UseLeftAlignmentOnEditing; property ValidateOnEnter; property OnChange; property OnEditValueChanged; property OnNewLookupDisplayText; property OnValidate; end; { TcxMaskEdit } TcxMaskEdit = class(TcxCustomMaskEdit) private function GetActiveProperties: TcxMaskEditProperties; function GetProperties: TcxMaskEditProperties; procedure SetProperties(Value: TcxMaskEditProperties); public class function GetPropertiesClass: TcxCustomEditPropertiesClass; override; property ActiveProperties: TcxMaskEditProperties read GetActiveProperties; published property Anchors; property AutoSize; property BeepOnEnter; property Constraints; property DragMode; property Enabled; property ParentColor; property ParentFont; property ParentShowHint; property PopupMenu; property Properties: TcxMaskEditProperties read GetProperties write SetProperties; property ShowHint; property Style; property StyleDisabled; property StyleFocused; property StyleHot; property TabOrder; property TabStop; property Text; property Visible; property DragCursor; property DragKind; property ImeMode; property ImeName; property OnClick; {$IFDEF DELPHI5} property OnContextPopup; {$ENDIF} property OnDblClick; property OnDragDrop; property OnDragOver; property OnEditing; property OnEndDrag; property OnEnter; property OnExit; property OnKeyDown; property OnKeyPress; property OnKeyUp; property OnMouseDown; property OnMouseEnter; property OnMouseLeave; property OnMouseMove; property OnMouseUp; property OnStartDrag; property OnEndDock; property OnStartDock; end; { TcxFilterMaskEditHelper } TcxFilterMaskEditHelper = class(TcxFilterTextEditHelper) public class function GetFilterEditClass: TcxCustomEditClass; override; class function GetSupportedFilterOperators( AProperties: TcxCustomEditProperties; AValueTypeClass: TcxValueTypeClass; AExtendedSet: Boolean = False): TcxFilterControlOperators; override; class procedure InitializeProperties(AProperties, AEditProperties: TcxCustomEditProperties; AHasButtons: Boolean); override; end; function IsAlphaChar(ch: Char): Boolean; //function GetSaveLiteralChars(AMaskEdit: TcxCustomMaskEdit): Boolean; implementation uses cxVariants; function IsAlphaChar(ch: Char): Boolean; begin Result := IsCharAlpha(ch); end; {function GetSaveLiteralChars(AMaskEdit: TcxCustomMaskEdit): Boolean; begin Result := False; if AMaskEdit.Mode is TcxMaskEditStandardMode then if TcxMaskEditStandardMode(AMaskEdit.Mode).FMask <> nil then Result := TcxMaskEditStandardMode(AMaskEdit.Mode).FMask.SaveLiteralCharacters; end;} { TcxMaskEditCustomMode } constructor TcxMaskEditCustomMode.Create(AEdit: TcxCustomMaskEdit; AProperties: TcxCustomMaskEditProperties); begin inherited Create; FEdit := AEdit; if FEdit = nil then FProperties := AProperties; FClipboardTextLength := 0; FNeedUpdateEditValue := False; FCharCase := ecNormal; FEchoMode := eemNormal; end; procedure TcxMaskEditCustomMode.BeepOnError; begin if Properties.BeepOnError then Beep; end; procedure TcxMaskEditCustomMode.SynchronizeEditValue; var ADisplayValue: Variant; begin if HasEdit then begin with FEdit do begin if ModifiedAfterEnter then begin ADisplayValue := FEdit.DisplayValue; ADisplayValue := GetFormattedText(ADisplayValue); end else ActiveProperties.PrepareDisplayValue(EditValue, ADisplayValue, Focused); end; FEdit.SetInternalDisplayValue(ADisplayValue); end; end; procedure TcxMaskEditCustomMode.ClearText; begin if HasEdit then FEdit.DataBinding.UpdateNotConnectedDBEditDisplayValue; end; function TcxMaskEditCustomMode.GetMaskKind: TcxEditMaskKind; begin Result := emkStandard; end; function TcxMaskEditCustomMode.HasEdit: Boolean; begin Result := (FEdit <> nil) and not FEdit.PropertiesChangeLocked; end; function TcxMaskEditCustomMode.GetProperties: TcxCustomMaskEditProperties; begin if FEdit <> nil then Result := FEdit.ActiveProperties else Result := FProperties; end; { TcxMaskEditStandardMode } constructor TcxMaskEditStandardMode.Create(AEdit: TcxCustomMaskEdit; AProperties: TcxCustomMaskEditProperties); begin inherited Create(AEdit, AProperties); FMask := TcxStandardMask.Create; end; destructor TcxMaskEditStandardMode.Destroy; begin FMask.Free; inherited Destroy; end; procedure TcxMaskEditStandardMode.AfterPasteFromClipboard; var AText: string; begin AText := Clipboard.AsText; FEdit.SelStart := FSelStart + Length(AText); if FEdit.SelStart >= Length(FEdit.EditText) then FEdit.SelStart := Length(FEdit.EditText) - 1; if FEdit.SelStart < 0 then FEdit.SelStart := 0; if FMask.Items[FEdit.SelStart] is TcxStandardMaskLiteralItem then begin FEdit.FShiftOn := False; PressRight; end; end; procedure TcxMaskEditStandardMode.Compile(AMask: string); begin FEditMask := AMask; if Properties.EmptyMask(AMask) then Exit; FMask.Compile(AMask); FNeedUpdateEditValue := not HasEdit; end; function TcxMaskEditStandardMode.GetEmptyString: string; begin Result := FMask.EmptyString; end; function TcxMaskEditStandardMode.GetFormattedText(AText: string; AMatchForBlanksAndLiterals: Boolean = True): string; begin FMask.Format(AText, True, AMatchForBlanksAndLiterals); Result := AText; end; procedure TcxMaskEditStandardMode.GotoEnd; begin end; function TcxMaskEditStandardMode.IsCursorBegin: Boolean; var I: Integer; ACount: Integer; begin ACount := 0; for I := 0 to FMask.Count - 1 do begin if FMask.Items[I] is TcxStandardMaskLiteralItem then Inc(ACount) else Break; end; Result := (FEdit.SelStart <= ACount) and (FEdit.SelLength <= 1) or (FEdit.SelStart <= ACount) and (FEdit.CursorPos = FEdit.SelStart); end; function TcxMaskEditStandardMode.IsCursorEnd: Boolean; begin Result := FEdit.SelStart = Length(FEdit.EditText); end; function TcxMaskEditStandardMode.IsFullValidText(AText: string): Boolean; begin Result := FMask.IsFullValid(AText); if not Result and Properties.IgnoreMaskBlank then Result := AText = GetFormattedText(''); end; procedure TcxMaskEditStandardMode.LMouseDown; begin if FEdit.HandleAllocated and Properties.IsMasked then begin if FEdit.SelLength = 0 then FEdit.DirectSetSelLength(1); end; end; procedure TcxMaskEditStandardMode.PrePasteFromClipboard; var AText: string; begin AText := Clipboard.AsText; FSelStart := FEdit.SelStart; FEdit.DirectSetSelStart(FSelStart); FEdit.DirectSetSelLength(Length(AText)); end; function TcxMaskEditStandardMode.PressBackSpace: Boolean; begin Result := False; if FEdit.SelLength <= 1 then PressLeft; PressDelete; end; function TcxMaskEditStandardMode.PressDelete: Boolean; var ABlank: Char; ASelStart: Integer; AText: string; I: Integer; begin Result := False; AText := FEdit.EditText; ASelStart := FEdit.SelStart; for I := FEdit.SelStart to FEdit.SelStart + FEdit.SelLength - 1 do begin if FMask.Items[I] is TcxStandardMaskManyItem then begin ABlank := GetBlank(I + 1); if ABlank <> #0 then begin Delete(AText, I + 1, 1); Insert(ABlank, AText, I + 1); FEdit.SetInternalDisplayValue(AText); FEdit.SelStart := ASelStart; end; end; end; end; function TcxMaskEditStandardMode.PressEnd: Boolean; begin if FEdit.FShiftOn then begin Result := True; Exit; end else Result := False; FEdit.SelStart := Length(FEdit.EditText); end; function TcxMaskEditStandardMode.PressHome: Boolean; begin if FEdit.FShiftOn then begin Result := True; Exit; end else Result := False; FEdit.SelStart := 0; if FMask.Count > 0 then if FMask.Items[FEdit.SelStart] is TcxStandardMaskLiteralItem then PressRight; end; function TcxMaskEditStandardMode.PressLeft: Boolean; function GetSelStart: Integer; var I: Integer; AReset: Boolean; AEnd: Integer; begin Result := 0; AReset := True; AEnd := FEdit.SelStart + FEdit.SelLength; if AEnd >= Length(FEdit.EditText) then Dec(AEnd); if AEnd < 0 then AEnd := 0; for I := FEdit.SelStart to AEnd do begin if FMask.Items[I] is TcxStandardMaskLiteralItem then Inc(Result) else begin AReset := False; Break; end; end; if AReset then begin if FEdit.SelStart + FEdit.SelLength >= Length(FEdit.EditText) then begin Result := AEnd - FEdit.SelStart; Inc(Result); end else Result := 0; end; end; var ADec: Integer; ALeftLiteralCount: Integer; I: Integer; begin if FEdit.FShiftOn then begin if FEdit.SelLength = 1 then begin FEdit.SelStart := FEdit.SelStart + 1; FEdit.SelLength := 0; FEdit.SendMyKeyDown(VK_LEFT, []); FEdit.SendMyKeyDown(VK_LEFT, []); end; Result := True; Exit; end else Result := False; if FEdit.SelLength > 1 then begin I := FEdit.SelStart + GetSelStart; FEdit.SelStart := 0; FEdit.SelStart := I; Exit; end; ALeftLiteralCount := 0; for I := FEdit.SelStart - 1 downto 0 do begin if FMask.Items[I] is TcxStandardMaskLiteralItem then Inc(ALeftLiteralCount) else Break; end; ADec := ALeftLiteralCount + 1; if FEdit.SelStart - ADec < 0 then ADec := 0; if FEdit.SelStart > 0 then FEdit.SelStart := FEdit.SelStart - ADec; end; function TcxMaskEditStandardMode.PressRight: Boolean; function GetSelStart(AI: Integer): Integer; var I: Integer; AReset: Boolean; begin Result := 0; AReset := True; for I := AI downto FEdit.SelStart do begin if FMask.Items[I] is TcxStandardMaskLiteralItem then Inc(Result) else begin AReset := False; Break; end; end; if AReset then Result := 0; end; var AInc: Integer; ARightLiteralCount: Integer; I: Integer; begin if FEdit.FShiftOn then begin if (FEdit.SelLength = 1) and (FEdit.SelStart = FEdit.CursorPos) then FEdit.SelLength := 0; Result := True; Exit; end else Result := False; if FEdit.SelLength > 1 then begin I := FEdit.SelStart + FEdit.SelLength; if I < Length(FEdit.EditText) then begin Dec(I); Dec(I, GetSelStart(I)); end; FEdit.SelStart := 0; FEdit.SelStart := I; Exit; end; ARightLiteralCount := 0; for I := FEdit.SelStart + 1 to FMask.Count - 1 do begin if FMask.Items[I] is TcxStandardMaskLiteralItem then Inc(ARightLiteralCount) else Break; end; AInc := ARightLiteralCount + 1; if FEdit.SelStart + AInc > Length(FEdit.EditText) then AInc := 0; FEdit.SelStart := FEdit.SelStart + AInc; end; function TcxMaskEditStandardMode.PressSymbol(var ASymbol: Char): Boolean; var AText: string; ASelStart: Integer; begin Result := False; if Length(FEdit.EditText) <= 0 then Exit; if FEdit.SelStart >= Length(FEdit.EditText) then Exit; if FMask.Items[FEdit.SelStart] is TcxStandardMaskLiteralItem then begin FEdit.FShiftOn := False; if FEdit.SelLength > 1 then PressDelete; ASelStart := FEdit.SelStart; PressRight; if FEdit.SelStart > ASelStart then PressSymbol(ASymbol); end else begin if FMask.Items[FEdit.SelStart].Check(ASymbol) and FEdit.IsCharValidForPos(ASymbol, FEdit.SelStart + 1) then if ASymbol <> #0 then begin if FEdit.SelLength > 1 then PressDelete; AText := FEdit.EditText; ASelStart := FEdit.SelStart; Delete(AText, FEdit.SelStart + 1 , 1); Insert(ASymbol, AText, FEdit.SelStart + 1); FEdit.SetInternalDisplayValue(AText); FEdit.SelStart := ASelStart; FEdit.FShiftOn := False; PressRight; end else BeepOnError; end; end; procedure TcxMaskEditStandardMode.SetText(AText: string); begin LMouseDown; end; procedure TcxMaskEditStandardMode.SynchronizeEditValue; begin inherited SynchronizeEditValue; LMouseDown; end; procedure TcxMaskEditStandardMode.UpdateEditValue; begin if FNeedUpdateEditValue then begin FEdit.InternalEditValue := FMask.EmptyString; FNeedUpdateEditValue := False; end; end; function TcxMaskEditStandardMode.GetUpdatedText(const AText: string; AMatchForBlanksAndLiterals: Boolean = True): string; begin Result := AText; if FMask.Count > 0 then begin FMask.Format(Result, Properties.CharCase = ecNormal, AMatchForBlanksAndLiterals); FMask.Format2(Result); end; end; function TcxMaskEditStandardMode.GetBlank(APos: Integer): Char; begin Result := FMask.Blank; end; { TcxMaskEditRegExprMode } constructor TcxMaskEditRegExprMode.Create(AEdit: TcxCustomMaskEdit; AProperties: TcxCustomMaskEditProperties); begin inherited Create(AEdit, AProperties); FRegExpr := TcxRegExpr.Create; FRegExpr.CaseInsensitive := Properties.CaseInsensitive; FMouseAction := False; end; destructor TcxMaskEditRegExprMode.Destroy; begin FRegExpr.Free; inherited Destroy; end; procedure TcxMaskEditRegExprMode.AfterPasteFromClipboard; begin end; procedure TcxMaskEditRegExprMode.Compile(AMask: string); var I: Integer; AStream: TStringStream; AStr: string; begin FEditMask := AMask; if Properties.EmptyMask(AMask) then Exit; AStream := TStringStream.Create(AMask); try try FRegExpr.Compile(AStream); except on E: EcxRegExprError do begin AStr := cxGetResourceString(@scxMaskEditRegExprError); for I := 0 to E.Errors.Count - 1 do AStr := AStr + #13#10 + E.Errors[I].FullMessage; raise EcxMaskEditError.Create(AStr); end; end; finally AStream.Free; end; end; function TcxMaskEditRegExprMode.PressDelete: Boolean; begin CursorCorrection; if FEdit.SelLength <= 0 then begin if FTail <> '' then begin FSelect := FTail[1]; Delete(FTail, 1, 1); if not NextTail then begin ClearTail; if FEdit.SelStart > 0 then FEdit.DirectSetSelStart(FEdit.SelStart - 1); end; end; Result := True; end else begin DeleteSelection; if NextTail then Result := True else begin FEdit.SendMyKeyDown(VK_DELETE, []); ClearTail; Result := False; end; end; FSelect := ''; if not Result then BeepOnError; end; function TcxMaskEditRegExprMode.PressEnd: Boolean; var I: Integer; begin CursorCorrection; Result := True; if FTail <> '' then begin for I := 1 to Length(FTail) do begin FRegExpr.Next(FTail[I]); end; FHead := FHead + FTail; FTail := ''; end; end; function TcxMaskEditRegExprMode.PressHome: Boolean; begin CursorCorrection; Result := True; if FHead <> '' then begin FTail := FHead + FTail; FHead := ''; FRegExpr.Reset; end; end; function TcxMaskEditRegExprMode.GetEmptyString: string; begin Result := ''; end; function TcxMaskEditRegExprMode.GetFormattedText(AText: string; AMatchForBlanksAndLiterals: Boolean = True): string; var I: Integer; begin if not FRegExpr.IsCompiled then begin Result := ''; Exit; end; FRegExpr.Reset; Result := ''; for I := 1 to Length(AText) do begin if FRegExpr.Next(AText[I]) then Result := Result + AText[I]; end; end; procedure TcxMaskEditRegExprMode.GotoEnd; var I: Integer; begin CursorCorrection; if FTail = '' then Exit; for I := 1 to Length(FTail) do begin FRegExpr.Next(FTail[I]); end; FHead := FHead + FTail; FTail := ''; end; function TcxMaskEditRegExprMode.IsCursorBegin: Boolean; begin Result := FEdit.SelStart = 0; end; function TcxMaskEditRegExprMode.IsCursorEnd: Boolean; begin Result := FEdit.SelStart = Length(FEdit.Text); end; function TcxMaskEditRegExprMode.IsFullValidText(AText: string): Boolean; var ARegExpr: TcxRegExpr; I: Integer; begin Result := AText = ''; if not Result then begin ARegExpr := TcxRegExpr.Create; ARegExpr.CaseInsensitive := Properties.CaseInsensitive; Result := CompileRegExpr(ARegExpr); if Result then begin for I := 1 to Length(AText) do begin if not ARegExpr.Next(AText[I]) then begin Result := False; Break; end; end; if Result then if not Properties.IgnoreMaskBlank then Result := ARegExpr.IsFinal; end; ARegExpr.Free; end; end; procedure TcxMaskEditRegExprMode.LMouseDown; begin FMouseAction := True; end; procedure TcxMaskEditRegExprMode.PrePasteFromClipboard; begin end; function TcxMaskEditRegExprMode.PressBackSpace: Boolean; begin CursorCorrection; if FEdit.SelLength <= 0 then begin if FHead <> '' then begin FRegExpr.Prev; if NextTail then Delete(FHead, Length(FHead), 1) else ClearTail; end; Result := True; end else begin DeleteSelection; if NextTail then Result := True else begin FEdit.SendMyKeyPress(#8); ClearTail; Result := False; end; end; FSelect := ''; if not Result then BeepOnError; end; function TcxMaskEditRegExprMode.PressLeft: Boolean; var I: Integer; begin CursorCorrection; Result := True; if FHead <> '' then begin if FEdit.SelLength > 0 then begin if (FEdit.CursorPos = FEdit.SelStart + FEdit.SelLength) and not FEdit.FShiftOn then begin for I := 0 to FEdit.SelLength - 1 do begin FRegExpr.Prev; FTail := FHead[Length(FHead)] + FTail; Delete(FHead, Length(FHead), 1); end; Exit; end else if (FEdit.CursorPos = FEdit.SelStart) and not FEdit.FShiftOn then Exit; end; FRegExpr.Prev; FTail := FHead[Length(FHead)] + FTail; Delete(FHead, Length(FHead), 1); end; end; function TcxMaskEditRegExprMode.PressRight: Boolean; procedure GetTailFirstChar; begin FRegExpr.Next(FTail[1]); FHead := FHead + FTail[1]; Delete(FTail, 1, 1); end; var I: Integer; begin CursorCorrection; Result := True; if FTail <> '' then begin if FEdit.SelLength > 0 then begin if (FEdit.CursorPos = FEdit.SelStart) and not FEdit.FShiftOn then begin for I := 0 to FEdit.SelLength - 1 do GetTailFirstChar; Exit; end else if (FEdit.CursorPos = FEdit.SelStart + FEdit.SelLength) and not FEdit.FShiftOn then Exit; end; GetTailFirstChar; end; end; function TcxMaskEditRegExprMode.PressSymbol(var ASymbol: Char): Boolean; begin CursorCorrection; if FEdit.SelLength > 0 then DeleteSelection; if FRegExpr.Next(ASymbol) then begin FHead := FHead + ASymbol; if not NextTail then begin if FSelect <> '' then begin FEdit.SendMyKeyDown(VK_DELETE, []); FEdit.SendMyKeyPress(ASymbol); Result := False; end else Result := True; ClearTail; end else Result := True; end else begin RestoreSelection; Result := False; end; FSelect := ''; if not Result then BeepOnError; end; procedure TcxMaskEditRegExprMode.SetText(AText: string); var I: Integer; begin FRegExpr.Reset; if (ClipboardTextLength > 0) and (Length(AText) > 0) then begin FRegExpr.Reset; for I := 1 to FEdit.SelStart + ClipboardTextLength do begin FRegExpr.Next(AText[I]); end; FHead := Copy(AText, 1, FEdit.SelStart + ClipboardTextLength); FTail := Copy(AText, FEdit.SelStart + ClipboardTextLength + 1, Length(AText)); ClipboardTextLength := 0; end else begin FHead := ''; FTail := AText; end; end; procedure TcxMaskEditRegExprMode.SetRegExprCaseInsensitive; begin FRegExpr.CaseInsensitive := Properties.CaseInsensitive; end; procedure TcxMaskEditRegExprMode.UpdateEditValue; begin end; function TcxMaskEditRegExprMode.GetUpdatedText(const AText: string; AMatchForBlanksAndLiterals: Boolean = True): string; begin Result := AText; end; procedure TcxMaskEditRegExprMode.ClearTail; var AStr: string; begin AStr := FEdit.DataBinding.DisplayValue; Delete(AStr, FEdit.SelStart + 1, Length(FTail)); FEdit.DataBinding.DisplayValue := AStr; FEdit.DirectSetSelStart(Length(AStr)); FTail := ''; end; function TcxMaskEditRegExprMode.CompileRegExpr( ARegExpr: TcxRegExpr): Boolean; begin if FRegExpr.Stream = nil then begin Result := False; Exit; end; Result := True; try ARegExpr.Compile(FRegExpr.Stream); except on EcxMaskEditError do Result := False; end; end; procedure TcxMaskEditRegExprMode.CursorCorrection; var I: Integer; ASymbol: Char; begin if ((FHead = '') and (FTail = '') and (FEdit.Text <> '')) or FMouseAction then begin FMouseAction := False; FRegExpr.Reset; FTail := FEdit.Text; FHead := ''; for I := 0 to FEdit.CursorPos - 1 do begin if Length(FEdit.Text) > I then begin ASymbol := Char(FEdit.Text[I + 1]); FRegExpr.Next(ASymbol); FHead := FHead + FTail[1]; Delete(FTail, 1, 1); end; end; end; end; procedure TcxMaskEditRegExprMode.DeleteSelection; var I: Integer; begin if FEdit.SelStart = Length(FHead) then // Begin cursor begin FSelect := Copy(FTail, 1, FEdit.SelLength); Delete(FTail, 1, FEdit.SelLength); FBeginCursor := True; end else if (FEdit.SelStart + FEdit.SelLength) = Length(FHead) then // End cursor begin FSelect := Copy(FHead, FEdit.SelStart + 1, FEdit.SelLength); Delete(FHead, FEdit.SelStart + 1, FEdit.SelLength); for I := 1 to Length(FSelect) do FRegExpr.Prev; FBeginCursor := False; end; end; function TcxMaskEditRegExprMode.GetMaskKind: TcxEditMaskKind; begin Result := emkRegExpr; end; function TcxMaskEditRegExprMode.NextTail: Boolean; var AIsCharValid: Boolean; I, J, NextNumber: Integer; begin NextNumber := 0; for I := 1 to Length(FTail) do begin AIsCharValid := FRegExpr.Next(FTail[I]); if AIsCharValid then Inc(NextNumber) else begin for J := 0 to NextNumber - 1 do FRegExpr.Prev; Result := False; Exit; end; end; for I := 1 to Length(FTail) do FRegExpr.Prev; Result := True; end; procedure TcxMaskEditRegExprMode.RestoreSelection; var I: Integer; begin if FBeginCursor then FTail := FSelect + FTail else begin FHead := FHead + FSelect; for I := 1 to Length(FSelect) do begin FRegExpr.Next(FSelect[I]); end; end; end; procedure TcxMaskEditRegExprMode.SynchronizeEditValue; begin inherited SynchronizeEditValue; FEdit.SelStart := Length(FEdit.Text); FHead := FEdit.Text; FTail := ''; FRegExpr.Reset; FRegExpr.NextEx(FHead); end; { TcxMaskEditRegExprExMode } constructor TcxMaskEditRegExprExMode.Create(AEdit: TcxCustomMaskEdit; AProperties: TcxCustomMaskEditProperties); begin inherited Create(AEdit, AProperties); FRegExpr.OnSymbolUpdate := SymbolUpdate; FRegExpr.OnSymbolDelete := SymbolDelete; FRegExpr.UpdateOn := True; FNewCursorPos := -1; Clear; end; destructor TcxMaskEditRegExprExMode.Destroy; begin inherited Destroy; end; procedure TcxMaskEditRegExprExMode.Clear; begin FUpdate := ''; FDeleteNumber := 0; end; procedure TcxMaskEditRegExprExMode.RestoreSelection; begin FRegExpr.UpdateOn := False; inherited RestoreSelection; FRegExpr.UpdateOn := True; if FUpdate <> '' then begin FRegExpr.Prev; Clear; end; end; procedure TcxMaskEditRegExprExMode.SymbolDelete; begin Inc(FDeleteNumber); end; procedure TcxMaskEditRegExprExMode.SymbolUpdate(ASymbol: Char); begin FUpdate := FUpdate + ASymbol; end; procedure TcxMaskEditRegExprExMode.AfterPasteFromClipboard; begin if FNewCursorPos < 0 then Exit; FEdit.DirectSetSelStart(FNewCursorPos); FNewCursorPos := -1; end; procedure TcxMaskEditRegExprExMode.Compile(AMask: string); var I: Integer; AStream: TStringStream; AStr: string; begin Clear; FEditMask := AMask; if Properties.EmptyMask(AMask) then Exit; AStream := TStringStream.Create(AMask); try try FRegExpr.Compile(AStream); except on E: EcxRegExprError do begin AStr := cxGetResourceString(@scxMaskEditRegExprError); for I := 0 to E.Errors.Count - 1 do AStr := AStr + #13#10 + E.Errors[I].FullMessage; raise EcxMaskEditError.Create(AStr); end; end; finally AStream.Free; end; FNeedUpdateEditValue := not HasEdit; end; function TcxMaskEditRegExprExMode.GetEmptyString: string; var ARegExpr: TcxRegExpr; begin ARegExpr := TcxRegExpr.Create; ARegExpr.CaseInsensitive := Properties.CaseInsensitive; ARegExpr.UpdateOn := False; if CompileRegExpr(ARegExpr) then begin ARegExpr.OnSymbolUpdate := InternalSymbolUpdate; FInternalUpdate := ''; ARegExpr.UpdateOn := True; Result := FInternalUpdate; end else Result := ''; ARegExpr.Free; end; function TcxMaskEditRegExprExMode.GetFormattedText(AText: string; AMatchForBlanksAndLiterals: Boolean = True): string; begin if not FRegExpr.IsCompiled then begin Result := ''; Exit; end; FRegExpr.UpdateOn := False; Clear; Result := inherited GetFormattedText(AText, AMatchForBlanksAndLiterals); FRegExpr.UpdateOn := True; Result := Result + FUpdate; end; procedure TcxMaskEditRegExprExMode.GotoEnd; begin FRegExpr.UpdateOn := False; inherited GotoEnd; FRegExpr.UpdateOn := True; end; function TcxMaskEditRegExprExMode.IsFullValidText(AText: string): Boolean; var ARegExpr: TcxRegExpr; function IsStart: Boolean; begin ARegExpr.UpdateOn := True; Result := AText = FInternalUpdate; end; var I: Integer; begin ARegExpr := TcxRegExpr.Create; ARegExpr.CaseInsensitive := Properties.CaseInsensitive; ARegExpr.UpdateOn := False; Result := CompileRegExpr(ARegExpr); if Result then begin ARegExpr.OnSymbolUpdate := InternalSymbolUpdate; FInternalUpdate := ''; if not IsStart then begin ARegExpr.UpdateOn := False; ARegExpr.Reset; for I := 1 to Length(AText) do begin if not ARegExpr.Next(AText[I]) then begin Result := False; Break; end; end; if Result then if not Properties.IgnoreMaskBlank then Result := ARegExpr.IsFinal; end; end; ARegExpr.Free; end; procedure TcxMaskEditRegExprExMode.PrePasteFromClipboard; begin CursorCorrection; end; function TcxMaskEditRegExprExMode.PressBackSpace: Boolean; var ASelLength: Integer; I: Integer; begin CursorCorrection; Clear; if FEdit.SelLength <= 0 then begin if FHead = '' then begin Result := False; Exit; end; FRegExpr.Prev; if FRegExpr.IsStart then if FEdit.SelStart = FDeleteNumber then begin FRegExpr.Next(FHead[1]); Result := False; BeepOnError; Exit; end; Delete(FHead, Length(FHead) - FDeleteNumber, FDeleteNumber + 1); for I := 0 to FDeleteNumber do FEdit.SendMyKeyPress(#8); FRegExpr.UpdateOn := False; if NextTail then UpdateTail else ClearTail; FRegExpr.UpdateOn := True; end else begin DeleteSelection; if FEdit.SelStart = 0 then begin FRegExpr.UpdateOn := False; FRegExpr.UpdateOn := True; if FUpdate <> '' then begin FHead := FUpdate; Clear; ASelLength := FEdit.SelLength; FEdit.SelStart := Length(FHead); FEdit.SelLength := ASelLength - FEdit.SelStart; FTail := Copy(FEdit.Text, FEdit.SelStart + 1, FEdit.SelLength) + FTail; Result := PressBackSpace; Exit; end end; FEdit.SendMyKeyPress(#8); FRegExpr.UpdateOn := False; if NextTail then UpdateTail else ClearTail; FRegExpr.UpdateOn := True; end; Result := False; end; function TcxMaskEditRegExprExMode.PressDelete: Boolean; var I: Integer; begin CursorCorrection; Clear; if FEdit.SelLength <= 0 then begin if FTail = '' then begin Result := False; Exit; end; if FEdit.SelStart = 0 then begin FRegExpr.UpdateOn := False; FRegExpr.UpdateOn := True; if FUpdate <> '' then begin FRegExpr.Prev; Clear; Result := False; BeepOnError; Exit; end; end; FRegExpr.Next(FTail[1]); for I := 0 to Length(FUpdate) do FEdit.SendMyKeyDown(VK_DELETE, []); Delete(FTail, 1, Length(FUpdate) + 1); FRegExpr.Prev; FRegExpr.UpdateOn := False; if NextTail then UpdateTail else ClearTail; FRegExpr.UpdateOn := True; end else PressBackSpace; Result := False; end; function TcxMaskEditRegExprExMode.PressEnd: Boolean; begin Result := True; CursorCorrection; Clear; FRegExpr.UpdateOn := False; inherited PressEnd; FRegExpr.UpdateOn := True; end; function TcxMaskEditRegExprExMode.PressHome: Boolean; begin Result := True; CursorCorrection; Clear; inherited PressHome; end; function TcxMaskEditRegExprExMode.PressLeft: Boolean; var I: Integer; begin Result := True; CursorCorrection; Clear; if FEdit.SelLength > 0 then begin if (FEdit.CursorPos = FEdit.SelStart + FEdit.SelLength) and not FEdit.FShiftOn then begin FRegExpr.UpdateOn := False; inherited PressLeft; Clear; FRegExpr.UpdateOn := True; if FUpdate <> '' then FRegexpr.Prev; Exit; end else if (FEdit.CursorPos = FEdit.SelStart) and not FEdit.FShiftOn then Exit; end; inherited PressLeft; if FRegExpr.IsStart then if FEdit.SelStart = 0 then begin if FEdit.SelLength = FDeleteNumber then Dec(FDeleteNumber); end else if FEdit.SelStart = FDeleteNumber then Dec(FDeleteNumber); if FDeleteNumber > 0 then begin for I := 0 to FDeleteNumber - 1 do begin FTail := FHead[Length(FHead) - I] + FTail; FEdit.SendMyKeyDown(VK_LEFT, []); end; Delete(FHead, Length(FHead) - FDeleteNumber + 1, FDeleteNumber); end; end; function TcxMaskEditRegExprExMode.PressRight: Boolean; var I: Integer; begin Result := True; CursorCorrection; Clear; if FEdit.SelLength > 0 then begin if (FEdit.CursorPos = FEdit.SelStart) and not FEdit.FShiftOn then begin FRegExpr.UpdateOn := False; inherited PressRight; Clear; FRegExpr.UpdateOn := True; Exit; end else if (FEdit.CursorPos = FEdit.SelStart + Fedit.SelLength) and not FEdit.FShiftOn then Exit; end; inherited PressRight; if FUpdate <> '' then begin for I := 1 to Length(FUpdate) do begin FHead := FHead + FTail[I]; FEdit.SendMyKeyDown(VK_RIGHT, []); end; Delete(FTail, 1, Length(FUpdate)); end; end; function TcxMaskEditRegExprExMode.PressSymbol(var ASymbol: Char): Boolean; var I: Integer; ASelLength: Integer; begin CursorCorrection; Clear; if FEdit.SelLength > 0 then begin DeleteSelection; if FEdit.SelStart = 0 then begin FRegExpr.UpdateOn := False; FRegExpr.UpdateOn := True; if FUpdate <> '' then begin FHead := FUpdate; Clear; ASelLength := FEdit.SelLength; FEdit.SelStart := Length(FHead); FEdit.SelLength := ASelLength - FEdit.SelStart; FTail := Copy(FEdit.Text, FEdit.SelStart + 1, FEdit.SelLength) + FTail; Result := PressSymbol(ASymbol); Exit; end end; end; if FRegExpr.Next(ASymbol) then begin FHead := FHead + ASymbol + FUpdate; FEdit.SendMyKeyPress(ASymbol); for I := 1 to Length(FUpdate) do FEdit.SendMyKeyPress(FUpdate[I]); FRegExpr.UpdateOn := False; if NextTail then UpdateTail else ClearTail; FRegExpr.UpdateOn := True; end else begin if FEdit.SelLength > 0 then RestoreSelection; BeepOnError; end; FSelect := ''; Result := False; end; procedure TcxMaskEditRegExprExMode.SetText(AText: string); var I: Integer; begin FRegExpr.UpdateOn := False; FRegExpr.Reset; for I := 1 to Length(AText) do begin FRegExpr.Next(AText[I]); end; Clear; FRegExpr.UpdateOn := True; FHead := AText + FUpdate; FTail := ''; if HasEdit then begin FMouseAction := True; CursorCorrection; end; ClipboardTextLength := 0; end; procedure TcxMaskEditRegExprExMode.UpdateEditValue; begin if FNeedUpdateEditValue then begin FEdit.InternalEditValue := FUpdate; FNeedUpdateEditValue := False; end; end; procedure TcxMaskEditRegExprExMode.CursorCorrection; procedure Next; begin if FTail <> '' then begin Clear; FRegExpr.Next(FTail[1]); FHead := FHead + Copy(FTail, 1, Length(FUpdate) + 1); Delete(FTail, 1, Length(FUpdate) + 1); end; end; procedure Prev; begin if FHead <> '' then begin Clear; FRegExpr.Prev; FTail := Copy(FHead, Length(FHead) - FDeleteNumber, FDeleteNumber + 1) + FTail; if FRegExpr.IsStart then FHead := '' else Delete(FHead, Length(FHead) - FDeleteNumber, FDeleteNumber + 1); end; end; var ASelStart: Integer; ASelEnd: Integer; procedure CorrectSelLength; begin while True do begin Next; if ASelEnd <= Length(FHead) then begin FEdit.DirectSetSelLength(Length(FHead) - FEdit.SelStart); Break; end; end; end; begin if not HasEdit or not FEdit.HandleAllocated then Exit; if (FHead = '') and (FTail = '') and (FEdit.Text <> '') then begin FTail := FEdit.Text; FRegExpr.Reset; FMouseAction := True; end; if not FMouseAction then Exit else FMouseAction := False; ASelStart := FEdit.SelStart; ASelEnd := FEdit.SelStart + FEdit.SelLength; // Correct FEdit.SelStart if ASelStart > Length(FHead) then while True do begin Next; if ASelStart < Length(FHead) then begin Prev; FEdit.DirectSetSelStart(Length(FHead)); Break; end else if ASelStart = Length(FHead) then Break; end else if ASelStart < Length(FHead) then while True do begin Prev; if ASelStart > Length(FHead) then begin FEdit.DirectSetSelStart(Length(FHead)); Break; end else if ASelStart = Length(FHead) then Break; end; // Correct FEdit.SelLength if ASelEnd > ASelStart then CorrectSelLength; end; procedure TcxMaskEditRegExprExMode.DeleteSelection; begin FRegExpr.UpdateOn := False; inherited DeleteSelection; FRegExpr.UpdateOn := True; if FUpdate <> '' then begin FRegExpr.Prev; Clear; end; end; function TcxMaskEditRegExprExMode.GetMaskKind: TcxEditMaskKind; begin Result := emkRegExprEx; end; procedure TcxMaskEditRegExprExMode.UpdateTail; var I: Integer; begin Clear; if FTail = '' then Exit; for I := 1 to Length(FTail) do begin FRegExpr.Next(FTail[I]); FEdit.DirectSetSelStart(FEdit.SelStart + 1); end; FRegExpr.UpdateOn := True; if FUpdate <> '' then for I := 1 to Length(FUpdate) do begin FTail := FTail + FUpdate[I]; FEdit.SendMyKeyPress(FUpdate[I]); end; FRegExpr.UpdateOn := False; for I := 1 to Length(FTail) do begin FRegExpr.Prev; FEdit.DirectSetSelStart(FEdit.SelStart - 1); end; end; procedure TcxMaskEditRegExprExMode.InternalSymbolUpdate(ASymbol: Char); begin FInternalUpdate := FInternalUpdate + ASymbol; end; { TcxCustomMaskEditProperties } constructor TcxCustomMaskEditProperties.Create(AOwner: TPersistent); begin inherited Create(AOwner); MaskKind := emkStandard; FAlwaysShowBlanksAndLiterals := False; ValidateOnEnter := True; CaseInsensitive := True; FTempMode := nil; end; destructor TcxCustomMaskEditProperties.Destroy; begin FTempMode.Free; inherited Destroy; end; procedure TcxCustomMaskEditProperties.Assign(Source: TPersistent); begin if Source is TcxCustomMaskEditProperties then begin BeginUpdate; try inherited Assign(Source); with Source as TcxCustomMaskEditProperties do begin Self.MaskKind := MaskKind; Self.EditMask := EditMask; Self.CaseInsensitive := CaseInsensitive; Self.IgnoreMaskBlank := IgnoreMaskBlank; Self.AlwaysShowBlanksAndLiterals := AlwaysShowBlanksAndLiterals; end finally EndUpdate; end end else inherited Assign(Source); end; procedure TcxCustomMaskEditProperties.Changed; begin FreeAndNil(FTempMode); inherited Changed; end; class function TcxCustomMaskEditProperties.GetContainerClass: TcxContainerClass; begin Result := TcxMaskEdit; end; function TcxCustomMaskEditProperties.UseLookupData: Boolean; begin Result := not IsMasked and inherited UseLookupData; end; {function TcxCustomMaskEditProperties.GetEditValueSource(AEditFocused: Boolean): TcxDataEditValueSource; begin if IsMasked then Result := evsValue else Result := inherited GetEditValueSource(AEditFocused); end;} function TcxCustomMaskEditProperties.IsEditValueValid(var EditValue: TcxEditValue; AEditFocused: Boolean): Boolean; begin Result := IsMasked or inherited IsEditValueValid(EditValue, AEditFocused); end; procedure TcxCustomMaskEditProperties.PrepareDisplayValue( const AEditValue: TcxEditValue; var DisplayValue: TcxEditValue; AEditFocused: Boolean); var AText: string; begin if IsMasked and not (not AEditFocused and (IDefaultValuesProvider <> nil) and IDefaultValuesProvider.IsDisplayFormatDefined(True)) then begin AText := VarToStr(AEditValue); if (FTempMode = nil) or not TestTempMaskKind or not TestTempEditMask then begin FreeAndNil(FTempMode); FTempMode := CreateMode; end; if FTempMode <> nil then begin if not AEditFocused and (FTempMode is TcxMaskEditStandardMode) then begin if not FAlwaysShowBlanksAndLiterals then DisplayValue := FTempMode.GetUpdatedText(AText, False) else DisplayValue := FTempMode.GetFormattedText(AText, False); end else DisplayValue := FTempMode.GetFormattedText(AText, False); end; end else inherited PrepareDisplayValue(AEditValue, DisplayValue, AEditFocused); end; procedure TcxCustomMaskEditProperties.ValidateDisplayValue(var ADisplayValue: TcxEditValue; var AErrorText: TCaption; var Error: Boolean; AEdit: TcxCustomEdit); var AText: string; begin if not Error then begin if not IsMasked{ or IgnoreMaskBlank }then Error := False else begin AText := VarToStr(ADisplayValue); Error := not TcxCustomMaskEdit(AEdit).Mode.IsFullValidText(AText); if Error then AErrorText := cxGetResourceString(@scxMaskEditInvalidEditValue); end; end; inherited ValidateDisplayValue(ADisplayValue, AErrorText, Error, AEdit); end; function TcxCustomMaskEditProperties.CreateMode: TcxMaskEditCustomMode; begin Result := nil; if not EmptyMask(EditMask) then begin Result := GetModeClass(FMaskKind).Create(nil, Self); Result.Compile(EditMask); end; end; function TcxCustomMaskEditProperties.CreateMode1: TcxMaskEditCustomMode; begin Result := GetModeClass(MaskKind).Create(nil, Self); end; function TcxCustomMaskEditProperties.EmptyMask(AMask: string): Boolean; var I: Integer; begin Result := AMask = ''; if not Result then begin for I := 1 to Length(AMask) do if not SpaceToken(AMask[I]) then begin Result := False; Exit; end; Result := True; end; end; function TcxCustomMaskEditProperties.GetEditMask: TcxEditMask; begin if FMaskKind <> emkStandard then Result := FEditMask else begin if EmptyMask(FEditMask) then begin if IDefaultValuesProvider <> nil then Result := IDefaultValuesProvider.DefaultEditMask else Result := ''; end else Result := FEditMask end; end; function TcxCustomMaskEditProperties.GetIsMasked: Boolean; begin Result := not EmptyMask(EditMask); end; procedure TcxCustomMaskEditProperties.SetAlwaysShowBlanksAndLiterals(AValue: Boolean); begin if AValue <> FAlwaysShowBlanksAndLiterals then begin FAlwaysShowBlanksAndLiterals := AValue; Changed; end; end; procedure TcxCustomMaskEditProperties.SetCaseInsensitive(AValue: Boolean); begin if CharCase = ecNormal then FCaseInsensitive := AValue else FCaseInsensitive := True; Changed; end; procedure TcxCustomMaskEditProperties.SetEditMask(Value: TcxEditMask); var AMode: TcxMaskEditCustomMode; begin if EditMask = Value then FEditMask := Value else begin AMode := CreateMode1; try AMode.Compile(Value); FEditMask := Value; Changed; finally AMode.Free; end; end; end; procedure TcxCustomMaskEditProperties.SetMaskKind(Value: TcxEditMaskKind); begin if Value <> FMaskKind then begin FMaskKind := Value; Changed; end; end; function TcxCustomMaskEditProperties.GetDisplayFormatOptions: TcxEditDisplayFormatOptions; begin if not IsMasked then Result := [dfoSupports] else Result := []; end; function TcxCustomMaskEditProperties.GetModeClass( AMaskKind: TcxEditMaskKind): TcxMaskEditCustomModeClass; begin case AMaskKind of emkStandard: Result := TcxMaskEditStandardMode; emkRegExpr: Result := TcxMaskEditRegExprMode; else Result := TcxMaskEditRegExprExMode; end; end; procedure TcxCustomMaskEditProperties.MaxLengthChanged; begin if IsMasked then begin if FMaxLengthSetting then Exit; FMaxLengthSetting := True; BeginUpdate; try MaxLength := 0; finally FMaxLengthSetting := False; EndUpdate; end; end else inherited MaxLengthChanged; end; function TcxCustomMaskEditProperties.SpaceToken(AToken: Char): Boolean; begin Result := IsSpaceChar(AToken); end; function TcxCustomMaskEditProperties.GetEmptyString: string; begin Result := FEmptyString; end; procedure TcxCustomMaskEditProperties.SetCharCase(Value: TEditCharCase); begin if Value in [ecLowerCase, ecUpperCase] then FCaseInsensitive := True; inherited SetCharCase(Value); end; function TcxCustomMaskEditProperties.TestTempEditMask: Boolean; begin Result := FTempMode.EditMask = EditMask; end; function TcxCustomMaskEditProperties.TestTempMaskKind: Boolean; begin Result := False; case FMaskKind of emkStandard: Result := FTempMode is TcxMaskEditStandardMode; emkRegExpr: Result := FTempMode is TcxMaskEditRegExprMode; emkRegExprEx: Result := FTempMode is TcxMaskEditRegExprExMode; end; end; { TcxCustomMaskEdit } {$IFDEF CBUILDER10} constructor TcxCustomMaskEdit.Create(AOwner: TComponent); begin inherited Create(AOwner); end; {$ENDIF} destructor TcxCustomMaskEdit.Destroy; begin FreeAndNil(FMode); inherited Destroy; end; procedure TcxCustomMaskEdit.CutToClipboard; begin if ActiveProperties.IsMasked then begin if not Focused or DoEditing then begin CopyToClipboard; if Mode.PressDelete then SendMyKeyPress(Char(VK_BACK)); end end else inherited CutToClipBoard; end; class function TcxCustomMaskEdit.GetPropertiesClass: TcxCustomEditPropertiesClass; begin Result := TcxCustomMaskEditProperties; end; procedure TcxCustomMaskEdit.SendMyKeyDown(Key: Word; Shift: TShiftState); begin FMyMessage := True; try SendKeyDown(Self, Key, Shift); finally FMyMessage := False; end; end; procedure TcxCustomMaskEdit.SendMyKeyPress(AKey: Char); begin FMyMessage := True; try SendKeyPress(Self, AKey); finally FMyMessage := False; end; end; procedure TcxCustomMaskEdit.ChangeHandler(Sender: TObject); begin FText := FMode.GetUpdatedText(InnerEdit.EditValue); inherited ChangeHandler(Sender); end; procedure TcxCustomMaskEdit.DblClick; begin if ActiveProperties.IsMasked then Mode.GotoEnd; inherited DblClick; end; procedure TcxCustomMaskEdit.DoEnter; begin if ActiveProperties.IsMasked then if ActiveProperties.AutoSelect then Mode.GotoEnd; inherited DoEnter; end; procedure TcxCustomMaskEdit.DoEditKeyDown(var Key: Word; Shift: TShiftState); var AAfterKeyDownNeed: Boolean; begin if not ActiveProperties.IsMasked or IsSpecialKey(Key, Shift) then begin inherited DoEditKeyDown(Key, Shift); Exit; end; if not ValidateKeyDown(Key, Shift) then begin DoAfterKeyDown(Key, Shift); Key := 0; Exit; end; if Key = VK_TAB then begin inherited DoEditKeyDown(Key, Shift); Exit; end; FShiftOn := ssShift in Shift; if ((Key = VK_UP) or (Key = VK_DOWN)) and not HasPopupWindow then begin DoAfterKeyDown(Key, Shift); Key := 0; end else if Key = VK_LEFT then begin if ssCtrl in Shift then begin SendMyKeyDown(VK_HOME, Shift); if not Mode.PressHome then Key := 0; end else begin AAfterKeyDownNeed := IsCursorBegin; if not Mode.PressLeft then begin if AAfterKeyDownNeed then DoAfterKeyDown(Key, Shift); Key := 0; end; end; end else if Key = VK_RIGHT then begin if ssCtrl in Shift then begin SendMyKeyDown(VK_END, Shift); if not Mode.PressEnd then Key := 0; end else begin AAfterKeyDownNeed := IsCursorEnd; if not Mode.PressRight then begin if AAfterKeyDownNeed then DoAfterKeyDown(Key, Shift); Key := 0; end; end; end else if Key = VK_DELETE then begin if ssShift in Shift then begin if SelLength = 0 then if not Mode.PressBackSpace then Key := 0; end else if not Mode.PressDelete then Key := 0; end else if Key = VK_HOME then begin if not Mode.PressHome then Key := 0; end else if Key = VK_END then begin if not Mode.PressEnd then Key := 0; end; if Key <> 0 then inherited DoEditKeyDown(Key, Shift); end; procedure TcxCustomMaskEdit.DoEditKeyPress(var Key: Char); begin if not ActiveProperties.IsMasked then begin inherited DoEditKeyPress(Key); Exit; end; if (Key = #9) or (Key = #27) then Key := #0 else if not ValidateKeyPress(Key) then Key := #0 else begin if Key <> #13 then begin if not ActiveProperties.IsMasked then inherited DoEditKeyPress(Key) else begin if (Key = #3) or (Key = #22) or (Key = #24) then // ^c ^v ^x begin inherited DoEditKeyPress(Key); end else begin if Key = #8 then // Backspace begin if not Mode.PressBackSpace then Key := #0; end else if not Mode.PressSymbol(Key) then Key := #0; end; end; end; end; end; function TcxCustomMaskEdit.GetEditText: TCaption; begin Result := InnerEdit.EditValue; end; function TcxCustomMaskEdit.GetProperties: TcxCustomMaskEditProperties; begin Result := TcxCustomMaskEditProperties(FProperties); end; function TcxCustomMaskEdit.GetActiveProperties: TcxCustomMaskEditProperties; begin Result := TcxCustomMaskEditProperties(InternalGetActiveProperties); end; function TcxCustomMaskEdit.InternalGetEmptyString: string; begin if ActiveProperties.IsMasked then begin if Mode <> nil then Result := Mode.GetEmptyString else Result := ''; end else Result := ''; end; procedure TcxCustomMaskEdit.InternalSetValue(AValue: string); begin if ActiveProperties.IsMasked and CanSynchronizeModeText then Mode.SetText(AValue); end; function TcxCustomMaskEdit.IsCursorBegin: Boolean; begin Result := FMode.IsCursorBegin; end; function TcxCustomMaskEdit.IsCursorEnd: Boolean; begin Result := FMode.IsCursorEnd; end; procedure TcxCustomMaskEdit.SetEditText(AValue: TCaption); var AEditText: string; begin if not Focused and (Mode is TcxMaskEditStandardMode) then begin if not ActiveProperties.AlwaysShowBlanksAndLiterals then AEditText := Mode.GetUpdatedText(AValue) else AEditText := Mode.GetFormattedText(AValue); end else AEditText := Mode.GetFormattedText(AValue); InnerEdit.EditValue := AEditText; FEditValue := FText; end; procedure TcxCustomMaskEdit.SetProperties(Value: TcxCustomMaskEditProperties); begin FProperties.Assign(Value); end; procedure TcxCustomMaskEdit.DoEditKeyUp(var Key: Word; Shift: TShiftState); begin if not ActiveProperties.IsMasked then begin inherited DoEditKeyUp(Key, Shift); Exit; end; inherited DoEditKeyUp(Key, Shift); end; procedure TcxCustomMaskEdit.Initialize; begin inherited Initialize; FMode := ActiveProperties.GetModeClass(emkStandard).Create(Self, ActiveProperties); FShiftOn := False; ActiveProperties.FEmptyString := InternalGetEmptyString; end; function TcxCustomMaskEdit.InternalGetText: string; begin if ActiveProperties.IsMasked then Result := FText else Result := inherited InternalGetText; end; procedure TcxCustomMaskEdit.InternalSetDisplayValue(const Value: TcxEditValue); var AText: string; begin if ActiveProperties.IsMasked and not IsLoading then begin AText := VarToStr(Value); if not Focused and (Mode is TcxMaskEditStandardMode) then begin if not ActiveProperties.AlwaysShowBlanksAndLiterals then inherited InternalSetDisplayValue(Mode.GetUpdatedText(AText)) else inherited InternalSetDisplayValue(Mode.GetFormattedText(AText)); end else inherited InternalSetDisplayValue(Mode.GetFormattedText(AText)); InternalSetValue(Text); end else inherited InternalSetDisplayValue(Value); end; function TcxCustomMaskEdit.InternalSetText(const Value: string): Boolean; begin if ActiveProperties.IsMasked then begin Result := True; InternalEditValue := Value; FEditValue := FText; end else Result := inherited InternalSetText(Value); end; procedure TcxCustomMaskEdit.KeyDown(var Key: Word; Shift: TShiftState); begin if not FMyMessage then inherited KeyDown(Key, Shift); end; procedure TcxCustomMaskEdit.KeyPress(var Key: Char); begin if not FMyMessage then inherited KeyPress(Key); end; procedure TcxCustomMaskEdit.KeyUp(var Key: Word; Shift: TShiftState); begin if not FMyMessage then inherited KeyUp(Key, Shift); end; procedure TcxCustomMaskEdit.Loaded; begin inherited Loaded; if ActiveProperties.IsMasked then begin LockChangeEvents(True, False); try UpdateTextFormatting; finally LockChangeEvents(False, False); end; end; end; procedure TcxCustomMaskEdit.LockInnerEditRepainting; begin if HasInnerEdit then if ActiveProperties.IsMasked then SendMessage(InnerEdit.Control.Handle, WM_SETREDRAW, 0, 0) else inherited LockInnerEditRepainting; end; procedure TcxCustomMaskEdit.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if ActiveProperties.IsMasked then if Button = mbLeft then Mode.LMouseDown; inherited MouseDown(Button, Shift, X, Y); end; procedure TcxCustomMaskEdit.MouseMove(Shift: TShiftState; X, Y: Integer); var AShiftOn: Boolean; begin if ActiveProperties.IsMasked then if ssLeft in Shift then begin AShiftOn := FShiftOn; FShiftOn := True; Mode.LMouseDown; FShiftOn := AShiftOn; end; inherited MouseMove(Shift, X, Y); end; procedure TcxCustomMaskEdit.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin inherited MouseUp(Button, Shift, X, Y); end; procedure TcxCustomMaskEdit.PropertiesChanged(Sender: TObject); var AEditMask: string; ASelStart: Integer; ASelLength: Integer; AEditMaskCleared: Boolean; procedure DoMaskChanged; begin ActiveProperties.MaxLength := 0; FMode.Compile(AEditMask); if AEditMaskCleared then ActiveProperties.FEditMask := AEditMask; if not ActiveProperties.EmptyMask(AEditMask) then FMode.SynchronizeEditValue else begin if FMode is TcxMaskEditStandardMode then begin if HandleAllocated and (SelLength = 1) then begin ASelStart := SelStart; SelLength := 0; SelStart := ASelStart; end; end; end; ActiveProperties.FEmptyString := InternalGetEmptyString; end; procedure DoMaskKindChanged; var APrevMaskKind: TcxEditMaskKind; APrevEditMask: string; begin APrevMaskKind := FMode.GetMaskKind; APrevEditMask := FMode.EditMask; FreeAndNil(FMode); if ActiveProperties.MaskKind = emkRegExpr then begin if APrevMaskKind = emkStandard then begin ActiveProperties.FEditMask := ''; AEditMaskCleared := True; end; FMode := ActiveProperties.GetModeClass(emkRegExpr).Create(Self, ActiveProperties) end else if ActiveProperties.MaskKind = emkRegExprEx then begin if APrevMaskKind = emkStandard then begin ActiveProperties.FEditMask := ''; AEditMaskCleared := True; end; FMode := ActiveProperties.GetModeClass(emkRegExprEx).Create(Self, ActiveProperties) end else if ActiveProperties.MaskKind = emkStandard then begin if (APrevMaskKind = emkRegExpr) or (APrevMaskKind = emkRegExprEx) then begin ActiveProperties.FEditMask := ''; AEditMaskCleared := True; end; FMode := ActiveProperties.GetModeClass(emkStandard).Create(Self, ActiveProperties) end; FMode.Compile(ActiveProperties.EditMask); if not ActiveProperties.EmptyMask(ActiveProperties.EditMask) then FMode.SynchronizeEditValue; ActiveProperties.FEmptyString := InternalGetEmptyString; end; procedure DoCharCaseChanged; begin if ActiveProperties.CharCase = ecNormal then begin if HasInnerEdit then InnerTextEdit.CharCase := ecNormal; FMode.SynchronizeEditValue; end; FMode.CharCase := ActiveProperties.CharCase; end; procedure SaveSels; begin ASelStart := SelStart; ASelLength := SelLength; end; procedure LoadSels; begin SelStart := ASelStart; SelLength := ASelLength; end; var AEditMaskChanged: Boolean; AEditMaskKindChanged: Boolean; ACharCaseChanged: Boolean; begin AEditMaskCleared := False; ActiveProperties.LockUpdate(True); AEditMask := ActiveProperties.EditMask; AEditMaskChanged := (FMode.EditMask <> ActiveProperties.EditMask) or ActiveProperties.FormatChanging; AEditMaskKindChanged := FMode.GetMaskKind <> ActiveProperties.MaskKind; ACharCaseChanged := ActiveProperties.CharCase <> FMode.CharCase; if AEditMaskKindChanged then DoMaskKindChanged; if AEditMaskChanged then DoMaskChanged; if ACharCaseChanged then DoCharCaseChanged; if (ActiveProperties.EchoMode <> FMode.EchoMode) and HandleAllocated then SaveSels; if not(not PropertiesChangeLocked and VarIsNull(EditValue)) and ActiveProperties.IsMasked then FMode.UpdateEditValue; ActiveProperties.LockUpdate(False); if FMode is TcxMaskEditRegExprMode then TcxMaskEditRegExprMode(FMode).SetRegExprCaseInsensitive; inherited PropertiesChanged(Sender); if ActiveProperties.EchoMode <> FMode.EchoMode then begin if HandleAllocated then LoadSels; FMode.EchoMode := ActiveProperties.EchoMode; end; if ACharCaseChanged or AEditMaskKindChanged or AEditMaskChanged then FText := FMode.GetUpdatedText(InnerEdit.EditValue); end; procedure TcxCustomMaskEdit.PrepareEditValue(const ADisplayValue: TcxEditValue; out EditValue: TcxEditValue; AEditFocused: Boolean); begin if ActiveProperties.IsMasked then if not AEditFocused and (Mode is TcxMaskEditStandardMode) and (TcxMaskEditStandardMode(Mode).FMask.SaveLiteralCharacters or not ActiveProperties.AlwaysShowBlanksAndLiterals) then inherited PrepareEditValue(ADisplayValue, EditValue, AEditFocused) else EditValue := Mode.GetUpdatedText(ADisplayValue) else inherited PrepareEditValue(ADisplayValue, EditValue, AEditFocused); end; procedure TcxCustomMaskEdit.PasteFromClipboard; begin if not Clipboard.HasFormat(CF_TEXT) then Exit; if not ActiveProperties.IsMasked then begin inherited PasteFromClipboard; Exit; end; Mode.ClipboardTextLength := Length(Clipboard.AsText); Mode.PrePasteFromClipboard; // inherited PasteFromClipboard; SelText := Clipboard.AsText; // TODO Mode.AfterPasteFromClipboard; end; procedure TcxCustomMaskEdit.SelChange(Sender: TObject); begin inherited SelChange(Sender); if not FInternalTextSelection then Mode.LMouseDown; end; procedure TcxCustomMaskEdit.SetSelText(const Value: TCaption); begin if not ActiveProperties.IsMasked then inherited SetSelText(Value) else begin Mode.ClipboardTextLength := Length(Value); Mode.PrePasteFromClipboard; inherited SetSelText(Value); Mode.AfterPasteFromClipboard; end; end; procedure TcxCustomMaskEdit.SynchronizeDisplayValue; begin inherited SynchronizeDisplayValue; if ActiveProperties.IsMasked then InternalSetValue(Text); end; procedure TcxCustomMaskEdit.UndoPerformed; begin InternalSetValue(Text); end; procedure TcxCustomMaskEdit.UnlockInnerEditRepainting; begin if HasInnerEdit then if ActiveProperties.IsMasked then begin SendMessage(InnerEdit.Control.Handle, WM_SETREDRAW, 1, 0); InnerEdit.Control.Invalidate; end else inherited UnlockInnerEditRepainting; end; function TcxCustomMaskEdit.CanSynchronizeModeText: Boolean; begin Result := True; end; procedure TcxCustomMaskEdit.DirectSetSelLength(AValue: Integer); begin FInternalTextSelection := True; try SelLength := AValue; finally FInternalTextSelection := False; end; end; procedure TcxCustomMaskEdit.DirectSetSelStart(AValue: Integer); begin FInternalTextSelection := True; try SelStart := AValue; finally FInternalTextSelection := False; end; end; function TcxCustomMaskEdit.IsCharValidForPos(var AChar: Char; APos: Integer): Boolean; begin Result := True; end; procedure TcxCustomMaskEdit.UpdateTextFormatting; begin InternalSetDisplayValue(Text); end; { TcxMaskEdit } class function TcxMaskEdit.GetPropertiesClass: TcxCustomEditPropertiesClass; begin Result := TcxMaskEditProperties; end; function TcxMaskEdit.GetActiveProperties: TcxMaskEditProperties; begin Result := TcxMaskEditProperties(InternalGetActiveProperties); end; function TcxMaskEdit.GetProperties: TcxMaskEditProperties; begin Result := TcxMaskEditProperties(FProperties); end; procedure TcxMaskEdit.SetProperties(Value: TcxMaskEditProperties); begin FProperties.Assign(Value); end; { TcxFilterMaskEditHelper } class function TcxFilterMaskEditHelper.GetFilterEditClass: TcxCustomEditClass; begin Result := TcxMaskEdit; end; class function TcxFilterMaskEditHelper.GetSupportedFilterOperators( AProperties: TcxCustomEditProperties; AValueTypeClass: TcxValueTypeClass; AExtendedSet: Boolean = False): TcxFilterControlOperators; begin Result := [fcoEqual, fcoNotEqual, fcoLess, fcoLessEqual, fcoGreater, fcoGreaterEqual, fcoBlanks, fcoNonBlanks]; if not TcxCustomMaskEditProperties(AProperties).IsMasked and ((AValueTypeClass <> nil) and AValueTypeClass.IsString) then Result := Result + [fcoLike, fcoNotLike]; if AExtendedSet then Result := Result + [fcoBetween..fcoNotInList]; end; class procedure TcxFilterMaskEditHelper.InitializeProperties(AProperties, AEditProperties: TcxCustomEditProperties; AHasButtons: Boolean); begin inherited InitializeProperties(AProperties, AEditProperties, AHasButtons); with TcxCustomMaskEditProperties(AProperties) do begin if TcxCustomMaskEditProperties(AEditProperties).MaskKind = emkRegExpr then MaskKind := emkRegExprEx; AutoSelect := not IsMasked; end; end; initialization GetRegisteredEditProperties.Register(TcxMaskEditProperties, scxSEditRepositoryMaskItem); FilterEditsController.Register(TcxMaskEditProperties, TcxFilterMaskEditHelper); finalization FilterEditsController.Unregister(TcxMaskEditProperties, TcxFilterMaskEditHelper); end.