{********************************************************************} { } { Developer Express Visual Component Library } { ExpressScheduler } { } { Copyright (c) 2003-2009 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 cxSchedulerYearView; {$I cxVer.inc} interface uses {$IFDEF DELPHI6} Types, DateUtils, {$ENDIF} Windows, Forms, Classes, SysUtils, Math, StdCtrls, Graphics, Controls, Menus, cxClasses, cxControls, cxGraphics, cxStyles, cxGeometry, cxLookAndFeelPainters, cxSchedulerCustomControls, cxSchedulerCustomResourceView, cxSchedulerUtils, cxSchedulerStorage, cxSchedulerStrs, cxDateUtils; const cxMaxSelectedDaysCount = 20; MaxYearViewWeekDays = 37; cxYearViewScrollCurrentYearPos = 10; cxYearViewScrollMaxPos = 21; cxYearViewScrollMinPos = 0; cxcsMonthHeader = 0; cxcsUnusedContent = 1; cxcsMaxYearViewStyle = cxcsUnusedContent; // hittests htcYear = $11; htcMonth = $12; type TcxSchedulerMonthHeaderCellViewInfo = class; TcxSchedulerMonthHeaderPopupMenu = class; TcxSchedulerYearView = class; TcxSchedulerYearViewViewInfo = class; TcxSchedulerYearViewNavigation = class; TcxSchedulerYearViewStyles = class; TcxSchedulerYearViewContentCellViewInfo = class; { TcxSchedulerYearViewController } TcxSchedulerYearViewController = class(TcxSchedulerCustomResourceViewController) protected function CreateDragEventHelper: TcxDragEventHelper; override; function CreateNavigation: TcxSchedulerViewNavigation; override; function CreateResizeEventHelper: TcxEventSizingHelper; override; procedure KeyDown(var Key: Word; Shift: TShiftState); override; end; { TcxSchedulerYearViewHitTest } TcxSchedulerYearViewHitTest = class(TcxSchedulerCustomResourceViewHitTest) public property HitAtYear: Boolean index htcYear read GetBitState; property HitAtMonth: Boolean index htcMonth read GetBitState; end; { IcxSchedulerYearViewAdapter } IcxSchedulerYearViewAdapter = interface ['{7B39CB3C-256E-4269-9B24-5A59BC3D868D}'] function GetMonthCount: Integer; function GetFirstMonth: Integer; function GetShowMonthHeaders: Boolean; function GetShowWeekDayHeaders: Boolean; function GetStartDayIndex: Integer; function GetDayCountPerPage: Integer; end; { TcxSchedulerYearViewPainter } TcxSchedulerYearViewPainter = class(TcxSchedulerCustomViewPainter) private function GetViewInfo: TcxSchedulerYearViewViewInfo; public procedure Paint; override; property ViewInfo: TcxSchedulerYearViewViewInfo read GetViewInfo; end; { TcxSchedulerYearViewEventCellViewInfo } TcxSchedulerYearViewEventCellViewInfo = class(TcxSchedulerEventCellViewInfo) protected procedure CalculateBorders; override; procedure CalculateCaptions; override; procedure CalculateEventTimeVisibility; override; function CanAutoHideStandardImages: Boolean; override; function GetForceShowClockInHeaderEvent: Boolean; override; procedure InitHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override; end; { TcxSchedulerYearViewViewInfo } TcxSchedulerYearViewViewInfo = class(TcxSchedulerCustomResourceViewViewInfo) private FAdapterFirstMonth: Integer; FAdapterMonthCount: Integer; function GetAdapterFirstMonth: Integer; function GetAdapterMonthCount: Integer; function GetDaysCell(AIndex: Integer): TcxSchedulerYearViewContentCellViewInfo; function GetDaysCellCount: Integer; function GetMonthBounds(AIndex: Integer): TRect; function GetYearView: TcxSchedulerYearView; protected FContentFont: TFont; FContentSmallFont: TFont; FDayCells: TList; FDayTextHeight: Integer; FMonthHeaderCells: TcxSchedulerViewInfoCellList; FMonthHeaderWidth: Integer; FShowMonthHeaders: Boolean; FStartDayIndex: Integer; FMaxYearViewWeekDays: Integer; FMaxEventsCount: Integer; FYear: Word; FYearViewExtraAdapter: IcxSchedulerYearViewAdapter; FRangeStart: Integer; FRangeFinish: Integer; procedure AddEventButtons(APlace: TcxSchedulerEventPlace); procedure AddEventForCalculation(ABuilder: TcxSchedulerEventLayoutBuilder; AEvent: TcxSchedulerControlEvent); procedure AddEventToYearView(APlace: TcxSchedulerEventPlace); function AddMonthHeader(AYear, AMonth: Integer; const ARect: TRect; AFirstMonth: Integer = 0; AMonthCount: Integer = 12): TcxSchedulerMonthHeaderCellViewInfo; function AddWeekDayHeader(AWeekDay: Integer; ARect: TRect): TcxSchedulerWeekDayHeaderCellViewInfo; function AddYearViewContentCell(ARect: TRect; ADate: TDate; ASelected: Boolean; AParams: TcxViewParams; AColIndex: Integer): TcxSchedulerYearViewContentCellViewInfo; procedure CalculateContentCellMonthParams(AMonth: Integer; out AMonthBounds: TRect; out AStartOfMonth: TDate; out AStartMonthColumn, ADaysPerMonth: Integer); procedure CalculateContentCells; virtual; procedure CalculateContentNavigationButtons; override; procedure CalculateDaysHeader; virtual; procedure CalculateEventsViewInfo; virtual; procedure CalculateMetrics; override; procedure CalculateMonthHeaderWidth; procedure CalculateMonthsHeader; virtual; procedure CheckLayout(ADate: TDateTime); procedure Clear; override; function ContentCellClass: TcxSchedulerContentCellViewInfoClass; override; function CreateEventCellViewInfo(AViewData: TcxSchedulerEventViewData): TcxSchedulerEventCellViewInfo; override; function GetPartOfTheYear(ADate: TDateTime): Word; procedure DoCalculate; override; procedure DoContentNavigationButtonClick(Sender: TcxSchedulerContentNavigationButtonViewInfo); override; function GetMonthColumnDate(AStartOfMonth: TDateTime; ADaysPerMonth, AStartMonthColumn, AColumn: Integer): TDateTime; function GetSmallFont(const AParams: TcxViewParams): TFont; function IsEventVisible(AEvent: TcxSchedulerControlEvent): Boolean; procedure PrepareSmallContentFont; // page splitting function GetFirstMonth: Integer; virtual; function GetMonthCountPerPage: Integer; virtual; property AdapterFirstMonth: Integer read GetAdapterFirstMonth write FAdapterFirstMonth; property AdapterMonthCount: Integer read GetAdapterMonthCount write FAdapterMonthCount; property FirstMonth: Integer read GetFirstMonth; property MonthCountPerPage: Integer read GetMonthCountPerPage; public constructor Create(AOwner: TcxSchedulerSubControl); override; destructor Destroy; override; procedure CalculateHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override; procedure UpdateSelection; property DaysCellCount: Integer read GetDaysCellCount; property DaysCells[AIndex: Integer]: TcxSchedulerYearViewContentCellViewInfo read GetDaysCell; property MonthBounds[AIndex: Integer]: TRect read GetMonthBounds; property MonthHeaderCells: TcxSchedulerViewInfoCellList read FMonthHeaderCells; property View: TcxSchedulerYearView read GetYearView; property Year: Word read FYear; end; { TcxSchedulerYearViewNavigation } TcxSchedulerYearViewNavigation = class(TcxSchedulerCustomResourceViewNavigation) private FCanChangeSelection: Boolean; FSaveSelFinish: TDateTime; FSaveSelStart: TDateTime; function GetYearView: TcxSchedulerYearView; function GetYearViewInfo: TcxSchedulerYearViewViewInfo; protected function ContentCell(AIndex: Integer): TcxSchedulerYearViewContentCellViewInfo; procedure CorrectCurrentAnchor; procedure DoKeyDown(var AKey: Word; AShift: TShiftState); override; procedure GotoCornerCell(AGotoEnd: Boolean); virtual; procedure GotoNextCellHorz(AGotoNext: Boolean); virtual; procedure GotoNextCellVert(AGoForward: Boolean); virtual; procedure GotoNextPage(AGotoForward: Boolean); virtual; public procedure KeyDown(var AKey: Word; AShift: TShiftState); override; procedure ValidateSelection(var ASelStart, ASelFinish: TDateTime; var AResource: TcxSchedulerStorageResourceItem); override; property View: TcxSchedulerYearView read GetYearView; property ViewInfo: TcxSchedulerYearViewViewInfo read GetYearViewInfo; end; { TcxSchedulerMonthHeaderCellViewInfo } TcxSchedulerMonthHeaderCellViewInfo = class(TcxSchedulerDayHeaderCellViewInfo) private FFirstMonth: Integer; FMonth: Integer; FMonthCount: Integer; FYear: Integer; procedure SetFirstMonth(AValue: Integer); procedure SetMonth(AValue: Integer); procedure SetMonthCount(AValue: Integer); procedure SetYear(AValue: Integer); protected FColStart: Integer; procedure CalculateDisplayText; virtual; procedure InitHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override; public property FirstMonth: Integer read FFirstMonth write SetFirstMonth; property Month: Integer read FMonth write SetMonth; property MonthCount: Integer read FMonthCount write SetMonthCount; property Year: Integer read FYear write SetYear; end; { TcxSchedulerYearViewContentCellViewInfo } TcxSchedulerYearViewContentCellViewInfo = class(TcxSchedulerMonthDayContentCellViewInfo) protected FColIndex: Integer; procedure InitHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override; end; { TcxYearViewDragEventHelper } TcxYearViewDragEventHelper = class(TcxDragEventHelper) protected procedure UpdateViewClonesTime; override; end; { TcxYearViewEventSizing } TcxYearViewEventSizing = class(TcxEventSizingHelper) protected procedure UpdateEventBounds; override; end; { TcxSchedulerYearViewStyles } TcxSchedulerYearViewGetUnusedContentStyleEvent = procedure(Sender: TcxSchedulerYearView; AYear, AMonth, ADayOfWeek: Integer; var AStyle: TcxStyle) of object; TcxSchedulerYearViewGetMonthHeaderStyleEvent = procedure(Sender: TcxSchedulerYearView; AYear, AMonth: Integer; var AStyle: TcxStyle) of object; TcxSchedulerYearViewStyles = class(TcxStyles) private FScheduler: TcxCustomScheduler; FYearView: TcxSchedulerYearView; FOnGetMonthHeaderStyle: TcxSchedulerYearViewGetMonthHeaderStyleEvent; FOnGetUnusedContentStyle: TcxSchedulerYearViewGetUnusedContentStyleEvent; function GetPainter: TcxCustomLookAndFeelPainterClass; protected procedure Changed(AIndex: Integer); override; procedure GetDefaultViewParams(Index: Integer; AData: TObject; out AParams: TcxViewParams); override; property Painter: TcxCustomLookAndFeelPainterClass read GetPainter; public constructor Create(AOwner: TPersistent); override; procedure Assign(Source: TPersistent); override; function GetMonthHeaderParams(AYear, AMonth: Integer): TcxViewParams; function GetUnusedContentParams( AYear, AMonth, ADayOfWeek: Integer): TcxViewParams; property Scheduler: TcxCustomScheduler read FScheduler; property YearView: TcxSchedulerYearView read FYearView; published property MonthHeader: TcxStyle index cxcsMonthHeader read GetValue write SetValue; property UnusedContent: TcxStyle index cxcsUnusedContent read GetValue write SetValue; property OnGetMonthHeaderStyle: TcxSchedulerYearViewGetMonthHeaderStyleEvent read FOnGetMonthHeaderStyle write FOnGetMonthHeaderStyle; property OnGetUnusedContentStyle: TcxSchedulerYearViewGetUnusedContentStyleEvent read FOnGetUnusedContentStyle write FOnGetUnusedContentStyle; end; { TcxSchedulerYearView } TcxSchedulerYearView = class(TcxSchedulerCustomResourceView) private FAllDayEventsOnly: Boolean; FMaxSelectedDaysCount: Integer; FMonthHeaderPopupMenu: TcxSchedulerMonthHeaderPopupMenu; FStyles: TcxSchedulerYearViewStyles; FScale: Integer; function GetHitTest: TcxSchedulerYearViewHitTest; function GetNavigation: TcxSchedulerYearViewNavigation; function GetViewInfo: TcxSchedulerYearViewViewInfo; function GetYear: Word; procedure SetAllDayEventsOnly(AValue: Boolean); procedure SetMaxSelectedDaysCount(AValue: Integer); procedure SetMonthHeaderPopupMenu(AValue: TcxSchedulerMonthHeaderPopupMenu); procedure SetScale(AValue: Integer); procedure SetStyles(AValue: TcxSchedulerYearViewStyles); protected procedure CreateSubClasses; override; function CreateViewAdapter: TcxCustomResourceViewAdapter; override; procedure DestroySubClasses; override; function CanDeactivateOnDateNavigatorSelectionChange: Boolean; override; function CanSelectPeriod: Boolean; override; procedure ChangeLayout(ACurrentAnchor: TDateTime); function CreateController: TcxSchedulerSubControlController; override; function CreateHitTest: TcxSchedulerSubControlHitTest; override; function CreateMonthHeaderPopupMenu: TcxSchedulerMonthHeaderPopupMenu; virtual; function CreatePainter: TcxSchedulerSubControlPainter; override; function CreateStyles: TcxSchedulerYearViewStyles; virtual; function CreateViewInfo: TcxSchedulerSubControlViewInfo; override; function DoShowPopupMenu(X, Y: Integer): Boolean; override; function GetCompressWeekEnd: Boolean; override; function GetGroupingKind: TcxSchedulerGroupingKind; override; function GetFirstVisibleDate: TDateTime; override; function GetLastVisibleDate: TDateTime; override; function GetScrollPos: Integer; virtual; function GetVisibleDaysRange: Integer; override; procedure InitScrollBarsParameters; override; procedure MakeEventVisible(AEvent: TcxSchedulerControlEvent; const ADate: TDateTime; AResource: TcxSchedulerStorageResourceItem); override; procedure Notification(AComponent: TComponent; Operation: TOperation); override; procedure Scroll(AScrollBarKind: TScrollBarKind; AScrollCode: TScrollCode; var AScrollPos: Integer); override; procedure SelectedDaysChanged; override; procedure SetGroupingKind(AValue: TcxSchedulerGroupingKind); override; property Navigation: TcxSchedulerYearViewNavigation read GetNavigation; property ViewInfo: TcxSchedulerYearViewViewInfo read GetViewInfo; public constructor Create(AOwner: TcxCustomScheduler); override; procedure Assign(Source: TPersistent); override; property HitTest: TcxSchedulerYearViewHitTest read GetHitTest; property Year: Word read GetYear; published property Active; property AllDayEventsOnly: Boolean read FAllDayEventsOnly write SetAllDayEventsOnly default False; property MaxSelectedDaysCount: Integer read FMaxSelectedDaysCount write SetMaxSelectedDaysCount default 0; property MonthHeaderPopupMenu: TcxSchedulerMonthHeaderPopupMenu read FMonthHeaderPopupMenu write SetMonthHeaderPopupMenu; property Scale: Integer read FScale write SetScale default 12; property Styles: TcxSchedulerYearViewStyles read FStyles write SetStyles; end; { TcxSchedulerYearViewAdapter } TcxSchedulerYearViewAdapter = class(TcxCustomResourceViewAdapter, IcxSchedulerYearViewAdapter) private FPredefinedCurrentAnchor: TDateTime; protected { IUnknown } function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; { IcxSchedulerYearViewAdapter } function GetDayCountPerPage: Integer; virtual; function GetFirstMonth: Integer; virtual; function GetMonthCount: Integer; virtual; function GetShowMonthHeaders: Boolean; virtual; function GetShowWeekDayHeaders: Boolean; virtual; function GetStartDayIndex: Integer; virtual; property PredefinedCurrentAnchor: TDateTime read FPredefinedCurrentAnchor write FPredefinedCurrentAnchor; end; { TcxSchedulerMonthHeaderPopupMenu } TcxSchedulerMonthHeaderPopupMenuItem = (mhpmiNewEvent, mhpmiNewAllDayEvent, mhpmiNewReccuringEvent, mhpmiFullYear, mhpmiHalfYear, mhpmiQuarter); TcxSchedulerMonthHeaderPopupMenuItems = set of TcxSchedulerMonthHeaderPopupMenuItem; TcxSchedulerMonthHeaderPopupMenuPopupEvent = procedure ( Sender: TcxSchedulerMonthHeaderPopupMenu; ABuiltInMenu: TPopupMenu; var AHandled: Boolean) of object; TcxSchedulerMonthHeaderPopupMenuClickEvent = procedure ( Sender: TcxSchedulerMonthHeaderPopupMenu; AItem: TcxSchedulerMonthHeaderPopupMenuItem; var AHandled: Boolean) of object; TcxSchedulerMonthHeaderPopupMenu = class(TcxSchedulerCustomContentPopupMenu) private FItems: TcxSchedulerMonthHeaderPopupMenuItems; FOnPopup: TcxSchedulerMonthHeaderPopupMenuPopupEvent; FOnClick: TcxSchedulerMonthHeaderPopupMenuClickEvent; function GetYearView: TcxSchedulerYearView; protected procedure CreateItems; override; procedure DoExecute(ACommand: Integer); override; function DoOnClick(ACommand: Integer): Boolean; override; function DoOnPopup: Boolean; override; function IsValidCommand(ACommand: Integer): Boolean; override; property YearView: TcxSchedulerYearView read GetYearView; public constructor Create(AScheduler: TcxCustomScheduler); override; procedure Assign(Source: TPersistent); override; procedure Execute(AItem: TcxSchedulerMonthHeaderPopupMenuItem); function GetMenuItem(AItem: TcxSchedulerMonthHeaderPopupMenuItem): TMenuItem; published property Items: TcxSchedulerMonthHeaderPopupMenuItems read FItems write FItems default [mhpmiNewEvent, mhpmiNewAllDayEvent, mhpmiNewReccuringEvent, mhpmiFullYear, mhpmiHalfYear, mhpmiQuarter]; property PopupMenu; property UseBuiltInPopupMenu; property OnClick: TcxSchedulerMonthHeaderPopupMenuClickEvent read FOnClick write FOnClick; property OnPopup: TcxSchedulerMonthHeaderPopupMenuPopupEvent read FOnPopup write FOnPopup; end; implementation const DayInc: array[Boolean] of Integer = (-1, 1); YearScales: array[0..2] of Integer = (12, 6, 3); type TcxSchedulerCustomViewInfoItemAccess = class(TcxSchedulerCustomViewInfoItem); TcxSchedulerCustomViewViewInfoAccess = class(TcxSchedulerCustomViewViewInfo); { TcxSchedulerYearViewController } function TcxSchedulerYearViewController.CreateDragEventHelper: TcxDragEventHelper; begin Result := TcxYearViewDragEventHelper.Create(Scheduler); end; function TcxSchedulerYearViewController.CreateNavigation: TcxSchedulerViewNavigation; begin Result := TcxSchedulerYearViewNavigation.Create(View); end; function TcxSchedulerYearViewController.CreateResizeEventHelper: TcxEventSizingHelper; begin Result := TcxYearViewEventSizing.Create(Scheduler); end; procedure TcxSchedulerYearViewController.KeyDown(var Key: Word; Shift: TShiftState); begin if View.Active and not EditController.IsEditing and TcxSchedulerYearViewNavigation(Navigation).IsKeyNavigation(Key, Shift) then TcxSchedulerYearViewNavigation(Navigation).DoKeyDown(Key, Shift) else inherited KeyDown(Key, Shift); end; { TcxSchedulerYearViewPainter } procedure TcxSchedulerYearViewPainter.Paint; begin inherited Paint; ViewInfo.MonthHeaderCells.Draw(Canvas, DrawHeaderCell); ViewInfo.DayHeaderCells.Draw(Canvas, DrawHeaderCell); ViewInfo.ContentCells.Draw(Canvas, DrawContentCell); ViewInfo.EventCells.Draw(Canvas, DrawEventCell); ViewInfo.Buttons.Draw(Canvas, DrawButtonCell); ViewInfo.NavigationButtons.Draw(Canvas, DrawButtonCell); end; function TcxSchedulerYearViewPainter.GetViewInfo: TcxSchedulerYearViewViewInfo; begin Result := TcxSchedulerYearViewViewInfo(inherited ViewInfo); end; { TcxSchedulerYearViewEventCellViewInfo } procedure TcxSchedulerYearViewEventCellViewInfo.CalculateBorders; begin if ViewData.ContentFinish < EventFinish then Exclude(FBorders, bRight); if ViewData.ContentStart > EventStart then Exclude(FBorders, bLeft); end; procedure TcxSchedulerYearViewEventCellViewInfo.CalculateCaptions; begin end; procedure TcxSchedulerYearViewEventCellViewInfo.CalculateEventTimeVisibility; var B: Boolean; begin B := IsHeaderEvent and not Event.AllDayEvent; ViewData.ShowStartTime := B and (TimeOf(Event.Start) <> 0) and (EventStart > ViewData.ContentStart); ViewData.ShowFinishTime := B and (TimeOf(Event.Finish) <> 0) and (EventFinish < ViewData.ContentFinish); end; function TcxSchedulerYearViewEventCellViewInfo.CanAutoHideStandardImages: Boolean; begin Result := True; end; function TcxSchedulerYearViewEventCellViewInfo.GetForceShowClockInHeaderEvent: Boolean; begin Result := False; end; procedure TcxSchedulerYearViewEventCellViewInfo.InitHitTest( AHitTest: TcxSchedulerCustomResourceViewHitTest); begin inherited InitHitTest(AHitTest); InitHitTestForHorzEvent(AHitTest); end; { TcxSchedulerYearViewViewInfo } constructor TcxSchedulerYearViewViewInfo.Create( AOwner: TcxSchedulerSubControl); begin inherited Create(AOwner); FContentSmallFont := TFont.Create; FDayCells := TList.Create; FDayCells.Capacity := 444; FMonthHeaderCells := TcxSchedulerViewInfoCellList.Create; FCells.Add(FMonthHeaderCells); end; destructor TcxSchedulerYearViewViewInfo.Destroy; begin FContentSmallFont.Free; FDayCells.Free; inherited Destroy; end; procedure TcxSchedulerYearViewViewInfo.CalculateHitTest( AHitTest: TcxSchedulerCustomResourceViewHitTest); begin if not MonthHeaderCells.CalculateHitTest(AHitTest) then inherited CalculateHitTest(AHitTest); end; procedure TcxSchedulerYearViewViewInfo.UpdateSelection; var I: Integer; ACell: TcxSchedulerMonthDayContentCellViewInfo; begin with View.Navigation do begin Self.FSelStart := DateTimeHelper.RoundTime(Min(SelStart, SelFinish)); Self.FSelFinish := DateTimeHelper.RoundTime(Max(SelStart, SelFinish)); end; for I := 0 to ContentCells.Count - 1 do begin ACell := TcxSchedulerMonthDayContentCellViewInfo(ContentCells[I]); if (ACell.TimeStart <> NullDate) and ACell.UpdateSelection(not HideSelection and (ACell.TimeStart >= SelStart) and (ACell.TimeStart <= SelFinish)) then View.InvalidateRect(ACell.Bounds); end; end; procedure TcxSchedulerYearViewViewInfo.AddEventButtons( APlace: TcxSchedulerEventPlace); var I: Integer; begin for I := APlace.ColStart to APlace.ColFinish do if DaysCells[I].LineCount = 0 then begin AddButton(DaysCells[I].Bounds, DaysCells[I].TimeStart, True, APlace.Event); DaysCells[I].LineCount := 1; end; end; procedure TcxSchedulerYearViewViewInfo.AddEventForCalculation( ABuilder: TcxSchedulerEventLayoutBuilder; AEvent: TcxSchedulerControlEvent); var AStart, AFinish: TDateTime; AOfs, I, AStartIndex, AFinishIndex: Integer; AStartDay: TcxSchedulerYearViewContentCellViewInfo; begin if (FYearViewExtraAdapter = nil) then begin AStart := Max(FRangeStart, AEvent.Start); AFinish := Min(FRangeFinish, AEvent.Finish); AOfs := DayOfTheYear(EncodeDate(Year, FirstMonth, 1)); I := DayOfTheYear(AStart) - AOfs; AFinishIndex := Max(DayOfTheYear(AFinish) - 1 - AOfs, I); while (AFinishIndex < (DaysCellCount - 1)) and AEvent.IsDayEvent(DaysCells[AFinishIndex + 1].TimeStart) do Inc(AFinishIndex); end else begin I := 0; while (I < DaysCellCount) and not AEvent.IsDayEvent(DaysCells[I].TimeStart) do Inc(I); if I = DaysCellCount then Exit; AFinishIndex := I; while (AFinishIndex < DaysCellCount) and AEvent.IsDayEvent(DaysCells[AFinishIndex].TimeStart) do Inc(AFinishIndex); Dec(AFinishIndex); end; while I <= AFinishIndex do begin AStartIndex := I; AStartDay := DaysCells[I]; while (I <= AFinishIndex) and (AStartDay.Bounds.Top = DaysCells[I].Bounds.Top) do Inc(I); ABuilder.AddEventPlace(AEvent, AStartIndex, I - 1, 1, TObject(MonthOf(AStartDay.DateTime))); end; end; procedure TcxSchedulerYearViewViewInfo.AddEventToYearView( APlace: TcxSchedulerEventPlace); var ABounds: TRect; AViewData: TcxSchedulerEventViewData; AStart, AFinish: TDateTime; begin ABounds := MonthBounds[Integer(APlace.Resource)]; with DaysCells[APlace.ColStart] do begin AStart := TimeStart; ABounds.Left := Bounds.Left + cxTextOffset; end; with DaysCells[APlace.ColFinish] do begin AFinish := TimeFinish; ABounds.Right := Bounds.Right - cxTextOffset - 1; end; ABounds.Top := ABounds.Top + APlace.LineStart * (ContentLineHeight + cxTextOffset); ABounds.Bottom := ABounds.Top + ContentLineHeight; OffsetRect(ABounds, 0, FDayTextHeight); AViewData := CreateEventViewData(TcxSchedulerControlEvent(APlace.Event), ABounds, AStart, AFinish, nil); AViewData.VisibleRect := MonthBounds[Integer(APlace.Resource)]; Dec(AViewData.VisibleRect.Bottom, cxTextOffset); if AViewData.Bounds.Bottom > AViewData.VisibleRect.Bottom then begin //todo: lcm if not AViewData.Event.IsClone then AddEventButtons(APlace); AViewData.Free end else AddEventCell(AViewData); end; function TcxSchedulerYearViewViewInfo.AddMonthHeader(AYear, AMonth: Integer; const ARect: TRect; AFirstMonth, AMonthCount: Integer): TcxSchedulerMonthHeaderCellViewInfo; var AParams: TcxViewParams; begin AParams := View.Styles.GetMonthHeaderParams(AYear, AMonth); CreateCellInstance(TcxSchedulerMonthHeaderCellViewInfo, ARect, AParams, Result); Result.Month := AMonth; Result.Year := AYear; Result.RotateHeader := True; Result.FirstMonth := AFirstMonth; Result.MonthCount := AMonthCount; MonthHeaderCells.Add(Result); end; function TcxSchedulerYearViewViewInfo.AddWeekDayHeader(AWeekDay: Integer; ARect: TRect): TcxSchedulerWeekDayHeaderCellViewInfo; begin Inc(AWeekDay, Integer(View.StartOfWeek)); if AWeekDay >= 7 then Dec(AWeekDay, 7); CreateCellInstance(TcxSchedulerWeekDayHeaderCellViewInfo, ARect, StylesAdapter.GetDayHeaderParams(AWeekDay), Result); Result.DateTime := AWeekDay; DayHeaderCells.Add(Result); end; function TcxSchedulerYearViewViewInfo.AddYearViewContentCell( ARect: TRect; ADate: TDate; ASelected: Boolean; AParams: TcxViewParams; AColIndex: Integer): TcxSchedulerYearViewContentCellViewInfo; var AColor: TColor; begin CreateCellInstance(TcxSchedulerYearViewContentCellViewInfo, ARect, AParams, Result); Result.FSmallFont := True; Result.SmallTextFont := GetSmallFont(AParams); if ADate <> NullDate then begin Result.SetTime(ADate, ADate + 1); Result.SetContentState(True, ASelected, FDayTextHeight - cxTextOffset, FSelectionParams); AColor := StylesAdapter.GetContentParams(ADate, True, nil).Color; Result.Color := PainterHelper.GetContentColor(AColor, View.IsWorkTime(nil, ADate + View.WorkStart)); FDayCells.Add(Result); end; Result.LineCount := 0; Result.FColIndex := AColIndex; ContentCells.Add(Result); end; procedure TcxSchedulerYearViewViewInfo.CalculateContentCellMonthParams( AMonth: Integer; out AMonthBounds: TRect; out AStartOfMonth: TDate; out AStartMonthColumn, ADaysPerMonth: Integer); begin AMonthBounds := FMonthHeaderCells[AMonth + 1].Bounds; AStartOfMonth := EncodeDate(Year, AMonth + FirstMonth, 1); AStartMonthColumn := DayOfWeek(AStartOfMonth) - 1; Dec(AStartMonthColumn, Integer(View.GetStartOfWeek)); if AStartMonthColumn < 0 then Inc(AStartMonthColumn, 7); ADaysPerMonth := DaysPerMonth(Year, AMonth + FirstMonth); TcxSchedulerMonthHeaderCellViewInfo(FMonthHeaderCells[AMonth + 1]).FColStart := AStartMonthColumn; end; procedure TcxSchedulerYearViewViewInfo.CalculateContentCells; var I, J: Integer; R, DayBounds, MonthBounds: TRect; AStartOfMonth, ADate: TDate; ACell: TcxSchedulerYearViewContentCellViewInfo; AStartMonthColumn, ADaysPerMonth: Integer; ASelected: Boolean; AParams: TcxViewParams; begin FMaxEventsCount := 0; for I := 0 to MonthCountPerPage - 1 do begin CalculateContentCellMonthParams(I, MonthBounds, AStartOfMonth, AStartMonthColumn, ADaysPerMonth); for J := 0 to FMaxYearViewWeekDays - 1 do begin DayBounds := DayHeaderCells[J].Bounds; R := Rect(DayBounds.Left, MonthBounds.Top, DayBounds.Right, MonthBounds.Bottom); ADate := GetMonthColumnDate(AStartOfMonth, ADaysPerMonth, AStartMonthColumn, J + FStartDayIndex); ASelected := not HideSelection and (ADate >= SelStart) and (ADate <= SelFinish); if ADate = NullDate then AParams := View.Styles.GetUnusedContentParams(FYear, (I + FirstMonth), (Byte(View.OptionsView.ActualStartOfWeek) + J + FStartDayIndex) mod 7) else AParams := GetContentParams(ADate, nil); ACell := AddYearViewContentCell(R, ADate, ASelected, AParams, J); FMaxEventsCount := Max(FMaxEventsCount, (R.Bottom - R.Top) div FContentLineHeight + 1); if I < MonthCountPerPage then ACell.Borders := [bBottom, bRight] else ACell.Borders := [bRight]; end; end; end; procedure TcxSchedulerYearViewViewInfo.CalculateContentNavigationButtons; var ABounds: TRect; begin ABounds := Bounds; ABounds.Left := ABounds.Left + FMonthHeaderWidth; if IsValidNavigationButtonsPlace(ABounds) then AddContentNavigationButton(ABounds, -1, cprSingle); end; procedure TcxSchedulerYearViewViewInfo.CalculateDaysHeader; var R: TRect; I, W: Integer; begin W := Bounds.Right - Bounds.Left - FMonthHeaderWidth + 1; R := cxRectSetHeight(Bounds, FDayHeaderHeight); for I := 0 to FMaxYearViewWeekDays - 1 do begin R.Left := FMonthHeaderWidth + MulDiv(W, I, FMaxYearViewWeekDays); R.Right := FMonthHeaderWidth + MulDiv(W, I + 1, FMaxYearViewWeekDays); AddWeekDayHeader(((I + FStartDayIndex) mod 7), R); end; ProcessCheckBorders(DayHeaderCells, True, [nLeft]); ProcessDateToDisplayText(True); end; procedure TcxSchedulerYearViewViewInfo.CalculateEventsViewInfo; var I: Integer; AEvent: TcxSchedulerControlEvent; ABuilder: TcxSchedulerEventLayoutBuilder; begin ABuilder := TcxSchedulerEventLayoutBuilder.Create; try for I := 0 to Events.AbsoluteCount - 1 do begin AEvent := Events.AbsoluteItems[I]; if IsEventVisible(AEvent) then AddEventForCalculation(ABuilder, AEvent); end; ABuilder.Calculate; for I := 0 to DaysCellCount - 1 do DaysCells[I].LineCount := 0; for I := ABuilder.EventPlaceCount - 1 downto 0 do AddEventToYearView(ABuilder.EventPlaces[I]); finally ABuilder.Free; end; end; procedure TcxSchedulerYearViewViewInfo.CalculateMetrics; begin inherited CalculateMetrics; if FYearViewExtraAdapter = nil then FYear := View.Year else FYear := YearOf(SelectedDays[0]); FDayTextHeight := Round(FContentFontHeight * 2 / 3); end; procedure TcxSchedulerYearViewViewInfo.CalculateMonthHeaderWidth; var I: Integer; AFont: TFont; AStyle: TcxStyle; begin if not FShowMonthHeaders then begin FMonthHeaderWidth := 0; Exit; end; AStyle := View.Styles.MonthHeader; if (AStyle <> nil) and (cxStyles.svFont in AStyle.AssignedValues) then AFont := AStyle.Font else AFont := DefaultFont; FMonthHeaderWidth := cxTextWidth(AFont, 'WWWW') + 4 * cxTextOffset; for I := 1 to 12 do FMonthHeaderWidth := Max(FMonthHeaderWidth, cxTextWidth(AFont, LongMonthNames[I]) + 4 * cxTextOffset); end; procedure TcxSchedulerYearViewViewInfo.CalculateMonthsHeader; var R: TRect; I, H: Integer; begin CalculateMonthHeaderWidth; H := Bounds.Bottom - Bounds.Top - FDayHeaderHeight; R := cxRectSetHeight(cxRectSetWidth(Bounds, FMonthHeaderWidth), FDayHeaderHeight); AddMonthHeader(FYear, 0, R, AdapterFirstMonth, AdapterMonthCount).RotateHeader := False; for I := 0 to MonthCountPerPage - 1 do begin R.Top := MulDiv(H, I, MonthCountPerPage) + FDayHeaderHeight; R.Bottom := MulDiv(H, I + 1, MonthCountPerPage) + FDayHeaderHeight; AddMonthHeader(FYear, I + FirstMonth, R); end; ProcessCheckBorders(MonthHeaderCells, True, [], []); end; procedure TcxSchedulerYearViewViewInfo.CheckLayout(ADate: TDateTime); begin if (ADate < Trunc(TcxSchedulerCustomViewInfoItemAccess(FDayCells[0]).FDateTime)) or (ADate > Trunc(TcxSchedulerCustomViewInfoItemAccess(FDayCells[FDayCells.Count - 1]).FDateTime)) then begin View.Changed; View.ChangeLayout(ADate); end; end; procedure TcxSchedulerYearViewViewInfo.Clear; begin FDayCells.Clear; FMonthHeaderCells.Clear; inherited Clear; end; function TcxSchedulerYearViewViewInfo.ContentCellClass: TcxSchedulerContentCellViewInfoClass; begin Result := TcxSchedulerYearViewContentCellViewInfo; end; function TcxSchedulerYearViewViewInfo.CreateEventCellViewInfo( AViewData: TcxSchedulerEventViewData): TcxSchedulerEventCellViewInfo; begin Result := TcxSchedulerYearViewEventCellViewInfo.Create(AViewData); end; function TcxSchedulerYearViewViewInfo.GetPartOfTheYear(ADate: TDateTime): Word; var AYear, AMonth, ADay: Word; begin DecodeDate(ADate, AYear, AMonth, ADay); Result := 0; while AMonth >= (Result + 1) * AdapterMonthCount + 1 do Inc(Result); end; procedure TcxSchedulerYearViewViewInfo.DoCalculate; var ADate: TDateTime; begin ADate := SelectedDays[0]; SelectedDays.Clear; SelectedDays.Add(ADate); PrepareSmallContentFont; FStartDayIndex := 0; FShowMonthHeaders := True; FMaxYearViewWeekDays := MaxYearViewWeekDays; Supports(TObject(Adapter), IcxSchedulerYearViewAdapter, FYearViewExtraAdapter); try inherited DoCalculate; if FYearViewExtraAdapter <> nil then begin if not FYearViewExtraAdapter.GetShowWeekDayHeaders then FDayHeaderHeight := 0; FShowMonthHeaders := FYearViewExtraAdapter.GetShowMonthHeaders; FStartDayIndex := FYearViewExtraAdapter.GetStartDayIndex; FMaxYearViewWeekDays := FYearViewExtraAdapter.GetDayCountPerPage; FAdapterFirstMonth := FYearViewExtraAdapter.GetFirstMonth; FAdapterMonthCount := FYearViewExtraAdapter.GetMonthCount; end; FRangeStart := Trunc(EncodeDate(Year, FirstMonth, 1)); FRangeFinish := Trunc(EndOfTheMonth(EncodeDate(Year, FirstMonth + GetMonthCountPerPage - 1, 1))); CalculateMonthsHeader; CalculateDaysHeader; CalculateContentCells; CalculateEventsViewInfo; CalculateContentNavigationButtons; finally FYearViewExtraAdapter := nil; end; end; procedure TcxSchedulerYearViewViewInfo.DoContentNavigationButtonClick( Sender: TcxSchedulerContentNavigationButtonViewInfo); var ARequiredDay: TDateTime; begin ARequiredDay := SelectedDays[0] + Sender.Interval; View.Navigation.FCurrentAnchor := ARequiredDay; CheckLayout(ARequiredDay); end; function TcxSchedulerYearViewViewInfo.GetMonthColumnDate( AStartOfMonth: TDateTime; ADaysPerMonth, AStartMonthColumn, AColumn: Integer): TDateTime; begin Result := NullDate; Dec(AColumn, AStartMonthColumn); if (AColumn >= 0) and (AColumn < ADaysPerMonth) then Result := AStartOfMonth + AColumn; end; function TcxSchedulerYearViewViewInfo.GetSmallFont(const AParams: TcxViewParams): TFont; begin if AParams.Font = FContentFont then Result := FContentSmallFont else Result := nil; end; function TcxSchedulerYearViewViewInfo.GetFirstMonth: Integer; begin if FYearViewExtraAdapter = nil then Result := 1 else Result := FYearViewExtraAdapter.GetFirstMonth; end; function TcxSchedulerYearViewViewInfo.GetMonthCountPerPage: Integer; begin if FYearViewExtraAdapter = nil then Result := 12 else Result := FYearViewExtraAdapter.GetMonthCount; end; function TcxSchedulerYearViewViewInfo.IsEventVisible( AEvent: TcxSchedulerControlEvent): Boolean; begin Result := not View.AllDayEventsOnly or (AEvent.AllDayEvent or (AEvent.Duration > 1)); if Result then Result := (DateOf(AEvent.Start) <= FRangeFinish) and (AEvent.Finish > FRangeStart); end; procedure TcxSchedulerYearViewViewInfo.PrepareSmallContentFont; begin FContentFont := StylesAdapter.GetContentParams(NullDate, Nil).Font; FContentSmallFont.Assign(FContentFont); FContentSmallFont.Size := Round(FContentFont.Size * 2 / 3); end; function TcxSchedulerYearViewViewInfo.GetAdapterFirstMonth: Integer; begin Result := Max(FAdapterFirstMonth, 1); end; function TcxSchedulerYearViewViewInfo.GetAdapterMonthCount: Integer; begin Result := FAdapterMonthCount; if (Result < 1) or (Result > 12) then Result := 12; end; function TcxSchedulerYearViewViewInfo.GetDaysCell( AIndex: Integer): TcxSchedulerYearViewContentCellViewInfo; begin Result := TcxSchedulerYearViewContentCellViewInfo(FDayCells.List^[AIndex]) end; function TcxSchedulerYearViewViewInfo.GetDaysCellCount: Integer; begin Result := FDayCells.Count; end; function TcxSchedulerYearViewViewInfo.GetMonthBounds(AIndex: Integer): TRect; begin Result := MonthHeaderCells[AIndex - FirstMonth + 1].Bounds; Result.Left := Result.Right; Result.Right := Bounds.Right; end; function TcxSchedulerYearViewViewInfo.GetYearView: TcxSchedulerYearView; begin Result := TcxSchedulerYearView(inherited View); end; { TcxSchedulerYearViewNavigation } procedure TcxSchedulerYearViewNavigation.KeyDown(var AKey: Word; AShift: TShiftState); begin CorrectCurrentAnchor; FCanChangeSelection := True; case AKey of VK_Left, VK_Right: GotoNextCellHorz(AKey = VK_RIGHT); VK_UP, VK_DOWN: GotoNextCellVert(AKey = VK_DOWN); VK_HOME, VK_END: GotoCornerCell(AKey = VK_END); VK_NEXT, VK_PRIOR: GotoNextPage(AKey = VK_NEXT); end; if ViewInfo.FYearViewExtraAdapter <> nil then TcxSchedulerYearViewAdapter(ViewInfo.FYearViewExtraAdapter).PredefinedCurrentAnchor := FCurrentAnchor; ViewInfo.CheckLayout(FCurrentAnchor); SetSelAnchor(FCurrentAnchor, AShift); end; procedure TcxSchedulerYearViewNavigation.ValidateSelection( var ASelStart, ASelFinish: TDateTime; var AResource: TcxSchedulerStorageResourceItem); begin AResource := nil; FCanChangeSelection := FCanChangeSelection or View.HitTest.HitAtTime; if not FCanChangeSelection then begin ASelStart := FSaveSelStart; ASelFinish := FSaveSelFinish; end; ASelStart := Min(Max(ASelStart, View.FirstVisibleDate), View.LastVisibleDate); ASelFinish := Min(Max(ASelFinish, View.FirstVisibleDate), View.LastVisibleDate); if (View.MaxSelectedDaysCount > 0) then ASelFinish := Max(Min(ASelFinish, ASelStart + View.MaxSelectedDaysCount - 1), ASelStart - View.MaxSelectedDaysCount + 1); FSaveSelFinish := ASelFinish; FSaveSelStart := ASelStart; FCanChangeSelection := False; end; function TcxSchedulerYearViewNavigation.ContentCell( AIndex: Integer): TcxSchedulerYearViewContentCellViewInfo; begin Result := TcxSchedulerYearViewContentCellViewInfo(ViewInfo.ContentCells.List^[AIndex]); end; procedure TcxSchedulerYearViewNavigation.CorrectCurrentAnchor; begin FCurrentAnchor := Min(Max(FCurrentAnchor, View.FirstVisibleDate), View.LastVisibleDate); end; procedure TcxSchedulerYearViewNavigation.DoKeyDown( var AKey: Word; AShift: TShiftState); var APrevCurrentAnchor: TDateTime; begin if Scheduler.SelectedEventCount > 0 then Scheduler.UnselectEvents; FCurrentAnchor := SelAnchor; FCurrentResource := SelResource; APrevCurrentAnchor := FCurrentAnchor; FShift := AShift; KeyDown(AKey, AShift); if YearOf(APrevCurrentAnchor) = YearOf(FCurrentAnchor) then ViewInfo.UpdateSelection; end; procedure TcxSchedulerYearViewNavigation.GotoCornerCell(AGotoEnd: Boolean); var AMonth, AYear, ADay: Word; begin if ssCtrl in FShift then begin if AGotoEnd then FCurrentAnchor := View.LastVisibleDate else FCurrentAnchor := View.FirstVisibleDate; end else begin DecodeDate(FCurrentAnchor, AYear, AMonth, ADay); if AGotoEnd then FCurrentAnchor := EncodeDate(AYear, AMonth, DaysPerMonth(AYear, AMonth)) else FCurrentAnchor := EncodeDate(AYear, AMonth, 1); end; end; procedure TcxSchedulerYearViewNavigation.GotoNextCellHorz(AGotoNext: Boolean); begin FCurrentAnchor := FCurrentAnchor + DayInc[AGotoNext]; end; procedure TcxSchedulerYearViewNavigation.GotoNextCellVert(AGoForward: Boolean); function DayOfTheRange(ACurrentAnchor: TDateTime): Word; var AYear, AMonth, ADay: Word; begin DecodeDate(ACurrentAnchor, AYear, AMonth, ADay); Result := Trunc(ACurrentAnchor) - Trunc(EncodeDate(AYear, ViewInfo.AdapterFirstMonth, 1)) + 1; end; var AYear, AMonth, ADay, APart: Word; AIndex, AColIndex: Integer; begin APart := ViewInfo.GetPartOfTheYear(FCurrentAnchor); DecodeDate(FCurrentAnchor, AYear, AMonth, ADay); IncAMonth(AYear, AMonth, ADay, DayInc[AGoForward]); if (AYear = ViewInfo.Year) and (APart = ViewInfo.GetPartOfTheYear(EncodeDate(AYear, AMonth, ADay))) then begin AIndex := ViewInfo.FContentCells.IndexOf(ViewInfo.DaysCells[DayOfTheRange(FCurrentAnchor) - 1]); AColIndex := ContentCell(AIndex).FColIndex; AIndex := AIndex + DayInc[AGoForward]; while ContentCell(AIndex).FColIndex <> AColIndex do Inc(AIndex, DayInc[AGoForward]); while ContentCell(AIndex).TimeStart = NullDate do Inc(AIndex, DayInc[AColIndex < 20]); FCurrentAnchor := ContentCell(AIndex).TimeStart; end else FCurrentAnchor := EncodeDate(AYear, AMonth, ADay); end; procedure TcxSchedulerYearViewNavigation.GotoNextPage(AGotoForward: Boolean); var AYear, AMonth, ADay: Word; ANewMonth: Integer; begin DecodeDate(FCurrentAnchor, AYear, AMonth, ADay); ANewMonth := AMonth; Inc(ANewMonth, DayInc[AGotoForward] * ViewInfo.AdapterMonthCount); if ANewMonth < 1 then begin Dec(AYear); Inc(ANewMonth, 12); end; if ANewMonth > 12 then begin Inc(AYear); Dec(ANewMonth, 12); end; AMonth := ANewMonth; ADay := Min(ADay, DayOfTheMonth(EndOfAMonth(AYear, AMonth))); FCurrentAnchor := EncodeDate(AYear, AMonth, ADay); end; function TcxSchedulerYearViewNavigation.GetYearView: TcxSchedulerYearView; begin Result := TcxSchedulerYearView(inherited View); end; function TcxSchedulerYearViewNavigation.GetYearViewInfo: TcxSchedulerYearViewViewInfo; begin Result := TcxSchedulerYearViewViewInfo(inherited ViewInfo); end; { TcxSchedulerMonthHeaderCellViewInfo } procedure TcxSchedulerMonthHeaderCellViewInfo.CalculateDisplayText; function GetPartOfYear: string; begin if MonthCount = 0 then Exit; Result := ''; if MonthCount = 6 then Result := Result + scxHalfYearShort else if MonthCount = 3 then Result := Result + scxQuarterShort; if MonthCount <> 12 then Result := Result + IntToStr(FirstMonth div MonthCount + 1) + ' '; end; begin DateTime := NullDate; if FMonth = 0 then DisplayText := GetPartOfYear + IntToStr(FYear) else DisplayText := LongMonthNames[FMonth]; end; procedure TcxSchedulerMonthHeaderCellViewInfo.InitHitTest( AHitTest: TcxSchedulerCustomResourceViewHitTest); begin if FMonth = 0 then TcxSchedulerYearViewHitTest(AHitTest).SetHitTime(htcYear, EncodeDate(Year, 1, 1)) else TcxSchedulerYearViewHitTest(AHitTest).SetHitTime(htcMonth, EncodeDate(Year, FMonth, 1)); end; procedure TcxSchedulerMonthHeaderCellViewInfo.SetFirstMonth(AValue: Integer); begin FFirstMonth := AValue; CalculateDisplayText; end; procedure TcxSchedulerMonthHeaderCellViewInfo.SetMonth(AValue: Integer); begin FMonth := AValue; CalculateDisplayText; end; procedure TcxSchedulerMonthHeaderCellViewInfo.SetMonthCount(AValue: Integer); begin FMonthCount := AValue; CalculateDisplayText; end; procedure TcxSchedulerMonthHeaderCellViewInfo.SetYear(AValue: Integer); begin FYear := AValue; CalculateDisplayText; end; { TcxSchedulerYearViewContentCellViewInfo } procedure TcxSchedulerYearViewContentCellViewInfo.InitHitTest( AHitTest: TcxSchedulerCustomResourceViewHitTest); begin if Self.TimeStart <> NullDate then inherited InitHitTest(AHitTest); end; { TcxYearViewDragEventHelper } procedure TcxYearViewDragEventHelper.UpdateViewClonesTime; var I: Integer; ANewStart, ADelta: TDateTime; AShift: TDateTime; View: TcxSchedulerYearView; begin View := TcxSchedulerYearViewViewInfo(ViewInfo).GetYearView; AShift := HitTest.Time - Controller.StartDragHitTime; for I := 0 to Clones.Count - 1 do begin ANewStart := AShift + Clones[I].Source.Start; ADelta := Max(0, View.GetFirstVisibleDate - DateOf(ANewStart)); if ADelta = 0 then begin ADelta := Min(0, View.GetLastVisibleDate - DateOf(ANewStart) - DateOf(Clones[I].Duration) + Ord(Clones[I].AllDayEvent)); end; Clones[I].MoveTo(ANewStart + ADelta); end; end; { TcxYearViewEventSizing } procedure TcxYearViewEventSizing.UpdateEventBounds; begin if Event.AllDayEvent then inherited UpdateEventBounds else begin if Controller.DragKind = edkResizeStart then begin Event.AllDayEvent := TimeOf(Event.Finish) = 0; Event.Start := HitTest.Time; end else begin Event.AllDayEvent := TimeOf(Event.Start) = 0; if Event.AllDayEvent then Event.Finish := HitTest.Time else Event.Finish := HitTest.Time + 1; end; CheckEventState(Event); RefreshCurrentView; end; end; { TcxSchedulerYearViewStyles } constructor TcxSchedulerYearViewStyles.Create(AOwner: TPersistent); begin inherited Create(AOwner); FYearView := TcxSchedulerYearView(GetOwner); FScheduler := FYearView.Scheduler; BitmapInViewParams := True; end; procedure TcxSchedulerYearViewStyles.Assign(Source: TPersistent); var I: Integer; begin if Source is TcxSchedulerYearViewStyles then for I := 0 to cxcsMaxYearViewStyle do SetValue(I, TcxSchedulerYearViewStyles(Source).GetValue(I)); inherited Assign(Source); end; function TcxSchedulerYearViewStyles.GetMonthHeaderParams( AYear, AMonth: Integer): TcxViewParams; var AStyle: TcxStyle; begin AStyle := nil; if Assigned(FOnGetMonthHeaderStyle) then FOnGetMonthHeaderStyle(YearView, AYear, AMonth, AStyle); GetViewParams(cxcsMonthHeader, nil, AStyle, Result); end; function TcxSchedulerYearViewStyles.GetUnusedContentParams( AYear, AMonth, ADayOfWeek: Integer): TcxViewParams; var AStyle: TcxStyle; begin AStyle := nil; if Assigned(FOnGetUnusedContentStyle) then FOnGetUnusedContentStyle(YearView, AYear, AMonth, ADayOfWeek, AStyle); GetViewParams(cxcsUnusedContent, Pointer(ADayOfWeek), AStyle, Result); {with YearView do begin if (AStyle = nil) or not (svColor in AStyle.AssignedValues) then begin Result.Color := PainterHelper.GetContentColor(Result.Color, TDay(ADayOfWeek) in OptionsView.WorkDays); end; end;} //Do the same as GetDefaultViewParams end; procedure TcxSchedulerYearViewStyles.Changed(AIndex: Integer); begin inherited Changed(AIndex); FYearView.Refresh; end; procedure TcxSchedulerYearViewStyles.GetDefaultViewParams(Index: Integer; AData: TObject; out AParams: TcxViewParams); begin AParams.Bitmap := nil; AParams.Font := Scheduler.Font; AParams.TextColor := clBlack; AParams.Color := Scheduler.Color; case Index of cxcsUnusedContent: begin with FYearView do begin AParams.Color := PainterHelper.GetContentColor( clBtnFace, TDay(Integer(AData)) in OptionsView.WorkDays); end; end; cxcsMonthHeader: begin AParams.Color := Painter.DefaultHeaderColor; AParams.TextColor := Painter.DefaultHeaderTextColor; end; end; end; function TcxSchedulerYearViewStyles.GetPainter: TcxCustomLookAndFeelPainterClass; begin Result := FYearView.LookAndFeelPainter; end; { TcxSchedulerYearView } constructor TcxSchedulerYearView.Create(AOwner: TcxCustomScheduler); begin inherited Create(AOwner); FScale := 12; end; procedure TcxSchedulerYearView.Assign(Source: TPersistent); begin if Source is TcxSchedulerYearView then with TcxSchedulerYearView(Source) do begin Self.FMaxSelectedDaysCount := FMaxSelectedDaysCount; Self.FAllDayEventsOnly := FAllDayEventsOnly; Self.FMonthHeaderPopupMenu := FMonthHeaderPopupMenu; Self.FStyles.Assign(FStyles); Self.FScale := FScale; end; inherited Assign(Source); end; procedure TcxSchedulerYearView.CreateSubClasses; begin FStyles := CreateStyles; inherited CreateSubClasses; FMonthHeaderPopupMenu := CreateMonthHeaderPopupMenu; end; function TcxSchedulerYearView.CreateViewAdapter: TcxCustomResourceViewAdapter; begin Result := TcxSchedulerYearViewAdapter.Create(Self); end; procedure TcxSchedulerYearView.DestroySubClasses; begin FMonthHeaderPopupMenu.Free; inherited DestroySubClasses; FStyles.Free; end; function TcxSchedulerYearView.CanDeactivateOnDateNavigatorSelectionChange: Boolean; begin Result := False; end; function TcxSchedulerYearView.CanSelectPeriod: Boolean; begin Result := False; end; procedure TcxSchedulerYearView.ChangeLayout(ACurrentAnchor: TDateTime); begin Scheduler.DateNavigator.BeginUpdate; try SelectedDays.Clear; SelectedDays.Add(EncodeDate(YearOf(ACurrentAnchor), ViewInfo.GetPartOfTheYear(ACurrentAnchor) * ViewInfo.AdapterMonthCount + 1, 1)); UpdateDateNavigatorSelection; Changed; Scheduler.FullRefresh; finally Scheduler.DateNavigator.EndUpdate; end; end; function TcxSchedulerYearView.CreateController: TcxSchedulerSubControlController; begin Result := TcxSchedulerYearViewController.Create(Self); end; function TcxSchedulerYearView.CreateHitTest: TcxSchedulerSubControlHitTest; begin Result := TcxSchedulerYearViewHitTest.Create(Self); end; function TcxSchedulerYearView.CreateMonthHeaderPopupMenu: TcxSchedulerMonthHeaderPopupMenu; begin Result := TcxSchedulerMonthHeaderPopupMenu.Create(Scheduler); end; function TcxSchedulerYearView.CreatePainter: TcxSchedulerSubControlPainter; begin Result := TcxSchedulerYearViewPainter.Create(Self); end; function TcxSchedulerYearView.CreateStyles: TcxSchedulerYearViewStyles; begin Result := TcxSchedulerYearViewStyles.Create(Self); end; function TcxSchedulerYearView.CreateViewInfo: TcxSchedulerSubControlViewInfo; begin Result := TcxSchedulerYearViewViewInfo.Create(Self); end; function TcxSchedulerYearView.DoShowPopupMenu(X, Y: Integer): Boolean; begin if HitTest.HitAtMonth then Result := MonthHeaderPopupMenu.Popup(X, Y) else Result := inherited DoShowPopupMenu(X, Y); end; function TcxSchedulerYearView.GetCompressWeekEnd: Boolean; begin Result := False; end; function TcxSchedulerYearView.GetGroupingKind: TcxSchedulerGroupingKind; begin Result := gkNone; end; function TcxSchedulerYearView.GetFirstVisibleDate: TDateTime; begin Result := EncodeDate(Year, ViewInfo.AdapterFirstMonth, 1); end; function TcxSchedulerYearView.GetLastVisibleDate: TDateTime; var AMonth: Integer; begin AMonth := ViewInfo.AdapterFirstMonth + ViewInfo.AdapterMonthCount - 1; Result := EncodeDate(Year, AMonth, DayOfTheMonth(EndOfAMonth(Year, AMonth))); end; function TcxSchedulerYearView.GetScrollPos: Integer; var AMonthCount: Integer; begin AMonthCount := ViewInfo.AdapterMonthCount; if AMonthCount <> 0 then Result := Max(cxYearViewScrollMinPos, Min(MulDiv(cxYearViewScrollMaxPos, 12, AMonthCount), MulDiv((Year - YearOf(Now)), 12, AMonthCount) + ViewInfo.AdapterFirstMonth div AMonthCount - ViewInfo.GetPartOfTheYear(Now) + MulDiv(cxYearViewScrollCurrentYearPos, 12, AMonthCount))) else Result := Max(cxYearViewScrollMinPos, Min(cxYearViewScrollMaxPos, (Year - YearOf(Now) + cxYearViewScrollCurrentYearPos))); end; function TcxSchedulerYearView.GetVisibleDaysRange: Integer; begin Result := Trunc(GetLastVisibleDate - GetFirstVisibleDate); end; procedure TcxSchedulerYearView.InitScrollBarsParameters; var APos: Integer; begin inherited InitScrollBarsParameters; APos := GetScrollPos; SetScrollBarInfo(sbVertical, cxYearViewScrollMinPos, MulDiv(cxYearViewScrollMaxPos, 12, ViewInfo.AdapterMonthCount), 1, 1, APos, True, True); end; procedure TcxSchedulerYearView.MakeEventVisible(AEvent: TcxSchedulerControlEvent; const ADate: TDateTime; AResource: TcxSchedulerStorageResourceItem); begin if ADate <> NullDate then begin ViewInfo.CheckLayout(ADate); LayoutChanged; end; end; procedure TcxSchedulerYearView.Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if (Operation = opRemove) then begin if AComponent = Styles.UnusedContent then Styles.UnusedContent := nil; if AComponent = Styles.MonthHeader then Styles.MonthHeader := nil; end; MonthHeaderPopupMenu.Notification(AComponent, Operation); end; procedure TcxSchedulerYearView.Scroll(AScrollBarKind: TScrollBarKind; AScrollCode: TScrollCode; var AScrollPos: Integer); var AYear, AMonth, AMonthCount: Integer; ANavigation: TcxSchedulerYearViewNavigation; begin ANavigation := TcxSchedulerYearViewNavigation(Navigation); HideHintOnScroll(AScrollCode); AMonthCount := ViewInfo.AdapterMonthCount; if AMonthCount = 0 then AYear := YearOf(Now) - cxYearViewScrollCurrentYearPos + AScrollPos else AYear := MulDiv(YearOf(Now) - cxYearViewScrollCurrentYearPos, 12, AMonthCount) + ViewInfo.GetPartOfTheYear(Now) + AScrollPos; ANavigation.CorrectCurrentAnchor; case AScrollCode of scTrack: begin ShowHintOnScroll(IntToStr(AYear), sbHorizontal); Exit; end; scPosition: if AMonthCount = 0 then ViewInfo.CheckLayout(EncodeDate(AYear, 1, 1)) else begin AMonth := AYear mod (12 div AMonthCount) * AMonthCount + 1; AYear := AYear div (12 div AMonthCount); ANavigation.FCurrentAnchor := EncodeDate(AYear, AMonth, 1); end; scLineUp, scPageUp: ANavigation.GotoNextPage(False); scLineDown, scPageDown: ANavigation.GotoNextPage(True); end; ViewInfo.CheckLayout(ANavigation.FCurrentAnchor); AScrollPos := GetScrollPos; end; procedure TcxSchedulerYearView.SelectedDaysChanged; begin if SelectedDays.Count > 0 then ViewInfo.CheckLayout(SelectedDays[0]); end; procedure TcxSchedulerYearView.SetGroupingKind(AValue: TcxSchedulerGroupingKind); begin inherited SetGroupingKind(gkNone); end; function TcxSchedulerYearView.GetHitTest: TcxSchedulerYearViewHitTest; begin Result := TcxSchedulerYearViewHitTest(inherited HitTest); end; function TcxSchedulerYearView.GetNavigation: TcxSchedulerYearViewNavigation; begin Result := TcxSchedulerYearViewNavigation(Controller.Navigation); end; function TcxSchedulerYearView.GetViewInfo: TcxSchedulerYearViewViewInfo; begin Result := TcxSchedulerYearViewViewInfo(inherited ViewInfo); end; function TcxSchedulerYearView.GetYear: Word; begin Result := YearOf(inherited GetFirstVisibleDate); end; procedure TcxSchedulerYearView.SetAllDayEventsOnly(AValue: Boolean); begin if FAllDayEventsOnly <> AValue then begin FAllDayEventsOnly := AValue; Changed; end; end; procedure TcxSchedulerYearView.SetMaxSelectedDaysCount( AValue: Integer); begin AValue := Max(0, AValue); if AValue <> FMaxSelectedDaysCount then begin FMaxSelectedDaysCount := AValue; Changed; end; end; procedure TcxSchedulerYearView.SetMonthHeaderPopupMenu( AValue: TcxSchedulerMonthHeaderPopupMenu); begin FMonthHeaderPopupMenu.Assign(AValue); end; procedure TcxSchedulerYearView.SetScale(AValue: Integer); begin if (AValue <> FScale) and (AValue in [3, 6, 12]) then begin FScale := AValue; Changed; end; end; procedure TcxSchedulerYearView.SetStyles(AValue: TcxSchedulerYearViewStyles); begin FStyles.Assign(AValue); end; { TcxSchedulerYearViewAdapter } function TcxSchedulerYearViewAdapter.QueryInterface( const IID: TGUID; out Obj): HResult; stdcall; begin if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE; end; function TcxSchedulerYearViewAdapter._AddRef: Integer; begin Result := -1; end; function TcxSchedulerYearViewAdapter._Release: Integer; begin Result := -1; end; function TcxSchedulerYearViewAdapter.GetDayCountPerPage: Integer; begin Result := MaxYearViewWeekDays; end; function TcxSchedulerYearViewAdapter.GetFirstMonth: Integer; var AYear, AMonth, ADay: Word; AMonthCount: Integer; ACurrentAnchor: TDateTime; begin if PredefinedCurrentAnchor <> 0 then ACurrentAnchor := PredefinedCurrentAnchor else ACurrentAnchor := TcxSchedulerCustomViewViewInfoAccess(TcxSchedulerYearView(View).ViewInfo).FSelectedDays[0]; PredefinedCurrentAnchor := 0; DecodeDate(ACurrentAnchor, AYear, AMonth, ADay); AMonthCount := GetMonthCount; Result := 1; while Result + AMonthCount <= AMonth do Inc(Result, AMonthCount); end; function TcxSchedulerYearViewAdapter.GetMonthCount: Integer; begin Result := TcxSchedulerYearView(View).Scale; end; function TcxSchedulerYearViewAdapter.GetShowMonthHeaders: Boolean; begin Result := True; end; function TcxSchedulerYearViewAdapter.GetShowWeekDayHeaders: Boolean; begin Result := True; end; function TcxSchedulerYearViewAdapter.GetStartDayIndex: Integer; begin Result := 0; end; { TcxSchedulerMonthHeaderPopupMenu } constructor TcxSchedulerMonthHeaderPopupMenu.Create(AScheduler: TcxCustomScheduler); begin inherited Create(AScheduler); FItems := [mhpmiNewEvent, mhpmiNewAllDayEvent, mhpmiNewReccuringEvent, mhpmiFullYear, mhpmiHalfYear, mhpmiQuarter]; end; procedure TcxSchedulerMonthHeaderPopupMenu.Assign(Source: TPersistent); begin inherited Assign(Source); if Source is TcxSchedulerMonthHeaderPopupMenu then begin Items := TcxSchedulerMonthHeaderPopupMenu(Source).Items; OnClick := TcxSchedulerMonthHeaderPopupMenu(Source).OnClick; OnPopup := TcxSchedulerMonthHeaderPopupMenu(Source).OnPopup; end; end; procedure TcxSchedulerMonthHeaderPopupMenu.Execute(AItem: TcxSchedulerMonthHeaderPopupMenuItem); begin ExecuteCommand(Ord(AItem)); end; function TcxSchedulerMonthHeaderPopupMenu.GetMenuItem(AItem: TcxSchedulerMonthHeaderPopupMenuItem): TMenuItem; begin Result := FindItemByCommand(Root, Ord(AItem)); end; procedure TcxSchedulerMonthHeaderPopupMenu.CreateItems; function GetChecked(ACommand: Integer): Boolean; var AIndex: Integer; begin Result := False; AIndex := ACommand - Ord(mhpmiFullYear); if (AIndex >= 0) and (AIndex <= 2) then Result := YearView.Scale = YearScales[AIndex]; end; procedure CreateRulerItem(const ACaption: string; AItem: TcxSchedulerMonthHeaderPopupMenuItem); var ACommand: Integer; begin if AItem in Items then begin ACommand := Ord(AItem); CreateSubItem(Root, ACaption, ACommand, -1, True, GetChecked(ACommand)); end; end; begin CreateNewEventItems(mhpmiNewEvent in FItems, mhpmiNewAllDayEvent in FItems, mhpmiNewReccuringEvent in FItems, Ord(mhpmiNewEvent), Ord(mhpmiNewAllDayEvent), Ord(mhpmiNewReccuringEvent)); if Items * [mhpmiFullYear, mhpmiHalfYear, mhpmiQuarter] <> [] then begin AddValidSeparator(Root); CreateRulerItem(cxGetResourceString(@scxpmFullYear), mhpmiFullYear); CreateRulerItem(cxGetResourceString(@scxpmHalfYear), mhpmiHalfYear); CreateRulerItem(cxGetResourceString(@scxpmQuarter), mhpmiQuarter); end; end; function TcxSchedulerMonthHeaderPopupMenu.GetYearView: TcxSchedulerYearView; begin Result := Scheduler.CurrentView as TcxSchedulerYearView; end; procedure TcxSchedulerMonthHeaderPopupMenu.DoExecute(ACommand: Integer); var AIndex: Integer; begin if ACommand in [Ord(mhpmiNewEvent), Ord(mhpmiNewAllDayEvent), Ord(mhpmiNewReccuringEvent)] then inherited DoExecute(ACommand) else begin AIndex := ACommand - Ord(mhpmiFullYear); if AIndex in [0..2] then YearView.Scale := YearScales[AIndex]; end; end; function TcxSchedulerMonthHeaderPopupMenu.DoOnClick(ACommand: Integer): Boolean; begin Result := False; if Assigned(FOnClick) then FOnClick(Self, TcxSchedulerMonthHeaderPopupMenuItem(ACommand), Result); end; function TcxSchedulerMonthHeaderPopupMenu.DoOnPopup: Boolean; begin Result := False; if Assigned(FOnPopup) then FOnPopup(Self, InternalMenu, Result); end; function TcxSchedulerMonthHeaderPopupMenu.IsValidCommand(ACommand: Integer): Boolean; begin Result := (ACommand >= Ord(mhpmiNewEvent)) and (ACommand <= Ord(mhpmiQuarter)); end; end.