Files
lazarus-ccr/components/jvcllaz/run/JvCustomControls/jvvalidateedit.pas

1781 lines
56 KiB
ObjectPascal
Raw Normal View History

{-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.
The Original Code is JvValidateEdit, released on 20 February 2003,
by Christopher Latta
Portions created by Christopher Latta are Copyright (C) 2003 Christopher Latta.
All Rights Reserved.
Contributor(s): Peter Thornqvist
Peter Schraut (http://www.console-dev.de)
You may retrieve the latest version of this file at the Project JEDI's JVCL
home page, located at http://jvcl.delphi-jedi.org
Known Issues:
TJvValidateFormat uses the SysUtils.Format function to format numeric values.
While this uses the Windows regional settings for the currency symbol, decimal
separator and thousands separator, it does not format using the negative symbol,
negative number format, negative currency format and positive currency format.
This could be rectified by a custom-written formatting routine.
-----------------------------------------------------------------------------}
// $Id$
unit JvValidateEdit;
{$MODE OBJFPC}{$H+}
interface
uses
LCLIntf, LCLType, LMessages,
Controls, Graphics, SysUtils, Classes, StdCtrls, FMTBcd;
// JvEdit, JvDataSourceIntf;
type
TJvValidateEditDisplayFormat = (dfAlphabetic, dfAlphaNumeric, dfBinary,
dfCheckChars, dfCurrency, dfCustom, dfFloat, dfFloatGeneral, dfHex, dfInteger,
dfNonCheckChars, dfNone, dfOctal, dfPercent, dfScientific, dfYear, dfDecimal,
dfIdentifier, dfFloatFixed, dfBcd);
TJvValidateEditCriticalPointsCheck = (cpNone, cpMinValue, cpMaxValue, cpBoth);
TJvCustomValidateEdit = class;
(******************* NOT CONVERTED ***
TJvValidateEditDataConnector = class(TJvFieldDataConnector)
private
FEdit: TJvCustomValidateEdit;
FNullValue: Variant;
procedure SetNullValue(const Value: Variant);
function IsNullValueStored: Boolean;
protected
procedure RecordChanged; override;
procedure UpdateData; override;
public
constructor Create(AEdit: TJvCustomValidateEdit);
procedure Assign(Source: TPersistent); override;
property Control: TJvCustomValidateEdit read FEdit;
published
property NullValue: Variant read FNullValue write SetNullValue stored IsNullValueStored;
end;
**********************************)
TJvValidateEditCriticalPoints = class(TPersistent)
private
FCheckPoints: TJvValidateEditCriticalPointsCheck;
FColorAbove: TColor;
FColorBelow: TColor;
FMaxValue: Double;
FMinValue: Double;
FMaxValueIncluded: Boolean;
FMinValueIncluded: Boolean;
FOnChange: TNotifyEvent;
FDefCheckPoints: TJvValidateEditCriticalPointsCheck;
FDefColorAbove: TColor;
FDefColorBelow: TColor;
procedure DoChanged;
procedure SetMinValue(NewValue: Double);
procedure SetMaxValue(NewValue: Double);
procedure SetColorAbove(NewValue: TColor);
procedure SetColorBelow(NewValue: TColor);
procedure SetCheckPoints(NewValue: TJvValidateEditCriticalPointsCheck);
function IsCheckPointsStored: Boolean;
function IsColorAboveStored: Boolean;
function IsColorBelowStored: Boolean;
public
procedure Assign(Source: TPersistent); override;
procedure SetDefaults(ACheckPoints: TJvValidateEditCriticalPointsCheck;
AColorAbove, AColorBelow: TColor);
constructor Create;
published
property CheckPoints: TJvValidateEditCriticalPointsCheck read FCheckPoints
write SetCheckPoints stored IsCheckPointsStored;
property ColorAbove: TColor read FColorAbove write SetColorAbove stored IsColorAboveStored;
property ColorBelow: TColor read FColorBelow write SetColorBelow stored IsColorBelowStored;
property MaxValue: Double read FMaxValue write SetMaxValue;
property MinValue: Double read FMinValue write SetMinValue;
property MaxValueIncluded: Boolean read FMaxValueIncluded write FMaxValueIncluded;
property MinValueIncluded: Boolean read FMinValueIncluded write FMinValueIncluded;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
TJvCustomTextValidateEvent = procedure(Sender: TObject; Key: Char;
const AText: string; const Pos: Integer; var IsValid: Boolean) of object;
TJvCustomIsValidEvent = procedure(Sender: TObject; var IsValid: Boolean) of object;
TJvCustomDecimalRoundingEvent = procedure(Sender: TObject; var DecimalRoundedValue: Double;
const Value: Double) of object;
TJvCustomValidateEdit = class(TCustomEdit) //TJvCustomEdit)
private
FSelfChange: Boolean;
FCheckChars: string;
FDecimalPlaces: Cardinal;
FDisplayFormat: TJvValidateEditDisplayFormat;
FEditText: string;
FHasMaxValue: Boolean;
FHasMinValue: Boolean;
FMaxValue: Double;
FMinValue: Double;
FOnCustomValidate: TJvCustomTextValidateEvent;
FOnValueChanged: TNotifyEvent;
FZeroEmpty: Boolean;
FEmptyValue: string;
FIsEmptyValue: Boolean;
FEnterText: string;
FDisplayPrefix: string;
FDisplaySuffix: string;
FCriticalPoints: TJvValidateEditCriticalPoints;
FStandardFontColor: TColor;
FAutoAlignment: Boolean;
FTrimDecimals: Boolean;
FOldFontChange: TNotifyEvent;
FOnIsValid: TJvCustomIsValidEvent;
FOnDecimalRounding: TJvCustomDecimalRoundingEvent;
FAllowEmpty: Boolean;
FEnforcingMinMaxValue: Boolean;
FForceDecimalSeparatorInput: Boolean;
FKeepPrefixSuffixIntact: Boolean;
FHidePrefixSuffixIfEmpty: Boolean;
FLastDownKey: Word;
FIsLoaded: Boolean;
procedure DisplayText;
function ScientificStrToFloat(SciString: string): Double;
procedure SetHasMaxValue(NewValue: Boolean);
procedure SetHasMinValue(NewValue: Boolean);
procedure SetMaxValue(NewValue: Double);
procedure SetMinValue(NewValue: Double);
procedure SetDecimalPlaces(NewValue: Cardinal);
procedure SetDisplayFormat(NewValue: TJvValidateEditDisplayFormat);
procedure SetZeroEmpty(NewValue: Boolean);
function GetAsInteger: Int64;
procedure SetAsInteger(NewValue: Int64);
function GetAsCurrency: Currency;
procedure SetAsCurrency(NewValue: Currency);
function GetAsFloat: Double;
procedure SetAsFloat(NewValue: Double);
function GetAsBcd: TBcd;
procedure SetAsBcd(const NewValue: TBcd);
function GetValue: Variant;
procedure SetValue(NewValue: Variant);
procedure SetCheckChars(const NewValue: string);
function IsCheckCharsStored: Boolean;
function CurrRangeValue(CheckValue: Currency): Currency;
function FloatRangeValue(CheckValue: Double): Double;
function IntRangeValue(CheckValue: Int64): Int64;
function BcdRangeValue(const CheckValue: TBcd): TBcd;
function GetEditText: string;
procedure SetEditText(const NewValue: string);
procedure ChangeText(const NewValue: string);
function BaseToInt(const BaseValue: string; Base: Byte): Int64;
function IntToBase(NewValue: Int64; Base: Byte): string;
procedure DoValueChanged;
procedure SetDisplayPrefix(const NewValue: string);
procedure SetDisplaySuffix(const NewValue: string);
procedure CriticalPointsChange(Sender: TObject);
procedure SetFontColor;
procedure FontChange(Sender: TObject);
procedure EnforceMaxValue;
procedure EnforceMinValue;
procedure SetTrimDecimals(const Value: Boolean);
function GetUnprefixedUnsuffixedText(const Value: string): string;
function GetText: TCaption;
procedure SetText(const NewValue: TCaption);
procedure SetEmptyValue(const AValue: String);
protected
function IsValidChar(const S: string; var Key: Char; Posn: Integer): Boolean; virtual;
function MakeValid(const ParseString: string): string;virtual;
procedure Change; override;
procedure DoEnter; override;
procedure DoExit; override;
function DoValidate(const Key: Char; const AText: string; const Posn: Integer): Boolean;
procedure Loaded; override;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure KeyPress(var Key: Char); override;
procedure KeyUp(var Key: Word; Shift: TShiftState); override;
procedure WMPaste(var Msg: TLMessage); message LM_PASTE;
procedure DoEmptyValueEnter; virtual;
procedure DoEmptyValueExit; virtual;
(************************** NOT CONVERTED ***
function CreateDataConnector: TJvFieldDataConnector; override;
********************************************)
property CheckChars: string read FCheckChars write SetCheckChars stored IsCheckCharsStored;
property TrimDecimals: Boolean read FTrimDecimals write SetTrimDecimals;
property DecimalPlaces: Cardinal read FDecimalPlaces write SetDecimalPlaces;
property DisplayFormat: TJvValidateEditDisplayFormat read FDisplayFormat write SetDisplayFormat;
property EditText: string read GetEditText write SetEditText;
property HasMaxValue: Boolean read FHasMaxValue write SetHasMaxValue;
property HasMinValue: Boolean read FHasMinValue write SetHasMinValue;
property MaxValue: Double read FMaxValue write SetMaxValue;
property MinValue: Double read FMinValue write SetMinValue;
property Text: TCaption read GetText write SetText;
property OnCustomValidate: TJvCustomTextValidateEvent read FOnCustomValidate write FOnCustomValidate;
property OnValueChanged: TNotifyEvent read FOnValueChanged write FOnValueChanged;
property OnDecimalRounding: TJvCustomDecimalRoundingEvent read FOnDecimalRounding write FOnDecimalRounding;
property Value: Variant read GetValue write SetValue stored False;
property AllowEmpty: Boolean read FAllowEmpty write FAllowEmpty;
property ZeroEmpty: Boolean read FZeroEmpty write SetZeroEmpty;
property EmptyValue: string read FEmptyValue write SetEmptyValue;
property DisplayPrefix: string read FDisplayPrefix write SetDisplayPrefix;
property DisplaySuffix: string read FDisplaySuffix write SetDisplaySuffix;
property KeepPrefixSuffixIntact: Boolean read FKeepPrefixSuffixIntact write FKeepPrefixSuffixIntact default False;
property HidePrefixSuffixIfEmpty: Boolean read FHidePrefixSuffixIfEmpty write FHidePrefixSuffixIfEmpty default True;
property CriticalPoints: TJvValidateEditCriticalPoints read FCriticalPoints write FCriticalPoints;
property AutoAlignment: Boolean read FAutoAlignment write FAutoAlignment;
property OnIsValid: TJvCustomIsValidEvent read FOnIsValid write FOnIsValid;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function IsValid: Boolean; virtual; // fires OnIsValid if assigned
function IsEmpty: Boolean; virtual; // override;
// When the DecimalSeparator variable has changed, one should call
// RecalcCheckChars to ensure that it contains the new value (Mantis 4682)
procedure RecalcCheckChars;
procedure Assign(Source: TPersistent); override;
property AsInteger: Int64 read GetAsInteger write SetAsInteger;
property AsCurrency: Currency read GetAsCurrency write SetAsCurrency;
property AsFloat: Double read GetAsFloat write SetAsFloat;
property AsBcd: TBcd read GetAsBcd write SetAsBcd;
// If true and the user presses the VK_DECIMAL key, the key read in KeyPress
// will always be replaced by the value of DecimalSeparator. This is made
// to overcome the problem where some keyboard layouts send "." instead of
// the decimal separator when using the decimal key on the numerical keypad.
// The most commonly encountered layout is the French AZERTY one.
// Note that this property will be set automatically to True by the
// constructor when the conversion of VK_DECIMAL into a character does not
// return the DecimalSeparator value
property ForceDecimalSeparatorInput: Boolean read FForceDecimalSeparatorInput write FForceDecimalSeparatorInput;
end;
TJvValidateEdit = class(TJvCustomValidateEdit)
published
property AllowEmpty default False;
property Align;
property Alignment default taRightJustify;
property Anchors;
property AutoAlignment default True;
property AutoSelect;
property AutoSize;
property BiDiMode;
property DragCursor;
property DragKind;
property ParentBiDiMode;
property OnEndDock;
property OnStartDock;
property BorderSpacing;
property BorderStyle;
property CheckChars;
property CharCase;
property Color;
property Constraints;
property CriticalPoints;
property TrimDecimals default False;
property DisplayFormat default dfInteger;
property DecimalPlaces default 0;
property DisplayPrefix;
property DisplaySuffix;
property DragMode;
property EditText;
property Enabled;
property Font;
property HasMaxValue default False;
property HasMinValue default False;
property HideSelection;
property MaxLength;
property MaxValue;
property MinValue;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PasswordChar;
property PopupMenu;
property ReadOnly;
property ShowHint;
property TabOrder;
property TabStop;
property Text stored False;
property Value;
property Visible;
property ZeroEmpty default False;
property OnChange;
property OnClick;
property OnContextPopup;
property OnCustomValidate;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
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 OnValueChanged;
property OnIsValid;
property OnDecimalRounding;
property KeepPrefixSuffixIntact;
property HidePrefixSuffixIfEmpty;
{$IFDEF COMPILER12_UP}
//property NumbersOnly;
{$ENDIF}
{$IFDEF COMPILER14_UP}
property Touch;
{$ENDIF COMPILER14_UP}
property TextHint;
(************ NOT CONVERTED ***
property Flat;
property ImeMode;
property ImeName;
property OEMConvert;
property ParentFlat;
property BevelEdges;
property BevelInner;
property BevelKind default bkNone;
property BevelOuter;
property Caret;
property ClipboardCommands;
property DisabledColor;
property DisabledTextColor;
property DataConnector;
****************************)
end;
implementation
uses
Math, StrUtils, Variants,
JvJCLUtils, JvResources;
// JclStrings, JvJCLUtils, JvResources, JclSysUtils;
function IsGreater(Value, MaxValue: Double; MaxValueIncluded: Boolean): Boolean;
begin
if MaxValueIncluded then
Result := Value >= MaxValue
else
Result := Value > MaxValue;
end;
function IsLower(Value, MinValue: Double; MinValueIncluded: Boolean): Boolean;
begin
if MinValueIncluded then
Result := Value <= MinValue
else
Result := Value < MinValue;
end;
function BcdToStrFDefault(const Bcd: TBcd; DecimalPlaces: Integer): string;
begin
Result := BcdToStrF(Bcd, ffNumber, 64, DecimalPlaces);
end;
function BcdToInt64(const Bcd: TBcd; Truncate: Boolean = False): Int64;
var
ABcd: TBcd;
begin
if Truncate and (BcdScale(Bcd) > 0) then
NormalizeBcd(Bcd, ABcd{%H-}, Bcd.Precision, 0)
else
ABcd := Bcd;
Result := StrToInt64(BcdToStr(ABcd));
end;
function IsBcdZero(const Bcd: TBcd): Boolean;
var
I, Precision: Integer;
begin
Result := False;
I := 0;
Precision := Bcd.Precision;
while I < Precision div 2 do
begin
if Byte(Bcd.Fraction[I]) <> 0 then
Exit;
Inc(I);
end;
Result := (Precision mod 2 = 0) or (Byte(Bcd.Fraction[I]) shr 4 = 0);
end;
procedure ZeroBcd(var Bcd: TBcd);
var
I: Integer;
begin
Bcd.Precision := 10;
Bcd.SignSpecialPlaces := 2;
for I := 0 to 31 do
Bcd.Fraction[I] := 0;
end;
(************************** NOT CONVERTED ***
//=== { TJvValidateEditDataConnector } =======================================
procedure TJvValidateEditDataConnector.Assign(Source: TPersistent);
begin
inherited Assign(Source);
if Source is TJvFieldDataConnector then
begin
NullValue := TJvValidateEditDataConnector(Source).NullValue;
end;
end;
constructor TJvValidateEditDataConnector.Create(AEdit: TJvCustomValidateEdit);
begin
inherited Create;
FEdit := AEdit;
VarClear(FNullValue);
end;
function TJvValidateEditDataConnector.IsNullValueStored: Boolean;
begin
Result := not VarIsClear(NullValue);
end;
procedure TJvValidateEditDataConnector.RecordChanged;
begin
if Field.IsValid then
begin
FEdit.ReadOnly := not Field.CanModify;
if not Field.IsNull then
FEdit.Value := Field.Value
else
if NullValue <> Null then
FEdit.Value := NullValue
else
FEdit.Text := '';
end
else
begin
FEdit.Text := '';
FEdit.ReadOnly := False;
end;
end;
procedure TJvValidateEditDataConnector.SetNullValue(const Value: Variant);
begin
if Value <> FNullValue then
begin
FNullValue := Value;
Reset;
end;
end;
procedure TJvValidateEditDataConnector.UpdateData;
begin
if Field.CanModify and Field.IsValid then
begin
if FEdit.Value <> Null then
Field.Value := FEdit.Value
else
if NullValue <> Null then
Field.Value := FNullValue
else
RecordChanged;
end;
end;
*************************************)
//=== { TJvCustomValidateEdit } ==============================================
constructor TJvCustomValidateEdit.Create(AOwner: TComponent);
{
var
MappedDecimal: Cardinal;
const
MAPVK_VK_TO_CHAR = 2;
}
begin
inherited Create(AOwner);
FSelfChange := False;
FAutoAlignment := True;
FCriticalPoints := TJvValidateEditCriticalPoints.Create;
FCriticalPoints.OnChange := @CriticalPointsChange;
FDisplayFormat := dfInteger;
FCheckChars := '01234567890';
Alignment := taRightJustify;
FEditText := '';
Text := ''; // doesn't trigger OnChange because FEnterText = ''. That's what we want.
AutoSize := True;
FMinValue := 0;
FMaxValue := 0;
FHasMinValue := False;
FHasMaxValue := False;
FZeroEmpty := False;
FHidePrefixSuffixIfEmpty := True;
FStandardFontColor := Font.Color;
FOldFontChange := Font.OnChange;
Font.OnChange := @FontChange;
(******************** To DO ***********
MappedDecimal := MapVirtualKey(VK_DECIMAL, MAPVK_VK_TO_CHAR);
if MappedDecimal <> 0 then
FForceDecimalSeparatorInput := Char(MappedDecimal) <> JclFormatSettings.DecimalSeparator;
**********************************)
end;
destructor TJvCustomValidateEdit.Destroy;
begin
FreeAndNil(FCriticalPoints);
inherited Destroy;
end;
procedure TJvCustomValidateEdit.Assign(Source: TPersistent);
var
lcSource: TJvCustomValidateEdit;
begin
if Source is TJvCustomValidateEdit then
begin
lcSource := TJvCustomValidateEdit(Source);
CriticalPoints.Assign(lcSource.CriticalPoints);
DisplayFormat := lcSource.DisplayFormat;
DecimalPlaces := lcSource.DecimalPlaces;
MinValue := lcSource.MinValue;
MaxValue := lcSource.MaxValue;
HasMinValue := lcSource.HasMinValue;
HasMaxValue := lcSource.HasMaxValue;
ZeroEmpty := lcSource.ZeroEmpty;
AllowEmpty := lcSource.AllowEmpty;
end
else
inherited Assign(Source);
end;
procedure TJvCustomValidateEdit.Loaded;
begin
EditText := FEditText;
inherited Loaded;
FIsLoaded := True;
(**************** NOT CONVERTED ***
FOldFontColor := Font.Color;
SelStart := FStreamedSelStart;
SelLength := FStreamedSelLength;
**********************)
end;
(****************************** NOT CONVERTED ***
function TJvCustomValidateEdit.CreateDataConnector: TJvFieldDataConnector;
begin
Result := TJvValidateEditDataConnector.Create(Self);
end;
*******************************************************)
procedure TJvCustomValidateEdit.SetHasMaxValue(NewValue: Boolean);
begin
if FHasMaxValue <> NewValue then
begin
FHasMaxValue := NewValue;
if not (csLoading in ComponentState) then
EnforceMaxValue;
end;
end;
procedure TJvCustomValidateEdit.SetHasMinValue(NewValue: Boolean);
begin
if FHasMinValue <> NewValue then
begin
FHasMinValue := NewValue;
if not (csLoading in ComponentState) then
EnforceMinValue;
end;
end;
procedure TJvCustomValidateEdit.SetMaxValue(NewValue: Double);
begin
if FMaxValue <> NewValue then
begin
FMaxValue := NewValue;
{ make MinValue consistent }
if FMinValue > FMaxValue then
FMinValue := FMaxValue;
if not (csLoading in ComponentState) then
EnforceMaxValue;
end;
end;
procedure TJvCustomValidateEdit.SetMinValue(NewValue: Double);
begin
if FMinValue <> NewValue then
begin
FMinValue := NewValue;
{ make MaxValue consistent }
if FMaxValue < FMinValue then
FMaxValue := FMinValue;
if not (csLoading in ComponentState) then
EnforceMinValue;
end;
end;
procedure TJvCustomValidateEdit.SetTrimDecimals(const Value: Boolean);
begin
if Value <> FTrimDecimals then
begin
FTrimDecimals := Value;
if not (csLoading in ComponentState) then
EditText := FEditText;
end;
end;
procedure TJvCustomValidateEdit.SetDecimalPlaces(NewValue: Cardinal);
begin
if ControlState = [csReadingState] then
FDecimalPlaces := NewValue
else
if FDisplayFormat in [dfCurrency, dfFloat, dfFloatGeneral, dfScientific, dfPercent, dfFloatFixed, dfBcd] then
FDecimalPlaces := NewValue;
if not (csLoading in ComponentState) then
EditText := FEditText;
end;
procedure TJvCustomValidateEdit.SetDisplayFormat(NewValue: TJvValidateEditDisplayFormat);
var
OldFormat: TJvValidateEditDisplayFormat;
begin
if FDisplayFormat <> NewValue then
begin
OldFormat := FDisplayFormat;
FDisplayFormat := NewValue;
RecalcCheckChars;
case FDisplayFormat of
dfAlphabetic, dfAlphaNumeric, dfIdentifier,
dfCheckChars, dfNonCheckChars, dfCustom, dfNone:
if FAutoAlignment then
Alignment := taLeftJustify;
dfCurrency:
begin
if FAutoAlignment then
Alignment := taRightJustify;
if not (csLoading in ComponentState) then
if FDecimalPlaces = 0 then
FDecimalPlaces := FormatSettings.CurrencyDecimals;
end;
dfBinary, dfFloat, dfFloatGeneral, dfPercent, dfDecimal, dfHex,
dfInteger, dfOctal, dfScientific, dfFloatFixed, dfBcd:
if FAutoAlignment then
Alignment := taRightJustify;
dfYear:
begin
if FAutoAlignment then
Alignment := taRightJustify;
MaxLength := 4;
end;
end;
if OldFormat = dfYear then
MaxLength := 0;
if not IsEmpty then
begin
// Convert non-base 10 numbers to base 10 and base-10 numbers to non-base 10
if (OldFormat = dfBinary) and
(NewValue in [dfCurrency, dfFloat, dfFloatGeneral, dfDecimal, dfHex, dfInteger, dfOctal, dfPercent, dfScientific, dfYear, dfFloatFixed, dfBcd]) then
SetAsInteger(BaseToInt(FEditText, 2))
else
if (OldFormat in [dfCurrency, dfFloat, dfFloatGeneral, dfDecimal, dfPercent, dfFloatFixed, dfBcd]) and
(NewValue in [dfBinary, dfHex, dfOctal])
then
SetAsfloat(StrToFloatDef(FEditText, 0))
// SetAsFloat(JvSafeStrToFloatDef(FEditText, 0))
else
if (OldFormat = dfHex) and
(NewValue in [dfBinary, dfCurrency, dfFloat, dfFloatGeneral, dfDecimal, dfInteger, dfOctal, dfPercent, dfScientific, dfYear, dfFloatFixed, dfBcd]) then
SetAsInteger(BaseToInt(FEditText, 16))
else
if (OldFormat in [dfInteger, dfYear]) and
(NewValue in [dfBinary, dfHex, dfOctal]) then
SetAsInteger(StrToIntDef(FEditText, 0))
else
if (OldFormat = dfOctal) and
(NewValue in [dfBinary, dfCurrency, dfFloat, dfFloatGeneral, dfDecimal, dfHex, dfInteger, dfPercent, dfScientific, dfYear, dfFloatFixed, dfBcd]) then
SetAsInteger(BaseToInt(FEditText, 8))
else
begin
// ...or just display the value
if not (csLoading in ComponentState) then
EditText := FEditText;
end;
end;
end;
end;
procedure TJvCustomValidateEdit.SetZeroEmpty(NewValue: Boolean);
begin
if FZeroEmpty <> NewValue then
begin
FZeroEmpty := NewValue;
if not (csLoading in ComponentState) then
EditText := FEditText;
end;
end;
function TJvCustomValidateEdit.GetAsInteger: Int64;
begin
case FDisplayFormat of
dfBinary:
Result := BaseToInt(FEditText, 2);
dfHex:
Result := BaseToInt(FEditText, 16);
dfOctal:
Result := BaseToInt(FEditText, 8);
else
Result := StrToInt64Def(FEditText, 0);
end;
Result := IntRangeValue(Result);
end;
procedure TJvCustomValidateEdit.SetAsInteger(NewValue: Int64);
begin
case FDisplayFormat of
dfAlphabetic, dfAlphaNumeric, dfCheckChars, dfIdentifier, dfCustom,
dfNonCheckChars, dfNone:
EditText := IntToStr(NewValue);
dfBinary:
EditText := IntToBase(NewValue, 2);
dfHex:
EditText := IntToBase(NewValue, 16);
dfOctal:
EditText := IntToBase(NewValue, 8);
dfCurrency, dfFloat, dfFloatGeneral, dfDecimal, dfInteger, dfPercent, dfScientific, dfYear, dfFloatFixed, dfBcd:
EditText := IntToStr(IntRangeValue(NewValue));
end;
end;
function TJvCustomValidateEdit.GetAsCurrency: Currency;
begin
case FDisplayFormat of
dfBinary:
Result := BaseToInt(FEditText, 2);
dfHex:
Result := BaseToInt(FEditText, 16);
dfOctal:
Result := BaseToInt(FEditText, 8);
else
Result := StrToCurrDef(FEditText, 0);
end;
Result := CurrRangeValue(Result);
end;
procedure TJvCustomValidateEdit.SetAsCurrency(NewValue: Currency);
begin
case FDisplayFormat of
dfAlphabetic, dfAlphaNumeric, dfCheckChars, dfIdentifier, dfCustom,
dfNonCheckChars, dfNone:
EditText := CurrToStr(NewValue);
dfBinary:
EditText := IntToBase(Trunc(NewValue), 2);
dfHex:
EditText := IntToBase(Trunc(NewValue), 16);
dfOctal:
EditText := IntToBase(Trunc(NewValue), 8);
dfCurrency, dfFloat, dfFloatGeneral, dfDecimal, dfInteger, dfPercent, dfScientific, dfYear, dfFloatFixed, dfBcd:
EditText := CurrToStr(CurrRangeValue(NewValue));
end;
end;
function TJvCustomValidateEdit.GetAsFloat: Double;
//var
// Cur: Currency;
begin
case FDisplayFormat of
dfBinary:
Result := BaseToInt(FEditText, 2);
dfHex:
Result := BaseToInt(FEditText, 16);
dfOctal:
Result := BaseToInt(FEditText, 8);
dfScientific:
Result := ScientificStrToFloat(FEditText);
dfCurrency:
begin
// Mantis 3494: The Edit text may contain extra characters such as
// parenthesis that indicate the amount is negative. Using StrToFloatDef
// would not catch the negative part, hence the need to use a function
// that knows how to do the conversion.
//VarCyFromStr({$IFDEF RTL240_UP}PChar{$ENDIF RTL240_UP}(FEditText), LOCALE_USER_DEFAULT, 0, Cur);
//Result := Cur;
{ Laz workaround...}
Result := StrToCurrDef(FEditText, 0);
end;
dfBcd:
Result := BcdToDouble(AsBcd);
else
Result := StrToFloatDef(FEditText, 0); //, JvSafeStrToFloatDef(FEditText, 0);
end;
Result := FloatRangeValue(Result);
end;
procedure TJvCustomValidateEdit.SetAsFloat(NewValue: Double);
begin
case FDisplayFormat of
dfAlphabetic, dfAlphaNumeric, dfCheckChars, dfIdentifier, dfCustom,
dfNonCheckChars, dfNone:
EditText := FloatToStr(NewValue);
dfBinary:
EditText := IntToBase(Trunc(NewValue), 2);
dfHex:
EditText := IntToBase(Trunc(NewValue), 16);
dfOctal:
EditText := IntToBase(Trunc(NewValue), 8);
dfInteger, dfYear:
EditText := IntToStr(IntRangeValue(Trunc(NewValue)));
dfCurrency:
EditText := Format('%.*m', [FDecimalPlaces, FloatRangeValue(NewValue)]);
dfFloat, dfPercent:
EditText := Format('%.*n', [FDecimalPlaces, FloatRangeValue(NewValue)]);
dfFloatGeneral:
EditText := Format('%.*g', [FDecimalPlaces, FloatRangeValue(NewValue)]);
dfFloatFixed:
EditText := Format('%.*f', [FDecimalPlaces, FloatRangeValue(NewValue)]);
dfDecimal:
EditText := FloatToStr(FloatRangeValue(NewValue));
dfScientific:
EditText := Format('%e', [FloatRangeValue(NewValue)]);
dfBcd:
EditText := BcdToStrFDefault(DoubleToBcd(FloatRangeValue(NewValue)), FDecimalPlaces);
end;
end;
function TJvCustomValidateEdit.GetAsBcd: TBcd;
var
IntValue: Int64;
begin
case FDisplayFormat of
dfBinary, dfHex, dfOctal:
begin
IntValue := GetAsInteger;
if Abs(IntValue) < MaxInt then
Result := IntegerToBcd(IntValue)
else
Result := StrToBcd(IntToStr(IntValue));
end;
dfScientific:
Result := DoubleToBcd(ScientificStrToFloat(FEditText));
dfCurrency:
CurrToBCD(GetAsCurrency, Result);
dfFloat, dfFloatGeneral, dfFloatFixed:
Result := DoubleToBcd(AsFloat);
else
if not TryStrToBcd(FEditText, Result) then
ZeroBcd(Result);
end;
Result := BcdRangeValue(Result);
end;
procedure TJvCustomValidateEdit.SetAsBcd(const NewValue: TBcd);
begin
case FDisplayFormat of
dfAlphabetic, dfAlphaNumeric, dfCheckChars, dfIdentifier, dfCustom,
dfNonCheckChars, dfNone:
EditText := BcdToStrFDefault(NewValue, FDecimalPlaces);
dfBinary:
EditText := IntToBase(BcdToInt64(NewValue), 2);
dfHex:
EditText := IntToBase(BcdToInt64(NewValue), 16);
dfOctal:
EditText := IntToBase(BcdToInt64(NewValue), 8);
dfInteger, dfYear:
EditText := IntToStr(IntRangeValue(BcdToInt64(NewValue)));
dfCurrency:
EditText := Format('%.*m', [FDecimalPlaces, FloatRangeValue(BcdToDouble(NewValue))]);
dfFloat, dfPercent:
EditText := Format('%.*n', [FDecimalPlaces, FloatRangeValue(BcdToDouble(NewValue))]);
dfFloatGeneral:
EditText := Format('%.*g', [FDecimalPlaces, FloatRangeValue(BcdToDouble(NewValue))]);
dfFloatFixed:
EditText := Format('%.*f', [FDecimalPlaces, FloatRangeValue(BcdToDouble(NewValue))]);
dfDecimal:
EditText := FloatToStr(FloatRangeValue(BcdToDouble(NewValue)));
dfScientific:
EditText := Format('%e', [FloatRangeValue(BcdToDouble(NewValue))]);
dfBcd:
EditText := BcdToStrFDefault(BcdRangeValue(NewValue), FDecimalPlaces);
end;
end;
function TJvCustomValidateEdit.GetValue: Variant;
var
DisplayedText: string;
//Cur: Currency;
Bcd: TBcd;
begin
case FDisplayFormat of
dfCurrency:
begin
// Mantis 3494: The Edit text may contain extra characters such as
// parenthesis that indicate the amount is negative. Using StrToFloatDef
// would not catch the negative part, hence the need to use a function
// that knows how to do the conversion.
//VarCyFromStr({$IFDEF RTL240_UP}PChar{$ENDIF RTL240_UP}(FEditText), LOCALE_USER_DEFAULT, 0, Cur);
//Result := CurrRangeValue(Cur);
// Laz work-around
Result := CurrRangeValue(StrToCurrDef(FEditText, 0));
end;
dfFloat, dfFloatGeneral, dfDecimal, dfPercent, dfScientific, dfFloatFixed:
Result := FloatRangeValue(StrToFloatDef(FEditText, 0));
// Result := FloatRangeValue(JvSafeStrToFloatDef(FEditText, 0));
dfInteger, dfYear:
Result := IntRangeValue(StrToIntDef(FEditText, 0));
dfHex:
Result := IntRangeValue(StrToIntDef('$' + FEditText, 0));
dfBcd:
if TryStrToBcd(FEditText, Bcd{%H-}) then
Result := VarFMTBcdCreate(Bcd)
else
Result := VarFMTBcdCreate; // Null
else
DisplayedText := inherited Text;
// Remove DisplayPrefix and DisplaySuffix
DisplayedText := StrEnsureNoPrefix(DisplayPrefix, DisplayedText);
DisplayedText := StrEnsureNoSuffix(DisplaySuffix, DisplayedText);
Result := DisplayedText;
end;
end;
procedure TJvCustomValidateEdit.SetValue(NewValue: Variant);
begin
if AllowEmpty and (VarIsNull(NewValue) or VarIsEmpty(NewValue)) then
Clear
else
case FDisplayFormat of
dfAlphabetic, dfAlphaNumeric, dfCheckChars, dfNonCheckChars, dfIdentifier, dfNone, dfCustom:
EditText := NewValue;
dfBinary, dfHex, dfInteger, dfOctal, dfYear:
SetAsInteger(NewValue);
dfCurrency, dfFloat, dfDecimal, dfFloatGeneral, dfPercent, dfScientific, dfFloatFixed:
SetAsFloat(NewValue);
dfBcd:
if VarIsFMTBcd(NewValue) then
SetAsBcd(VarToBcd(NewValue))
else
SetAsBcd(StrToBcd(VarToStr(NewValue)));
end;
end;
procedure TJvCustomValidateEdit.SetCheckChars(const NewValue: string);
begin
if (csLoading in ComponentState) or
((FDisplayFormat in [dfNone, dfCheckChars, dfNonCheckChars]) and
(FCheckChars <> NewValue)) then
begin
FCheckChars := NewValue;
EditText := MakeValid(FEditText);
end;
end;
function TJvCustomValidateEdit.IsCheckCharsStored: Boolean;
begin
Result := (FDisplayFormat in [dfNone, dfCheckChars, dfNonCheckChars]);
end;
procedure TJvCustomValidateEdit.KeyPress(var Key: Char);
var
StrippedText: string;
begin
// Mantis 4952:
// - Must not take the prefix/suffix into account when checking a character's validity
// - Must not take into account the CurrencyString into account when checking a character's validity
StrippedText := GetUnprefixedUnsuffixedText(Text);
if not IsValidChar(StrippedText, Key, SelStart + 1) and (Key >= #32) then
Key := #0;
inherited KeyPress(Key);
end;
procedure TJvCustomValidateEdit.KeyUp(var Key: Word; Shift: TShiftState);
begin
FLastDownKey := 0;
inherited KeyUp(Key, Shift);
end;
procedure TJvCustomValidateEdit.WMPaste(var Msg: TLMessage);
begin
inherited;
EditText := MakeValid(GetUnprefixedUnsuffixedText(inherited Text));
end;
function TJvCustomValidateEdit.MakeValid(const ParseString: string): string;
var
C: Char;
I: Integer;
L: Integer;
begin
SetLength(Result, Length(ParseString));
L := 0;
for I := 1 to Length(ParseString) do
begin
C := ParseString[I];
if IsValidChar(Copy(ParseString, 1, I - 1), C, I) then
begin
Result[L + 1] := C;
Inc(L);
end;
end;
SetLength(Result, L);
end;
procedure TJvCustomValidateEdit.RecalcCheckChars;
const
Alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
Numbers = '0123456789';
begin
case FDisplayFormat of
dfAlphabetic:
FCheckChars := Alphabet;
dfAlphaNumeric:
FCheckChars := Alphabet + Numbers;
dfIdentifier:
FCheckChars := Alphabet + Numbers + '_';
dfBinary:
FCheckChars := '01';
dfCustom, dfNone:
if (FDisplayFormat = dfCustom) or not (csLoading in ComponentState) then
FCheckChars := '';
dfCurrency,
dfFloat, dfFloatGeneral, dfPercent, dfDecimal, dfFloatFixed, dfBcd:
FCheckChars := Numbers + FormatSettings.DecimalSeparator;
dfHex:
FCheckChars := Numbers + 'ABCDEFabcdef';
dfInteger, dfYear:
FCheckChars := Numbers;
dfOctal:
FCheckChars := '01234567';
dfScientific:
FCheckChars := Numbers + 'Ee' + FormatSettings.DecimalSeparator;
end;
end;
function TJvCustomValidateEdit.IsValidChar(const S: string;
var Key: Char; Posn: Integer): Boolean;
var
iPosE: Integer;
ExpectedNegPos: Integer;
ExpectedNegChar: Char;
begin
if (FLastDownKey = VK_DECIMAL) and ForceDecimalSeparatorInput then
Key := FormatSettings.DecimalSeparator;
case FDisplayFormat of
dfBinary, dfCheckChars, dfHex, dfOctal, dfYear:
Result := Pos(Key, FCheckChars) > 0;
dfAlphabetic:
Result := IsCharAlpha(Key);
dfAlphaNumeric:
Result := IsCharAlphaNumeric(Key);
dfCustom:
Result := DoValidate(Key, S, Posn);
dfInteger:
Result := (Pos(Key, FCheckChars) > 0) or
((Key = '+') and (Posn = 1) and ((Pos('+', S) = 0) or (SelLength > 0))) or
((Key = '-') and (Posn = 1) and ((Pos('-', S) = 0) or (SelLength > 0)));
dfFloat, dfFloatGeneral, dfDecimal, dfPercent, dfFloatFixed, dfBcd:
Result := ((Pos(Key, FCheckChars) > 0) and
(((Key = FormatSettings.DecimalSeparator) and (Pos(FormatSettings.DecimalSeparator, S) = 0)) or (Key <> FormatSettings.DecimalSeparator))) or
((Key = '+') and (Posn = 1) and ((Pos('+', S) = 0) or (SelLength > 0))) or
((Key = '-') and (Posn = 1) and ((Pos('-', S) = 0) or (SelLength > 0)));
dfCurrency:
begin
// The currency negative format can be quite complicated. The current
// one is indicated by the value of NegCurrFormat, and can have any
// value from 0 to 15 according to the MSDN and Delphi's help.
// So we must take into account that some format require the negative
// sign to be at the end, while some others replace it by parenthesis.
// See http://www.delphibasics.co.uk/RTL.asp?Name=NegCurrFormat for
// an online version of Delphi's help.
// If we were not to use this, it would trigger Mantis 3494, where
// the number would go from negative to positive simply by focusing out
// of the control.
ExpectedNegChar := '-';
ExpectedNegPos := 1;
case FormatSettings.NegCurrFormat of
0, 4, 14, 15:
begin
ExpectedNegPos := 1;
ExpectedNegChar := '(';
end;
1, 5, 8, 9:
ExpectedNegPos := 1;
2:
ExpectedNegPos := 2;
3, 7, 10, 11:
ExpectedNegPos := Length(S);
6:
ExpectedNegPos := Length(S) - 1;
12:
ExpectedNegPos := 3;
13:
ExpectedNegPos := Length(S) - 2;
end;
if (Key = '(') and (Posn = 1) and (FormatSettings.NegCurrFormat in [0, 4, 14, 15]) then
Key := '-';
Result := ((Pos(Key, FCheckChars) > 0) and
(((Key = FormatSettings.DecimalSeparator) and (Pos(FormatSettings.DecimalSeparator, S) = 0)) or
(Key <> FormatSettings.DecimalSeparator))) or
((Key = '+') and (Posn = 1) and ((Pos('+', S) = 0) or (SelLength > 0))) or
((Key = '-') and (Posn = ExpectedNegPos) and ((Pos(ExpectedNegChar, S) = 0) or
(SelLength > 0)));
end;
dfNonCheckChars:
Result := Pos(Key, FCheckChars) = 0;
dfNone:
Result := True;
dfScientific:
begin
Result := (Pos(Key, FCheckChars) > 0) or CharInSet(Key, ['+', '-']);
if Result then
begin
iPosE := Pos('e', LowerCase(S));
if Key = FormatSettings.DecimalSeparator then
begin
if iPosE = 0 then
Result := (Pos(FormatSettings.DecimalSeparator, S) = 0)
else
Result := ((Posn <= iPosE) and (Pos(FormatSettings.DecimalSeparator, Copy(S, 1, iPosE - 1)) = 0));
//or ((Posn > iPosE) and (Pos(DecimalSeparator, Copy(S, iPosE + 1, Length(S))) = 0));
// (outchy) XXXeY,YY are not valid scientific numbers, Y must be an integer value
end
else
if CharInSet(Key, ['E', 'e']) then
Result := (iPosE = 0) and (Posn > 1)
else
if Key = '+' then
Result := (Posn = 1) or (Posn = iPosE + 1)
else
if Key = '-' then
Result := (Posn = 1) or (Posn = iPosE + 1);
end;
end;
dfIdentifier:
begin
if Posn = 1 then
Result := (Key = '_') or (IsCharAlpha(Key))
else
Result := Pos(Key, FCheckChars) > 0;
end
else
Result := False;
end;
end;
function TJvCustomValidateEdit.DoValidate(const Key: Char;
const AText: string; const Posn: Integer): Boolean;
begin
Result := True;
if Assigned(FOnCustomValidate) then
FOnCustomValidate(Self, Key, AText, Posn, Result);
end;
procedure TJvCustomValidateEdit.KeyDown(var Key: Word; Shift: TShiftState);
begin
FLastDownKey := Key;
// if Key = VK_DELETE then EditText := MakeValid(inherited Text);
if Key = VK_ESCAPE then
begin
Key := 0;
EditText := FEnterText;
SelStart := 0;
SelLength := Length(FEditText);
end;
inherited KeyDown(Key, Shift);
end;
function TJvCustomValidateEdit.CurrRangeValue(CheckValue: Currency): Currency;
begin
Result := CheckValue;
if FHasMaxValue and (CheckValue > FMaxValue) then
Result := FMaxValue
else
if FHasMinValue and (CheckValue < FMinValue) then
Result := FMinValue;
end;
function TJvCustomValidateEdit.FloatRangeValue(CheckValue: Double): Double;
begin
Result := CheckValue;
if FHasMaxValue and (CheckValue > FMaxValue) then
Result := FMaxValue
else
if FHasMinValue and (CheckValue < FMinValue) then
Result := FMinValue;
end;
function TJvCustomValidateEdit.IntRangeValue(CheckValue: Int64): Int64;
begin
Result := CheckValue;
if FHasMaxValue and (CheckValue > FMaxValue) then
Result := Trunc(FMaxValue)
else
if FHasMinValue and (CheckValue < FMinValue) then
Result := Trunc(FMinValue);
end;
function TJvCustomValidateEdit.BcdRangeValue(const CheckValue: TBcd): TBcd;
begin
Result := CheckValue;
if FHasMaxValue and (BcdCompare(CheckValue, DoubleToBcd(FMaxValue)) = 1) then // CheckValue > FMaxValue
Result := DoubleToBcd(FMaxValue)
else
if FHasMinValue and (BcdCompare(CheckValue, DoubleToBcd(FMinValue)) = -1) then // CheckValue < FMinValue
Result := DoubleToBcd(FMinValue);
end;
function TJvCustomValidateEdit.GetEditText: string;
begin
Result := FEditText;
end;
function TJvCustomValidateEdit.GetUnprefixedUnsuffixedText(const Value: string): string;
begin
if not FKeepPrefixSuffixIntact then
begin
Result := StrEnsureNoPrefix(DisplayPrefix, StrEnsureNoSuffix(DisplaySuffix, Value));
Result := StrEnsureNoPrefix(FormatSettings.CurrencyString, StrEnsureNoSuffix(FormatSettings.CurrencyString, Result));
end
else
Result := Value;
end;
procedure TJvCustomValidateEdit.SetEditText(const NewValue: string);
begin
FEditText := MakeValid(GetUnprefixedUnsuffixedText(NewValue));
if (FDisplayFormat = dfYear) and ((not FHasMaxValue) or
(FHasMaxValue and (FMaxValue > 2000 + FormatSettings.TwoDigitYearCenturyWindow))) and
((MaxLength = 0) or (MaxLength > 3)) then
FEditText := IntToStr(MakeYear4Digit(StrToIntDef(FEditText, 0), FormatSettings.TwoDigitYearCenturyWindow));
if (FDisplayFormat in [dfBinary, dfCurrency, dfFloat, dfFloatGeneral, dfDecimal, dfHex, dfInteger,
dfOctal, dfPercent, dfScientific, dfYear, dfFloatFixed, dfBcd]) then
begin
EnforceMaxValue;
EnforceMinValue;
end;
// ChangeText(FEditText);
DisplayText;
DoValueChanged;
end;
procedure TJvCustomValidateEdit.DoEnter;
//procedure TJvCustomValidateEdit.FocusSet(PrevWnd: THandle);
begin
DisplayText;
inherited;
end;
procedure TJvCustomValidateEdit.DoExit;
//procedure TJvCustomValidateEdit.FocusKilled(NextWnd: THandle);
var
DisplayedText: string;
begin
if not (csDestroying in ComponentState) then
begin
DisplayedText := inherited Text;
EditText := GetUnprefixedUnsuffixedText(DisplayedText);
end;
inherited;
end;
procedure TJvCustomValidateEdit.ChangeText(const NewValue: string);
var
S, Exponent, DisplayValue: string;
Ps, I: Integer;
begin
FSelfChange := True;
try
Ps := 0;
if TrimDecimals then
begin
I := Pos('e', LowerCase(NewValue));
if (DisplayFormat = dfScientific) and (I <> 0) then
begin
Exponent := Copy(NewValue, I, Length(NewValue));
Dec(I);
end
else
begin
Exponent := '';
I := Length(NewValue);
end;
Ps := Pos(FormatSettings.DecimalSeparator, NewValue);
if Ps > 0 then
begin
while (I > Ps) and (NewValue[I] = '0') do
Dec(I);
if Ps = I then
Dec(I); // skip decimal separator (Ivo Bauer)
S := FDisplayPrefix + Copy(NewValue, 1, I) + Exponent + FDisplaySuffix;
DisplayValue := Copy(NewValue, 1, I);
if HidePrefixSuffixIfEmpty and (DisplayValue = '') and (Exponent = '') then
S := ''
else
S := FDisplayPrefix + DisplayValue + Exponent + FDisplaySuffix;
end;
end;
if Ps = 0 then
begin
if HidePrefixSuffixIfEmpty and (NewValue = '') and (Exponent = '') then
S := ''
else
S := FDisplayPrefix + NewValue + FDisplaySuffix;
end;
if S <> inherited Text then
SetText(S);
// inherited SetText(S);
finally
FSelfChange := False;
end;
end;
procedure TJvCustomValidateEdit.DisplayText;
function FormatedValue(Value: Double): Double;
begin
Result := Value;
if Assigned(FOnDecimalRounding) then
FOnDecimalRounding(Self, Result, Value);
end;
begin
// The number types need to be formatted
if FAllowEmpty and (FEditText = '') then
ChangeText('')
else
if (FDisplayFormat in [dfBinary, dfCurrency, dfFloat, dfFloatGeneral, dfDecimal, dfInteger, dfOctal,
dfPercent, dfScientific, dfYear, dfFloatFixed]) and
(AsFloat = 0) and FZeroEmpty then
ChangeText('')
else if (FDisplayFormat = dfBcd) and FZeroEmpty and IsBcdZero(AsBcd) then
ChangeText('')
else
begin
case FDisplayFormat of
dfCurrency:
ChangeText(Format('%.*m', [FDecimalPlaces, AsCurrency]));
dfInteger:
ChangeText(IntToStr(AsInteger));
dfFloat:
ChangeText(Format('%.*n', [FDecimalPlaces, FormatedValue(AsFloat)]));
dfFloatGeneral:
ChangeText(Format('%.*g', [FDecimalPlaces, FormatedValue(AsFloat)]));
dfFloatFixed:
ChangeText(Format('%.*f', [FDecimalPlaces, FormatedValue(AsFloat)]));
dfScientific:
ChangeText(Format('%.*e', [FDecimalPlaces, FormatedValue(AsFloat)]));
dfPercent:
ChangeText(Format('%.*n%', [FDecimalPlaces, FormatedValue(AsFloat)]));
dfBcd:
ChangeText(BcdToStrFDefault(AsBcd, FDecimalPlaces));
else
ChangeText(FEditText);
end;
// This needs to be done AFTER the text has been changed so that the color
// is directly shown correctly. (Mantis 3493)
if (FCriticalPoints.CheckPoints <> cpNone) and
(FDisplayFormat in [dfBinary, dfCurrency, dfFloat, dfFloatGeneral, dfDecimal, dfHex, dfInteger,
dfOctal, dfPercent, dfScientific, dfYear, dfFloatFixed, dfBcd]) then
SetFontColor;
end;
end;
function TJvCustomValidateEdit.ScientificStrToFloat(SciString: string): Double;
var
I: Cardinal;
sMantissa, sExponent: string;
bInExp: Boolean;
begin
if Pos('E', UpperCase(SciString)) = 0 then
Result := StrToFloatDef(SciString, 0)
// Result := JvSafeStrToFloatDef(SciString, 0)
else
begin
sMantissa := '';
sExponent := '';
bInExp := False;
for I := 1 to Length(SciString) do
begin
if UpperCase(SciString[I]) = 'E' then
bInExp := True
else
begin
if bInExp then
sExponent := sExponent + SciString[I]
else
sMantissa := sMantissa + SciString[I];
end;
end;
// NOTE: StrToFloatDefIgnoreInvalidCharacters now called JvSafeStrToFloatDef:
Result := StrToFloatDef(sMantissa, 0) * Power(10, StrToFloatDef(sExponent, 0));
// Result := JvSafeStrToFloatDef(sMantissa, 0) * Power(10, JvSafeStrToFloatDef(sExponent, 0));
end;
end;
function TJvCustomValidateEdit.BaseToInt(const BaseValue: string; Base: Byte): Int64;
begin
Assert(Base <= 36, RsEBaseTooBig);
Assert(Base > 1, RsEBaseTooSmall);
Result := Numb2Dec(BaseValue, Base);
end;
function TJvCustomValidateEdit.IntToBase(NewValue: Int64; Base: Byte): string;
begin
Assert(Base <= 36, RsEBaseTooBig);
Assert(Base > 1, RsEBaseTooSmall);
Result := Dec2Numb(NewValue, 0, Base);
end;
procedure TJvCustomValidateEdit.DoValueChanged;
begin
try
if Assigned(FOnValueChanged) and not (csLoading in ComponentState) and (FEnterText <> FEditText) then
FOnValueChanged(Self);
finally
FEnterText := FEditText;
end;
end;
procedure TJvCustomValidateEdit.Change;
var
DisplayedText: string;
begin
// Update FEditText for User changes, so that the AsInteger, etc,
// functions work while editing
if not FSelfChange then
begin
DisplayedText := inherited Text;
FEditText := GetUnprefixedUnsuffixedText(DisplayedText);
end;
inherited Change;
end;
function TJvCustomValidateEdit.GetText: TCaption;
begin
Result := inherited Text;
if (Result = EmptyValue) and (EmptyValue <> '') then
Result := '';
end;
procedure TJvCustomValidateEdit.SetText(const NewValue: TCaption);
begin
// If we are actually changing our value ourselves, there is no need
// to do it again. This may even trigger an infinite recursion, especially
// when in a derived component the display format is set in the constructor.
// In that case, the recursion would kill Delphi almost instantly.
if not FSelfChange then
begin
EditText := NewValue;
DoValueChanged;
end else
inherited Text := NewValue;
end;
procedure TJvCustomValidateEdit.SetEmptyValue(const AValue: string);
begin
FEmptyValue := AValue;
if HandleAllocated then
if Focused then
DoEmptyValueEnter
else
DoEmptyValueExit;
end;
procedure TJvCustomValidateEdit.DoEmptyValueEnter;
begin
if (csDesigning in ComponentState) or not FIsLoaded or (EmptyValue = '') then
Exit;
if EmptyValue <> '' then
begin
if (inherited Text) = EmptyValue then
begin
inherited Text := '';
FIsEmptyValue := False;
(***************** NOT CONVERTED ****
if not (csDesigning in ComponentState) then
Font.Color := FOldFontColor;
*************************************)
end;
end
(****************** NOT CONVERTED ***
else
if not (csDesigning in ComponentState) then
Font.Color := FOldFontColor;
***********************************)
end;
procedure TJvCustomValidateEdit.DoEmptyValueExit;
begin
if (csDesigning in ComponentState) or not FIsLoaded or (EmptyValue = '') then
Exit;
if EmptyValue <> '' then
begin
if Text = '' then
begin
Text := EmptyValue;
FIsEmptyValue := True;
(****************************** NOT CONVERTED **********
if not (csDesigning in ComponentState) then
begin
FOldFontColor := Font.Color;
Font.Color := FEmptyFontColor;
end;
*******************************************************)
end;
end
(**************************** NOT CONVERTED *************
else
if not (csDesigning in ComponentState) then
Font.Color := FOldFontColor;
*******************************************************)
end;
procedure TJvCustomValidateEdit.SetDisplayPrefix(const NewValue: string);
begin
FDisplayPrefix := NewValue;
DisplayText;
end;
procedure TJvCustomValidateEdit.SetDisplaySuffix(const NewValue: string);
begin
FDisplaySuffix := NewValue;
DisplayText;
end;
procedure TJvCustomValidateEdit.CriticalPointsChange(Sender: TObject);
begin
SetFontColor;
Invalidate;
end;
function TJvCustomValidateEdit.IsValid: Boolean;
begin
Result := True;
case FCriticalPoints.CheckPoints of
cpMaxValue:
Result := IsLower(AsFloat, FCriticalPoints.MaxValue, FCriticalPoints.MaxValueIncluded);
cpMinValue:
Result := IsGreater(AsFloat, FCriticalPoints.MinValue, FCriticalPoints.MinValueIncluded);
cpBoth:
Result := IsLower(AsFloat, FCriticalPoints.MaxValue, FCriticalPoints.MaxValueIncluded) and
IsGreater(AsFloat, FCriticalPoints.MinValue, FCriticalPoints.MinValueIncluded);
end;
if Assigned(FOnIsValid) then
FOnIsValid(Self, Result);
end;
function TJvCustomValidateEdit.IsEmpty: Boolean;
var
s: String;
begin
s := GetUnprefixedUnsuffixedText(Text);
Result := s = '';
end;
procedure TJvCustomValidateEdit.SetFontColor;
begin
if not (csDesigning in ComponentState) and not (csLoading in ComponentState) then
begin
Font.OnChange := nil;
case FCriticalPoints.CheckPoints of
cpNone:
Font.Color := FStandardFontColor;
cpMinValue:
if IsLower(AsFloat, FCriticalPoints.MinValue, not FCriticalPoints.MinValueIncluded) then
Font.Color := FCriticalPoints.ColorBelow
else
Font.Color := FStandardFontColor;
cpMaxValue:
if IsGreater(AsFloat, FCriticalPoints.MaxValue, not FCriticalPoints.MaxValueIncluded) then
Font.Color := FCriticalPoints.ColorAbove
else
Font.Color := FStandardFontColor;
cpBoth:
if IsGreater(AsFloat, FCriticalPoints.MaxValue, not FCriticalPoints.MaxValueIncluded) then
Font.Color := FCriticalPoints.ColorAbove
else if IsLower(AsFloat, FCriticalPoints.MinValue, not FCriticalPoints.MinValueIncluded) then
Font.Color := FCriticalPoints.ColorBelow
else
Font.Color := FStandardFontColor;
end;
Font.OnChange := @FontChange;
end;
Invalidate;
end;
procedure TJvCustomValidateEdit.FontChange(Sender: TObject);
begin
FStandardFontColor := Font.Color;
if Assigned(FOldFontChange) then
FOldFontChange(Sender);
end;
procedure TJvCustomValidateEdit.EnforceMaxValue;
begin
{ Check the Value is within this range }
if FHasMaxValue and (FDisplayFormat in [dfBinary, dfCurrency, dfFloat, dfFloatGeneral,
dfDecimal, dfHex, dfInteger, dfOctal, dfPercent, dfScientific, dfYear, dfFloatFixed, dfBcd]) and
(AsFloat > FMaxValue) and not FEnforcingMinMaxValue then
begin
if not (AllowEmpty and IsEmpty) then
begin
FEnforcingMinMaxValue := True;
try
SetAsFloat(FMaxValue);
finally
FEnforcingMinMaxValue := False;
end;
end;
end;
end;
procedure TJvCustomValidateEdit.EnforceMinValue;
begin
{ Check the Value is within this range }
if FHasMinValue and (FDisplayFormat in [dfBinary, dfCurrency, dfFloat, dfFloatGeneral,
dfDecimal, dfHex, dfInteger, dfOctal, dfPercent, dfScientific, dfYear, dfFloatFixed, dfBcd]) and
(AsFloat < FMinValue) and not FEnforcingMinMaxValue then
begin
if not (AllowEmpty and IsEmpty) then
begin
FEnforcingMinMaxValue := True;
try
SetAsFloat(FMinValue);
finally
FEnforcingMinMaxValue := False;
end;
end;
end;
end;
//=== { TJvValidateEditCriticalPoints } ======================================
constructor TJvValidateEditCriticalPoints.Create;
begin
inherited Create;
SetDefaults(cpNone, clBlue, clRed);
FMaxValueIncluded := False;
FMinValueIncluded := False;
end;
procedure TJvValidateEditCriticalPoints.SetCheckPoints(NewValue: TJvValidateEditCriticalPointsCheck);
begin
if FCheckPoints <> NewValue then
begin
FCheckPoints := NewValue;
DoChanged;
end;
end;
procedure TJvValidateEditCriticalPoints.SetColorAbove(NewValue: TColor);
begin
if FColorAbove <> NewValue then
begin
FColorAbove := NewValue;
DoChanged;
end;
end;
procedure TJvValidateEditCriticalPoints.SetColorBelow(NewValue: TColor);
begin
if FColorBelow <> NewValue then
begin
FColorBelow := NewValue;
DoChanged;
end;
end;
procedure TJvValidateEditCriticalPoints.SetMaxValue(NewValue: Double);
begin
if FMaxValue <> NewValue then
begin
FMaxValue := NewValue;
DoChanged;
end;
end;
procedure TJvValidateEditCriticalPoints.SetMinValue(NewValue: Double);
begin
if FMinValue <> NewValue then
begin
FMinValue := NewValue;
DoChanged;
end;
end;
procedure TJvValidateEditCriticalPoints.DoChanged;
begin
if Assigned(FOnChange) then
FOnChange(Self);
end;
procedure TJvValidateEditCriticalPoints.Assign(Source: TPersistent);
var
LocalSource: TJvValidateEditCriticalPoints;
begin
if Source is TJvValidateEditCriticalPoints then
begin
LocalSource := TJvValidateEditCriticalPoints(Source);
CheckPoints := LocalSource.CheckPoints;
ColorAbove := LocalSource.ColorAbove;
ColorBelow := LocalSource.ColorBelow;
MaxValue := LocalSource.MaxValue;
MinValue := LocalSource.MinValue;
end
else
inherited Assign(Source);
end;
function TJvValidateEditCriticalPoints.IsCheckPointsStored: Boolean;
begin
Result := (FCheckPoints <> FDefCheckPoints);
end;
function TJvValidateEditCriticalPoints.IsColorAboveStored: Boolean;
begin
Result := (FColorAbove <> FDefColorAbove);
end;
function TJvValidateEditCriticalPoints.IsColorBelowStored: Boolean;
begin
Result := (FColorBelow <> FDefColorBelow);
end;
procedure TJvValidateEditCriticalPoints.SetDefaults(ACheckPoints: TJvValidateEditCriticalPointsCheck;
AColorAbove, AColorBelow: TColor);
begin
FDefCheckPoints := ACheckPoints;
FCheckPoints := ACheckPoints;
FDefColorAbove := AColorAbove;
FColorAbove := AColorAbove;
FDefColorBelow := AColorBelow;
FColorBelow := AColorBelow;
end;
end.