tvplanit: Alternate solution for issue #39061

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9090 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2023-12-17 23:18:28 +00:00
parent 58b00ac007
commit 7548f46b4f
13 changed files with 674 additions and 58 deletions

View File

@ -202,6 +202,16 @@ resourcestring
RSAssignedCategory = 'Assigned category';
RSEventItems = 'Event items';
RSImportCheckedItems = 'Import checked items';
RSOpenEndEventsDurationLbl= 'Duration of "open-end" events';
RSDurationForOpenEndEvents= 'The calendar contains events without an end time and without a duration. '+
'Please define which duration will be assumed for these events.';
RSNoEventDurationSelected = 'No event duration selected.';
RSImportICalendarEvents = 'Import iCalendar Events';
RSOpenEndEvents = 'Open-end Events';
RSHalfAnHour = 'Half an hour';
RSOneHour = 'One hour';
RSTwoHours = 'Two hours';
RSFourHours = 'Four hours';
{Task Specific}
RSConfirmDeleteTask = 'Delete this task from your list?';
@ -339,7 +349,10 @@ resourcestring
RSOpenItemBtn = '&Open Item';
RS1Minute = '1 minute';
RSXMinutes = '%d minutes';
RS30Minutes = '30 mins';
RS1Hour = '1 hour';
RS2Hours = '2 hours';
RS4Hours = '4 hours';
RSXHours = '%d hours';
RS1Day = '1 day';
RSXDays = '%d days';

View File

@ -74,6 +74,7 @@ type
FAlarm: TVpICalAlarm;
FCategories: TStrings;
FPickedCategory: Integer;
FOpenEnd: Boolean;
function GetCategory(AIndex: Integer): String;
function GetCategoryCount: Integer;
function GetEndTime(UTC: Boolean): TDateTime;
@ -103,6 +104,7 @@ type
property RecurrenceByXXX: String read FRecurrenceByXXX write FRecurrenceByXXX;
property PickedCategory: Integer read FPickedCategory write FPickedCategory;
property UID: String read FUID write FUID;
property OpenEnd: Boolean read FOpenEnd;
end;
TVpICalToDo = class(TVpICalEntry)
@ -175,6 +177,8 @@ type
destructor Destroy; override;
procedure Add(AEntry: TVpICalEntry);
procedure Clear;
function ContainsOpenEndEvents: Boolean;
procedure FixOpenEndEvents(ADuration: TDateTime);
procedure LoadFromFile(const AFileName: String);
procedure LoadFromStream(const AStream: TStream);
procedure SaveToFile(const AFileName: String);
@ -190,7 +194,7 @@ type
implementation
uses
VpConst, VpBase;
VpConst, VpMisc, VpBase;
const
DATE_FORMAT = 'yyyymmdd';
@ -490,15 +494,9 @@ begin
end;
end;
end;
{
if (FEndTime = NO_DATE) and (FStartTime <> NO_DATE) then
begin
if FDuration = 0 then
FEndTime := FStartTime + 1.0/24 // 1 hour default
else
FEndTime := FStartTime + FDuration;
end;
}
if (FEndTime = NO_DATE) and ((FDuration = 0) or (FDuration = NO_DATE)) then
FOpenEnd := true;
end;
function TVpICalEvent.Categories: TStrings;
@ -918,6 +916,33 @@ begin
SetLength(FEntries, 0);
end;
function TVpICalendar.ContainsOpenEndEvents: Boolean;
var
i: Integer;
begin
for i := 0 to High(FEntries) do
if (FEntries[i] is TVpICalEvent) and TVpICalEvent(FEntries[i]).OpenEnd then
exit(true);
Result := false;
end;
procedure TVpICalendar.FixOpenEndEvents(ADuration: TDateTime);
var
i: Integer;
ev: TVpICalEvent;
startTime: TDateTime;
begin
for i := 0 to High(FEntries) do
if (FEntries[i] is TVpICalEvent) then
begin
ev := TVpICalEvent(FEntries[i]);
if ev.OpenEnd then begin
startTime := ev.StartTime[true];
ev.EndTime[true] := startTime + ADuration;
end;
end;
end;
function TVpICalendar.GetCount: Integer;
begin
Result := Length(FEntries);

