diff --git a/components/tvplanit/source/vpconst.pas b/components/tvplanit/source/vpconst.pas index 691edc983..41c5a136e 100644 --- a/components/tvplanit/source/vpconst.pas +++ b/components/tvplanit/source/vpconst.pas @@ -57,6 +57,7 @@ const 0, WS_HSCROLL, WS_VSCROLL, WS_HSCROLL or WS_VSCROLL{$IFDEF LCL},0,0,0{$ENDIF} ); + NO_DATE = 9999999; SecondsInDay = 86400; { Number of seconds in a day } SecondsInHour = 3600; { Number of seconds in an hour } SecondsInMinute = 60; { Number of seconds in a minute } diff --git a/components/tvplanit/source/vpdata.pas b/components/tvplanit/source/vpdata.pas index 12c475d11..261d551b3 100644 --- a/components/tvplanit/source/vpdata.pas +++ b/components/tvplanit/source/vpdata.pas @@ -313,7 +313,6 @@ type function CanEdit: Boolean; function CopyToSchedule(ASchedule: TVpSchedule): TVpEvent; function GetResource: TVpResource; - class function IsAllDayEvent(AStartTime, AEndTime: TDateTime): Boolean; function IsOverlayed: Boolean; procedure LoadFromICalendar(AEntry: TVpICalEvent); class procedure GetAlarmParams(ATrigger: TDateTime; out AdvTime: Integer; @@ -1343,13 +1342,6 @@ begin Result := FOwner.Owner; end; -{ Returns whether the event specified by its start and end time is an all-day - event. This is true when the time-part is zero in each case. } -class function TVpEvent.IsAllDayEvent(AStartTime, AEndTime: TDateTime): Boolean; -begin - Result := (frac(AStartTime) = 0) and (frac(AEndTime) = 0); -end; - { The event is overlayed if its ResourceID is different from that of the resource to which it belongs. } function TVpEvent.IsOverlayed: Boolean; @@ -1430,7 +1422,7 @@ begin end; { All-day event } - FAllDayEvent := TVpEvent.IsAllDayEvent(FStartTime, FEndTime); + FAllDayEvent := AEntry.IsAllDayEvent; { Alarm properties } if AEntry.Alarm <> nil then begin @@ -1796,10 +1788,10 @@ begin Continue; startTime := TVpICalEvent(ical[i]).StartTime[false]; // use local times endTime := TVpICalEvent(ical[i]).EndTime[false]; - if (startTime = 0) and (endTime = 0) then + if startTime = NO_DATE then continue; id := dataStore.GetNextID(EventsTableName); - event := AddEvent(id, starttime, endtime); + event := AddEvent(id, starttime, endtime - OneSecond); event.Changed := true; event.LoadFromICalendar(TVpICalEvent(ical[i])); if (event.Category = 0) and (ADefaultCategory <> -1) then diff --git a/components/tvplanit/source/vpical.pas b/components/tvplanit/source/vpical.pas index a8064cf68..f6fe90129 100644 --- a/components/tvplanit/source/vpical.pas +++ b/components/tvplanit/source/vpical.pas @@ -77,6 +77,7 @@ type destructor Destroy; override; procedure Analyze; override; function Categories: TStrings; + function IsAllDayEvent: Boolean; procedure UseAlarm; property Summary: String read FSummary; // is "Description" of tvp property Description: String read FDescription; // is "Notes" of tvp @@ -328,6 +329,9 @@ begin FCategories.Delimiter := VALUE_DELIMITER; FCategories.StrictDelimiter := True; FCategories.SkipLastLineBreak := True; + FStartTime := NO_DATE; + FEndTime := NO_DATE; + FDuration := NO_DATE; end; destructor TVpICalEvent.Destroy; @@ -420,6 +424,9 @@ end; function TVpICalEvent.GetEndTime(UTC: Boolean): TDateTime; begin + if (FEndTime = NO_DATE) and (FDuration = NO_DATE) then + Result := NO_DATE + else if FEndTime <> 0 then Result := FEndTime else @@ -430,12 +437,37 @@ end; function TVpICalEvent.GetStartTime(UTC: Boolean): TDateTime; begin + if FStartTime = NO_DATE then + Result := NO_DATE + else if UTC then Result := FStartTime else Result := FCalendar.LocalTimeToUTC(FStartTime, FStartTimeTZ); end; +{ Determines whether the event is an all-day event. + See specs (https://www.rfc-editor.org/rfc/rfc5545#page-54): + The "DTEND" property for a "VEVENT" calendar component specifies the + non-inclusive end of the event. For cases where a "VEVENT" calendar + component specifies a "DTSTART" property with a DATE value type but no + "DTEND" nor "DURATION" property, the event's duration is taken to + be one day. For cases where a "VEVENT" calendar component + specifies a "DTSTART" property with a DATE-TIME value type but no + "DTEND" property, the event ends on the same calendar date and + time of day specified by the "DTSTART" property. } +function TVpICalEvent.IsAllDayEvent: Boolean; +var + tstart, tend: TDateTime; +begin + tstart := GetStartTime(false); + tend := GetEndTime(false); + if ((FEndTime = NO_DATE) or (frac(tend) = 0.0)) and (frac(tstart) = 0.0) then + Result := true + else + Result := false; +end; + procedure TVpICalEvent.UseAlarm; begin FAlarm.Free; diff --git a/components/tvplanit/source/vpimportpreview_icalevent.pas b/components/tvplanit/source/vpimportpreview_icalevent.pas index b376f9b9a..8cded8ff2 100644 --- a/components/tvplanit/source/vpimportpreview_icalevent.pas +++ b/components/tvplanit/source/vpimportpreview_icalevent.pas @@ -24,6 +24,7 @@ type FDefaultCategory: String; FTimeFormat: String; function GetEventText(AEvent: TVpICalEvent): String; + procedure SetCalendar(const AValue: TVpICalendar); protected @@ -47,7 +48,7 @@ implementation {$R *.lfm} uses - VpSR; + VpSR, VpConst; constructor TVPImportPreviewICalEventForm.Create(AOwner: TComponent); begin @@ -89,6 +90,7 @@ function TVpImportPreviewICalEventForm.GetEventText(AEvent: TVpICalEvent): Strin var startTime, endTime: TDateTime; sStartTime, sEndTime: String; + nDays: Integer; advTime: Integer; advTimeUnits: TVpAlarmAdvType; dingPath: String; @@ -98,10 +100,11 @@ begin startTime := AEvent.StartTime[false]; endTime := AEvent.EndTime[false]; sStartTime := FormatDateTime(FTimeFormat, startTime); - sEndTime := FormatDateTime(FTimeFormat, endTime); - if TVpEvent.IsAllDayEvent(startTime, endTime) then + sEndTime := FormatDateTime(FTimeFormat, endTime - OneSecond); + if AEvent.IsAllDayEvent then begin - if trunc(startTime) = trunc(endTime) then + if endTime = NO_DATE then nDays := 1 else nDays := round(endTime - startTime); + if nDays in [0, 1] then Result := Format('%s (%s)', [sStartTime, RSAllDay]) else Result := Format('%s - %s (%s)', [sStartTime, sEndTime, RSAllDay]); @@ -119,8 +122,6 @@ begin begin cat := AEvent.Categories.Text; if cat = '' then cat := '(none)'; -// cat := FDatastore.FindBestEventCategory(AEvent.Categories); -// if cat = '' then cat := FDefaultCategory; Result := Result + cat; end; @@ -242,6 +243,7 @@ begin for i := 0 to FCalendar.Count-1 do if (FCalendar.Entry[i] is TVpICalEvent) then FItems.Add(FCalendar.Entry[i]); + inherited; if (FCalendar <> nil) and (FDataStore <> nil) and (Grid.Columns.Count = 2) then