Componentes.Terceros.DevExp.../official/x.26/ExpressScheduler 2/Sources/cxSchedulerReminderWindow.pas
2007-09-09 11:27:27 +00:00

601 lines
18 KiB
ObjectPascal

{********************************************************************}
{ }
{ Developer Express Visual Component Library }
{ ExpressScheduler }
{ }
{ Copyright (c) 2003-2007 Developer Express Inc. }
{ ALL RIGHTS RESERVED }
{ }
{ The entire contents of this file is protected by U.S. and }
{ International Copyright Laws. Unauthorized reproduction, }
{ reverse-engineering, and distribution of all or any portion of }
{ the code contained in this file is strictly prohibited and may }
{ result in severe civil and criminal penalties and will be }
{ prosecuted to the maximum extent possible under the law. }
{ }
{ RESTRICTIONS }
{ }
{ THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES }
{ (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE }
{ SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS }
{ LICENSED TO DISTRIBUTE THE EXPRESSSCHEDULER AND ALL ACCOMPANYING }
{ VCL CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY. }
{ }
{ THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED }
{ FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE }
{ COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE }
{ AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT }
{ AND PERMISSION FROM DEVELOPER EXPRESS INC. }
{ }
{ CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON }
{ ADDITIONAL RESTRICTIONS. }
{ }
{********************************************************************}
unit cxSchedulerReminderWindow;
{$I cxVer.Inc}
interface
uses
{$IFDEF DELPHI6}
Types,
{$ENDIF}
Windows, Messages, SysUtils, Classes, Controls, Graphics, ExtCtrls, Forms,
StdCtrls, cxLookAndFeels, cxSchedulerStorage, cxListView, cxButtons, ComCtrls,
cxDropDownEdit, cxLookAndFeelPainters, cxEdit, cxTextEdit, cxMaskEdit,
cxControls, cxContainer, cxClasses, Menus, cxGraphics;
const
WM_REDRAWHEADER = WM_USER + 160;
type
{ TcxSchedulerReminderForm }
TcxSchedulerReminderForm = class(TcxSchedulerCustomReminderForm)
btnDismiss: TcxButton;
btnDismissAll: TcxButton;
btnOpenItem: TcxButton;
btnSnooze: TcxButton;
cbSnoozeTime: TcxComboBox;
lbEventCaption: TLabel;
lbEventStartTime: TLabel;
lvItems: TcxListView;
pbImage: TPaintBox;
tmUpdate: TTimer;
procedure ButtonClick(Sender: TObject);
procedure DrawIcon(Sender: TObject);
procedure lvItemsSelectItem(Sender: TObject; Item: TListItem;
Selected: Boolean);
procedure lvItemsDblClick(Sender: TObject);
procedure tmUpdateTimer(Sender: TObject);
procedure lvItemsKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
private
FAdvanceCount: Integer;
FSelections: TcxObjectList;
function GetFocusedReminder: TcxSchedulerReminder;
function GetVisibleReminder(Index: Integer): TcxSchedulerReminder;
function GetVisibleReminderCount: Integer;
procedure SynchronizeSelection;
procedure WMRedrawHeader(var Msg: TMsg); message WM_REDRAWHEADER;
protected
procedure AddReminder(AReminder: TcxSchedulerReminder; const ADueInText: string);
function AddSnoozeAdvanceTime(const AText: string; AMinutes: Integer): Integer;
function AddSnoozeTime(const AText: string; AMinutes: Integer): Integer;
procedure CreateSnoozeAdvanceTimeItems; virtual;
procedure DismissEvents(All: Boolean);
procedure DoShow; override;
function GetImageIndexForReminder(AReminder: TcxSchedulerReminder): Integer; virtual;
function GetMaxAdvanceMinutes: Integer;
function GetSnoozeTime: TDateTime; virtual;
procedure SnoozeEvents;
procedure OpenFocusedEvent;
procedure RefreshSelectedInfo; virtual;
procedure ResetAdvanceCount;
procedure RestoreSelection; override;
procedure SaveSelection; override;
procedure SetupCaptions; virtual;
procedure UpdateDueTimeTexts;
procedure UpdateReminderList; override;
procedure UpdateSelectionCaptions; override;
procedure UpdateSnoozeComboBox; virtual;
property AdvanceCount: Integer read FAdvanceCount;
property VisibleReminderCount: Integer read GetVisibleReminderCount;
property VisibleReminders[Index: Integer]: TcxSchedulerReminder read GetVisibleReminder;
public
constructor Create(AReminders: TcxSchedulerReminders); override;
destructor Destroy; override;
end;
implementation
{$R *.DFM}
uses
cxSchedulerUtils, cxSchedulerStrs, cxSchedulerDialogs, CommCtrl, Math, cxDateUtils;
{ TcxSchedulerReminderForm }
constructor TcxSchedulerReminderForm.Create(
AReminders: TcxSchedulerReminders);
begin
inherited Create(AReminders);
Icon.Handle := LoadIcon(hInstance, 'REMINDERBELL');
lvItems.SmallImages := MenuImages;
end;
destructor TcxSchedulerReminderForm.Destroy;
begin
FSelections.Free;
inherited Destroy;
end;
procedure TcxSchedulerReminderForm.AddReminder(AReminder: TcxSchedulerReminder;
const ADueInText: string);
begin
with lvItems.Items.Add do
begin
Data := AReminder;
Caption := AReminder.Event.Caption;
ImageIndex := GetImageIndexForReminder(AReminder);
SubItems.Add(ADueInText);
end;
end;
function TcxSchedulerReminderForm.AddSnoozeAdvanceTime(const AText: string;
AMinutes: Integer): Integer;
begin
Result := AddSnoozeTime(AText, AMinutes);
Inc(FAdvanceCount);
end;
function TcxSchedulerReminderForm.AddSnoozeTime(const AText: string;
AMinutes: Integer): Integer;
begin
Result := cbSnoozeTime.Properties.Items.AddObject(AText, TObject(AMinutes));
end;
procedure TcxSchedulerReminderForm.CreateSnoozeAdvanceTimeItems;
var
AMaxAdvanceTime: Integer;
begin
if lvItems.SelCount = 1 then
begin
AMaxAdvanceTime := GetMaxAdvanceMinutes;
if AMaxAdvanceTime > 15 then
AddSnoozeAdvanceTime(cxGetResourceString(@scxAdvance15m), 15);
if AMaxAdvanceTime > 10 then
AddSnoozeAdvanceTime(cxGetResourceString(@scxAdvance10m), 10);
if AMaxAdvanceTime > 5 then
cbSnoozeTime.ItemIndex := AddSnoozeAdvanceTime(cxGetResourceString(@scxAdvance5m), 5);
if AMaxAdvanceTime > 0 then
AddSnoozeAdvanceTime(cxGetResourceString(@scxAdvance0h), 0);
end;
end;
procedure TcxSchedulerReminderForm.DismissEvents(All: Boolean);
var
I: Integer;
begin
with Reminders do
begin
if All then
DismissAll
else
begin
Storage.BeginUpdate;
try
for I := 0 to lvItems.Items.Count - 1 do
if lvItems.Items[I].Selected then
VisibleReminders[I].Dismiss;
finally
Storage.EndUpdate;
end;
end;
end;
end;
procedure TcxSchedulerReminderForm.DoShow;
begin
SetupCaptions;
lbEventCaption.Font.Style := lbEventCaption.Font.Style + [fsBold];
inherited DoShow;
with lvItems do if Items.Count > 0 then Selected := Items[Items.Count - 1];
btnOpenItem.Visible := OpenEventSupported;
RefreshSelectedInfo;
//force repaint header
PostMessage(Handle, WM_REDRAWHEADER, 0, 0);
tmUpdate.Enabled := True;
end;
function TcxSchedulerReminderForm.GetImageIndexForReminder(
AReminder: TcxSchedulerReminder): Integer;
begin
if AReminder.Event.EventType <> etNone then
Result := 3
else
Result := 2;
end;
function TcxSchedulerReminderForm.GetMaxAdvanceMinutes: Integer;
var
I: Integer;
ANow, AStart: TDateTime;
begin
ANow := Now;
Result := 0;
for I := 0 to lvItems.Items.Count - 1 do
begin
if lvItems.Items[I].Selected then
begin
AStart := TcxSchedulerReminder(lvItems.Items[I].Data).Event.Start;
Result := Max(Trunc((AStart - ANow) * MinsPerDay), Result);
end;
end;
end;
function TcxSchedulerReminderForm.GetSnoozeTime: TDateTime;
begin
with cbSnoozeTime do
begin
if ItemIndex >= 0 then
Result := Integer(Properties.Items.Objects[ItemIndex]) * MinuteToTime
else
Result := 5 * MinuteToTime;
end;
end;
procedure TcxSchedulerReminderForm.SnoozeEvents;
var
I: Integer;
AIsAdvanceTime: Boolean;
AEvent: TcxSchedulerControlEvent;
ASnoozeTime, AReminderDate: TDateTime;
begin
AIsAdvanceTime := (lvItems.SelCount = 1) and (cbSnoozeTime.ItemIndex < AdvanceCount);
ASnoozeTime := GetSnoozeTime;
if AIsAdvanceTime then
begin
AEvent := TcxSchedulerReminder(lvItems.Selected.Data).Event;
AReminderDate := AEvent.Start - ASnoozeTime;
if AEvent.EventType in [etCustom, etNone] then
AEvent.Source.ReminderDate := AReminderDate
else
begin
AEvent.Pattern.BeginEditing;
AEvent.Pattern.ReminderDate := AReminderDate;
AEvent.Pattern.RecurrenceInfo.DismissDate := DateOf(AReminderDate) - MinuteToTime;
AEvent.Pattern.EndEditing;
AEvent.Pattern.Post;
end;
AEvent.ReminderDate := AReminderDate;
end
else
with Reminders do
begin
Storage.BeginUpdate;
try
for I := 0 to lvItems.Items.Count - 1 do
if lvItems.Items[I].Selected then VisibleReminders[I].Snooze(ASnoozeTime);
finally
Storage.EndUpdate;
end;
end;
end;
procedure TcxSchedulerReminderForm.OpenFocusedEvent;
var
AReminder: TcxSchedulerReminder;
begin
AReminder := GetFocusedReminder;
if AReminder <> nil then
OpenEvent(AReminder.Event);
end;
procedure TcxSchedulerReminderForm.RefreshSelectedInfo;
var
AEnabled: Boolean;
begin
if IsLocked then Exit;
AEnabled := lvItems.SelCount > 0;
btnDismiss.Enabled := AEnabled;
btnDismissAll.Enabled := lvItems.Items.Count > 0;;
btnOpenItem.Enabled := lvItems.SelCount = 1;
btnSnooze.Enabled := AEnabled;
cbSnoozeTime.Enabled := AEnabled;
pbImage.Visible := AEnabled;
pbImage.Invalidate;
UpdateSelectionCaptions;
end;
procedure TcxSchedulerReminderForm.ResetAdvanceCount;
begin
FAdvanceCount := 0;
end;
procedure TcxSchedulerReminderForm.RestoreSelection;
begin
with lvItems.Items do
begin
BeginUpdate;
try
UpdateReminderList;
SynchronizeSelection;
finally
EndUpdate;
end;
end;
FreeAndNil(FSelections);
RefreshSelectedInfo;
end;
procedure TcxSchedulerReminderForm.SaveSelection;
var
I: Integer;
begin
FreeAndNil(FSelections);
with lvItems do
begin
if SelCount = 0 then Exit;
FSelections := TcxObjectList.Create;
for I := 0 to Items.Count - 1 do
if lvItems.Items[I].Selected then
FSelections.Add(TcxSchedulerReminderEventID.Create(Reminders[I].Event));
end;
end;
procedure TcxSchedulerReminderForm.SetupCaptions;
begin
lvItems.Columns[0].Caption := cxGetResourceString(@scxrSubject);
lvItems.Columns[1].Caption := cxGetResourceString(@scxrDueIn);
btnDismissAll.Caption := cxGetResourceString(@scxrDismissAllButton);
btnOpenItem.Caption := cxGetResourceString(@scxrOpenItemButton);
btnDismiss.Caption := cxGetResourceString(@scxrDismissButton);
btnSnooze.Caption := cxGetResourceString(@scxrSnoozeButton);
end;
procedure TcxSchedulerReminderForm.UpdateDueTimeTexts;
var
I: Integer;
ANow: TDateTime;
begin
ANow := Now;
lvItems.Items.BeginUpdate;
try
for I := 0 to VisibleReminderCount - 1 do
lvItems.Items[I].SubItems[0] := Reminders.GetEventDueTimeText(VisibleReminders[I], ANow);
finally
lvItems.Items.EndUpdate;
end;
end;
procedure TcxSchedulerReminderForm.UpdateReminderList;
var
I: Integer;
AReminder: TcxSchedulerReminder;
ANow: TDateTime;
begin
ANow := Now;
with lvItems.Items do
begin
BeginUpdate;
try
Clear;
for I := 0 to Reminders.Count - 1 do
begin
AReminder := Reminders[I];
AddReminder(AReminder, Reminders.GetEventDueTimeText(AReminder, ANow));
end;
finally
EndUpdate;
end;
end;
end;
procedure TcxSchedulerReminderForm.ButtonClick(Sender: TObject);
begin
if Sender is TcxButton then
case TcxButton(Sender).Tag of
0: DismissEvents(True);
1: OpenFocusedEvent;
2: DismissEvents(False);
3: SnoozeEvents;
end;
end;
procedure TcxSchedulerReminderForm.DrawIcon(Sender: TObject);
begin
if lvItems.SelCount = 1 then
MenuImages.Draw(pbImage.Canvas,
(pbImage.Width - MenuImages.Width) div 2,
(pbImage.Height - MenuImages.Height) div 2,
GetImageIndexForReminder(lvItems.Selected.Data));
end;
procedure TcxSchedulerReminderForm.lvItemsSelectItem(Sender: TObject;
Item: TListItem; Selected: Boolean);
begin
if csDestroying in ComponentState then Exit;
{$IFDEF DELPHI7}
if not Item.Deleting then
{$ENDIF}
RefreshSelectedInfo;
end;
function TcxSchedulerReminderForm.GetFocusedReminder: TcxSchedulerReminder;
begin
if lvItems.SelCount = 1 then
Result := TcxSchedulerReminder(lvItems.Selected.Data)
else
Result := nil;
end;
function TcxSchedulerReminderForm.GetVisibleReminder(
Index: Integer): TcxSchedulerReminder;
begin
with lvItems do
if (Index >= 0) and (Index < Items.Count) then
Result := TcxSchedulerReminder(Items[Index].Data)
else
Result := nil;
end;
function TcxSchedulerReminderForm.GetVisibleReminderCount: Integer;
begin
Result := lvItems.Items.Count;
end;
procedure TcxSchedulerReminderForm.SynchronizeSelection;
var
I, J: Integer;
AData: TcxSchedulerReminderEventID;
begin
if (FSelections = nil) or (VisibleReminderCount = 0) then Exit;
for I := 0 to FSelections.Count - 1 do
begin
AData := TcxSchedulerReminderEventID(FSelections[I]);
for J := 0 to VisibleReminderCount - 1 do
if VisibleReminders[J].EventID.Equals(AData) then
lvItems.Items[J].Selected := True;
end;
with lvItems do
begin
if SelCount = 0 then
Items[Items.Count - 1].Selected := True;
Items[Items.Count - 1].Focused := True;
end;
end;
procedure TcxSchedulerReminderForm.WMRedrawHeader(var Msg: TMsg);
var
AHeader: HWND;
begin
AHeader := ListView_GetHeader(lvItems.InnerListView.Handle);
Windows.InvalidateRect(AHeader, nil, True);
end;
procedure TcxSchedulerReminderForm.UpdateSelectionCaptions;
function GetValidCaption(const ACaption: string): string;
const
Ellipsis = '...';
var
ATotalWidth: Integer;
begin
Result := ACaption;
ATotalWidth := lbEventCaption.Width;
with TcxScreenCanvas.Create do
try
Font.Assign(lbEventCaption.Font);
if TextWidth(Result) > ATotalWidth then
begin
Dec(ATotalWidth, TextWidth(Ellipsis));
while (Length(Result) > 0) and (TextWidth(Result) > ATotalWidth) do
Delete(Result, Length(Result), 1);
Result := Result + Ellipsis;
end;
finally
Free;
end;
end;
var
AEvent: TcxSchedulerEvent;
begin
if lvItems.SelCount = 1 then
begin
AEvent := TcxSchedulerReminder(lvItems.Selected.Data).Event;
lbEventCaption.Caption := GetValidCaption(AEvent.Caption);
lbEventStartTime.Caption :=
Format(cxGetResourceString(@scxrStartTime), [FormatDateTime('dddddd t', AEvent.Start)]);
end
else
begin
lbEventCaption.Caption := '';
lbEventStartTime.Caption :=
Format(cxGetResourceString(@scxrSelected), [lvItems.SelCount]);
end;
UpdateSnoozeComboBox;
inherited UpdateSelectionCaptions;
end;
procedure TcxSchedulerReminderForm.UpdateSnoozeComboBox;
const
SnoozeTimes: array[1..15] of record P: Pointer; M: Integer end = (
(P: @scxTime5m; M: 5),
(P: @scxTime10m; M: 10),
(P: @scxTime15m; M: 15),
(P: @scxTime30m; M: 30),
(P: @scxTime1h; M: MinsPerHour),
(P: @scxTime2h; M: 2 * MinsPerHour),
(P: @scxTime4h; M: 4 * MinsPerHour),
(P: @scxTime8h; M: 8 * MinsPerHour),
(P: @scxTime12h; M: 12 * MinsPerHour),
(P: @scxTime1d; M: MinsPerDay),
(P: @scxTime2d; M: 2 * MinsPerDay),
(P: @scxTime3d; M: 3 * MinsPerDay),
(P: @scxTime4d; M: 4 * MinsPerDay),
(P: @scxTime1w; M: MinsPerWeek),
(P: @scxTime2w; M: 2 * MinsPerWeek));
var
I: Integer;
begin
ResetAdvanceCount;
cbSnoozeTime.Properties.Items.BeginUpdate;
try
cbSnoozeTime.Properties.Items.Clear;
cbSnoozeTime.ItemIndex := -1;
if lvItems.SelCount = 1 then
CreateSnoozeAdvanceTimeItems;
for I := Low(SnoozeTimes) to High(SnoozeTimes) do
AddSnoozeTime(cxGetResourceString(SnoozeTimes[I].P), SnoozeTimes[I].M);
if cbSnoozeTime.ItemIndex = -1 then cbSnoozeTime.ItemIndex := 1;
finally
cbSnoozeTime.Properties.Items.EndUpdate;
end;
end;
procedure TcxSchedulerReminderForm.lvItemsDblClick(Sender: TObject);
begin
OpenFocusedEvent;
end;
procedure TcxSchedulerReminderForm.tmUpdateTimer(Sender: TObject);
begin
if not IsLocked then
UpdateDueTimeTexts;
end;
procedure TcxSchedulerReminderForm.lvItemsKeyDown(Sender: TObject;
var Key: Word; Shift: TShiftState);
begin
if Key = VK_DELETE then
begin
with lvItems do
begin
if SelCount > 0 then
DismissEvents(False)
else
if Items.Count > 0 then
begin
Items[Items.Count - 1].Selected := True;
Items[Items.Count - 1].Focused := True;
end;
end;
end;
end;
procedure TcxSchedulerReminderForm.FormKeyDown(Sender: TObject;
var Key: Word; Shift: TShiftState);
begin
if (Key = VK_ESCAPE) and not HasOpenedPopupWindow(ActiveControl) then
Close;
end;
end.