Componentes.Terceros.DevExp.../internal/x.44/1/ExpressScheduler 3/Sources/cxSchedulerGanttView.pas
2009-06-29 12:09:02 +00:00

2284 lines
77 KiB
ObjectPascal

{********************************************************************}
{ }
{ 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 cxSchedulerGanttView;
{$I cxVer.inc}
interface
uses
Types, Forms, Windows, SysUtils, StdCtrls, Classes, Math, Controls, Graphics,
cxScrollBar, cxLookAndFeelPainters, cxSchedulerCustomControls, cxSchedulerStorage,
cxSchedulerCustomResourceView, cxSchedulerUtils, cxSchedulerStrs, cxDateUtils,
cxClasses, cxDrawTextUtils, cxSchedulerTimeGridView, cxGraphics, cxGeometry,
cxControls;
const
// hittest constants
htcLink = $15;
htcExpandButton = $17;
type
TcxSchedulerGanttView = class;
TcxSchedulerGanttViewController = class;
TcxSchedulerGanttViewViewInfo = class;
TcxSchedulerGanttViewEventStyle = (esDefault, esProgress);
{ TcxSchedulerGanttViewEventLayoutBuilder }
TcxSchedulerGanttViewEventLayoutBuilder = class(TcxSchedulerEventLayoutBuilder)
public
procedure Calculate; override;
end;
{ TcxSchedulerGanttViewLinkViewInfo }
TcxSchedulerGanttViewLinkLines = array of TRect;
TcxSchedulerGanttViewLinkViewInfo = class(TcxSchedulerCustomViewInfoItem)
private
FArrowDirection: TcxArrowDirection;
FArrowRect: TRect;
FClipRect: TRect;
FEventItemLink: TcxSchedulerEventItemLink;
FFinishEventViewInfo: TcxSchedulerEventCellViewInfo;
FHint: string;
FLines: TcxSchedulerGanttViewLinkLines;
FStartEventViewInfo: TcxSchedulerEventCellViewInfo;
FViewInfo: TcxSchedulerGanttViewViewInfo;
function GetArrowDirection(const AArrowStart, AArrowFinish: TPoint): TcxArrowDirection;
function GetFinishPoint(const AStartRect, AFinishRect: TRect): TPoint;
function GetIsHot: Boolean;
function GetRelation: TcxSchedulerEventRelation;
function GetStartPoint(const AStartRect: TRect): TPoint;
protected
function GetHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest; var ABreak: Boolean): Boolean; override;
procedure AfterCustomDraw(ACanvas: TcxCanvas); override;
procedure BeforeCustomDraw(ACanvas: TcxCanvas); override;
procedure Calculate(AStartRect: TRect; AFinishRect: TRect); virtual;
procedure CalculateArrowRect(const AArrowStart, AArrowFinish: TPoint); virtual;
procedure CalculateBounds; virtual;
procedure SetClipRegion(ACanvas: TcxCanvas);
property FinishEventViewInfo: TcxSchedulerEventCellViewInfo read FFinishEventViewInfo;
property StartEventViewInfo: TcxSchedulerEventCellViewInfo read FStartEventViewInfo;
property ClipRect: TRect read FClipRect;
public
procedure Initialize(AViewInfo: TcxSchedulerGanttViewViewInfo;
AStartEventViewInfo, AFinishEventViewInfo: TcxSchedulerEventCellViewInfo;
AEventItemLink: TcxSchedulerEventItemLink); virtual;
procedure Draw(ACanvas: TcxCanvas); override;
property ArrowDirection: TcxArrowDirection read FArrowDirection;
property ArrowRect: TRect read FArrowRect;
property EventItemLink: TcxSchedulerEventItemLink read FEventItemLink;
property Hint: string read FHint;
property IsHot: Boolean read GetIsHot;
property Lines: TcxSchedulerGanttViewLinkLines read FLines;
property Relation: TcxSchedulerEventRelation read GetRelation;
property ViewInfo: TcxSchedulerGanttViewViewInfo read FViewInfo;
end;
{ TcxSchedulerGanttViewExpandButtonViewInfo }
TcxSchedulerGanttViewExpandButtonViewInfo = class(TcxSchedulerCustomViewInfoItem)
private
FEvent: TcxSchedulerControlEvent;
FExpanded: Boolean;
protected
procedure DoClick;
procedure InitHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override;
public
procedure Draw(ACanvas: TcxCanvas); override;
property Event: TcxSchedulerControlEvent read FEvent;
property Expanded: Boolean read FExpanded;
end;
{ TcxSchedulerGanttViewTotalProgressViewInfo }
TcxSchedulerGanttViewTotalProgressViewInfo = class
private
FContentArea: TRect;
FDrawAsPolyline: Boolean;
FLineColor: TColor;
FPoints: array of TPoint;
FProgressNodes: array of TPoint;
FTimeLineRect: TRect;
FViewInfo: TcxSchedulerGanttViewViewInfo;
function FindUncompliteEventBeforeLine(const ALine: TRect;
AResource: TcxSchedulerStorageResourceItem; var AViewInfo: TcxSchedulerEventCellViewInfo): Boolean;
function GetTimeLineApproximateRect: TRect;
function GetTimeLineRect: TRect;
function GetUncompliteEventPoint(const ALine: TRect; var P: TPoint;
AResource: TcxSchedulerStorageResourceItem): Boolean;
public
constructor Create(AViewInfo: TcxSchedulerGanttViewViewInfo); virtual;
procedure Calculate; virtual;
procedure CalculatePolyline;
procedure Draw(ACanvas: TcxCanvas);
procedure DrawProgressNodes(ACanvas: TcxCanvas);
property ContentArea: TRect read FContentArea;
property DrawAsPolyline: Boolean read FDrawAsPolyline;
property LineColor: TColor read FLineColor;
property TimeLineRect: TRect read FTimeLineRect;
property ViewInfo: TcxSchedulerGanttViewViewInfo read FViewInfo;
end;
{ TcxSchedulerGanttViewViewInfo }
TcxSchedulerGanttViewViewInfo = class(TcxSchedulerTimeGridViewViewInfo)
private
FExpandButtons: TcxSchedulerViewInfoCellList;
FHotLink: TcxSchedulerGanttViewLinkViewInfo;
FLinks: TcxSchedulerViewInfoCellList;
FTotalProgressViewInfo: TcxSchedulerGanttViewTotalProgressViewInfo;
FVisibleEventEnumerationList: TcxObjectList;
FVisibleEventWithoutResourceCount: Integer;
function GetGanttView: TcxSchedulerGanttView;
function GetIsHotTrackEnabled: Boolean;
function GetLinkViewParams: TcxViewParams;
function GetVisibleEventEnumeration(AIndex: Integer): TcxSchedulerResourceViewInfo;
procedure SetHotLink(AHotLink: TcxSchedulerGanttViewLinkViewInfo);
protected
procedure AddEventForCalculation(ABuilder: TcxSchedulerEventLayoutBuilder;
AEvent: TcxSchedulerControlEvent; AResourceIndex: Integer); override;
procedure CalculateExpandButtonViewInfos;
procedure CheckEventVisibility(ACell: TcxSchedulerEventCellViewInfo; AIndex: Integer); override;
procedure Clear; override;
function CreateEventViewData(AEvent: TcxSchedulerControlEvent;
const ABounds: TRect; const AStart: TDateTime; const AFinish: TDateTime;
AResource: TcxSchedulerResourceViewInfo): TcxSchedulerEventViewData; override;
function CreateLayoutBuilder: TcxSchedulerEventLayoutBuilder; override;
function CreateLinkItemViewInfo(AEventViewInfo: TcxSchedulerEventCellViewInfo;
AEventItemLink: TcxSchedulerEventItemLink;
out ALinkItem: TcxSchedulerGanttViewLinkViewInfo): Boolean;
procedure DoCalculate; override;
function FindEventViewInfoBySource(AEvent: TcxSchedulerEvent;
const ADate: TDateTime; AResource: TcxSchedulerStorageResourceItem;
var AViewInfo: TcxSchedulerEventCellViewInfo): Boolean;
function GetEventBounds(AEvent: TcxSchedulerControlEvent; AResource: TcxSchedulerStorageResourceItem; out AEventRect: TRect): Boolean;
function GetEventForResourceCount(AResourceIndex: Integer; out AResourceID: Variant): Integer; override;
function GetEventWithoutResourceCount: Integer; override;
function GetIndentBetweenLines: Integer; override;
function GetNeedShowCurrentTime: Boolean; override;
function HasVisibleEvents: Boolean; override;
function IsEventCollapsed(AEvent: TcxSchedulerEvent; AHidden: Boolean): Boolean;
function IsTaskLinksExpanded(ATaskLinks: TcxSchedulerEventLinks): Boolean;
function NavigationButtonOffset(AKind: TcxSchedulerContentNavigationButtonKind;
AResourceIndex: Integer): Integer; override;
// Links
procedure CreateLinks; virtual;
procedure RecreateLinks; virtual;
property ExpandButtons: TcxSchedulerViewInfoCellList read FExpandButtons;
public
constructor Create(AOwner: TcxSchedulerSubControl); override;
destructor Destroy; override;
procedure CalculateHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override;
property HotLink: TcxSchedulerGanttViewLinkViewInfo read FHotLink write SetHotLink;
property Links: TcxSchedulerViewInfoCellList read FLinks;
property LinkViewParams: TcxViewParams read GetLinkViewParams;
property TotalProgressViewInfo: TcxSchedulerGanttViewTotalProgressViewInfo read FTotalProgressViewInfo;
property View: TcxSchedulerGanttView read GetGanttView;
property VisibleEventEnumerationList[AIndex: Integer]: TcxSchedulerResourceViewInfo read GetVisibleEventEnumeration;
end;
{ TcxSchedulerGanttViewPainter }
TcxSchedulerGanttViewPainter = class(TcxSchedulerTimeGridViewPainter)
private
function GetView: TcxSchedulerGanttView;
function GetViewInfo: TcxSchedulerGanttViewViewInfo;
procedure DoDrawExpandButton(AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean);
procedure DoDrawLinkItem(AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean);
public
procedure Paint; override;
property View: TcxSchedulerGanttView read GetView;
property ViewInfo: TcxSchedulerGanttViewViewInfo read GetViewInfo;
end;
{ TcxSchedulerGanttViewHitTest }
TcxSchedulerGanttViewHitTest = class(TcxSchedulerTimeGridViewHitTest)
private
function GetHitAtEventDraggingArea: Boolean;
function GetHitExpandButton: TcxSchedulerGanttViewExpandButtonViewInfo;
function GetHitLink: TcxSchedulerGanttViewLinkViewInfo;
function GetView: TcxSchedulerGanttView;
protected
FCalcEventDraggingArea: Boolean;
FEventDraggingArea: TRect;
property View: TcxSchedulerGanttView read GetView;
property HitExpandButton: TcxSchedulerGanttViewExpandButtonViewInfo read GetHitExpandButton;
property HitLink: TcxSchedulerGanttViewLinkViewInfo read GetHitLink;
public
property HitAtEventDraggingArea: Boolean read GetHitAtEventDraggingArea;
property HitAtExpandButton: Boolean index htcExpandButton read GetBitState;
property HitAtLink: Boolean index htcLink read GetBitState;
end;
{ TcxGanttDragEventHelper }
TcxSchedulerEventDragMode = (sedmNone, sedmMoveTo, sedmTaskLinkTo);
TcxSchedulerGanttDragObject = class(TcxSchedulerDragObject)
private
FDragGroupedTaskLinks: Boolean;
function GetController: TcxSchedulerGanttViewController;
protected
function GetDragCursor(Accepted: Boolean; X, Y: Integer): TCursor; override;
property Controller: TcxSchedulerGanttViewController read GetController;
public
constructor Create(AControl: TControl); override;
property DragGroupedTaskLinks: Boolean read FDragGroupedTaskLinks write FDragGroupedTaskLinks;
end;
TcxGanttDragEventHelper = class(TcxTimeGridDragEventHelper)
private
function GetController: TcxSchedulerGanttViewController;
function GetDragObject: TcxSchedulerGanttDragObject;
function GetHitTest: TcxSchedulerGanttViewHitTest;
function GetViewInfo: TcxSchedulerGanttViewViewInfo;
protected
procedure ApplyChanges; override;
procedure ApplyTaskLinks; virtual;
function CanDragTo(ADeltaTime: TDateTime): Boolean; virtual;
procedure DragOver(const P: TPoint; State: TDragState; var Accepted: Boolean); override;
procedure InternalApplyTaskLink(AEvent: TcxSchedulerControlEvent); virtual;
function IsAtOrigin: Boolean; override;
procedure PrepareGroupedTaskLinks; virtual;
procedure UpdateViewClonesTime; override;
property Controller: TcxSchedulerGanttViewController read GetController;
property DragObject: TcxSchedulerGanttDragObject read GetDragObject;
property HitTest: TcxSchedulerGanttViewHitTest read GetHitTest;
property ViewInfo: TcxSchedulerGanttViewViewInfo read GetViewInfo;
end;
{ TcxGanttEventSizing }
TcxGanttEventSizing = class(TcxTimeGridEventSizing)
protected
function CanResize: Boolean; virtual;
procedure DragOver(const P: TPoint; State: TDragState; var Accepted: Boolean); override;
function IsValidTime: Boolean; override;
end;
{ TcxSchedulerGanttViewController }
TcxSchedulerGanttViewController = class(TcxSchedulerTimeGridViewController)
private
FEventDragMode: TcxSchedulerEventDragMode;
FTimerScrollBarKind: TScrollBarKind;
FDragEventClipRect: TRect;
procedure CalcDragEventClipRect;
function GetDragEventHelper: TcxGanttDragEventHelper;
function GetEventHintData(var AHint: string): Boolean;
function GetHitTest: TcxSchedulerGanttViewHitTest;
function GetLinkHintData(var AHint: string): Boolean;
function GetView: TcxSchedulerGanttView;
function GetViewInfo: TcxSchedulerGanttViewViewInfo;
procedure InternalPaintDraggingLink(const AStart, AFinish: TPoint);
procedure SetEventDragMode(AValue: TcxSchedulerEventDragMode);
protected
FPrevDragPoint: TPoint;
FStartDragPoint: TPoint;
procedure CheckScrolling(const APos: TPoint); override;
procedure CheckTaskLinkDrawOnScroll(AScrollBarKind: TScrollBarKind; AScrollCode: TScrollCode); virtual;
function ConsiderHiddenEvents: Boolean; override;
function CreateDragEventHelper: TcxDragEventHelper; override;
function CreateResizeEventHelper: TcxEventSizingHelper; override;
procedure DragOver(Source: TObject; X, Y: Integer; State: TDragState;
var Accept: Boolean); override;
procedure EndDrag(Target: TObject; X, Y: Integer); override;
procedure EraseDraggingLink; virtual;
function GetDragEventClipRect: TRect; virtual;
procedure InitTimer(AllowStart: Boolean; AScrollCode: TScrollCode); override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure OnTimer(Sender: TObject); override;
procedure PaintDraggingLink(const P: TPoint); virtual;
procedure Scrolling(AScrollCode: TScrollCode; var AScrollPos: Integer); override;
function ShowHint: Boolean; override;
procedure StartDrag(var DragObject: TDragObject); override;
procedure UpdateDraggingLink(const P: TPoint); virtual;
procedure UpdateEventDragMode;
property DragEventHelper: TcxGanttDragEventHelper read GetDragEventHelper;
property EventDragMode: TcxSchedulerEventDragMode read FEventDragMode write SetEventDragMode;
property HitTest: TcxSchedulerGanttViewHitTest read GetHitTest;
property View: TcxSchedulerGanttView read GetView;
property ViewInfo: TcxSchedulerGanttViewViewInfo read GetViewInfo;
end;
{ TcxSchedulerGanttView }
TcxSchedulerShowTaskDependencyEditorEvent = procedure (Sender: TcxCustomScheduler;
ALink: TcxSchedulerEventItemLink; var AHandled: Boolean) of object;
TcxSchedulerStartLinkEventEvent = procedure (Sender: TcxCustomScheduler;
AEvent: TcxSchedulerControlEvent; var AAllow: Boolean) of object;
TcxSchedulerEndLinkEventEvent = procedure (Sender: TcxCustomScheduler;
ALinkEvent: TcxSchedulerControlEvent; var AAllow: Boolean) of object;
TcxSchedulerGanttView = class(TcxSchedulerTimeGridView)
private
FEventsStyle: TcxSchedulerGanttViewEventStyle;
FLinkLineColor: TColor;
FShowExpandButtons: Boolean;
FShowTotalProgressLine: Boolean;
FTotalProgressLineColor: TColor;
FOnEndLinkEvent: TcxSchedulerEndLinkEventEvent;
FOnShowTaskDependencyEditor: TcxSchedulerShowTaskDependencyEditorEvent;
FOnStartLinkEvent: TcxSchedulerStartLinkEventEvent;
function GetController: TcxSchedulerGanttViewController;
function GetHitTest: TcxSchedulerGanttViewHitTest;
function GetViewInfo: TcxSchedulerGanttViewViewInfo;
procedure SetEventsStyle(AValue: TcxSchedulerGanttViewEventStyle);
procedure SetLinkLineColor(AColor: TColor);
procedure SetShowExpandButtons(AValue: Boolean);
procedure SetShowTotalProgressLine(AValue: Boolean);
procedure SetTotalProgressLineColor(AValue: TColor);
protected
function CheckEventsVisibility: Boolean; override;
function CreateController: TcxSchedulerSubControlController; override;
function CreateHitTest: TcxSchedulerSubControlHitTest; override;
function CreatePainter: TcxSchedulerSubControlPainter; override;
function CreateViewInfo: TcxSchedulerSubControlViewInfo; override;
function DoEndLinkEvent(ALink: TcxSchedulerControlEvent): Boolean; virtual;
function DoShowTaskDependencyEditor(ALink: TcxSchedulerEventItemLink): Boolean; virtual;
function DoStartLinkEvent(AEvent: TcxSchedulerControlEvent): Boolean; virtual;
function GetDragObjectClass: TDragControlObjectClass; override;
function GetEventHintText(AEvent: TcxSchedulerControlEvent): string; override;
function IsInplaceEditingEnabled: Boolean; override;
function ShowTaskComplete: Boolean; override;
procedure ShowTaskDependencyEditor(ALink: TcxSchedulerEventItemLink); virtual;
procedure ValidateContentPopupMenuItems(var AItems: TcxSchedulerContentPopupMenuItems); override;
property Controller: TcxSchedulerGanttViewController read GetController;
property EventDetailInfo;
property ViewInfo: TcxSchedulerGanttViewViewInfo read GetViewInfo;
public
constructor Create(AOwner: TcxCustomScheduler); override;
property HitTest: TcxSchedulerGanttViewHitTest read GetHitTest;
published
property EventsStyle: TcxSchedulerGanttViewEventStyle read FEventsStyle write SetEventsStyle default esDefault;
property LinkLineColor: TColor read FLinkLineColor write SetLinkLineColor default clNavy;
property ShowExpandButtons: Boolean read FShowExpandButtons write SetShowExpandButtons default False;
property ShowTotalProgressLine: Boolean read FShowTotalProgressLine write SetShowTotalProgressLine default False;
property TotalProgressLineColor: TColor read FTotalProgressLineColor write SetTotalProgressLineColor default clRed;
property OnEndLinkEvent: TcxSchedulerEndLinkEventEvent
read FOnEndLinkEvent write FOnEndLinkEvent;
property OnShowTaskDependencyEditor: TcxSchedulerShowTaskDependencyEditorEvent
read FOnShowTaskDependencyEditor write FOnShowTaskDependencyEditor;
property OnStartLinkEvent: TcxSchedulerStartLinkEventEvent
read FOnStartLinkEvent write FOnStartLinkEvent;
end;
implementation
uses
cxLibraryConsts, cxSchedulerDialogs, cxVariants;
const
LinkLineOffset = 5;
ProgressNodeRadius = 4;
type
TcxCustomSchedulerAccess = class(TcxCustomScheduler);
TcxSchedulerEventAccess = class(TcxSchedulerEvent);
TcxSchedulerControlEventAccess = class(TcxSchedulerControlEvent);
TcxSchedulerEventCellViewInfoAccess = class(TcxSchedulerEventCellViewInfo);
TcxSchedulerHintControllerAccess = class(TcxSchedulerHintController);
TcxSchedulerTimeGridResourceScrollAccess = class(TcxSchedulerTimeGridResourceScroll);
TcxSchedulerCustomDateNavigatorAccess = class(TcxSchedulerCustomDateNavigator);
function cxGanttViewCompareEventPlaces(AEventPlace1: TcxSchedulerEventPlace;
AEventPlace2: TcxSchedulerEventPlace): Integer;
function CheckClone(AEvent1, AEvent2: TcxSchedulerControlEvent;
var ASign: Integer): Boolean;
begin
if AEvent1.IsClone and (AEvent1.Source = AEvent2) then
ASign := 1
else
if AEvent2.IsClone and (AEvent2.Source = AEvent1) then
ASign := -1
else
ASign := 0;
Result := ASign <> 0;
end;
var
AEvent1: TcxSchedulerControlEvent;
AEvent2: TcxSchedulerControlEvent;
ATaskIndex1, ATaskIndex2: Integer;
begin
Result := Integer(AEventPlace1.Resource) - Integer(AEventPlace2.Resource);
if Result = 0 then
begin
AEvent1 := TcxSchedulerControlEvent(AEventPlace1.Event);
AEvent2 := TcxSchedulerControlEvent(AEventPlace2.Event);
if AEvent1.Pattern <> nil then
ATaskIndex1 := TcxSchedulerControlEvent(AEvent1.Pattern).TaskIndex
else
ATaskIndex1 := AEvent1.TaskIndex;
if AEvent2.Pattern <> nil then
ATaskIndex2 := TcxSchedulerControlEvent(AEvent2.Pattern).TaskIndex
else
ATaskIndex2 := AEvent2.TaskIndex;
Result := ATaskIndex1 - ATaskIndex2;
if Result <> 0 then
begin
if ATaskIndex1 = -1 then Result := 1;
if ATaskIndex2 = -1 then Result := -1;
end
else
if not CheckClone(AEvent1, AEvent2, Result) and
(ATaskIndex1 = -1) then
begin
Result := AEvent1.RecordIndex - AEvent2.RecordIndex;
if Result <> 0 then
begin
if AEvent1.RecordIndex < 0 then Result := 1;
if AEvent2.RecordIndex < 0 then Result := -1;
end;
end;
end;
end;
{ TcxSchedulerGanttView }
constructor TcxSchedulerGanttView.Create(AOwner: TcxCustomScheduler);
begin
inherited Create(AOwner);
FLinkLineColor := clNavy;
FTotalProgressLineColor := clRed;
end;
function TcxSchedulerGanttView.CheckEventsVisibility: Boolean;
begin
Result := False;
end;
function TcxSchedulerGanttView.CreateController: TcxSchedulerSubControlController;
begin
Result := TcxSchedulerGanttViewController.Create(Self);
end;
function TcxSchedulerGanttView.CreateHitTest: TcxSchedulerSubControlHitTest;
begin
Result := TcxSchedulerGanttViewHitTest.Create(Self);
end;
function TcxSchedulerGanttView.CreatePainter: TcxSchedulerSubControlPainter;
begin
Result := TcxSchedulerGanttViewPainter.Create(Self);
end;
function TcxSchedulerGanttView.CreateViewInfo: TcxSchedulerSubControlViewInfo;
begin
Result := TcxSchedulerGanttViewViewInfo.Create(Self);
end;
function TcxSchedulerGanttView.DoEndLinkEvent(ALink: TcxSchedulerControlEvent): Boolean;
begin
Result := True;
if Assigned(FOnEndLinkEvent) then
FOnEndLinkEvent(Scheduler, ALink, Result);
end;
function TcxSchedulerGanttView.DoShowTaskDependencyEditor(
ALink: TcxSchedulerEventItemLink): Boolean;
begin
Result := False;
if Assigned(OnShowTaskDependencyEditor) then
OnShowTaskDependencyEditor(Scheduler, ALink, Result);
end;
function TcxSchedulerGanttView.DoStartLinkEvent(AEvent: TcxSchedulerControlEvent): Boolean;
begin
Result := True;
if Assigned(FOnStartLinkEvent) then
FOnStartLinkEvent(Scheduler, AEvent, Result);
end;
function TcxSchedulerGanttView.GetDragObjectClass: TDragControlObjectClass;
begin
Result := TcxSchedulerGanttDragObject;
end;
function TcxSchedulerGanttView.GetEventHintText(
AEvent: TcxSchedulerControlEvent): string;
begin
Result := Format(cxGetResourceString(@scxGanttEventHint), [AEvent.Caption,
AEvent.TaskComplete, cxDateToStr(AEvent.Start), cxDateToStr(AEvent.Finish)]);
end;
function TcxSchedulerGanttView.IsInplaceEditingEnabled: Boolean;
begin
Result := EventsStyle <> esProgress;
end;
function TcxSchedulerGanttView.ShowTaskComplete: Boolean;
begin
Result := True;
end;
procedure TcxSchedulerGanttView.ShowTaskDependencyEditor(
ALink: TcxSchedulerEventItemLink);
begin
if not DoShowTaskDependencyEditor(ALink) then
cxShowTaskDependencyEditor(ALink, GetSchedulerLookAndFeel(True));
end;
procedure TcxSchedulerGanttView.ValidateContentPopupMenuItems(
var AItems: TcxSchedulerContentPopupMenuItems);
begin
if not (Scales.MinorUnit in [suHour, suDay]) then
Exclude(AItems, cpmiToday);
AItems := AItems - [cpmiGoToDate, cpmiGoToThisDay];
end;
function TcxSchedulerGanttView.GetController: TcxSchedulerGanttViewController;
begin
Result := TcxSchedulerGanttViewController(inherited Controller);
end;
function TcxSchedulerGanttView.GetHitTest: TcxSchedulerGanttViewHitTest;
begin
Result := TcxSchedulerGanttViewHitTest(inherited HitTest);
end;
function TcxSchedulerGanttView.GetViewInfo: TcxSchedulerGanttViewViewInfo;
begin
Result := TcxSchedulerGanttViewViewInfo(inherited ViewInfo);
end;
procedure TcxSchedulerGanttView.SetEventsStyle(AValue: TcxSchedulerGanttViewEventStyle);
begin
if AValue <> EventsStyle then
begin
FEventsStyle := AValue;
Changed;
end;
end;
procedure TcxSchedulerGanttView.SetLinkLineColor(AColor: TColor);
begin
if AColor <> LinkLineColor then
begin
FLinkLineColor := AColor;
Changed;
end;
end;
procedure TcxSchedulerGanttView.SetShowExpandButtons(AValue: Boolean);
begin
if AValue <> ShowExpandButtons then
begin
FShowExpandButtons := AValue;
Changed;
end;
end;
procedure TcxSchedulerGanttView.SetShowTotalProgressLine(AValue: Boolean);
begin
if ShowTotalProgressLine <> AValue then
begin
FShowTotalProgressLine := AValue;
Changed;
end;
end;
procedure TcxSchedulerGanttView.SetTotalProgressLineColor(AValue: TColor);
begin
if TotalProgressLineColor <> AValue then
begin
FTotalProgressLineColor := AValue;
Changed;
end;
end;
{ TcxSchedulerGanttViewLinkItemViewInfo }
procedure TcxSchedulerGanttViewLinkViewInfo.Initialize(
AViewInfo: TcxSchedulerGanttViewViewInfo;
AStartEventViewInfo, AFinishEventViewInfo: TcxSchedulerEventCellViewInfo;
AEventItemLink: TcxSchedulerEventItemLink);
begin
FViewInfo := AViewInfo;
FFinishEventViewInfo := AFinishEventViewInfo;
FStartEventViewInfo := AStartEventViewInfo;
FEventItemLink := AEventItemLink;
FHint := Format(cxGetResourceString(@scxLinkHint), [
cxGetResourceString(sEventRelations[Integer(Relation)]),
cxGetResourceString(sEventRelationsShort[Integer(Relation)]),
StartEventViewInfo.Caption, FinishEventViewInfo.Caption]);
Calculate(AStartEventViewInfo.Bounds, AFinishEventViewInfo.Bounds);
CalculateBounds;
end;
procedure TcxSchedulerGanttViewLinkViewInfo.AfterCustomDraw(ACanvas: TcxCanvas);
begin
// nothing to do
end;
procedure TcxSchedulerGanttViewLinkViewInfo.BeforeCustomDraw(ACanvas: TcxCanvas);
begin
ACanvas.Brush.Style := bsSolid;
ACanvas.SetBrushColor(ViewParams.Color);
ACanvas.Pen.Color := ViewParams.Color;
end;
procedure TcxSchedulerGanttViewLinkViewInfo.Calculate(
AStartRect: TRect; AFinishRect: TRect);
function GetValidRect(const P1, P2: TPoint): TRect;
begin
if P1.X = P2.X then
Result := Rect(P1.X, Min(P1.Y, P2.Y), P1.X + 1, Max(P1.Y, P2.Y) + 1)
else
Result := Rect(Min(P1.X, P2.X), P2.Y, Max(P1.X, P2.X) + 1, P2.Y + 1);
end;
function GetLineXOffset(const R, R1: TRect): Integer;
begin
Result := Min(Abs(R.Right - R1.Left), Abs(R1.Right - R.Left));
if Result > LinkLineOffset then
Result := LinkLineOffset;
end;
procedure AddLine(const P1, P2: TPoint; var ALineNumber: Integer);
begin
if ALineNumber >= Length(FLines) then
SetLength(FLines, ALineNumber + 1);
FLines[ALineNumber] := GetValidRect(P1, P2);
Inc(ALineNumber);
end;
procedure InitializePoints(var AStart, AFinish: TPoint; var ALineNumber: Integer);
var
AOffset: Integer;
P: TPoint;
R: TRect;
begin
R := AStartRect;
P := GetStartPoint(AStartRect);
AOffset := GetLineXOffset(AStartRect, AFinishRect);
InflateRect(AStartRect, AOffset, AOffset);
AStart := GetStartPoint(AStartRect);
AddLine(P, AStart, ALineNumber);
P := GetFinishPoint(R, AFinishRect);
if (Relation = trFinishToStart) and (AFinishRect.Left >= R.Right) then
InflateRect(AFinishRect, 0, 2 * LinkLineOffset)
else
InflateRect(AFinishRect, 2 * LinkLineOffset, 0);
AFinish := GetFinishPoint(R, AFinishRect);
AddLine(AFinish, P, ALineNumber);
CalculateArrowRect(AFinish, P);
end;
function GetNextPoint(var APoint: TPoint; AFinishPoint: TPoint;
AXOffset: Integer; var ALineNumber: Integer): Boolean;
var
P: TPoint;
R: TRect;
begin
Result := True;
P := APoint;
P.X := APoint.X + AXOffset;
if cxRectIntersect(R, AStartRect, GetValidRect(APoint, P)) and
(R.Right - R.Left > 1) then
begin
P := APoint;
Result := P.Y <> AFinishPoint.Y;
if Relation in [trFinishToFinish, trStartToStart] then
P.Y := AFinishPoint.Y
else
if AFinishPoint.Y > P.Y then
P.Y := AStartRect.Bottom + 1
else
P.Y := AStartRect.Top - 1;
end;
AddLine(APoint, P, ALineNumber);
APoint := P;
end;
var
AFinishPoint: TPoint;
ALineNumber: Integer;
P: TPoint;
begin
ALineNumber := 0;
SetLength(FLines, 10);
InitializePoints(P, AFinishPoint, ALineNumber);
while GetNextPoint(P, AFinishPoint, AFinishPoint.X - P.X, ALineNumber) and
(P.X <> AFinishPoint.X) do ;
AddLine(P, AFinishPoint, ALineNumber);
SetLength(FLines, ALineNumber);
end;
procedure TcxSchedulerGanttViewLinkViewInfo.CalculateArrowRect(
const AArrowStart, AArrowFinish: TPoint);
begin
FArrowDirection := GetArrowDirection(AArrowStart, AArrowFinish);
case ArrowDirection of
adUp:
FArrowRect := Rect(AArrowStart.X - LinkLineOffset + 1, AArrowFinish.Y,
AArrowStart.X + LinkLineOffset, AArrowStart.Y - LinkLineOffset);
adDown:
FArrowRect := Rect(AArrowStart.X - LinkLineOffset + 1,
AArrowStart.Y + LinkLineOffset, AArrowStart.X + LinkLineOffset,
AArrowFinish.Y);
adLeft:
FArrowRect := Rect(AArrowFinish.X, AArrowStart.Y - LinkLineOffset,
AArrowStart.X - LinkLineOffset, AArrowFinish.Y + LinkLineOffset);
adRight:
FArrowRect := Rect(AArrowStart.X + LinkLineOffset,
AArrowFinish.Y - LinkLineOffset, AArrowFinish.X, AArrowFinish.Y + LinkLineOffset);
end;
end;
procedure TcxSchedulerGanttViewLinkViewInfo.CalculateBounds;
var
R: TRect;
K, I: Integer;
ALines: TcxSchedulerGanttViewLinkLines;
begin
FClipRect := ViewInfo.GetEventClipRect(StartEventViewInfo);
K := 0;
SetLength(ALines, Length(FLines));
for I := 0 to High(Lines) do
if cxRectIntersect(R, FLines[I], FClipRect) then
begin
ALines[K] := R;
Inc(K);
end;
SetLength(ALines, K);
FLines := ALines;
R := ArrowRect;
for I := 0 to High(Lines) do
R := cxRectUnion(R, Lines[I]);
InflateRect(R, 3, 3); // todo: valid redraw after hot link
FBounds := R;
end;
function TcxSchedulerGanttViewLinkViewInfo.GetArrowDirection(
const AArrowStart, AArrowFinish: TPoint): TcxArrowDirection;
begin
if AArrowStart.X = AArrowFinish.X then
if AArrowStart.Y > AArrowFinish.Y then
Result := adUp
else
Result := adDown
else
if AArrowStart.X > AArrowFinish.X then
Result := adLeft
else
Result := adRight;
end;
function TcxSchedulerGanttViewLinkViewInfo.GetFinishPoint(
const AStartRect, AFinishRect: TRect): TPoint;
begin
Result.Y := (AFinishRect.Bottom + AFinishRect.Top) div 2;
case Relation of
trFinishToStart, trStartToStart:
begin
Result.X := AFinishRect.Left;
if (Relation = trFinishToStart) and (AStartRect.Right <= AFinishRect.Left) then
if AStartRect.Top >= Result.Y then
Result.Y := AFinishRect.Bottom
else
Result.Y := AFinishRect.Top;
end;
trFinishToFinish, trStartToFinish:
Result.X := AFinishRect.Right;
end;
end;
function TcxSchedulerGanttViewLinkViewInfo.GetHitTest(
AHitTest: TcxSchedulerCustomResourceViewHitTest; var ABreak: Boolean): Boolean;
var
I: Integer;
begin
Result := False;
for I := 0 to Length(FLines) - 1 do
begin
Result := PtInRect(cxRectInflate(FLines[I], 1, 1), AHitTest.HitPoint);
if Result then
begin
with TcxSchedulerGanttViewHitTest(AHitTest) do
begin
SetBitState(htcLink, True);
FHitObject := Self;
ABreak := True;
end;
Break;
end;
end;
end;
function TcxSchedulerGanttViewLinkViewInfo.GetIsHot: Boolean;
begin
Result := ViewInfo.HotLink = Self;
end;
function TcxSchedulerGanttViewLinkViewInfo.GetStartPoint(
const AStartRect: TRect): TPoint;
begin
Result.Y := (AStartRect.Bottom + AStartRect.Top) div 2;
Result.X := AStartRect.Right;
if Relation in [trStartToStart, trStartToFinish] then
Result.X := AStartRect.Left;
end;
function TcxSchedulerGanttViewLinkViewInfo.GetRelation: TcxSchedulerEventRelation;
begin
Result := EventItemLink.Relation;
end;
procedure TcxSchedulerGanttViewLinkViewInfo.SetClipRegion(ACanvas: TcxCanvas);
var
I: Integer;
begin
ACanvas.SetClipRegion(TcxRegion.Create(ClipRect), roSet);
for I := 0 to ViewInfo.NavigationButtons.Count - 1 do
with ViewInfo.NavigationButtons.Items[I] do
ACanvas.SetClipRegion(TcxRegion.Create(Bounds), roSubtract);
ACanvas.ExcludeClipRect(StartEventViewInfo.Bounds);
ACanvas.ExcludeClipRect(FinishEventViewInfo.Bounds);
end;
procedure TcxSchedulerGanttViewLinkViewInfo.Draw(ACanvas: TcxCanvas);
function CheckRect(const R: TRect): TRect;
begin
Result := R;
if IsHot then
InflateRect(Result, 1, 1);
end;
var
AArrowPoints: TcxArrowPoints;
I: Integer;
begin
ACanvas.SaveClipRegion;
try
SetClipRegion(ACanvas);
TcxCustomLookAndFeelPainter.CalculateArrowPoints(CheckRect(ArrowRect),
AArrowPoints, ArrowDirection, True, LinkLineOffset + Byte(IsHot) * 2);
ACanvas.Polygon(AArrowPoints);
for I := 0 to Length(FLines) - 1 do
ACanvas.FillRect(CheckRect(FLines[I]));
finally
ACanvas.RestoreClipRegion;
end;
end;
{ TcxSchedulerGanttViewPainter }
procedure TcxSchedulerGanttViewPainter.DoDrawExpandButton(
AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean);
begin
// nothing to do
end;
procedure TcxSchedulerGanttViewPainter.DoDrawLinkItem(
AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean);
begin
// nothing to do
end;
function TcxSchedulerGanttViewPainter.GetView: TcxSchedulerGanttView;
begin
Result := inherited View as TcxSchedulerGanttView;
end;
function TcxSchedulerGanttViewPainter.GetViewInfo: TcxSchedulerGanttViewViewInfo;
begin
Result := TcxSchedulerGanttViewViewInfo(inherited ViewInfo);
end;
procedure TcxSchedulerGanttViewPainter.Paint;
begin
inherited Paint;
ViewInfo.Links.Draw(Canvas, DoDrawLinkItem);
ViewInfo.ExpandButtons.Draw(Canvas, DoDrawExpandButton);
if View.ShowTotalProgressLine then
ViewInfo.TotalProgressViewInfo.Draw(Canvas);
View.Controller.EraseDraggingLink;
end;
{ TcxSchedulerGanttViewHitTest }
function TcxSchedulerGanttViewHitTest.GetHitAtEventDraggingArea: Boolean;
function GetEventDraggingArea: TRect;
var
ADragEvent: TcxSchedulerControlEvent;
R: TRect;
begin
Result := cxNullRect;
ADragEvent := View.Controller.DragEvent;
if (View.Controller.DragEventHelper = nil) or (ADragEvent = nil) or (ADragEvent.Source = nil) or
(View = nil) or (View.ViewInfo = nil) then
Exit;
if View.ViewInfo.GetEventBounds(ADragEvent, Resource, R) then
begin
Result := View.ViewInfo.Bounds;
Result.Top := R.Top;
Result.Bottom := R.Bottom;
FCalcEventDraggingArea := True;
end;
end;
begin
if not FCalcEventDraggingArea then
FEventDraggingArea := GetEventDraggingArea;
Result := PtInRect(FEventDraggingArea, HitPoint);
end;
function TcxSchedulerGanttViewHitTest.GetHitExpandButton: TcxSchedulerGanttViewExpandButtonViewInfo;
begin
if FHitObject is TcxSchedulerGanttViewExpandButtonViewInfo then
Result := TcxSchedulerGanttViewExpandButtonViewInfo(FHitObject)
else
Result := nil
end;
function TcxSchedulerGanttViewHitTest.GetHitLink: TcxSchedulerGanttViewLinkViewInfo;
begin
if FHitObject is TcxSchedulerGanttViewLinkViewInfo then
Result := TcxSchedulerGanttViewLinkViewInfo(FHitObject)
else
Result := nil;
end;
function TcxSchedulerGanttViewHitTest.GetView: TcxSchedulerGanttView;
begin
Result := TcxSchedulerGanttView(inherited Owner);
end;
{ TcxSchedulerGanttDragObject }
constructor TcxSchedulerGanttDragObject.Create(AControl: TControl);
begin
inherited Create(AControl);
DragGroupedTaskLinks := True;
end;
function TcxSchedulerGanttDragObject.GetDragCursor(Accepted: Boolean; X, Y: Integer): TCursor;
const
ACursors: array [Boolean] of TCursor = (crNoDrop, crTaskLink);
var
ACursor: Boolean;
begin
if Controller.EventDragMode <> sedmTaskLinkTo then
Result := inherited GetDragCursor(Accepted, X, Y)
else
begin
ACursor := Controller.DragEvent <> nil;
ACursor := ACursor and
(((Controller.HitTest.Resource <> nil) and (Scheduler.Storage.ResourceCount > 0) and Controller.DragEvent.IsResourceEvent(Controller.HitTest.Resource, True)) or
(Scheduler.Storage.ResourceCount = 0));
ACursor := ACursor and ((Controller.HitTest.Event = nil) or
(Controller.DragEvent.Source.CanLink(Controller.HitTest.Event.Source) and Controller.DragEvent.Source.CanLink(Controller.HitTest.Event)));
Result := ACursors[ACursor];
end;
end;
function TcxSchedulerGanttDragObject.GetController: TcxSchedulerGanttViewController;
begin
Result := TcxSchedulerGanttViewController(DragEventHelper.Controller);
end;
{ TcxGanttDragEventHelper }
procedure TcxGanttDragEventHelper.ApplyChanges;
begin
if Controller.EventDragMode <> sedmTaskLinkTo then
inherited ApplyChanges
else
ApplyTaskLinks;
end;
procedure TcxGanttDragEventHelper.ApplyTaskLinks;
var
I: Integer;
begin
for I := 0 to Clones.Count - 1 do
InternalApplyTaskLink(TcxSchedulerControlEvent(TcxSchedulerControlEvent(Clones[I]).Source));
end;
function TcxGanttDragEventHelper.CanDragTo(ADeltaTime: TDateTime): Boolean;
function EventInClones(AEvent: TcxSchedulerEvent): TcxSchedulerControlEvent;
var
I: Integer;
begin
Result := nil;
for I := 0 to Clones.Count - 1 do
begin
if AEvent = TcxSchedulerControlEvent(Clones[I].Source).Source then
begin
Result := Clones[I];
Break;
end;
end;
end;
function CanMoving(AClone: TcxSchedulerControlEvent): Boolean;
var
AStartTime, AFinishTime: TDateTime;
ANewTime: TDateTime;
I: Integer;
ARelation: TcxSchedulerEventRelation;
begin
Result := (AClone.TaskStatus = tsComplete) or (AClone.TaskLinkOwners.Count = 0);
if not Result then
begin
ANewTime := AClone.Source.Start - ADeltaTime;
for I := 0 to AClone.TaskLinkOwners.Count - 1 do
begin
AStartTime := MinDateTime;
AFinishTime := MaxDateTime;
if not AClone.GetTaskLinkOwnerRelation(AClone.TaskLinkOwners[I], ARelation) then
Continue;
TcxSchedulerEventAccess(AClone).GetValidTaskTimeRangeByRelation(ARelation, AClone.TaskLinkOwners[I], AStartTime, AFinishTime);
if EventInClones(AClone.TaskLinkOwners[I]) <> nil then
begin
if AStartTime <> MinDateTime then
AStartTime := AStartTime - ADeltaTime;
if AFinishTime <> MaxDateTime then
AFinishTime := AFinishTime - ADeltaTime;
end;
Result := (AStartTime <= ANewTime) and (AFinishTime >= (ANewTime + AClone.Duration));
if not Result then Break;
end;
end;
end;
var
I: Integer;
begin
Result := True;
for I := 0 to Clones.Count - 1 do
begin
Result := Result and CanMoving(Clones[I]);
if not Result then Break;
end;
end;
procedure TcxGanttDragEventHelper.DragOver(const P: TPoint;
State: TDragState; var Accepted: Boolean);
var
ADeltaTime: TDateTime;
begin
if Controller.EventDragMode <> sedmTaskLinkTo then
inherited DragOver(P, State, Accepted);
case Destination of
dodView:
ADeltaTime := Controller.StartDragHitTime - HitTest.Time;
dodDateNavigator:
ADeltaTime := Controller.StartDragHitTime - TcxSchedulerCustomDateNavigatorAccess(DateNavigator).HitTest.Time;
else
ADeltaTime := MinDateTime;
end;
Accepted := (Accepted or HitTest.HitAtExpandButton or HitTest.HitAtLink) and (CanDragTo(ADeltaTime) or
(Controller.EventDragMode = sedmTaskLinkTo));
end;
procedure TcxGanttDragEventHelper.InternalApplyTaskLink(AEvent: TcxSchedulerControlEvent);
function CreateCustom(APattern: TcxSchedulerEvent; ADate: TDateTime): TcxSchedulerEvent;
begin
Result := APattern.GetOccurrence(ADate);
if Result <> nil then
begin
Result.EventType := etCustom;
Result.Post;
end;
end;
var
AHitEvent, ADragEvent: TcxSchedulerEvent;
AHitEventPattern, ADragEventPattern: TcxSchedulerEvent;
AHitEventDate, ADragEventDate: TDateTime;
ADragEventType: TcxEventType;
begin
if (HitTest.Event <> nil) and (HitTest.Event.Source <> nil) and
not HitTest.Event.IsClone and AEvent.CanLink(HitTest.Event) and AEvent.CanLink(HitTest.Event.Source) and
(Scheduler.Storage <> nil) and (HitTest.Event <> AEvent) and Controller.View.DoEndLinkEvent(HitTest.Event) then
begin
Scheduler.Storage.BeginUpdate;
try
AHitEvent := HitTest.Event;
AHitEventDate := AHitEvent.Start;
AHitEventPattern := AHitEvent.Pattern;
ADragEvent := AEvent;
ADragEventType := AEvent.EventType;
ADragEventDate := AEvent.Start;
ADragEventPattern := ADragEvent.Pattern;
if AHitEvent.EventType = etOccurrence then
AHitEvent := CreateCustom(AHitEventPattern, AHitEventDate)
else
AHitEvent := TcxSchedulerControlEvent(AHitEvent).Source;
if ADragEventType = etOccurrence then
ADragEvent := CreateCustom(ADragEventPattern, ADragEventDate);
if ADragEvent <> nil then
ADragEvent.TaskLinks.Add(AHitEvent, trFinishToStart);
finally
Scheduler.Storage.EndUpdate;
end;
end;
end;
function TcxGanttDragEventHelper.IsAtOrigin: Boolean;
begin
Result := inherited IsAtOrigin and (Controller.EventDragMode <> sedmTaskLinkTo);
end;
procedure TcxGanttDragEventHelper.PrepareGroupedTaskLinks;
function GetControlEvent(ASource: TcxSchedulerEvent): TcxSchedulerControlEvent;
var
I: Integer;
begin
Result := nil;
for I := 0 to Events.Count - 1 do
if Events[I].Source = ASource then
begin
Result := Events[I];
Break;
end;
end;
procedure AddClones(ALinksHeaderEvent: TcxSchedulerEvent);
var
I: Integer;
AEvent: TcxSchedulerControlEvent;
begin
for I := 0 to ALinksHeaderEvent.TaskLinks.Count - 1 do
begin
if (ALinksHeaderEvent.TaskLinks[I].Link = nil) or
(ALinksHeaderEvent.TaskLinks[I].Link.TaskLinkOwners.Count > 1) then Continue;
AEvent := GetControlEvent(ALinksHeaderEvent.TaskLinks[I].Link);
if AEvent = nil then Continue;
Events.Selection.Add(AEvent, [ssCtrl]);
AddClones(ALinksHeaderEvent.TaskLinks[I].Link);
end;
end;
var
I: Integer;
begin
if not DragObject.DragGroupedTaskLinks then Exit;
for I := 0 to DragObject.DragEvents.Count - 1 do
if not ViewInfo.IsTaskLinksExpanded(DragObject.DragEvents[I].TaskLinks) then
AddClones(DragObject.DragEvents[I]);
Events.CreateClones;
end;
procedure TcxGanttDragEventHelper.UpdateViewClonesTime;
var
I: Integer;
ADelta: TDateTime;
begin
ADelta := Controller.StartDragHitTime - HitTest.Time;
if not CanDragTo(ADelta) then
Exit;
for I := 0 to Clones.Count - 1 do
with TcxSchedulerControlEventAccess(Clones[I]) do
InternalMoveTo(Source.Start - ADelta);
CorrectAllDayEventProperty;
end;
function TcxGanttDragEventHelper.GetController: TcxSchedulerGanttViewController;
begin
Result := TcxSchedulerGanttViewController(inherited Controller);
end;
function TcxGanttDragEventHelper.GetDragObject: TcxSchedulerGanttDragObject;
begin
Result := TcxSchedulerGanttDragObject(inherited DragObject);
end;
function TcxGanttDragEventHelper.GetHitTest: TcxSchedulerGanttViewHitTest;
begin
Result := TcxSchedulerGanttViewHitTest(inherited HitTest);
end;
function TcxGanttDragEventHelper.GetViewInfo: TcxSchedulerGanttViewViewInfo;
begin
Result := TcxSchedulerGanttViewViewInfo(inherited ViewInfo);
end;
{ TcxGanttEventSizing }
function TcxGanttEventSizing.CanResize: Boolean;
var
AStartTime, AFinishTime: TDateTime;
begin
TcxSchedulerControlEvent(Event).GetValidTaskTimeRange(AStartTime, AFinishTime);
Result := (HitTest.Time >= AStartTime) and (HitTest.Time < AFinishTime);
end;
procedure TcxGanttEventSizing.DragOver(const P: TPoint; State: TDragState; var Accepted: Boolean);
begin
inherited DragOver(P, State, Accepted);
FHasConflicts := not Accepted;
end;
function TcxGanttEventSizing.IsValidTime: Boolean;
begin
Result := inherited IsValidTime and CanResize;
end;
{ TcxSchedulerGanttViewController }
procedure TcxSchedulerGanttViewController.CheckScrolling(const APos: TPoint);
var
ACanScroll: Boolean;
AScrollCode: TScrollCode;
R: TRect;
begin
if DragEvent = nil then
begin
inherited CheckScrolling(APos);
Exit;
end;
R := GetDragEventClipRect;
FPos := APos;
ACanScroll := True;
AScrollCode := TScrollCode(Timer.Tag);
if APos.X < (R.Left + cxScrollZoneSize) then
begin
AScrollCode := scLineUp;
R.Right := R.Left + cxScrollZoneSize;
FTimerScrollBarKind := sbHorizontal;
end
else
begin
if APos.X >= (R.Right - cxScrollZoneSize) then
begin
AScrollCode := scLineDown;
R.Left := R.Right - cxScrollZoneSize;
FTimerScrollBarKind := sbHorizontal;
end
else
begin
if APos.Y >= (R.Bottom - cxScrollZoneSize) then
begin
AScrollCode := scLineDown;
R.Top := R.Bottom - cxScrollZoneSize;
FTimerScrollBarKind := sbVertical;
end
else
begin
if APos.Y < (R.Top + cxScrollZoneSize) then
begin
AScrollCode := scLineUp;
R.Bottom := R.Top + cxScrollZoneSize;
FTimerScrollBarKind := sbVertical;
end
else
ACanScroll := False;
end;
end;
end;
ACanScroll := ACanScroll and cxRectPtIn(R, APos);
if (ACanScroll <> Timer.Enabled) or (Integer(AScrollCode) <> Timer.Tag) then
InitTimer(ACanScroll, AScrollCode);
end;
procedure TcxSchedulerGanttViewController.CheckTaskLinkDrawOnScroll(AScrollBarKind: TScrollBarKind;
AScrollCode: TScrollCode);
var
ADelta: Integer;
begin
EraseDraggingLink;
if EventDragMode = sedmTaskLinkTo then
begin
ADelta := 0;
case AScrollCode of
scLineDown, scPageDown:
ADelta := -1;
scLineUp, scPageUp:
ADelta := 1;
end;
if ADelta <> 0 then
begin
case AScrollBarKind of
sbHorizontal:
begin
ADelta := ADelta * ViewInfo.FColumnWidth;
Inc(FStartDragPoint.X, ADelta);
end;
sbVertical:
begin
ADelta := ADelta * (ViewInfo.FEventRowHeight);
Inc(FStartDragPoint.Y, ADelta);
end;
end;
end;
end;
PaintDraggingLink(HitTest.HitPoint);
end;
function TcxSchedulerGanttViewController.ConsiderHiddenEvents: Boolean;
begin
Result := False;
end;
function TcxSchedulerGanttViewController.CreateDragEventHelper: TcxDragEventHelper;
begin
Result := TcxGanttDragEventHelper.Create(Scheduler);
end;
function TcxSchedulerGanttViewController.CreateResizeEventHelper: TcxEventSizingHelper;
begin
Result := TcxGanttEventSizing.Create(Scheduler);
end;
procedure TcxSchedulerGanttViewController.DragOver(Source: TObject; X, Y: Integer; State: TDragState;
var Accept: Boolean);
var
ADragMode: TcxSchedulerEventDragMode;
begin
ADragMode := EventDragMode;
if Assigned(DragEventHelper) then
begin
EraseDraggingLink;
UpdateEventDragMode;
end;
inherited DragOver(Source, X, Y, State, Accept);
if ADragMode = sedmTaskLinkTo then
PaintDraggingLink(HitTest.HitPoint);
end;
procedure TcxSchedulerGanttViewController.EndDrag(Target: TObject; X, Y: Integer);
begin
inherited EndDrag(Target, X, Y);
EraseDraggingLink;
EventDragMode := sedmNone;
HitTest.FCalcEventDraggingArea := False;
HitTest.FEventDraggingArea := cxNullRect;
end;
procedure TcxSchedulerGanttViewController.EraseDraggingLink;
begin
if EventDragMode <> sedmTaskLinkTo then Exit;
InternalPaintDraggingLink(FStartDragPoint, FPrevDragPoint);
FPrevDragPoint := FStartDragPoint;
end;
function TcxSchedulerGanttViewController.GetDragEventClipRect: TRect;
begin
Result := FDragEventClipRect;
end;
function TcxSchedulerGanttViewController.GetLinkHintData(var AHint: string): Boolean;
begin
Result := HitTest.HitAtLink and (HitTest.HitLink <> nil);
if Result then
AHint := HitTest.HitLink.Hint;
end;
procedure TcxSchedulerGanttViewController.InitTimer(AllowStart: Boolean; AScrollCode: TScrollCode);
begin
inherited InitTimer(AllowStart, AScrollCode);
if not AllowStart then
FPrevDragPoint := FStartDragPoint;
end;
procedure TcxSchedulerGanttViewController.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
FStartDragPoint := HitTest.HitPoint;
if (Button = mbLeft) and HitTest.HitAtExpandButton then
HitTest.HitExpandButton.DoClick
else
if (Button = mbLeft) and HitTest.HitAtLink then
View.ShowTaskDependencyEditor(HitTest.HitLink.FEventItemLink)
else
inherited MouseDown(Button, Shift, X, Y);
end;
procedure TcxSchedulerGanttViewController.OnTimer(Sender: TObject);
begin
inherited OnTimer(Sender);
FPrevDragPoint := FStartDragPoint;
end;
procedure TcxSchedulerGanttViewController.PaintDraggingLink(const P: TPoint);
begin
if EventDragMode <> sedmTaskLinkTo then Exit;
InternalPaintDraggingLink(FStartDragPoint, P);
FPrevDragPoint := P;
end;
procedure TcxSchedulerGanttViewController.Scrolling(AScrollCode: TScrollCode; var AScrollPos: Integer);
var
ADelta: Integer;
AResourceIndex: Integer;
ALastScrollPos: Integer;
begin
if FTimerScrollBarKind = sbHorizontal then
begin
CheckTaskLinkDrawOnScroll(FTimerScrollBarKind, AScrollCode);
View.Scroll(FTimerScrollBarKind, AScrollCode, AScrollPos);
end
else
begin
if DragEvent = nil then Exit;
ADelta := 0;
case AScrollCode of
scLineUp:
ADelta := -1;
scLineDown:
ADelta := 1;
end;
if ViewInfo.ResourceCount = 0 then
AResourceIndex := 0
else
AResourceIndex := DragEvent.GetResourceItem.Index;
if AResourceIndex >= 0 then
begin
ALastScrollPos := AScrollPos;
AScrollPos := -TcxSchedulerTimeGridResourceScrollAccess(ViewInfo.ResourceViewShift[AResourceIndex]).FShift + ADelta;
if (AScrollPos >= 0) and (AScrollPos <= ViewInfo.GetResourceScrollBarMax(AResourceIndex)) then
begin
CheckTaskLinkDrawOnScroll(FTimerScrollBarKind, AScrollCode);
ViewInfo.DoResourceVerticalScroll(ViewInfo.ResourceViewShift[AResourceIndex].ScrollBar, AScrollCode, AScrollPos);
end
else
begin
EraseDraggingLink;
AScrollPos := ALastScrollPos;
end;
end;
end;
end;
function TcxSchedulerGanttViewController.ShowHint: Boolean;
var
AHintText: string;
begin
Result := GetLinkHintData(AHintText) or GetEventHintData(AHintText);
if Result then
begin
if not SameText(TcxSchedulerHintControllerAccess(HintController).FHintText,
AHintText)
then
InternalHideHint;
InternalShowHint(GetMouseCursorPos, AHintText);
end
else
Result := inherited ShowHint;
end;
procedure TcxSchedulerGanttViewController.StartDrag(var DragObject: TDragObject);
begin
FEventDragMode := sedmNone;
FPrevDragPoint := FStartDragPoint;
HitTest.FCalcEventDraggingArea := False;
HitTest.FEventDraggingArea := cxNullRect;
CalcDragEventClipRect;
inherited StartDrag(DragObject);
DragEventHelper.PrepareGroupedTaskLinks;
end;
procedure TcxSchedulerGanttViewController.UpdateDraggingLink(const P: TPoint);
begin
EraseDraggingLink;
PaintDraggingLink(P);
end;
procedure TcxSchedulerGanttViewController.UpdateEventDragMode;
begin
if (EventDragMode = sedmNone) and not DragEventHelper.IsAtOrigin then
EventDragMode := sedmMoveTo;
if (EventDragMode <> sedmTaskLinkTo) and not IsCopyDragDrop and not HitTest.HitAtEventDraggingArea and
((EventDragMode = sedmNone) or (HitTest.HitAtEvent and (HitTest.Event.Source <> DragEvent))) then
EventDragMode := sedmTaskLinkTo;
end;
procedure TcxSchedulerGanttViewController.CalcDragEventClipRect;
var
AViewInfo: TcxSchedulerEventCellViewInfo;
begin
if (DragEvent <> nil) and
ViewInfo.FindEventViewInfoBySource(DragEvent.Source, DateOf(DragEvent.Start), HitTest.Resource, AViewInfo) then
FDragEventClipRect := ViewInfo.GetEventClipRect(AViewInfo)
else
FDragEventClipRect := cxEmptyRect;
end;
function TcxSchedulerGanttViewController.GetDragEventHelper: TcxGanttDragEventHelper;
begin
Result := TcxGanttDragEventHelper(inherited DragEventHelper);
end;
function TcxSchedulerGanttViewController.GetEventHintData(var AHint: string): Boolean;
var
AEvent: TcxSchedulerControlEvent;
begin
Result := (EventDragMode = sedmNone) and HitTest.HitAtEvent;
if Result then
begin
AEvent := HitTest.Event;
AHint := View.GetEventHintText(AEvent);
TcxCustomSchedulerAccess(Scheduler).GetEventUserHintText(AEvent, AHint);
end;
end;
function TcxSchedulerGanttViewController.GetHitTest: TcxSchedulerGanttViewHitTest;
begin
Result := View.HitTest;
end;
function TcxSchedulerGanttViewController.GetView: TcxSchedulerGanttView;
begin
Result := TcxSchedulerGanttView(inherited View);
end;
function TcxSchedulerGanttViewController.GetViewInfo: TcxSchedulerGanttViewViewInfo;
begin
Result := View.ViewInfo;
end;
procedure TcxSchedulerGanttViewController.InternalPaintDraggingLink(const AStart, AFinish: TPoint);
begin
if (AStart.X = AFinish.X) and (AStart.Y = AFinish.Y) then
Exit;
with View.GetControlCanvas do
begin
SaveClipRegion;
try
SetClipRegion(TcxRegion.Create(GetDragEventClipRect), roSet);
Pen.Mode := pmNotXor;
Pen.Style := psSolid;
Pen.Color := View.LinkLineColor;
MoveTo(AStart.X, AStart.Y);
LineTo(AFinish.X, AFinish.Y);
finally
RestoreClipRegion;
end;
end;
end;
procedure TcxSchedulerGanttViewController.SetEventDragMode(AValue: TcxSchedulerEventDragMode);
var
I: Integer;
begin
if AValue = FEventDragMode then Exit;
if AValue = sedmTaskLinkTo then
begin
if not View.DoStartLinkEvent(DragEvent) then Exit;
for I := 0 to DragEventHelper.Clones.Count -1 do
with DragEventHelper.Clones[I] do
begin
MoveTo(Source.Start);
ResourceID := Source.ResourceID;
end;
View.Refresh;
FPrevDragPoint := FStartDragPoint;
end;
FEventDragMode := AValue;
end;
{ TcxSchedulerGanttViewEventLayoutBuilder }
procedure TcxSchedulerGanttViewEventLayoutBuilder.Calculate;
function FindStartOfRecurrence(AEventPlace: TcxSchedulerEventPlace;
ACheckEventPlaceCount: Integer; out AIndex: Integer): Boolean;
var
AMin: Integer;
APlace: TcxSchedulerEventPlace;
I: Integer;
begin
Result := False;
if AEventPlace.Event.Pattern <> nil then
begin
AMin := MAXINT;
for I := 0 to ACheckEventPlaceCount - 1 do
begin
APlace := EventPlaces[I];
if (APlace.Resource = AEventPlace.Resource) and
(APlace.Event.Pattern = AEventPlace.Event.Pattern) and
(APlace.Event.RecurrenceIndex < AMin) and
(((I > 0) and (APlace.LineStart >= 0)) or (I = 0)) then
begin
AMin := APlace.Event.RecurrenceIndex;
Result := APlace <> AEventPlace;
if Result then
AIndex := APlace.LineStart;
end;
end;
end;
end;
procedure CheckEventPlaceResource(AEventPlace: TcxSchedulerEventPlace;
var ALastResource, APlaceIndex: Integer);
begin
if ALastResource <> Integer(AEventPlace.Resource) then
begin
ALastResource := Integer(AEventPlace.Resource);
APlaceIndex := 0;
end;
end;
function GetTaskIndex(AEventPlace: TcxSchedulerEventPlace;
ACheckEventPlaceCount: Integer; var APlaceIndex: Integer): Integer;
begin
if not FindStartOfRecurrence(AEventPlace, ACheckEventPlaceCount, APlaceIndex) then
APlaceIndex := Max(AEventPlace.Event.TaskIndex, APlaceIndex);
Result := APlaceIndex;
Inc(APlaceIndex);
end;
var
AEventPlace: TcxSchedulerEventPlace;
APlaceIndex: Integer;
ALastResource: Integer;
I: Integer;
begin
APlaceIndex := 0;
ALastResource := -1;
EventPlacesList.Sort(TListSortCompare(@cxGanttViewCompareEventPlaces));
for I := 0 to EventPlaceCount - 1 do
begin
AEventPlace := EventPlaces[I];
CheckEventPlaceResource(AEventPlace, ALastResource, APlaceIndex);
AEventPlace.LineStart := GetTaskIndex(AEventPlace, I + 1, APlaceIndex);
AEventPlace.LineFinish := AEventPlace.LineStart;
end;
end;
{ TcxSchedulerGanttViewExpandButtonViewInfo }
procedure TcxSchedulerGanttViewExpandButtonViewInfo.Draw(ACanvas: TcxCanvas);
begin
Painter.DrawExpandButton(ACanvas, Bounds, Expanded);
end;
procedure TcxSchedulerGanttViewExpandButtonViewInfo.DoClick;
begin
with Event.TaskLinks do
Expanded := not Expanded;
end;
procedure TcxSchedulerGanttViewExpandButtonViewInfo.InitHitTest(
AHitTest: TcxSchedulerCustomResourceViewHitTest);
begin
inherited InitHitTest(AHitTest);
TcxSchedulerGanttViewHitTest(AHitTest).SetBitState(htcExpandButton, True);
end;
{ TcxSchedulerGanttViewTotalProgressViewInfo }
constructor TcxSchedulerGanttViewTotalProgressViewInfo.Create(
AViewInfo: TcxSchedulerGanttViewViewInfo);
begin
FViewInfo := AViewInfo;
end;
procedure TcxSchedulerGanttViewTotalProgressViewInfo.Calculate;
begin
FDrawAsPolyline := ViewInfo.View.EventsStyle = esProgress;
FLineColor := ViewInfo.View.TotalProgressLineColor;
FTimeLineRect := GetTimeLineRect;
FContentArea := ViewInfo.Bounds;
Inc(FContentArea.Left, ViewInfo.ResourceHeaderWidth);
if DrawAsPolyline then
CalculatePolyline;
end;
procedure TcxSchedulerGanttViewTotalProgressViewInfo.CalculatePolyline;
var
ANodeIndex: Integer;
APointIndex: Integer;
AVisibleLineCount: Integer;
I: Integer;
R: TRect;
procedure AddPoint(X, Y: Integer);
begin
FPoints[APointIndex] := Point(X, Y);
Inc(APointIndex);
end;
procedure AddPointsByResource(const ALine, ABounds: TRect;
AResource: TcxSchedulerStorageResourceItem);
var
APoint: TPoint;
ATop: Integer;
begin
ATop := ABounds.Top;
while ATop < ABounds.Bottom do
begin
AddPoint(ALine.Left, ATop);
Inc(ATop, ViewInfo.IndentBetweenLines);
if GetUncompliteEventPoint(Rect(ALine.Left, ATop, ALine.Right,
ATop + ViewInfo.ContentLineHeight), APoint, AResource)
then
begin
AddPoint(ALine.Left, ATop);
AddPoint(APoint.X, ATop + ViewInfo.ContentLineHeight div 2);
FProgressNodes[ANodeIndex] := Point(APoint.X,
ATop + ViewInfo.ContentLineHeight div 2);
Inc(ANodeIndex);
end;
Inc(ATop, ViewInfo.ContentLineHeight);
end;
AddPoint(ALine.Left, ABounds.Bottom);
end;
begin
APointIndex := 0;
ANodeIndex := 0;
AVisibleLineCount := (1 + cxRectHeight(ViewInfo.Bounds) div ViewInfo.FEventRowHeight);
SetLength(FPoints, 3 * AVisibleLineCount);
SetLength(FProgressNodes, AVisibleLineCount);
AddPoint(TimeLineRect.Left, TimeLineRect.Top);
if ViewInfo.ResourceCount = 0 then
begin
R := ViewInfo.Bounds;
R.Top := ViewInfo.ScalesHeight;
AddPointsByResource(TimeLineRect, R, nil);
end
else
for I := 0 to ViewInfo.ResourceCount - 1 do
begin
AddPointsByResource(TimeLineRect, ViewInfo.ResourceHeaderCells.Items[I + 1].Bounds,
ViewInfo.Resources[I].ResourceItem);
end;
SetLength(FPoints, APointIndex);
SetLength(FProgressNodes, ANodeIndex);
end;
procedure TcxSchedulerGanttViewTotalProgressViewInfo.Draw(ACanvas: TcxCanvas);
var
I: Integer;
begin
ACanvas.SaveClipRegion;
try
ACanvas.SetClipRegion(TcxRegion.Create(ContentArea), roSet);
for I := 0 to ViewInfo.NavigationButtons.Count - 1 do
with ViewInfo.NavigationButtons.Items[I] do
ACanvas.SetClipRegion(TcxRegion.Create(Bounds), roSubtract);
for I := 0 to ViewInfo.GroupSeparatorCells.Count - 1 do
ACanvas.ExcludeClipRect(ViewInfo.GroupSeparatorCells.Items[I].Bounds);
if DrawAsPolyline then
begin
ACanvas.Pen.Color := LineColor;
ACanvas.Polyline(FPoints);
DrawProgressNodes(ACanvas);
end
else
ACanvas.FillRect(TimeLineRect, LineColor);
finally
ACanvas.RestoreClipRegion;
end;
end;
procedure TcxSchedulerGanttViewTotalProgressViewInfo.DrawProgressNodes(
ACanvas: TcxCanvas);
var
I: Integer;
R: TRect;
begin
ACanvas.Brush.Color := LineColor;
for I := 0 to High(FProgressNodes) do
begin
R.TopLeft := FProgressNodes[I];
R.BottomRight := FProgressNodes[I];
InflateRect(R, ProgressNodeRadius, ProgressNodeRadius);
ACanvas.Canvas.Ellipse(R);
end;
end;
function TcxSchedulerGanttViewTotalProgressViewInfo.FindUncompliteEventBeforeLine(
const ALine: TRect; AResource: TcxSchedulerStorageResourceItem;
var AViewInfo: TcxSchedulerEventCellViewInfo): Boolean;
var
AEventViewInfo: TcxSchedulerEventCellViewInfo;
I: Integer;
R: TRect;
begin
Result := False;
for I := 0 to ViewInfo.EventCells.Count - 1 do
begin
AEventViewInfo := TcxSchedulerEventCellViewInfo(ViewInfo.EventCells.Items[I]);
R := AEventViewInfo.Bounds;
if (AResource = nil) or (AResource = AEventViewInfo.ResourceItem) then
if (R.Left <= ALine.Left) and (R.Top >= ALine.Top) and (R.Bottom <= ALine.Bottom) then
if (AEventViewInfo.Event.TaskComplete < 100) and not AEventViewInfo.Hidden then
begin
AViewInfo := AEventViewInfo;
Result := True;
Break; // todo: need find nearest event (not first!)
end;
end;
end;
function TcxSchedulerGanttViewTotalProgressViewInfo.GetTimeLineApproximateRect: TRect;
var
AVisibleStart: TDateTime;
begin
AVisibleStart := ViewInfo.View.VisibleStart;
if Now > AVisibleStart then
begin
Result := ViewInfo.Bounds;
Inc(Result.Left, ViewInfo.ResourceHeaderWidth);
Inc(Result.Left, Trunc((Now - AVisibleStart) *
(Result.Right - Result.Left) / (ViewInfo.FLastVisibleTime - AVisibleStart)));
Result.Right := Result.Left;
end
else
Result := cxEmptyRect;
end;
function TcxSchedulerGanttViewTotalProgressViewInfo.GetTimeLineRect: TRect;
var
ACell: TcxSchedulerTimeGridSelectionBarCell;
AItem: TcxSchedulerCustomViewInfoItem;
I: Integer;
begin
Result := cxEmptyRect;
for I := 0 to ViewInfo.TimeLineCells.Count - 1 do
begin
AItem := ViewInfo.TimeLineCells.Items[I];
if AItem is TcxSchedulerTimeGridSelectionBarCell then
begin
ACell := TcxSchedulerTimeGridSelectionBarCell(AItem);
if ACell.IsCurrentTimeCell then
begin
Result := ACell.TimeLineRect;
Break;
end;
end;
end;
if IsRectEmpty(Result) then
Result := GetTimeLineApproximateRect;
end;
function TcxSchedulerGanttViewTotalProgressViewInfo.GetUncompliteEventPoint(
const ALine: TRect; var P: TPoint;
AResource: TcxSchedulerStorageResourceItem): Boolean;
var
AEventViewInfo: TcxSchedulerEventCellViewInfo;
R: TRect;
begin
Result := FindUncompliteEventBeforeLine(ALine, AResource, AEventViewInfo);
if Result then
begin
R := cxRectContent(AEventViewInfo.Bounds,
ViewInfo.View.ExternalPainter.Painter.SchedulerEventProgressOffsets);
P := Point(Min(ALine.Left, R.Left + Trunc((R.Right - R.Left) *
AEventViewInfo.Event.TaskComplete / 100)), (ALine.Top + ALine.Bottom) div 2);
end;
end;
{ TcxSchedulerGanttViewViewInfo }
constructor TcxSchedulerGanttViewViewInfo.Create(AOwner: TcxSchedulerSubControl);
begin
inherited Create(AOwner);
FExpandButtons := TcxSchedulerViewInfoCellList.Create;
FLinks := TcxSchedulerViewInfoCellList.Create;
FTotalProgressViewInfo := TcxSchedulerGanttViewTotalProgressViewInfo.Create(Self);
FVisibleEventEnumerationList := TcxObjectList.Create;
FCells.Add(FExpandButtons);
FCells.Add(FLinks);
end;
destructor TcxSchedulerGanttViewViewInfo.Destroy;
begin
FreeAndNil(FTotalProgressViewInfo);
FreeAndNil(FVisibleEventEnumerationList);
inherited Destroy;
end;
procedure TcxSchedulerGanttViewViewInfo.AddEventForCalculation(
ABuilder: TcxSchedulerEventLayoutBuilder; AEvent: TcxSchedulerControlEvent;
AResourceIndex: Integer);
begin
if not IsEventCollapsed(AEvent, False) then
inherited AddEventForCalculation(ABuilder, AEvent, AResourceIndex);
end;
procedure TcxSchedulerGanttViewViewInfo.CalculateExpandButtonViewInfos;
function CalculateButtonBounds(const AEventRect: TRect): TRect;
var
ASize: Integer;
begin
ASize := LookAndFeelPainter.ExpandButtonSize;
Result.Left := AEventRect.Right - ASize;
Result.Top := (AEventRect.Top + AEventRect.Bottom - ASize) div 2;
Result.Bottom := Result.Top + ASize;
Result.Right := AEventRect.Right;
OffsetRect(Result, 3, 0);
end;
var
AButtonViewInfo: TcxSchedulerGanttViewExpandButtonViewInfo;
AEventCell: TcxSchedulerEventCellViewInfo;
I: Integer;
begin
if not FShowLinks then Exit;
FExpandButtons.Clear;
if View.ShowExpandButtons then
for I := 0 to EventCells.Count - 1 do
begin
AEventCell := TcxSchedulerEventCellViewInfo(EventCells.Items[I]);
if AEventCell.Event.TaskLinks = nil then Continue;
if not AEventCell.Hidden and (AEventCell.Event.NonExceptionLinkCount > 0) then
begin
CreateCellInstance(TcxSchedulerGanttViewExpandButtonViewInfo,
CalculateButtonBounds(AEventCell.Bounds), LinkViewParams, AButtonViewInfo);
AButtonViewInfo.FExpanded := IsTaskLinksExpanded(AEventCell.Event.TaskLinks);
AButtonViewInfo.FEvent := AEventCell.Event;
FExpandButtons.Add(AButtonViewInfo);
end;
end;
end;
procedure TcxSchedulerGanttViewViewInfo.CalculateHitTest(
AHitTest: TcxSchedulerCustomResourceViewHitTest);
begin
if (View.Controller.DragEventHelper <> nil) or
((View.Controller.DragAndDropObject <> nil) and (View.Controller.DragAndDropObject.SizingHelper <> nil)) or
not (ExpandButtons.CalculateHitTest(AHitTest) or Links.CalculateHitTest(AHitTest)) then
inherited CalculateHitTest(AHitTest);
if GetIsHotTrackEnabled then
HotLink := TcxSchedulerGanttViewHitTest(AHitTest).HitLink
else
HotLink := nil;
end;
procedure TcxSchedulerGanttViewViewInfo.CheckEventVisibility(
ACell: TcxSchedulerEventCellViewInfo; AIndex: Integer);
begin
if not ACell.Hidden and IsEventCollapsed(ACell.Event, False) then
begin
ACell.Free;
FEventCells.Delete(AIndex);
end;
end;
procedure TcxSchedulerGanttViewViewInfo.Clear;
begin
inherited Clear;
FVisibleEventEnumerationList.Clear;
FVisibleEventWithoutResourceCount := 0;
end;
function TcxSchedulerGanttViewViewInfo.CreateEventViewData(
AEvent: TcxSchedulerControlEvent; const ABounds: TRect; const AStart: TDateTime;
const AFinish: TDateTime; AResource: TcxSchedulerResourceViewInfo): TcxSchedulerEventViewData;
procedure IncreaseVisibleEventCounter;
var
AResourceIndex: Integer;
AResourceFound: Boolean;
begin
AResourceFound := False;
for AResourceIndex := 0 to ResourceCount - 1 do
if AEvent.IsSharedWithResource(VisibleEventEnumerationList[AResourceIndex].ResourceID) then
begin
VisibleEventEnumerationList[AResourceIndex].VisibleEventCount :=
VisibleEventEnumerationList[AResourceIndex].VisibleEventCount + 1;
AResourceFound := True;
end;
if not AResourceFound then
Inc(FVisibleEventWithoutResourceCount);
end;
begin
Result := inherited CreateEventViewData(AEvent, ABounds, AStart, AFinish, AResource);
Result.DrawAsProgress := View.EventsStyle = esProgress;
if (AEvent.Start < FLastVisibleTime) and
(AEvent.Finish > View.VisibleStart) then
IncreaseVisibleEventCounter;
end;
function TcxSchedulerGanttViewViewInfo.CreateLayoutBuilder: TcxSchedulerEventLayoutBuilder;
begin
Result := TcxSchedulerGanttViewEventLayoutBuilder.Create;
end;
function TcxSchedulerGanttViewViewInfo.CreateLinkItemViewInfo(
AEventViewInfo: TcxSchedulerEventCellViewInfo;
AEventItemLink: TcxSchedulerEventItemLink;
out ALinkItem: TcxSchedulerGanttViewLinkViewInfo): Boolean;
var
AFinishViewInfo: TcxSchedulerEventCellViewInfo;
begin
Result := AEventItemLink.Link <> nil;
if Result then
begin
Result := FindEventViewInfoBySource(AEventItemLink.Link, AEventItemLink.Link.Start,
AEventViewInfo.ResourceItem, AFinishViewInfo);
if Result then
begin
CreateCellInstance(TcxSchedulerGanttViewLinkViewInfo, AEventViewInfo.Bounds,
AEventViewInfo.Bounds, LinkViewParams, ALinkItem);
ALinkItem.Initialize(Self, AEventViewInfo, AFinishViewInfo, AEventItemLink);
end;
end;
end;
procedure TcxSchedulerGanttViewViewInfo.CreateLinks;
var
AEventViewInfo: TcxSchedulerEventCellViewInfo;
ALinkItem: TcxSchedulerGanttViewLinkViewInfo;
ALinkIndex: Integer;
ATaskLinks: TcxSchedulerEventLinks;
I: Integer;
begin
if not FShowLinks then Exit;
for I := 0 to EventCells.Count - 1 do
begin
AEventViewInfo := TcxSchedulerEventCellViewInfo(EventCells.Items[I]);
ATaskLinks := AEventViewInfo.Event.TaskLinks;
if (ATaskLinks = nil) or not IsTaskLinksExpanded(ATaskLinks) then Continue;
for ALinkIndex := 0 to ATaskLinks.Count - 1 do
if CreateLinkItemViewInfo(AEventViewInfo, ATaskLinks.ItemLinks[ALinkIndex],
ALinkItem)
then
FLinks.Add(ALinkItem);
end;
end;
procedure TcxSchedulerGanttViewViewInfo.DoCalculate;
begin
Adapter.GetPageResources(FVisibleEventEnumerationList);
inherited DoCalculate;
CalculateExpandButtonViewInfos;
if View.ShowTotalProgressLine then
TotalProgressViewInfo.Calculate;
RecreateLinks;
end;
function TcxSchedulerGanttViewViewInfo.FindEventViewInfoBySource(
AEvent: TcxSchedulerEvent; const ADate: TDateTime;
AResource: TcxSchedulerStorageResourceItem;
var AViewInfo: TcxSchedulerEventCellViewInfo): Boolean;
var
ATempViewInfo: TcxSchedulerEventCellViewInfo;
I: Integer;
begin
AViewInfo := nil;
for I := 0 to EventCells.Count - 1 do
begin
ATempViewInfo := TcxSchedulerEventCellViewInfo(EventCells.Items[I]);
if ATempViewInfo.Event.IsOrigin(AEvent) then
if (AResource = nil) or (ATempViewInfo.ResourceItem = AResource) then
begin
AViewInfo := ATempViewInfo;
with TcxSchedulerEventCellViewInfoAccess(ATempViewInfo) do
if (ADate = NullDate) or ((DateOf(ContentStart) = ADate) or
(IsHeaderEvent and (ADate >= DateOf(ContentStart)) and
(ADate < DateOf(ContentFinish))))
then
Break;
end;
end;
Result := AViewInfo <> nil;
end;
function TcxSchedulerGanttViewViewInfo.GetEventBounds(AEvent: TcxSchedulerControlEvent; AResource: TcxSchedulerStorageResourceItem; out AEventRect: TRect): Boolean;
var
I: Integer;
ATempViewInfo: TcxSchedulerEventCellViewInfo;
begin
Result := False;
for I := 0 to EventCells.Count - 1 do
begin
ATempViewInfo := TcxSchedulerEventCellViewInfo(EventCells.Items[I]);
Result := (ATempViewInfo.Event = AEvent) and (ATempViewInfo.ResourceItem = AResource);
if Result then
begin
AEventRect := ATempViewInfo.Bounds;
Break;
end;
end;
end;
function TcxSchedulerGanttViewViewInfo.GetEventForResourceCount(
AResourceIndex: Integer; out AResourceID: Variant): Integer;
var
I: Integer;
AFound: Boolean;
begin
Result := inherited GetEventForResourceCount(AResourceIndex, AResourceID);
AFound := False;
I := 0;
while (I < ResourceCount) and not AFound do
begin
if VarEquals(VisibleEventEnumerationList[I].ResourceID, AResourceID) then
begin
Result := VisibleEventEnumerationList[I].VisibleEventCount;
AFound := True;
end;
Inc(I);
end;
end;
function TcxSchedulerGanttViewViewInfo.GetEventWithoutResourceCount: Integer;
begin
Result := FVisibleEventWithoutResourceCount;
end;
function TcxSchedulerGanttViewViewInfo.GetGanttView: TcxSchedulerGanttView;
begin
Result := TcxSchedulerGanttView(inherited View);
end;
function TcxSchedulerGanttViewViewInfo.GetIndentBetweenLines: Integer;
begin
Result := 3 * LinkLineOffset;
end;
function TcxSchedulerGanttViewViewInfo.GetNeedShowCurrentTime: Boolean;
begin
Result := not View.ShowTotalProgressLine;
end;
function TcxSchedulerGanttViewViewInfo.GetIsHotTrackEnabled: Boolean;
begin
Result := View.Scheduler.OptionsBehavior.HotTrack and (View.Controller.EventDragMode = sedmNone);
end;
function TcxSchedulerGanttViewViewInfo.GetLinkViewParams: TcxViewParams;
begin
Result.Bitmap := nil;
Result.Color := View.LinkLineColor;
Result.Font := Scheduler.Font;
Result.TextColor := View.LinkLineColor;
end;
function TcxSchedulerGanttViewViewInfo.GetVisibleEventEnumeration(
AIndex: Integer): TcxSchedulerResourceViewInfo;
begin
if (FVisibleEventEnumerationList <> nil) and
(AIndex < FVisibleEventEnumerationList.Count) then
Result := TcxSchedulerResourceViewInfo(FVisibleEventEnumerationList[AIndex])
else
Result := nil;
end;
function TcxSchedulerGanttViewViewInfo.HasVisibleEvents: Boolean;
var
AResourceIndex, AEventCount: Integer;
begin
AEventCount := 0;
for AResourceIndex := 0 to ResourceCount - 1 do
Inc(AEventCount, VisibleEventEnumerationList[AResourceIndex].VisibleEventCount);
Result := AEventCount + GetEventWithoutResourceCount <> 0;
end;
function TcxSchedulerGanttViewViewInfo.IsEventCollapsed(AEvent: TcxSchedulerEvent;
AHidden: Boolean): Boolean;
var
AOwnerEvent: TcxSchedulerEvent;
I: Integer;
begin
Result := AHidden;
if Result or (AEvent.TaskLinkOwners = nil) then Exit;
for I := 0 to AEvent.TaskLinkOwners.Count - 1 do
begin
AOwnerEvent := AEvent.TaskLinkOwners.Items[I];
Result := IsEventCollapsed(AOwnerEvent,
not IsTaskLinksExpanded(AOwnerEvent.TaskLinks));
if not Result then
Break;
end;
end;
function TcxSchedulerGanttViewViewInfo.IsTaskLinksExpanded(
ATaskLinks: TcxSchedulerEventLinks): Boolean;
begin
Result := not View.ShowExpandButtons or ATaskLinks.Expanded;
end;
function TcxSchedulerGanttViewViewInfo.NavigationButtonOffset(
AKind: TcxSchedulerContentNavigationButtonKind;
AResourceIndex: Integer): Integer;
begin
AResourceIndex := Max(AResourceIndex, 0);
if (AKind = nbkNext) and
(TcxSchedulerTimeGridResourceScroll(ResourceViewShift[AResourceIndex]).ScrollBar <> nil) then
Result := -TcxSchedulerTimeGridResourceScroll(ResourceViewShift[AResourceIndex]).ScrollBar.Width
else
Result := 0;
end;
procedure TcxSchedulerGanttViewViewInfo.RecreateLinks;
begin
Links.Clear;
CreateLinks;
end;
procedure TcxSchedulerGanttViewViewInfo.SetHotLink(
AHotLink: TcxSchedulerGanttViewLinkViewInfo);
function GetRefreshRect(AOldLink, ANewLink: TcxSchedulerGanttViewLinkViewInfo): TRect;
begin
if ANewLink = nil then
Result := AOldLink.ClipRect
else
Result := ANewLink.ClipRect;
end;
var
AOldLink: TcxSchedulerGanttViewLinkViewInfo;
begin
if HotLink <> AHotLink then
begin
AOldLink := HotLink;
FHotLink := AHotLink;
View.RepaintRect(GetRefreshRect(AOldLink, HotLink));
end;
end;
end.