You've already forked lazarus-ccr
tvplanit: Import tasks from VTODO section of iCalendar files (*.ics, *.ical)
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6502 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -929,6 +929,12 @@ msgid "Add event..."
|
||||
msgstr "Ereignis hinzufügen..."
|
||||
|
||||
#: vpsr.rspopupaddeventfromical
|
||||
msgctxt "vpsr.rspopupaddeventfromical"
|
||||
msgid "Import from iCalendar file(s)..."
|
||||
msgstr ""
|
||||
|
||||
#: vpsr.rspopupaddtaskfromical
|
||||
msgctxt "vpsr.rspopupaddtaskfromical"
|
||||
msgid "Import from iCalendar file(s)..."
|
||||
msgstr ""
|
||||
|
||||
|
@ -920,6 +920,12 @@ msgid "Add event..."
|
||||
msgstr ""
|
||||
|
||||
#: vpsr.rspopupaddeventfromical
|
||||
msgctxt "vpsr.rspopupaddeventfromical"
|
||||
msgid "Import from iCalendar file(s)..."
|
||||
msgstr ""
|
||||
|
||||
#: vpsr.rspopupaddtaskfromical
|
||||
msgctxt "vpsr.rspopupaddtaskfromical"
|
||||
msgid "Import from iCalendar file(s)..."
|
||||
msgstr ""
|
||||
|
||||
|
@ -935,6 +935,12 @@ msgid "Add event..."
|
||||
msgstr "Ajouter un événement..."
|
||||
|
||||
#: vpsr.rspopupaddeventfromical
|
||||
msgctxt "vpsr.rspopupaddeventfromical"
|
||||
msgid "Import from iCalendar file(s)..."
|
||||
msgstr ""
|
||||
|
||||
#: vpsr.rspopupaddtaskfromical
|
||||
msgctxt "vpsr.rspopupaddtaskfromical"
|
||||
msgid "Import from iCalendar file(s)..."
|
||||
msgstr ""
|
||||
|
||||
|
@ -929,6 +929,12 @@ msgid "Add event..."
|
||||
msgstr "Gebeurtenis toevoegen..."
|
||||
|
||||
#: vpsr.rspopupaddeventfromical
|
||||
msgctxt "vpsr.rspopupaddeventfromical"
|
||||
msgid "Import from iCalendar file(s)..."
|
||||
msgstr ""
|
||||
|
||||
#: vpsr.rspopupaddtaskfromical
|
||||
msgctxt "vpsr.rspopupaddtaskfromical"
|
||||
msgid "Import from iCalendar file(s)..."
|
||||
msgstr ""
|
||||
|
||||
|
@ -919,6 +919,12 @@ msgid "Add event..."
|
||||
msgstr ""
|
||||
|
||||
#: vpsr.rspopupaddeventfromical
|
||||
msgctxt "vpsr.rspopupaddeventfromical"
|
||||
msgid "Import from iCalendar file(s)..."
|
||||
msgstr ""
|
||||
|
||||
#: vpsr.rspopupaddtaskfromical
|
||||
msgctxt "vpsr.rspopupaddtaskfromical"
|
||||
msgid "Import from iCalendar file(s)..."
|
||||
msgstr ""
|
||||
|
||||
|
@ -929,6 +929,12 @@ msgid "Add event..."
|
||||
msgstr "Добавить событие..."
|
||||
|
||||
#: vpsr.rspopupaddeventfromical
|
||||
msgctxt "vpsr.rspopupaddeventfromical"
|
||||
msgid "Import from iCalendar file(s)..."
|
||||
msgstr ""
|
||||
|
||||
#: vpsr.rspopupaddtaskfromical
|
||||
msgctxt "vpsr.rspopupaddtaskfromical"
|
||||
msgid "Import from iCalendar file(s)..."
|
||||
msgstr ""
|
||||
|
||||
|
@ -185,6 +185,7 @@ resourcestring
|
||||
{Task Specific}
|
||||
RSConfirmDeleteTask = 'Delete this task from your list?';
|
||||
RSTaskPopupAdd = 'Add task...';
|
||||
RSPopupAddTaskFromICal = 'Import from iCalendar file(s)...';
|
||||
RSTaskPopupEdit = 'Edit task...';
|
||||
RSTaskPopupDelete = 'Delete task...';
|
||||
RSTaskTitleResource = 'Task list - '; {!!.01}
|
||||
|
@ -422,6 +422,7 @@ type
|
||||
public
|
||||
constructor Create(Owner: TVpTasks);
|
||||
destructor Destroy; override;
|
||||
procedure LoadFromICalendar(AEntry: TVpICalToDo);
|
||||
property Loading: Boolean read FLoading write FLoading;
|
||||
property Changed: Boolean read FChanged write SetChanged;
|
||||
property Deleted: Boolean read FDeleted write FDeleted;
|
||||
@ -439,8 +440,8 @@ type
|
||||
property Complete: Boolean read FComplete write SetComplete;
|
||||
property CreatedOn: TDateTime read FCreatedOn write SetCreatedOn;
|
||||
property CompletedOn: TDateTIme read FCompletedOn write SetCompletedOn;
|
||||
property Priority: Integer read FPriority write SetPriority;
|
||||
property Category: Integer read FCategory write SetCategory;
|
||||
property Priority: Integer read FPriority write SetPriority; // --> TVpTaskPriority
|
||||
property Category: Integer read FCategory write SetCategory; // --> TVpCategoryType
|
||||
|
||||
{ Reserved for your use }
|
||||
property UserField0: string read FUserField0 write FUserField0;
|
||||
@ -1305,7 +1306,6 @@ begin
|
||||
FCategory := k;
|
||||
end;
|
||||
|
||||
|
||||
{ All-day event }
|
||||
FAllDayEvent := (frac(FStartTime) = 0) and (frac(FEndTime) = 0);
|
||||
|
||||
@ -1361,18 +1361,6 @@ begin
|
||||
FRepeatCode := rtCustom;
|
||||
FCustInterval := AEntry.RecurrenceInterval; // * SecondsInDay;
|
||||
end;
|
||||
(*
|
||||
'HOURLY':
|
||||
begin
|
||||
FRepeatCode := rtCustom;
|
||||
FCustInterval := AEntry.RecurrenceInterval * SecondsInHour;
|
||||
end;
|
||||
'MINUTELY':
|
||||
begin
|
||||
FRepeatCode := rtCustom;
|
||||
FCustInterval := AEntry.RecurrenceInterval * SecondsInMinute;
|
||||
end;
|
||||
*)
|
||||
end;
|
||||
if (AEntry.RecurrenceEndDate = 0) and (AEntry.RecurrenceCount > 0) then begin
|
||||
FRepeatRangeEnd := trunc(FStartTime);
|
||||
@ -1388,9 +1376,6 @@ begin
|
||||
end;
|
||||
end else
|
||||
FRepeatRangeEnd := AEntry.RecurrenceEndDate;
|
||||
|
||||
// There is also "CustomInterval" which may be extracted from the RecurrenceByXXXX data
|
||||
// But this is very complex...
|
||||
end;
|
||||
|
||||
procedure TVpEvent.SetAlarmAdv(Value: Integer);
|
||||
@ -2674,6 +2659,55 @@ begin
|
||||
result := (Trunc(DueDate) < now + 1);
|
||||
end;
|
||||
|
||||
procedure TVpTask.LoadFromICalendar(AEntry: TVpICalToDo);
|
||||
var
|
||||
dt: Double;
|
||||
cat: String;
|
||||
i, j, k: Integer;
|
||||
ct: TVpCategoryType;
|
||||
catFound: Boolean;
|
||||
begin
|
||||
if AEntry = nil then
|
||||
exit;
|
||||
|
||||
{ Standard event properties }
|
||||
FDescription := AEntry.Summary;
|
||||
FDetails := AEntry.Comment;
|
||||
FCreatedOn := AEntry.StartTime[false];
|
||||
FDueDate := AEntry.DueTime[false];
|
||||
FCompletedOn := AEntry.CompletedTime[false];
|
||||
|
||||
{ Status }
|
||||
FComplete := SameText(AEntry.Status, 'COMPLETED');
|
||||
|
||||
{ Priority }
|
||||
case AEntry.Priority of
|
||||
1, 2, 3: FPriority := ord(tpHigh);
|
||||
4, 5, 6: FPriority := ord(tpNormal);
|
||||
7, 8, 9: FPriority := ord(tpLow);
|
||||
else FPriority := ord(tpNormal);
|
||||
end;
|
||||
|
||||
{ Category }
|
||||
{ tvplanit has only 1 category, ical may have several. We pick the first one
|
||||
defined by TVpCategorytype. If none is found we select ctOther. }
|
||||
FCategory := ord(ctOther);
|
||||
catFound := false;
|
||||
if AEntry.CategoryCount > 0 then begin
|
||||
for i := 0 to AEntry.CategoryCount-1 do begin
|
||||
cat := AEntry.category[i];
|
||||
for ct in TVpCategoryType do begin
|
||||
if cat = CategoryLabel(ct) then begin
|
||||
FCategory := ord(ct);
|
||||
catFound := true;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
if catFound then break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TVpTask.SetCategory(const Value: Integer);
|
||||
begin
|
||||
if Value <> FCategory then begin
|
||||
|
@ -89,6 +89,40 @@ type
|
||||
property RecurrenceByXXX: String read FRecurrenceByXXX;
|
||||
end;
|
||||
|
||||
TVpICalToDo = class(TVpICalEntry)
|
||||
private
|
||||
FSummary: String;
|
||||
FComment: String;
|
||||
FStartTime: TDateTime;
|
||||
FStartTimeTZ: String;
|
||||
FDueTime: TDateTime;
|
||||
FDueTimeTZ: String;
|
||||
FCompletedTime: TDateTime;
|
||||
FCompletedTimeTZ: String;
|
||||
FDuration: double;
|
||||
FCategories: TStrings;
|
||||
FPriority: integer;
|
||||
FStatus: String;
|
||||
function GetCategory(AIndex: integer): String;
|
||||
function GetCategoryCount: Integer;
|
||||
function GetCompletedTime(UTC: Boolean): TDateTime;
|
||||
function GetDueTime(UTC: Boolean): TDateTime;
|
||||
function GetStartTime(UTC: Boolean): TDateTime;
|
||||
public
|
||||
constructor Create(AOwner: TVpICalendar); override;
|
||||
destructor Destroy; override;
|
||||
procedure Analyze; override;
|
||||
property Summary: String read FSummary;
|
||||
property Comment: String read FComment;
|
||||
property StartTime[UTC: Boolean]: TDateTime read GetStartTime;
|
||||
property DueTime[UTC: Boolean]: TDateTime read GetDueTime;
|
||||
property CompletedTime[UTC: Boolean]: TDateTime read GetCompletedTime;
|
||||
property Category[AIndex: Integer]: String read GetCategory;
|
||||
property CategoryCount: Integer read GetCategoryCount;
|
||||
property Priority: Integer read FPriority; // 0=undefined, 1-highest, 9=lowest
|
||||
property Status: String read FStatus;
|
||||
end;
|
||||
|
||||
TVpICalendar = class
|
||||
private
|
||||
FEntries: array of TVpICalEntry;
|
||||
@ -411,6 +445,114 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
{==============================================================================}
|
||||
{ TVpICalToDo }
|
||||
{==============================================================================}
|
||||
|
||||
constructor TVpICalToDo.Create(AOwner: TVpICalendar);
|
||||
begin
|
||||
inherited;
|
||||
FCategories := TStringList.Create;
|
||||
FCategories.Delimiter := VALUE_DELIMITER;
|
||||
FCategories.StrictDelimiter := true;
|
||||
end;
|
||||
|
||||
destructor TVpICalToDo.Destroy;
|
||||
begin
|
||||
FCategories.Free;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
procedure TVpICalToDo.Analyze;
|
||||
var
|
||||
i, j: Integer;
|
||||
item: TVpICalItem;
|
||||
L: TStrings;
|
||||
s: String;
|
||||
isUTC: Boolean;
|
||||
begin
|
||||
inherited;
|
||||
|
||||
for i := 0 to FItems.Count-1 do begin
|
||||
item := TVpICalItem(FItems[i]);
|
||||
case item.Key of
|
||||
'SUMMARY':
|
||||
FSummary := item.Value;
|
||||
'COMMENT':
|
||||
FComment := item.Value;
|
||||
'DTSTART':
|
||||
begin
|
||||
FStartTimeTZ := item.GetAttribute('TZID');
|
||||
FStartTime := iCalDateTime(item.Value, isUTC);
|
||||
if not isUTC then
|
||||
FStartTime := FCalendar.LocalTimeToUTC(FStartTime, FStartTimeTZ);
|
||||
end;
|
||||
'DUE':
|
||||
begin
|
||||
FDueTimeTZ := item.GetAttribute('TZID');
|
||||
FDueTime := iCalDateTime(item.Value, isUTC);
|
||||
if not isUTC then
|
||||
FDueTime := FCalendar.LocalTimeToUTC(FDueTime, FDueTimeTZ);
|
||||
end;
|
||||
'DURATION':
|
||||
FDuration := ICalDuration(item.Value);
|
||||
'COMPLETED':
|
||||
begin
|
||||
FCompletedTimeTZ := item.GetAttribute('TZID');
|
||||
FCompletedTime := iCalDateTime(item.Value, isUTC);
|
||||
if not isUTC then
|
||||
FCompletedTime := FCalendar.LocalTimeToUTC(FCompletedTime, FCompletedTimeTZ);
|
||||
end;
|
||||
'CATEGORIES':
|
||||
FCategories.DelimitedText := item.Value;
|
||||
'PRIORITY':
|
||||
FPriority := StrToIntDef(item.Value, 0);
|
||||
'STATUS':
|
||||
FStatus := item.Value;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TVpICalToDo.GetCategory(AIndex: Integer): String;
|
||||
begin
|
||||
if (AIndex >= 0) and (AIndex < FCategories.Count) then
|
||||
Result := FCategories[AIndex]
|
||||
else
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
function TVpICalToDo.GetCategoryCount: Integer;
|
||||
begin
|
||||
Result := FCategories.Count;
|
||||
end;
|
||||
|
||||
function TVpICalToDo.GetCompletedTime(UTC: Boolean): TDateTime;
|
||||
begin
|
||||
Result := FCompletedTime;
|
||||
if (Result > 0) and (not UTC) then
|
||||
Result := FCalendar.UTCToLocalTime(Result, FCompletedTimeTZ);
|
||||
end;
|
||||
|
||||
function TVpICalToDo.GetDueTime(UTC: Boolean): TDateTime;
|
||||
begin
|
||||
if FDueTime <> 0 then
|
||||
Result := FDueTime
|
||||
else
|
||||
Result := FStartTime + FDuration;
|
||||
if (Result > 0) and (not UTC) then
|
||||
Result := FCalendar.UTCToLocalTime(Result, FDueTimeTZ);
|
||||
end;
|
||||
|
||||
function TVpICalToDo.GetStartTime(UTC: Boolean): TDateTime;
|
||||
begin
|
||||
if UTC then
|
||||
Result := FStartTime
|
||||
else
|
||||
Result := FCalendar.LocalTimeToUTC(FStartTime, FStartTimeTZ);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{==============================================================================}
|
||||
{ TVpICalendar }
|
||||
{==============================================================================}
|
||||
@ -512,12 +654,15 @@ begin
|
||||
currEntry := TVpICalEvent.Create(self);
|
||||
FEntries[n] := currEntry;
|
||||
end;
|
||||
'VFREEBUSY':
|
||||
currEntry := nil;
|
||||
'VTODO':
|
||||
currEntry := nil;
|
||||
begin
|
||||
currEntry :=TVpICalToDo.Create(self);
|
||||
FEntries[n] := currEntry;
|
||||
end;
|
||||
'VJOURNAL':
|
||||
currEntry := nil;
|
||||
'VFREEBUSY':
|
||||
currEntry := nil;
|
||||
'VALARM':
|
||||
if currEntry is TVpICalEvent then begin
|
||||
oldEntry := currEntry;
|
||||
|
@ -172,6 +172,7 @@ type
|
||||
{ internal methods }
|
||||
procedure InitializeDefaultPopup;
|
||||
procedure PopupAddTask(Sender: TObject);
|
||||
procedure PopupAddFromICalFile(Sender: TObject);
|
||||
procedure PopupDeleteTask(Sender: TObject);
|
||||
procedure PopupEditTask(Sender: TObject);
|
||||
procedure tlSetVScrollPos;
|
||||
@ -259,7 +260,8 @@ type
|
||||
implementation
|
||||
|
||||
uses
|
||||
SysUtils, Forms, Dialogs, VpTaskEditDlg, VpDlg, VpTasklistPainter;
|
||||
SysUtils, Forms, Dialogs,
|
||||
VpDlg, VpTaskEditDlg, VpTasklistPainter, VpICal;
|
||||
|
||||
(*****************************************************************************)
|
||||
|
||||
@ -848,7 +850,7 @@ procedure TVpTaskList.InitializeDefaultPopup;
|
||||
var
|
||||
NewItem: TMenuItem;
|
||||
begin
|
||||
if RSTaskPopupAdd <> '' then begin
|
||||
if RSTaskPopupAdd <> '' then begin // "Add"
|
||||
NewItem := TMenuItem.Create(Self);
|
||||
NewItem.Caption := RSTaskPopupAdd;
|
||||
NewItem.OnClick := PopupAddTask;
|
||||
@ -856,7 +858,15 @@ begin
|
||||
FDefaultPopup.Items.Add(NewItem);
|
||||
end;
|
||||
|
||||
if RSTaskPopupEdit <> '' then begin
|
||||
if RSPopupAddTaskFromICal <> '' then begin // Import from iCal
|
||||
NewItem := TMenuItem.Create(Self);
|
||||
NewItem.Caption := RSPopupAddTaskFromICal;
|
||||
NewItem.OnClick := PopupAddFromICalFile;
|
||||
NewItem.Tag := 0;
|
||||
FDefaultPopup.Items.Add(NewItem);
|
||||
end;
|
||||
|
||||
if RSTaskPopupEdit <> '' then begin // "Edit"
|
||||
NewItem := TMenuItem.Create(Self);
|
||||
NewItem.Caption := RSTaskPopupEdit;
|
||||
NewItem.OnClick := PopupEditTask;
|
||||
@ -864,7 +874,7 @@ begin
|
||||
FDefaultPopup.Items.Add(NewItem);
|
||||
end;
|
||||
|
||||
if RSTaskPopupDelete <> '' then begin
|
||||
if RSTaskPopupDelete <> '' then begin // "Delete"
|
||||
NewItem := TMenuItem.Create(Self);
|
||||
NewItem.Caption := RSTaskPopupDelete;
|
||||
NewItem.OnClick := PopupDeleteTask;
|
||||
@ -886,6 +896,51 @@ begin
|
||||
end;
|
||||
{=====}
|
||||
|
||||
procedure TVpTaskList.PopupAddFromICalFile(Sender: TObject);
|
||||
var
|
||||
dlg: TOpenDialog;
|
||||
ical: TVpICalendar;
|
||||
fn: String;
|
||||
i: Integer;
|
||||
id: Integer;
|
||||
begin
|
||||
if ReadOnly or (not CheckCreateResource) then
|
||||
exit;
|
||||
|
||||
dlg := TOpenDialog.Create(nil);
|
||||
try
|
||||
dlg.Title := RSLoadICalTitle;
|
||||
dlg.Filter := RSICalFilter;
|
||||
dlg.FileName := '';
|
||||
dlg.Options := dlg.Options + [ofAllowMultiSelect, ofFileMustExist];
|
||||
if dlg.Execute then begin
|
||||
Screen.Cursor := crHourGlass;
|
||||
Application.ProcessMessages;
|
||||
ical := TVpICalendar.Create;
|
||||
try
|
||||
for fn in dlg.Files do begin
|
||||
ical.LoadFromFile(fn);
|
||||
for i := 0 to ical.Count-1 do begin
|
||||
if not (ical[i] is TVpICalToDo) then
|
||||
Continue;
|
||||
id := DataStore.GetNextID(EventsTableName);
|
||||
FActiveTask := Datastore.Resource.Tasks.AddTask(id);
|
||||
FActiveTask.LoadFromICalendar(TVpICalToDo(ical[i]));
|
||||
Datastore.PostTasks;
|
||||
Datastore.NotifyDependents;
|
||||
end;
|
||||
end;
|
||||
Invalidate;
|
||||
finally
|
||||
ical.Free;
|
||||
Screen.Cursor := crDefault;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
dlg.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TVpTaskList.PopupDeleteTask(Sender: TObject);
|
||||
begin
|
||||
if ReadOnly then
|
||||
|
Reference in New Issue
Block a user