View File

@ -4,17 +4,88 @@ inherited VpImportPreviewICalEventForm: TVpImportPreviewICalEventForm
Caption = ''
ClientHeight = 400
ClientWidth = 667
OnActivate = FormActivate
inherited ButtonPanel: TPanel
Top = 369
Width = 655
ClientWidth = 655
inherited btnExecute: TButton
Left = 446
BorderSpacing.Left = 8
OnClick = btnExecuteClick
end
inherited btnCancel: TButton
Left = 593
Width = 62
AutoSize = True
end
object lblOpenEndDuration: TLabel[2]
AnchorSideLeft.Control = ButtonPanel
AnchorSideTop.Control = ButtonPanel
AnchorSideTop.Side = asrCenter
Left = 6
Height = 15
Top = 5
Width = 163
BorderSpacing.Left = 6
BorderSpacing.Right = 8
Caption = 'Duration of "open end" events:'
Visible = False
end
object rbOpenEndDuration30mins: TRadioButton[3]
AnchorSideLeft.Control = lblOpenEndDuration
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = ButtonPanel
AnchorSideTop.Side = asrCenter
Left = 177
Height = 19
Top = 3
Width = 54
BorderSpacing.Right = 9
Caption = '30 min'
TabOrder = 2
Visible = False
end
object rbOpenEndDuration1Hr: TRadioButton[4]
AnchorSideLeft.Control = rbOpenEndDuration30mins
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = ButtonPanel
AnchorSideTop.Side = asrCenter
Left = 240
Height = 19
Top = 3
Width = 52
BorderSpacing.Right = 8
Caption = '1 hour'
TabOrder = 3
Visible = False
end
object rbOpenEndDuration2Hrs: TRadioButton[5]
AnchorSideLeft.Control = rbOpenEndDuration1Hr
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = ButtonPanel
AnchorSideTop.Side = asrCenter
Left = 300
Height = 19
Top = 3
Width = 57
BorderSpacing.Right = 8
Caption = '2 hours'
TabOrder = 4
Visible = False
end
object rbOpenEndDuration4Hrs: TRadioButton[6]
AnchorSideLeft.Control = rbOpenEndDuration2Hrs
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = ButtonPanel
AnchorSideTop.Side = asrCenter
Left = 365
Height = 19
Top = 3
Width = 57
Caption = '4 hours'
TabOrder = 5
Visible = False
end
end
end

View File

@ -1,3 +1,8 @@
{"version":1,"strings":[
{"hash":4294967295,"name":"tvpimportpreviewicaleventform.caption","sourcebytes":[],"value":""}
{"hash":4294967295,"name":"tvpimportpreviewicaleventform.caption","sourcebytes":[],"value":""},
{"hash":75933738,"name":"tvpimportpreviewicaleventform.lblopenendduration.caption","sourcebytes":[68,117,114,97,116,105,111,110,32,111,102,32,34,111,112,101,110,32,101,110,100,34,32,101,118,101,110,116,115,58],"value":"Duration of \"open end\" events:"},
{"hash":56783870,"name":"tvpimportpreviewicaleventform.rbopenendduration30mins.caption","sourcebytes":[51,48,32,109,105,110],"value":"30 min"},
{"hash":53933762,"name":"tvpimportpreviewicaleventform.rbopenendduration1hr.caption","sourcebytes":[49,32,104,111,117,114],"value":"1 hour"},
{"hash":74411171,"name":"tvpimportpreviewicaleventform.rbopenendduration2hrs.caption","sourcebytes":[50,32,104,111,117,114,115],"value":"2 hours"},
{"hash":107965603,"name":"tvpimportpreviewicaleventform.rbopenendduration4hrs.caption","sourcebytes":[52,32,104,111,117,114,115],"value":"4 hours"}
]}

