{*********************************************************} {* OVCEDTIM.PAS 4.06 *} {*********************************************************} {* ***** BEGIN LICENSE BLOCK ***** *} {* Version: MPL 1.1 *} {* *} {* 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/ *} {* *} {* Software distributed under the License is distributed on an "AS IS" basis, *} {* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License *} {* for the specific language governing rights and limitations under the *} {* License. *} {* *} {* The Original Code is TurboPower Orpheus *} {* *} {* The Initial Developer of the Original Code is TurboPower Software *} {* *} {* Portions created by TurboPower Software Inc. are Copyright (C)1995-2002 *} {* TurboPower Software Inc. All Rights Reserved. *} {* *} {* Contributor(s): *} {* *} {* ***** END LICENSE BLOCK ***** *} {$I OVC.INC} {$B-} {Complete Boolean Evaluation} {$I+} {Input/Output-Checking} {$P+} {Open Parameters} {$T-} {Typed @ Operator} {.W-} {Windows Stack Frame} {$X+} {Extended Syntax} unit ovcedtim; {-time edit field} interface uses {$IFNDEF LCL} Windows, Messages, {$ELSE} LclIntf, LMessages, LclType, MyMisc, {$ENDIF} Buttons, Classes, Controls, Forms, Graphics, Menus, StdCtrls, SysUtils, OvcConst, OvcData, OvcExcpt, OvcIntl, OvcMisc, OvcEditF, OvcDate; type TOvcTimeField = (tfHours, tfMinutes, tfSeconds); TOvcTimeMode = (tmClock, tmDuration); TOvcDurationDisplay = (ddHMS, ddHM, ddMS, ddHHH, ddMMM, ddSSS); TOvcGetTimeEvent = procedure(Sender : TObject; var Value : string) of object; TOvcPreParseTimeEvent = procedure(Sender : TObject; var Value : string) of object; TOvcCustomTimeEdit = class(TOvcCustomEdit) {.Z+} protected {private} {property variables} FDurationDisplay : TOvcDurationDisplay; FNowString : string; FDefaultToPM : Boolean; FPrimaryField : TOvcTimeField; FShowSeconds : Boolean; FShowUnits : Boolean; FTime : TDateTime; FTimeMode : TOvcTimeMode; FUnitsLength : Integer; {event variables} FOnGetTime : TOvcGetTimeEvent; FOnPreParseTime : TOvcPreParseTimeEvent; FOnSetTime : TNotifyEvent; {property methods} function GetAsHours : LongInt; function GetAsMinutes : LongInt; function GetAsSeconds : LongInt; function GetTime : TDateTime; procedure SetAsHours(Value : LongInt); procedure SetAsMinutes(Value : LongInt); procedure SetAsSeconds(Value : LongInt); procedure SetDurationDisplay(Value : TOvcDurationDisplay); procedure SetShowSeconds(Value : Boolean); procedure SetShowUnits(Value : Boolean); procedure SetTimeMode(Value : TOvcTimeMode); procedure SetUnitsLength(Value : Integer); {internal methods} procedure ParseFields(const Value : string; S : TStringList); protected procedure DoExit; override; procedure SetTime(Value : TDateTime); procedure SetTimeText(Value : string); dynamic; {.Z-} {protected properties} property DefaultToPM : Boolean read FDefaultToPM write FDefaultToPM; property DurationDisplay : TOvcDurationDisplay read FDurationDisplay write SetDurationDisplay; property NowString : string read FNowString write FNowString; property PrimaryField : TOvcTimeField read FPrimaryField write FPrimaryField; property ShowSeconds : Boolean read FShowSeconds write SetShowSeconds; property ShowUnits : Boolean read FShowUnits write SetShowUnits; property TimeMode : TOvcTimeMode read FTimeMode write SetTimeMode; property UnitsLength : Integer read FUnitsLength write SetUnitsLength; {protected events} property OnGetTime : TOvcGetTimeEvent read FOnGetTime write FOnGetTime; property OnPreParseTime : TOvcPreParseTimeEvent read FOnPreParseTime write FOnPreParseTime; property OnSetTime : TNotifyEvent read FOnSetTime write FOnSetTime; public {.Z+} constructor Create(AOwner : TComponent); override; {.Z-} function FormatTime(Value : TDateTime) : string; dynamic; {public properties} property AsDateTime : TDateTime read GetTime write SetTime; property AsHours : LongInt read GetAsHours write SetAsHours; property AsMinutes : LongInt read GetAsMinutes write SetAsMinutes; property AsSeconds : LongInt read GetAsSeconds write SetAsSeconds; end; TOvcTimeEdit = class(TOvcCustomTimeEdit) published {properties} {$IFDEF VERSION4} property Anchors; property Constraints; property DragKind; {$ENDIF} property About; {$IFNDEF LCL} property AutoSelect; {$ENDIF} property AutoSize; property BorderStyle; property CharCase; property Color; property Controller; property Ctl3D; property Cursor; property DefaultToPM; property DragCursor; property DragMode; property DurationDisplay; property Enabled; property Font; {$IFNDEF LCL} property HideSelection; property ImeMode; property ImeName; {$ENDIF} property LabelInfo; property MaxLength; property NowString; {$IFNDEF LCL} property OEMConvert; {$IFDEF VERSION4} property ParentBiDiMode; {$ENDIF} {$ENDIF} property ParentColor; {$IFNDEF LCL} property ParentCtl3D; {$ENDIF} property ParentFont; property ParentShowHint; property PopupMenu; property PrimaryField; property ReadOnly; property ShowHint; property ShowSeconds; property ShowUnits; property TabOrder; property TabStop; property TimeMode; property UnitsLength; property Visible; {inherited events} property OnChange; property OnClick; property OnDblClick; property OnDragDrop; property OnDragOver; {$IFDEF VERSION4} property OnEndDock; {$ENDIF} property OnEndDrag; property OnEnter; property OnExit; property OnGetTime; property OnKeyDown; property OnKeyPress; property OnKeyUp; property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnPreParseTime; property OnSetTime; property OnStartDrag; end; implementation procedure DateTimeToHMS(D : TDateTime; var H, M, S : LongInt); var HS, Days : Double; begin HS := 1 / 86400 / 2; {half second portion of a day} Days := Trunc(D); D := (D-Days) * 24; H := Trunc(D + HS); D := (D - H) * 60; M := Trunc(D + HS); S := Trunc((D - M + HS) * 60); H := Trunc(H + Days * 24); end; function HMSToDateTime(H, M, S : LongInt) : TDateTime; var HID, MID, SID : Double; begin HID := 24; MID := 24*60; SID := 24*60*60; Result := H / HID + M / MID + S / SID; end; {*** TOvcCustomTimeEdit ***} constructor TOvcCustomTimeEdit.Create(AOwner : TComponent); begin inherited Create(AOwner); ControlStyle := ControlStyle - [csSetCaption]; FDurationDisplay := ddHMS; FPrimaryField := tfHours; FNowString := TimeSeparator; FShowSeconds := False; FTime := SysUtils.Time; FTimeMode := tmClock; FUnitsLength := 1; end; procedure TOvcCustomTimeEdit.DoExit; begin try SetTimeText(Text); except SetFocus; raise; end; inherited DoExit; end; function TOvcCustomTimeEdit.FormatTime(Value : TDateTime) : string; var H, M, S : LongInt; TimeMask : string; begin TimeMask := OvcIntlSup.InternationalTime(FShowSeconds); if FTimeMode = tmClock then Result := OvcIntlSup.TimeToTimeString(TimeMask, DateTimeToSTTime(Value), False) else begin DateTimeToHMS(Value, H, M, S); if FShowUnits then begin case FDurationDisplay of ddHMS : Result := IntToStr(H) + ' ' + Copy(GetOrphStr(SCHoursName), 1, FUnitsLength) + ' ' + InttoStr(M) + ' ' + Copy(GetOrphStr(SCMinutesName), 1, FUnitsLength) + ' ' + InttoStr(S) + ' ' + Copy(GetOrphStr(SCSecondsName), 1, FUnitsLength); ddHM : Result := IntToStr(H) + ' ' + Copy(GetOrphStr(SCHoursName), 1, FUnitsLength) + ' ' + InttoStr(M) + ' ' + Copy(GetOrphStr(SCMinutesName), 1, FUnitsLength); ddMS : Result := InttoStr(H*60+M) + ' ' + Copy(GetOrphStr(SCMinutesName), 1, FUnitsLength) + ' ' + InttoStr(S) + ' ' + Copy(GetOrphStr(SCSecondsName), 1, FUnitsLength); ddHHH : Result := IntToStr(H) + ' ' + Copy(GetOrphStr(SCHoursName), 1, FUnitsLength); ddMMM : Result := InttoStr(H*60+M) + ' ' + Copy(GetOrphStr(SCMinutesName), 1, FUnitsLength); ddSSS : Result := InttoStr((H*60+M)*60+S) + ' ' + Copy(GetOrphStr(SCSecondsName), 1, FUnitsLength); end; end else begin case FDurationDisplay of ddHMS : Result := IntToStr(H) + TimeSeparator + InttoStr(M) + TimeSeparator + InttoStr(S); ddHM : Result := IntToStr(H) + TimeSeparator + InttoStr(M); ddMS : Result := IntToStr(H*60+M) + TimeSeparator + InttoStr(S); ddHHH : Result := IntToStr(H); ddMMM : Result := IntToStr(H*60+M); ddSSS : Result := IntToStr((H*60+M)*60+S); end; end; end; end; function TOvcCustomTimeEdit.GetAsHours : LongInt; var H, M, S : LongInt; begin DateTimeToHMS(FTime, H, M, S); Result := H; end; function TOvcCustomTimeEdit.GetAsMinutes : LongInt; var H, M, S : LongInt; begin DateTimeToHMS(FTime, H, M, S); Result := H*60+M; end; function TOvcCustomTimeEdit.GetAsSeconds : LongInt; var H, M, S : LongInt; begin DateTimeToHMS(FTime, H, M, S); Result := (H*60+M)*60+S; end; function TOvcCustomTimeEdit.GetTime : TDateTime; begin SetTimeText(Text); Result := FTime; end; procedure TOvcCustomTimeEdit.SetAsHours(Value : LongInt); var D, H : Integer; begin H := Value; D := H div 24; H := H - D * 24; SetTime(D + EncodeTime(H, 0, 0, 0)); end; procedure TOvcCustomTimeEdit.SetAsMinutes(Value : LongInt); var D, H, M : Integer; begin M := Value; D := M div (24 * 60); M := M - D * (24 * 60); H := M div 60; M := M - H * 60; SetTime(D + EncodeTime(H, M, 0, 0)); end; procedure TOvcCustomTimeEdit.SetAsSeconds(Value : LongInt); var D, H, M, S : Integer; begin S := Value; D := S div (24 * 60 * 60); S := S - D * (24 * 60 * 60); H := S div (60 * 60); S := S - H * (60 * 60); M := S div 60; S := S - M * 60; SetTime(D + EncodeTime(H, M, S, 0)); end; procedure TOvcCustomTimeEdit.SetDurationDisplay(Value : TOvcDurationDisplay); begin if Value <> FDurationDisplay then begin FDurationDisplay := Value; if not (csLoading in ComponentState) then SetTime(FTime); {force redisplay with current options} end; end; procedure TOvcCustomTimeEdit.SetShowSeconds(Value : Boolean); begin if Value <> FShowSeconds then begin FShowSeconds := Value; if not (csLoading in ComponentState) then SetTime(FTime); {force redisplay with current options} end; end; procedure TOvcCustomTimeEdit.SetShowUnits(Value : Boolean); begin if Value <> FShowUnits then begin FShowUnits := Value; if not (csLoading in ComponentState) then SetTime(FTime); {force redisplay with current options} end; end; procedure TOvcCustomTimeEdit.SetTime(Value : TDateTime); begin FTime := Value; Modified := True; if FTime < 0 then Text := '' else Text := FormatTime(FTime); if Assigned(FOnSetTime) then FOnSetTime(Self); end; procedure TOvcCustomTimeEdit.SetTimeMode(Value : TOvcTimeMode); begin if Value <> FTimeMode then begin FTimeMode := Value; if not (csLoading in ComponentState) then SetTime(FTime); {force redisplay with current options} end; end; procedure TOvcCustomTimeEdit.ParseFields(const Value : string; S : TStringList); var I : Integer; I1 : Integer; I2 : Integer; T : string; begin {parse the string into subfields using a string list to hold the parts} I1 := 1; while (I1 <= Length(Value)) and not (Value[I1] in ['0'..'9', 'A'..'Z']) do Inc(I1); while I1 <= Length(Value) do begin I2 := I1; while (I2 <= Length(Value)) and (Value[I2] in ['0'..'9', 'A'..'Z']) do Inc(I2); T := Copy(Value, I1, I2-I1); {if this is a combination of numbers and letters without sperators} {representing multiple fields, split them up} while Length(T) > 0 do begin I := 1; case T[1] of 'A'..'Z' : while T[I] in ['A'..'Z'] do Inc(I); '0'..'9' : while T[I] in ['0'..'9'] do Inc(I); end; S.Add(Copy(T, 1, I-1)); Delete(T, 1, I-1); end; while (I2 <= Length(Value)) and not (Value[I2] in ['0'..'9', 'A'..'Z']) do Inc(I2); I1 := I2; end; end; procedure TOvcCustomTimeEdit.SetTimeText(Value : string); var Field : Integer; Error : Integer; Hours : Integer; Minutes : Integer; Seconds : Integer; FieldList : TStringList; S : string; FieldCount : Integer; Am, Pm, AmPm : string[1]; FoundUnits : Boolean; V : Integer; begin if Assigned(FOnPreParseTime) then FOnPreParseTime(Self, Value); if Assigned(FOnGetTime) then FOnGetTime(Self, Value); if (Value = '') then begin FTime := 0; Text := ''; Exit; end; if AnsiCompareText(Value, NowString) = 0 then begin SetTime(SysUtils.Time); Text := FormatTime(FTime); end else begin Value := AnsiUpperCase(Value); FieldList := TStringList.Create; try {break entry into fields} ParseFields(Value, FieldList); Hours := -1; Minutes := -1; Seconds := -1; if FTimeMode = tmDuration then begin {if a single field entered, assume primary field} if FieldList.Count = 1 then begin case FPrimaryField of tfHours : Hours := StrToIntDef(FieldList[0], -1); tfMinutes : Minutes := StrToIntDef(FieldList[0], -1); tfSeconds : Seconds := StrToIntDef(FieldList[0], -1); end; end else begin FieldCount := FieldList.Count; FoundUnits := False; for Field := 1 to FieldCount do begin if FoundUnits then begin FoundUnits := False; Continue; {skip this field - it is a unit field} end; S := FieldList[Field-1]; V := StrToIntDef(S, -1); {if more fields, see if next field is units for this one} if Field < FieldCount then begin S := FieldList[Field]; {get next field value} if not (S[1] in ['0'..'9']) then begin if PartialCompare(S, GetOrphStr(SCHoursName)) then begin Hours := V; FoundUnits := True; end else if PartialCompare(S, GetOrphStr(SCMinutesName)) then begin Minutes := V; FoundUnits := True; end else if PartialCompare(S, GetOrphStr(SCSecondsName)) then begin Seconds := V; FoundUnits := True; end; end; end; {uses "logical" units for the time field based on prior fields} if not FoundUnits then begin if Hours = -1 then Hours := V else if Minutes = -1 then Minutes := V else if Seconds = -1 then Seconds := V; end; end; end; {if a value assigned, set time and exit} if (Hours > -1) or (Minutes > -1) or (Seconds > -1) then begin if Hours = -1 then Hours := 0; if Minutes = -1 then Minutes := 0; if Seconds = -1 then Seconds := 0; SetTime(HMSToDateTime(Hours, Minutes, Seconds)); Exit; end; end; {handle as "normal" time -- "hh:mm:ss tt" format or variations} Hours := 0; Minutes := 0; Seconds := 0; Error := 0; {set default am/pm} {in case user has deleted these window settings} if (TimeAmString > '') and (TimePmString > '') then begin Am := AnsiUpperCase(TimeAmString[1]); Pm := AnsiUpperCase(TimePmString[1]); end else begin Am := 'A'; Pm := 'P' end; if FDefaultToPM then AmPm := Pm else AmPm := Am; {see if we're using a 24 hour time format} if (Pos(Am, ShortTimeFormat) = 0) and (Pos(Pm, ShortTimeFormat) = 0) then AmPm := ''; FieldCount := FieldList.Count; for Field := FieldCount-1 downto 0 do begin S := AnsiUpperCase(FieldList[Field]); if Pos(Am, S) > 0 then begin AmPm := Am; FieldList.Delete(Field); Continue; end; if Pos(Pm, S) > 0 then begin AmPm := Pm; FieldList.Delete(Field); Continue; end; end; FieldCount := FieldList.Count; for Field := 1 to FieldCount do begin S := FieldList[Field-1]; case Field of 1 : begin if (S = '') or (S[1] in ['0'..'9']) then begin V := StrToIntDef(S, 0); if FTimeMode = tmDuration then begin case FPrimaryField of tfHours : Hours := V; tfMinutes : Minutes := V; tfSeconds : Seconds := V; end; end else begin Hours := V; if (Hours < 12) and (AmPm = Pm) then Inc(Hours, 12); if not (Hours in [0..23]) then Error := SCTimeConvertError; end; end; if Error > 0 then Break; end; 2 : begin if (S = '') or (S[1] in ['0'..'9']) then begin V := StrToIntDef(S, 0); if FTimeMode = tmDuration then begin case FPrimaryField of tfHours : Minutes := V; tfMinutes : Seconds := V; end; end else begin Minutes := V; if not (Minutes in [0..59]) then Error := SCTimeConvertError; end; end; if Error > 0 then Break; end; 3 : begin if (S = '') or (S[1] in ['0'..'9']) then begin V := StrToIntDef(S, 0); if FTimeMode = tmDuration then begin case FPrimaryField of tfHours : Seconds := V; end; end else begin Seconds := V; if not (Seconds in [0..59]) then Error := SCTimeConvertError; end; end; if Error > 0 then Break; end; end; end; {special handling for times at or just after midnight} if (AmPm = Am) then if (Hours = 12) or (Hours = 24) then Hours := 0; if Error > 0 then raise EOvcException.Create(GetOrphStr(Error) + ' "' + Value + '"'); SetTime(HMSToDateTime(Hours, Minutes, Seconds)); finally FieldList.Free; end; end; end; procedure TOvcCustomTimeEdit.SetUnitsLength(Value : Integer); begin if Value <> FUnitsLength then begin FUnitsLength := Value; if not (csLoading in ComponentState) then SetTime(FTime); {force redisplay with current options} end; end; end.