home *** CD-ROM | disk | FTP | other *** search
- unit FInput;
- {$X+}
- {
- This unit implements a derivative of TInputLine that supports several
- data types dynamically. It also provides formatted input for all the
- numerical types, keystroke filtering and uppercase conversion, field
- justification, and range checking.
-
- When the field is initialized, many filtering and uppercase converions
- are implemented pertinent to the particular data type.
-
- The CheckRange and ErrorHandler methods should be overridden if the
- user wants to implement then.
-
- This is just an initial implementation and comments are welcome. You
- can contact me via Compuserve. (76066,3202)
-
- I am releasing this into the public domain and anyone can use or modify
- it for their own personal use.
-
- Copyright (c) 1990 by Allen Bauer (76066,3202)
-
- This is version 1.1 - fixed input validation functions
-
- }
-
- interface
- uses Objects, Drivers, Dialogs;
-
- type
- VKeys = set of char;
-
- PFInputLine = ^TFInputLine;
- TFInputLine = object(TInputLine)
- ValidKeys : VKeys;
- DataType,Decimals : byte;
- imMode : word;
- Validated, ValidSent : boolean;
- constructor Init(var Bounds: TRect; AMaxLen: integer;
- ChrSet: VKeys;DType, Dec: byte);
- constructor Load(var S: TStream);
- procedure Store(var S: TStream);
- procedure HandleEvent(var Event: TEvent); virtual;
- procedure GetData(var Rec); virtual;
- procedure SetData(var Rec); virtual;
- function DataSize: word; virtual;
- procedure Draw; virtual;
- function CheckRange: boolean; virtual;
- procedure ErrorHandler; virtual;
- end;
-
- const
- imLeftJustify = $0001;
- imRightJustify = $0002;
- imConvertUpper = $0004;
-
- DString = 0;
- DChar = 1;
- DReal = 2;
- DByte = 3;
- DShortInt = 4;
- DInteger = 5;
- DLongInt = 6;
- DWord = 7;
- DDate = 8;
- DTime = 9;
-
- DRealSet : VKeys = [#1..#31,'+','-','0'..'9','.','E','e'];
- DSignedSet : VKeys = [#1..#31,'+','-','0'..'9'];
- DUnSignedSet : VKeys = [#1..#31,'0'..'9'];
- DCharSet : VKeys = [#1..#31,' '..'~'];
- DUpperSet : VKeys = [#1..#31,' '..'`','{'..'~'];
- DAlphaSet : VKeys = [#1..#31,'A'..'Z','a'..'z'];
- DFileNameSet : VKeys = [#1..#31,'!','#'..')','-'..'.','0'..'9','@'..'Z','^'..'{','}'..'~'];
- DPathSet : VKeys = [#1..#31,'!','#'..')','-'..'.','0'..':','@'..'Z','^'..'{','}'..'~','\'];
- DFileMaskSet : VKeys = [#1..#31,'!','#'..'*','-'..'.','0'..':','?'..'Z','^'..'{','}'..'~','\'];
- DDateSet : VKeys = [#1..#31,'0'..'9','/'];
- DTimeSet : VKeys = [#1..#31,'0'..'9',':'];
-
- cmValidateYourself = 2000;
-
- procedure RegisterFInputLine;
-
- const
- RFInputLine : TStreamRec = (
- ObjType: 20000;
- VmtLink: Ofs(typeof(TFInputLine)^);
- Load: @TFInputLine.Load;
- Store: @TFinputLine.Store
- );
-
- implementation
-
- uses Views, MsgBox, StrFmt, Dos;
-
- function CurrentDate : string;
- var
- Year,Month,Day,DOW : word;
- DateStr : string[10];
- begin
- GetDate(Year,Month,Day,DOW);
- DateStr := SFLongint(Month,2)+'/'
- +SFLongInt(Day,2)+'/'
- +SFLongInt(Year mod 100,2);
- for DOW := 1 to length(DateStr) do
- if DateStr[DOW] = ' ' then
- DateStr[DOW] := '0';
- CurrentDate := DateStr;
- end;
-
- function CurrentTime : string;
- var
- Hour,Minute,Second,Sec100 : word;
- TimeStr : string[10];
- begin
- GetTime(Hour,Minute,Second,Sec100);
- TimeStr := SFLongInt(Hour,2)+':'
- +SFLongInt(Minute,2)+':'
- +SFLongInt(Second,2);
- for Sec100 := 1 to length(TimeStr) do
- if TimeStr[Sec100] = ' ' then
- TimeStr[Sec100] := '0';
- CurrentTime := TimeStr;
- end;
-
- procedure RegisterFInputLine;
- begin
- RegisterType(RFInputLine);
- end;
-
- constructor TFInputLine.Init(var Bounds: TRect; AMaxLen: integer;
- ChrSet: VKeys; DType, Dec: byte);
- begin
- if (DType in [DDate,DTime]) and (AMaxLen < 8) then
- AMaxLen := 8;
-
- TInputLine.Init(Bounds,AMaxLen);
-
- ValidKeys:= ChrSet;
- DataType := DType;
- Decimals := Dec;
- Validated := true;
- ValidSent := false;
- case DataType of
- DReal,DByte,DLongInt,
- DShortInt,DWord : imMode := imRightJustify;
-
- DChar,DString,
- DDate,DTime : imMode := imLeftJustify;
- end;
- if ValidKeys = DUpperSet then
- imMode := imMode or imConvertUpper;
- EventMask := EventMask or evMessage;
- end;
-
- constructor TFInputLine.Load(var S: TStream);
- begin
- TInputLine.Load(S);
- S.Read(ValidKeys, sizeof(VKeys));
- S.Read(DataType, sizeof(byte));
- S.Read(Decimals, sizeof(byte));
- S.Read(imMode, sizeof(word));
- S.Read(Validated, sizeof(boolean));
- S.Read(ValidSent, sizeof(boolean));
- end;
-
- procedure TFInputLine.Store(var S: TStream);
- begin
- TInputLine.Store(S);
- S.Write(ValidKeys, sizeof(VKeys));
- S.Write(DataType, sizeof(byte));
- S.Write(Decimals, sizeof(byte));
- S.Write(imMode, sizeof(word));
- S.Write(Validated, sizeof(boolean));
- S.Write(ValidSent, sizeof(boolean));
- end;
-
- procedure TFInputLine.HandleEvent(var Event: TEvent);
- var
- NewEvent: TEvent;
- begin
- case Event.What of
- evKeyDown : begin
- if (imMode and imConvertUpper) <> 0 then
- Event.CharCode := upcase(Event.CharCode);
- if not(Event.CharCode in [#0..#31]) then
- begin
- Validated := false;
- ValidSent := false;
- end;
- if (Event.CharCode <> #0) and not(Event.CharCode in ValidKeys) then
- ClearEvent(Event);
- end;
- evBroadcast: begin
- if (Event.Command = cmReceivedFocus) and
- (Event.InfoPtr <> @Self) and
- ((Owner^.State and sfSelected) <> 0) and
- not(Validated) and not(ValidSent) then
- begin
- NewEvent.What := evBroadcast;
- NewEvent.InfoPtr := @Self;
- NewEvent.Command := cmValidateYourself;
- PutEvent(NewEvent);
- ValidSent := true;
- end;
- if (Event.Command = cmValidateYourself) and
- (Event.InfoPtr = @Self) then
- begin
- if not CheckRange then
- begin
- ErrorHandler;
- Select;
- end
- else
- Validated := true;
- ValidSent := false;
- ClearEvent(Event);
- end;
- end;
- end;
- TInputLine.HandleEvent(Event);
- end;
-
- procedure TFInputLine.GetData(var Rec);
- var
- Code : integer;
- begin
- case DataType of
- Dstring,
- DDate,
- DTime : TInputLine.GetData(Rec);
- DChar : char(Rec) := Data^[1];
- DReal : val(Data^, real(Rec) , Code);
- DByte : val(Data^, byte(Rec) , Code);
- DShortInt : val(Data^, shortint(Rec) , Code);
- DInteger : val(Data^, integer(Rec) , Code);
- DLongInt : val(Data^, longint(Rec) , Code);
- DWord : val(Data^, word(Rec) , Code);
- end;
- end;
-
- procedure TFInputLine.SetData(var Rec);
- begin
- case DataType of
- DString,
- DDate,
- DTime : TInputLine.SetData(Rec);
- DChar : Data^ := char(Rec);
- DReal : Data^ := SFDReal(real(Rec),MaxLen,Decimals);
- DByte : Data^ := SFLongInt(byte(Rec),MaxLen);
- DShortInt : Data^ := SFLongInt(shortint(Rec),MaxLen);
- DInteger : Data^ := SFLongInt(integer(Rec),MaxLen);
- DLongInt : Data^ := SFLongInt(longint(Rec),MaxLen);
- DWord : Data^ := SFLongInt(word(Rec),MaxLen);
- end;
- SelectAll(true);
- end;
-
- function TFInputLine.DataSize: word;
- begin
- case DataType of
- DString,
- DDate,
- DTime : DataSize := TInputLine.DataSize;
- DChar : DataSize := sizeof(char);
- DByte : DataSize := sizeof(byte);
- DShortInt : DataSize := sizeof(shortint);
- DInteger : DataSize := sizeof(integer);
- DLongInt : DataSize := sizeof(longint);
- DWord : DataSize := sizeof(word);
- end;
- end;
-
- procedure TFInputLine.Draw;
- var
- RD : real;
- Code : integer;
- begin
- case DataType of
- DReal : begin
- if Data^ = '' then
- Data^ := SFDReal(0.0,MaxLen,Decimals)
- else
- begin
- val(Data^, RD, Code);
- Data^ := SFDReal(RD,MaxLen,Decimals);
- end;
- end;
-
- DByte,
- DShortInt,
- DInteger,
- DLongInt,
- DWord : if Data^ = '' then Data^ := SFLongInt(0,MaxLen);
-
- DDate : if Data^ = '' then Data^ := CurrentDate;
- DTime : if Data^ = '' then Data^ := CurrentTime;
-
- end;
-
- if State and (sfFocused+sfSelected) <> 0 then
- begin
- if (imMode and imRightJustify) <> 0 then
- while (length(Data^) > 0) and (Data^[1] = ' ') do
- delete(Data^,1,1);
- end
- else
- begin
- if ((imMode and imRightJustify) <> 0) and (Data^ <> '') then
- while (length(Data^) < MaxLen) do
- insert(' ',Data^,1);
- if (imMode and imLeftJustify) <> 0 then
- while (length(Data^) > 0) and (Data^[1] = ' ') do
- delete(Data^,1,1);
-
- end;
- TInputLine.Draw;
- end;
-
- function TFInputLine.CheckRange: boolean;
- var
- MH,DM,YS : longint;
- Code : integer;
- MHs,DMs,YSs : string[2];
- Delim : char;
- Ok : boolean;
- begin
- Ok := true;
- case DataType of
- DDate,
- DTime : begin
- if DataType = DDate then Delim := '/' else Delim := ':';
- if pos(Delim,Data^) > 0 then
- begin
- MHs := copy(Data^,1,pos(Delim,Data^));
- DMs := copy(Data^,pos(Delim,Data^)+1,2);
- delete(Data^,pos(Delim,Data^),1);
- YSs := copy(Data^,pos(Delim,Data^)+1,2);
- if length(MHs) < 2 then MHs := '0' + MHs;
- if length(DMs) < 2 then DMs := '0' + DMs;
- if length(YSs) < 2 then YSs := '0' + YSs;
- Data^ := MHs + DMs + YSs;
- end;
- if (length(Data^) >= 6) and (pos(Delim,Data^) = 0) then
- begin
- val(copy(Data^,1,2), MH, Code);
- if Code <> 0 then MH := 0;
- val(copy(Data^,3,2), DM, Code);
- if Code <> 0 then DM := 0;
- val(copy(Data^,5,2), YS, Code);
- if Code <> 0 then YS := 0;
- if DataType = DDate then
- begin
- if (MH > 12) or (MH < 1) or
- (DM > 31) or (DM < 1) then Ok := false;
- end
- else
- begin
- if (MH > 23) or (MH < 0) or
- (DM > 59) or (DM < 0) or
- (YS > 59) or (YS < 0) then Ok := false;
- end;
- insert(Delim,Data^,5);
- insert(Delim,Data^,3);
- end
- else
- Ok := false;
- end;
-
- DByte : begin
- val(Data^, MH, Code);
- if (Code <> 0) or (MH > 255) or (MH < 0) then Ok := false;
- end;
-
- DShortint :
- begin
- val(Data^, MH, Code);
- if (Code <> 0) or (MH < -127) or (MH > 127) then Ok := false;
- end;
-
- DInteger :
- begin
- val(Data^, MH, Code);
- if (Code <> 0) or (MH < -32768) or (MH > 32767) then Ok := false;
- end;
-
- DWord : begin
- val(Data^, MH, Code);
- if (Code <> 0) or (MH < 0) or (MH > 65535) then Ok := false;
- end;
- end;
- CheckRange := Ok;
- end;
-
- procedure TFInputLine.ErrorHandler;
- var
- MsgString : string[80];
- Params : array[0..1] of longint;
- Event: TEvent;
- begin
- fillchar(Params,sizeof(params),#0);
- MsgString := '';
- case DataType of
- DDate : MsgString := ' Invalid Date Format! Enter Date as MM/DD/YY ';
- DTime : MsgString := ' Invalid Time Format! Enter Time as HH:MM:SS ';
- DByte,
- DShortInt,
- DInteger,
- DWord : begin
- MsgString := ' Number must be between %d and %d ';
- case DataType of
- DByte : Params[1] := 255;
- DShortInt : begin Params[0] := -128; Params[1] := 127; end;
- DInteger : begin Params[0] := -32768; Params[1] := 32768; end;
- DWord : Params[1] := 65535;
- end;
- end;
- end;
- MessageBox(MsgString, @Params, mfError + mfOkButton);
- end;
-
- end.
-