View File

@ -4,27 +4,43 @@ unit VpImportPreview_ICalEvent;
interface
uses lazlogger,
Classes, SysUtils, Forms, Controls, Graphics, Dialogs,
VpData, VpBaseDS, VpImportPreview, VpICal, Grids;
uses
LCLVersion, Classes, SysUtils, Forms, Controls, Graphics, Dialogs,
VpData, VpBaseDS, VpImportPreview, VpICal, Grids, StdCtrls, Spin;
type
{ TVpImportPreviewICalEventForm }
TVpImportPreviewICalEventForm = class(TVpImportPreviewForm)
procedure GridGetEditText(Sender: TObject; {%H-}ACol, {%H-}ARow: Integer;
lblOpenEndDuration: TLabel;
rbOpenEndDuration30mins: TRadioButton;
rbOpenEndDuration1Hr: TRadioButton;
rbOpenEndDuration2Hrs: TRadioButton;
rbOpenEndDuration4Hrs: TRadioButton;
procedure btnExecuteClick(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure GridGetEditText(Sender: TObject; {%H-}ACol, {%H-}ARow: Integer;
var Value: string);
procedure GridSetEditText(Sender: TObject; {%H-}ACol, {%H-}ARow: Integer;
const Value: string);
private
FActivated: Boolean;
FCalendar: TVpICalendar;
FDefaultCategory: String;
FTimeFormat: String;
function GetEventText(AEvent: TVpICalEvent): String;
procedure SetCalendar(const AValue: TVpICalendar);
{$IF LCL_FullVersion >= 3000000}
private
FCanCloseTaskDialog: Boolean;
procedure OpenEndEventsDialog;
procedure OpenendEventsDialogButtonClicked(Sender: TObject;
AModalResult: TModalResult; var ACanClose: Boolean);
procedure OpenEndEventsDialogRadioButtonClicked(Sender: TObject);
{$ENDIF}
protected
function GetCellText(ACol, ARow: Integer): String; override;
procedure PrepareItems; override;
@ -55,6 +71,12 @@ begin
Grid.OnSetEditText := @GridSetEditText;
Caption := RSImportICalEvent;
lblOpenEndDuration.Caption := RSOpenEndEventsDurationLbl;
rbOpenEndDuration30mins.Caption := RS30Minutes;
rbOpenEndDuration1Hr.Caption := RS1Hour;
rbOpenEndDuration2Hrs.Caption := RS2Hours;
rbOpenEndDuration4Hrs.Caption := RS4Hours;
FTimeFormat := 'c'; // short date + long time format
end;
@ -196,6 +218,49 @@ begin
Value := Grid.Columns[2].PickList[event.PickedCategory];
end;
procedure TVpImportPreviewICalEventForm.btnExecuteClick(Sender: TObject);
begin
if FCalendar.ContainsOpenEndEvents then
begin
{$IF LCL_FullVersion >= 3000000}
OpenEndEventsDialog;
{$ELSE}
if not (rbOpenEndDuration30mins.Checked or rbOpenEndDuration1Hr.Checked or
rbOpenEndDuration2Hrs.Checked or rbOpenEndDuration4Hrs.Checked) then
begin
MessageDlg(RSDurationForOpenEndEvents, mtInformation, [mbOK], 0);
ModalResult := mrNone;
exit;
end;
if rbOpenEndDuration30mins.Checked then
FCalendar.FixOpenEndEvents(0.5/24)
else if rbOpenEndDuration1Hr.Checked then
FCalendar.FixOpenEndEvents(1.0/24)
else if rbOpenEndDuration2Hrs.Checked then
FCalendar.FixOpenEndEvents(2.0/24)
else if rbOpenEndDuration4Hrs.Checked then
FCalendar.FixOpenEndEvents(4.0/24);
{$IFEND}
end;
end;
procedure TVpImportPreviewICalEventForm.FormActivate(Sender: TObject);
var
x1: Integer = 0;
x2: Integer;
begin
if not FActivated then
begin
FActivated := true;
{$IF LCL_FullVersion < 3000000} // This part is only seen without Taskdialog
x1 := rbOpenEndDuration4Hrs.Left + rbOpenEndDuration4Hrs.Width;
{$IFEND}
x2 := ClientWidth - btnExecute.Left + btnExecute.BorderSpacing.Left;
Constraints.MinWidth := x1 + x2;
if Width < Constraints.MinWidth then Width := 0;
end;
end;
procedure TVpImportPreviewICalEventForm.GridSetEditText(Sender: TObject; ACol,
ARow: Integer; const Value: string);
var
@ -217,7 +282,55 @@ begin
if (item <> nil) then
Result := item.Checked;
end;
{$IF LCL_FullVersion >= 3000000}
procedure TVpImportPreviewICalEventForm.OpenendEventsDialog;
const
DURATIONS: array[0..3] of Double = (0.5/24, 1.0/24, 2.0/24, 4.0/24);
var
dlg: TTaskDialog;
begin
dlg := TTaskDialog.Create(nil);
try
dlg.Caption := RSImportICalendarEvents;
dlg.Title := RSOpenEndEvents;
dlg.Text := RSDurationForOpenEndEvents;
dlg.RadioButtons.Add.Caption := RSHalfAnHour;
dlg.RadioButtons.Add.Caption := RSOneHour;
dlg.RadioButtons.Add.Caption := RSTwoHours;
dlg.RadioButtons.Add.Caption := RSFourHours;
dlg.OnButtonClicked := @OpenEndEventsDialogButtonClicked;
dlg.OnRadioButtonClicked := @OpenEndEventsDialogRadioButtonClicked;
dlg.Flags := dlg.Flags + [tfNoDefaultRadioButton];
dlg.Execute;
if dlg.ModalResult = mrOK then
FCalendar.FixOpenEndEvents(DURATIONS[dlg.RadioButton.Index]);
finally
dlg.Free;
end;
end;
procedure TVpImportPreviewICalEventForm.OpenendEventsDialogButtonClicked(
Sender: TObject; AModalResult: TModalResult; var ACanClose: Boolean);
var
i: Integer;
begin
if AModalResult = mrCancel then
exit;
with TTaskDialog(Sender) do
ACanClose := FCanCloseTaskDialog;
if not ACanClose then
MessageDlg(RSNoEventDurationSelected, mtError, [mbOK], 0);
end;
procedure TVpImportPreviewICalEventForm.OpenEndEventsDialogRadioButtonClicked(Sender: TObject);
begin
FCanCloseTaskDialog := true;
end;
{$ENDIF}
procedure TVpImportPreviewICalEventForm.PrepareItems;
var
i: Integer;
@ -240,6 +353,7 @@ begin
FItems.Clear;
if (FCalendar <> nil) and (Datastore <> nil) then
begin
for i := 0 to FCalendar.Count-1 do
if (FCalendar.Entry[i] is TVpICalEvent) then
begin
@ -254,7 +368,16 @@ begin
else
event.PickedCategory := 0;
end;
{$IF LCL_FullVersion < 3000000}
lblOpenEndDuration.Visible := FCalendar.ContainsOpenEndEvents;
rbOpenEndDuration30mins.Visible := lblOpenEndDuration.Visible;
rbOpenEndDuration1Hr.Visible := lblOpenEndDuration.Visible;
rbOpenEndDuration2Hrs.Visible := lblOpenEndDuration.Visible;
rbOpenEndDuration4Hrs.Visible := lblOpenEndDuration.Visible;
{$IFEND}
end;
inherited;
end;