You've already forked lazarus-ccr
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8461 8e941d3f-bd1b-0410-a28a-d453659cc2b4
1923 lines
52 KiB
ObjectPascal
1923 lines
52 KiB
ObjectPascal
unit VpGanttView;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
LCLType, LCLIntf, LMessages,
|
|
Classes, SysUtils, Graphics, Types, Controls, StdCtrls, Menus, Forms,
|
|
VpConst, VpMisc, VpBase, VpBaseDS, VpData;
|
|
|
|
type
|
|
TVpGanttViewOption = (
|
|
gvoActiveDate, gvoHorizGrid, gvoVertGrid, gvoWeekends, gvoHolidays
|
|
);
|
|
TVpGanttViewOptions = set of TVpGanttViewOption;
|
|
|
|
TVpGanttSpecialDayMode = (sdmColumn, sdmHeader);
|
|
|
|
const
|
|
DEFAULT_GANTTVIEWOPTIONS = [
|
|
gvoActiveDate, gvoHorizGrid, gvoVertGrid, gvoWeekends, gvoHolidays
|
|
];
|
|
|
|
type
|
|
TVpGanttView = class;
|
|
|
|
TVpGanttEventRec = record
|
|
Event: TVpEvent;
|
|
Caption: String;
|
|
HeadRect: TRect;
|
|
EventRect: TRect;
|
|
end;
|
|
|
|
TVpGanttDayRec = record
|
|
Date: TDateTime;
|
|
Rect: TRect;
|
|
end;
|
|
|
|
TVpGanttMonthRec = record
|
|
Date: TDateTime;
|
|
Rect: TRect;
|
|
end;
|
|
|
|
TVpGanttHeaderAttributes = class(TPersistent)
|
|
private
|
|
FGanttView: TVpGanttView;
|
|
FColor: TColor;
|
|
procedure SetColor(AValue: TColor);
|
|
protected
|
|
procedure UpdateGanttView;
|
|
public
|
|
constructor Create(AOwner: TVpGanttView); virtual;
|
|
published
|
|
property Color: TColor read FColor write SetColor default DEFAULT_HEADERCOLOR;
|
|
end;
|
|
|
|
TVpGanttRowHeaderAttributes = class(TVpGanttHeaderAttributes)
|
|
private
|
|
FEventFont: TVpFont;
|
|
procedure SetEventFont(AValue: TVpFont);
|
|
protected
|
|
public
|
|
constructor Create(AOwner: TVpGanttView); override;
|
|
destructor Destroy; override;
|
|
published
|
|
property EventFont: TVpFont read FEventFont write SetEventFont;
|
|
end;
|
|
|
|
TVpGanttColHeaderAttributes = class(TVpGanttHeaderAttributes)
|
|
private
|
|
FDayFont: TVpFont;
|
|
FMonthFont: TVpFont;
|
|
procedure SetDayFont(AValue: TVpFont);
|
|
procedure SetMonthFont(AValue: TVpFont);
|
|
public
|
|
constructor Create(AOwner: TVpGanttView); override;
|
|
destructor Destroy; override;
|
|
published
|
|
property DayFont: TVpFont read FDayFont write SetDayFont;
|
|
property MonthFont: TVpFont read FMonthFont write SetMonthFont;
|
|
end;
|
|
|
|
TVpGanttView = class(TVpLinkableControl)
|
|
private
|
|
FActiveCol: Integer; // Selected column
|
|
FActiveRow: Integer; // Selected row
|
|
FActiveEvent: TVpEvent; // Selected event
|
|
FActiveDate: TDateTime; // Selected date
|
|
FFirstDate: TDateTime; // Date of the first event in the resource
|
|
FLastDate: TDateTime; // Date of the last event in the resource
|
|
FStartDate: TDateTime; // Date of the first event to be displayed/printed
|
|
FEndDate: TDateTime; // Date of the last event to be displayed/printed
|
|
|
|
FLeftCol: Integer; // Index of the left-most day column
|
|
FTopRow: Integer; // Index of the top-most event row
|
|
FVisibleCols: Integer;
|
|
FVisibleRows: Integer;
|
|
FRowCount: Integer;
|
|
FColCount: Integer;
|
|
FScrollBars: TScrollStyle;
|
|
|
|
FInLinkHandler: Boolean;
|
|
FLoaded: Boolean;
|
|
FPainting: Boolean;
|
|
FMouseDown: Boolean;
|
|
FMouseDownPoint: TPoint;
|
|
|
|
FColWidth: Integer;
|
|
FFixedColWidth: Integer;
|
|
FRowHeight: Integer;
|
|
FMonthColHeaderHeight: Integer;
|
|
FDayColHeaderHeight: Integer;
|
|
FTotalColHeaderHeight: Integer;
|
|
FTextMargin: Integer;
|
|
|
|
FColor: TColor;
|
|
FHolidayColor: TColor;
|
|
FLineColor: TColor;
|
|
FWeekendColor: TColor;
|
|
|
|
FColHeaderAttributes: TVpGanttColHeaderAttributes;
|
|
FRowHeaderAttributes: TVpGanttRowHeaderAttributes;
|
|
|
|
FComponentHint: TTranslateString;
|
|
FDateFormat: array[0..2] of String;
|
|
FDrawingStyle: TVpDrawingStyle;
|
|
FDefaultPopup: TPopupMenu;
|
|
FExternalPopup: TPopupMenu;
|
|
FHintMode: TVpHintMode;
|
|
FMouseEvent: TVpEvent;
|
|
FOptions: TVpGanttViewOptions;
|
|
FSpecialDayMode: TVpGanttSpecialDayMode;
|
|
FTimeFormat: TVpTimeFormat;
|
|
|
|
FOnAddEvent: TVpOnAddNewEvent;
|
|
FOnDeletingEvent: TVpOnDeletingEvent;
|
|
FOnHoliday: TVpHolidayEvent;
|
|
FOnModifyEvent: TVpOnModifyEvent;
|
|
FOwnerEditEvent: TVpEditEvent;
|
|
|
|
function GetDateFormat(AIndex: Integer): String;
|
|
function GetDayRec(AIndex: Integer): TVpGanttDayRec;
|
|
function GetEventRec(AIndex: Integer): TVpGanttEventRec;
|
|
function GetMonthRec(AIndex: Integer): TVpGanttMonthRec;
|
|
function GetNumDays: Integer;
|
|
function GetNumEvents: Integer;
|
|
function GetNumMonths: Integer;
|
|
function IsStoredColWidth: Boolean;
|
|
function IsStoredDateFormat(AIndex: Integer): Boolean;
|
|
procedure SetActiveCol(AValue: Integer);
|
|
procedure SetActiveDate(AValue: TDateTime);
|
|
procedure SetActiveEvent(AValue: TVpEvent);
|
|
procedure SetActiveRow(AValue: Integer);
|
|
procedure SetColor(Value: TColor); reintroduce;
|
|
procedure SetColWidth(AValue: Integer);
|
|
procedure SetDateFormat(AIndex: Integer; AValue: String);
|
|
procedure SetDrawingStyle(AValue: TVpDrawingStyle);
|
|
procedure SetFixedColWidth(AValue: Integer);
|
|
procedure SetHolidayColor(AValue: TColor);
|
|
procedure SetLeftCol(AValue: Integer);
|
|
procedure SetLineColor(AValue: TColor);
|
|
procedure SetOptions(AValue: TVpGanttViewOptions);
|
|
procedure SetPopupMenu(AValue: TPopupMenu);
|
|
procedure SetSpecialDayMode(AValue: TVpGanttSpecialDayMode);
|
|
procedure SetTextMargin(AValue: Integer);
|
|
procedure SetTopRow(AValue: Integer);
|
|
procedure SetWeekendColor(AValue: TColor);
|
|
|
|
protected
|
|
// Needed by the painter
|
|
FEventRecords: array of TVpGanttEventRec;
|
|
FDayRecords: array of TVpGanttDayRec;
|
|
FMonthRecords: array of TVpGanttMonthRec;
|
|
|
|
{ internal methods }
|
|
procedure CalcColHeaderHeight;
|
|
procedure CalcRowHeight;
|
|
function GetColAtCoord(X: Integer): Integer;
|
|
function GetDateOfCol(ACol: Integer): TDateTime;
|
|
function GetDateTimeAtCoord(X: Integer): TDateTime;
|
|
function GetEventAtCoord(X, Y: Integer): TVpEvent;
|
|
function GetEventOfRow(ARow: Integer): TVpEvent;
|
|
function GetRowAtCoord(Y: Integer): Integer;
|
|
function GetRowOfEvent(AEvent: TVpEvent): Integer;
|
|
procedure GetEventDateRange;
|
|
function IsEventOnDate(AEvent: TVpEvent; ADate: TDateTime): Boolean;
|
|
procedure Hookup;
|
|
procedure Populate;
|
|
procedure PopulateDayRecords;
|
|
procedure PopulateEventRecords;
|
|
procedure PopulateMonthRecords;
|
|
procedure ScrollDateIntoView(ADate: TDateTime);
|
|
procedure ScrollHorizontal(ANumCols: Integer);
|
|
procedure ScrollRowIntoView(ARow: Integer);
|
|
procedure ScrollVertical(ANumRows: Integer);
|
|
procedure SetHScrollPos;
|
|
procedure SetVScrollPos;
|
|
procedure SpawnEventEditDialog(IsNewEvent: Boolean);
|
|
|
|
{ inherited methods }
|
|
procedure CreateParams(var AParams: TCreateParams); override;
|
|
procedure DblClick; override;
|
|
function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override;
|
|
function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override;
|
|
procedure DoOnResize; override;
|
|
class function GetControlClassDefaultSize: TSize; override;
|
|
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
|
|
procedure Loaded; override;
|
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
|
|
procedure MouseEnter; override;
|
|
procedure MouseLeave; override;
|
|
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
|
|
procedure Paint; override;
|
|
procedure WMHScroll(var Msg: TLMHScroll); message LM_HSCROLL;
|
|
procedure WMVScroll(var Msg: TLMVScroll); message LM_VSCROLL;
|
|
|
|
{ LCL scaling }
|
|
{$IF VP_LCL_SCALING <> 0}
|
|
procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy;
|
|
const AXProportion, AYProportion: Double); override;
|
|
{$IFEND}
|
|
|
|
{ Hints }
|
|
procedure ShowHintWindow(APoint: TPoint; AEvent: TVpEvent);
|
|
procedure HideHintWindow;
|
|
procedure SetHint(const AValue: TTranslateString); override;
|
|
procedure SetHintMode(const AValue: TVpHintMode);
|
|
|
|
{ Popup }
|
|
function GetPopupMenu: TPopupMenu; override;
|
|
procedure InitializeDefaultPopup;
|
|
procedure PopupAddEvent(Sender: TObject);
|
|
procedure PopupDeleteEvent(Sender: TObject);
|
|
procedure PopupEditEvent(Sender: TObject);
|
|
procedure UpdatePopupMenuState;
|
|
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
|
|
function BuildEventString(AEvent: TVpEvent; UseAsHint: Boolean): String;
|
|
procedure DeleteActiveEvent(Prompt: Boolean);
|
|
function GetControlType: TVpItemType; override;
|
|
procedure Init;
|
|
function IsHoliday(ADate: TDate; out AHolidayName: String): Boolean;
|
|
procedure LoadLanguage;
|
|
procedure LinkHandler(Sender: TComponent;
|
|
NotificationType: TVpNotificationType; const Value: Variant); override;
|
|
procedure RenderToCanvas(RenderCanvas: TCanvas; RenderIn: TRect;
|
|
Angle: TVpRotationAngle; Scale: Extended; RenderDate: TDateTime;
|
|
StartLine, StopLine: Integer; UseGran: TVpGranularity;
|
|
DisplayOnly: Boolean); override;
|
|
|
|
{$IF VP_LCL_SCALING = 2}
|
|
procedure FixDesignFontsPPI(const ADesignTimePPI: Integer); override;
|
|
procedure ScaleFontsPPI(const AToPPI: Integer; const AProportion: Double); override;
|
|
{$ELSE}
|
|
{$IF VP_LCL_SCALING = 1}
|
|
procedure ScaleFontsPPI(const AProportion: Double); override;
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
|
|
// Methods to be called by painter
|
|
function CalcVisibleCols(AWidth, AFixedColWidth, AColWidth: Integer): Integer;
|
|
function CalcVisibleRows(AHeight, AHeaderHeight, ARowHeight: Integer): Integer;
|
|
|
|
property ActiveCol: Integer read FActiveCol write SetActiveCol;
|
|
property ActiveEvent: TVpEvent read FActiveEvent write SetActiveEvent;
|
|
property ActiveDate: TDateTime read FActiveDate write SetActiveDate;
|
|
property ActiveRow: Integer read FActiveRow write SetActiveRow;
|
|
property FirstDate: TDateTime read FFirstDate;
|
|
property LastDate: TDateTime read FLastDate;
|
|
property StartDate: TDateTime read FStartDate write FStartDate;
|
|
property EndDate: TDateTime read FEndDate write FEndDate;
|
|
property ColCount: Integer read FColCount write FColCount;
|
|
property RowCount: Integer read FRowCount write FRowCount;
|
|
property VisibleCols: Integer read FVisibleCols write FVisibleCols;
|
|
property VisibleRows: Integer read FVisibleRows write FVisibleRows;
|
|
property LeftCol: Integer read FLeftCol write SetLeftCol;
|
|
property TopRow: Integer read FTopRow write SetTopRow;
|
|
|
|
property RowHeight: Integer read FRowHeight;
|
|
property DayColHeaderHeight: Integer read FDayColHeaderHeight;
|
|
property MonthColHeaderHeight: Integer read FMonthColHeaderHeight;
|
|
property TotalColHeaderHeight: Integer read FTotalColHeaderHeight;
|
|
|
|
property DayRecords[AIndex: Integer]: TVpGanttDayRec read GetDayRec;
|
|
property EventRecords[AIndex: Integer]: TVpGanttEventRec read GetEventRec;
|
|
property MonthRecords[AIndex: Integer]: TVpGanttMonthRec read GetMonthRec;
|
|
|
|
property NumDays: Integer read GetNumDays;
|
|
property NumEvents: Integer read GetNumEvents;
|
|
property NumMonths: Integer read GetNumMonths;
|
|
|
|
published
|
|
// inherited properties
|
|
property Align;
|
|
property Anchors;
|
|
property BorderSpacing;
|
|
property ReadOnly;
|
|
// new properties
|
|
property ColHeaderAttributes: TVpGanttColHeaderAttributes read FColHeaderAttributes write FColHeaderAttributes;
|
|
property Color: TColor read FColor write SetColor default DEFAULT_COLOR;
|
|
property ColWidth: Integer read FColWidth write SetColWidth stored IsStoredColWidth;
|
|
property DayFormat: String index 0 read GetDateFormat write SetDateFormat stored IsStoredDateFormat;
|
|
property DrawingStyle: TVpDrawingStyle read FDrawingStyle write SetDrawingStyle default ds3d;
|
|
property FixedColWidth: Integer read FFixedColWidth write SetFixedColWidth default 120;
|
|
property HintMode: TVpHintMode read FHintMode write SetHintMode default hmPlannerHint;
|
|
property HolidayColor: TColor read FHolidayColor write SetHolidayColor default HOLIDAY_COLOR;
|
|
property LineColor: TColor read FLineColor write SetLineColor default DEFAULT_LINECOLOR;
|
|
property MonthFormat: String index 1 read GetDateFormat write SetDateFormat stored IsStoredDateFormat;
|
|
property MonthFormat_short: String index 2 read GetDateFormat write SetDateFormat stored IsStoredDateFormat;
|
|
property Options: TVpGanttViewOptions read FOptions write SetOptions default DEFAULT_GANTTVIEWOPTIONS;
|
|
property PopupMenu: TPopupMenu read GetPopupMenu write SetPopupMenu;
|
|
property RowHeaderAttributes: TVpGanttRowHeaderAttributes read FRowHeaderAttributes write FRowHeaderAttributes;
|
|
property SpecialDayMode: TVpGanttSpecialDayMode read FSpecialDayMode write SetSpecialDayMode default sdmColumn;
|
|
property TextMargin: Integer read FTextMargin write SetTextMargin default 2;
|
|
property TimeFormat: TVpTimeFormat read FTimeFormat write FTimeFormat default tf12Hour;
|
|
property WeekendColor: TColor read FWeekendColor write SetWeekendColor default WEEKEND_COLOR;
|
|
// inherited events
|
|
property OnClick;
|
|
// new events
|
|
property OnAddEvent: TVpOnAddNewEvent read FOnAddEvent write FOnAddEvent;
|
|
property OnDeletingEvent: TVpOnDeletingEvent read FOnDeletingEvent write FOnDeletingEvent;
|
|
property OnHoliday: TVpHolidayEvent read FOnHoliday write FOnHoliday;
|
|
property OnModifyEvent: TVpOnModifyEvent read FOnModifyEvent write FOnModifyEvent;
|
|
property OwnerEditEvent: TVpEditEvent read FOwnerEditEvent write FOwnerEditEvent;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
DateUtils, Math, Dialogs,
|
|
VpSR, VpGanttViewPainter, VpEvntEditDlg;
|
|
|
|
const
|
|
DEFAULT_DAYFORMAT = 'd';
|
|
DEFAULT_MONTHFORMAT = 'mmmm yyyy';
|
|
DEFAULT_MONTHFORMAT_SHORT = 'mmm yyyy';
|
|
DEFAULT_COLWIDTH = 20;
|
|
|
|
{******************************************************************************}
|
|
{ TVpGanttHeaderAttributes }
|
|
{******************************************************************************}
|
|
constructor TVpGanttHeaderAttributes.Create(AOwner: TVpGanttView);
|
|
begin
|
|
inherited Create;
|
|
FGanttView := AOwner;
|
|
FColor := DEFAULT_HEADERCOLOR;
|
|
end;
|
|
|
|
procedure TVpGanttHeaderAttributes.SetColor(AValue: TColor);
|
|
begin
|
|
if FColor <> AValue then
|
|
begin
|
|
FColor := AValue;
|
|
UpdateGanttView;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttHeaderAttributes.UpdateGanttView;
|
|
begin
|
|
if Assigned(FGanttView) then
|
|
FGanttView.Invalidate;
|
|
end;
|
|
|
|
|
|
{******************************************************************************}
|
|
{ TVpGanttRowHeaderAttributes }
|
|
{******************************************************************************}
|
|
constructor TVpGanttRowHeaderAttributes.Create(AOwner: TVpGanttView);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FEventFont := TVpFont.Create(AOwner);
|
|
end;
|
|
|
|
destructor TVpGanttRowHeaderAttributes.Destroy;
|
|
begin
|
|
FEventFont.Free;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TVpGanttRowHeaderAttributes.SetEventFont(AValue: TVpFont);
|
|
begin
|
|
if FEventFont <> AValue then
|
|
begin
|
|
FEventFont := AValue;
|
|
FEventFont.Owner := FGanttView;
|
|
UpdateGanttView;
|
|
end;
|
|
end;
|
|
|
|
|
|
{******************************************************************************}
|
|
{ TVpGanttColHeaderAttributes }
|
|
{******************************************************************************}
|
|
constructor TVpGanttColHeaderAttributes.Create(AOwner: TVpGanttView);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FDayFont := TVpFont.Create(AOwner);
|
|
FMonthFont := TVpFont.Create(AOwner);
|
|
end;
|
|
|
|
destructor TVpGanttColHeaderAttributes.Destroy;
|
|
begin
|
|
FDayFont.Free;
|
|
FMonthFont.Free;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TVpGanttColHeaderAttributes.SetDayFont(AValue: TVpFont);
|
|
begin
|
|
if FDayFont <> AValue then
|
|
begin
|
|
FDayFont := AValue;
|
|
FDayFont.Owner := FGanttView;
|
|
UpdateGanttView;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttColHeaderAttributes.SetMonthFont(AValue: TVpFont);
|
|
begin
|
|
if FMonthFont <> AValue then
|
|
begin
|
|
FMonthFont := AValue;
|
|
FMonthFont.Owner := FGanttView;
|
|
UpdateGanttView;
|
|
end;
|
|
end;
|
|
|
|
|
|
{******************************************************************************}
|
|
{ TVpGanttView }
|
|
{******************************************************************************}
|
|
constructor TVpGanttView.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
ControlStyle := [csCaptureMouse, csOpaque, csClickEvents, csDoubleClicks];
|
|
|
|
FInLinkHandler := false;
|
|
FLoaded := false;
|
|
FPainting := false;
|
|
FMouseDown := false;
|
|
|
|
SetActiveDate(Now);
|
|
|
|
FColWidth := DEFAULT_COLWIDTH;
|
|
FFixedColWidth := 120;
|
|
FTextMargin := 2;
|
|
|
|
FColor := DEFAULT_COLOR;
|
|
FLineColor := DEFAULT_LINECOLOR;
|
|
FWeekendColor := WEEKEND_COLOR;
|
|
FHolidayColor := HOLIDAY_COLOR;
|
|
|
|
FRowHeaderAttributes := TVpGanttRowHeaderAttributes.Create(self);
|
|
FColHeaderAttributes := TVpGanttColHeaderAttributes.Create(self);
|
|
|
|
FDateFormat[0] := DEFAULT_DAYFORMAT;
|
|
FDateFormat[1] := DEFAULT_MONTHFORMAT;
|
|
FDateFormat[2] := DEFAULT_MONTHFORMAT_SHORT;
|
|
FDrawingStyle := ds3d;
|
|
FScrollBars := ssBoth;
|
|
|
|
FOptions := DEFAULT_GANTTVIEWOPTIONS;
|
|
|
|
// Popup menu
|
|
FDefaultPopup := TPopupMenu.Create(Self);
|
|
FDefaultPopup.Name := 'default';
|
|
InitializeDefaultPopup;
|
|
Self.PopupMenu := FDefaultPopup;
|
|
|
|
// Initial size of the control
|
|
with GetControlClassDefaultSize do
|
|
SetInitialBounds(0, 0, CX, CY);
|
|
|
|
Hookup;
|
|
end;
|
|
|
|
destructor TVpGanttView.Destroy;
|
|
begin
|
|
FRowHeaderAttributes.Free;
|
|
FColHeaderAttributes.Free;
|
|
inherited;
|
|
end;
|
|
|
|
function TVpGanttView.BuildEventString(AEvent: TVpEvent;
|
|
UseAsHint: Boolean): String;
|
|
const
|
|
DATE_FORMAT = 'ddddd';
|
|
var
|
|
timeFmt: String;
|
|
startDateStr, endDateStr: string;
|
|
s: String;
|
|
begin
|
|
Result := '';
|
|
|
|
if (AEvent = nil) or (Datastore = nil) or (Datastore.Resource = nil) then
|
|
exit;
|
|
|
|
if UseAsHint then begin
|
|
{ Usage as hint }
|
|
startDateStr := FormatDateTime(DATE_FORMAT, AEvent.StartTime);
|
|
if trunc(AEvent.StartTime) = trunc(AEvent.EndTime) then
|
|
endDateStr := ''
|
|
else
|
|
endDateStr := FormatDateTime(DATE_FORMAT, AEvent.EndTime);
|
|
|
|
if AEvent.AllDayEvent then
|
|
begin
|
|
if endDateStr <> '' then endDateStr := ' - ' + endDateStr;
|
|
Result := startDateStr + endDatestr + LineEnding + RSAllDay;
|
|
end else
|
|
begin
|
|
timefmt := GetTimeFormatStr(TimeFormat);
|
|
startDateStr := startDateStr + ' ' + FormatDateTime(timeFmt, AEvent.StartTime) + ' - ';
|
|
if endDateStr <> '' then endDateStr := endDateStr + ' ';
|
|
endDateStr := endDateStr + FormatDateTime(timeFmt, AEvent.EndTime);
|
|
Result := startDateStr + endDateStr;
|
|
end;
|
|
|
|
// Event description
|
|
Result := Result + LineEnding2 +
|
|
RSEvent + ':' + LineEnding + AEvent.Description;
|
|
|
|
// Event notes
|
|
if (AEvent.Notes <> '') then begin
|
|
s := WrapText(AEvent.Notes, MAX_HINT_WIDTH);
|
|
s := StripLastLineEnding(s);
|
|
Result := Result + LineEnding2 +
|
|
RSNotes + ':' + LineEnding + s;
|
|
end;
|
|
|
|
// Event location
|
|
if (AEvent.Location <> '') then
|
|
Result := Result + LineEnding2 +
|
|
RSLocation + ':' + LineEnding + AEvent.Location;
|
|
end
|
|
else
|
|
{ Usage as cell text }
|
|
Result := '';
|
|
end;
|
|
|
|
procedure TVpGanttView.CalcColHeaderHeight;
|
|
var
|
|
s: String;
|
|
h: Integer;
|
|
begin
|
|
h := GetCanvasTextHeight(Canvas, FColHeaderAttributes.MonthFont);
|
|
FMonthColHeaderHeight := h + 2 * FTextMargin;
|
|
|
|
// A typical date string to measure the text height (line breaks in DayFormat allowed)
|
|
s := FormatDateTime(DayFormat, EncodeDate(2000, 12, 28));
|
|
h := GetCanvasTextHeight(Canvas, FColHeaderAttributes.DayFont, s);
|
|
FDayColHeaderHeight := h + FTextMargin;
|
|
|
|
FTotalColHeaderHeight := FMonthColHeaderHeight + FDayColHeaderHeight;
|
|
end;
|
|
|
|
procedure TVpGanttView.CalcRowHeight;
|
|
var
|
|
h: Integer;
|
|
begin
|
|
h := GetCanvasTextHeight(Canvas, FRowHeaderAttributes.EventFont);
|
|
FRowHeight := h + 2 * FTextMargin;
|
|
end;
|
|
|
|
function TVpGanttView.CalcVisibleCols(AWidth, AFixedColWidth, AColWidth: Integer): Integer;
|
|
var
|
|
d: Integer = 0; // Result of div
|
|
m: Integer = 0; // Result of mod
|
|
begin
|
|
if AColWidth <> 0 then
|
|
begin
|
|
DivMod(AWidth - AFixedColWidth, AColWidth, d, m);
|
|
if (m = 0) and (d > 1) then dec(d);
|
|
Result := d;
|
|
end else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TVpGanttView.CalcVisibleRows(AHeight, AHeaderHeight, ARowHeight: Integer): Integer;
|
|
var
|
|
d: Integer = 0; // Result of div
|
|
m: Integer = 0; // Result of mod
|
|
begin
|
|
if ARowHeight <> 0 then
|
|
begin
|
|
DivMod(AHeight - AHeaderHeight, ARowHeight, d, m);
|
|
if (m = 0) and (d > 1) then dec(d);
|
|
Result := d;
|
|
end else
|
|
Result := 0;
|
|
end;
|
|
|
|
procedure TVpGanttView.CreateParams(var AParams: TCreateParams);
|
|
begin
|
|
inherited CreateParams(AParams);
|
|
with AParams do
|
|
begin
|
|
Style := Style or WS_TABSTOP;
|
|
if FScrollBars in [ssVertical, ssBoth, ssAutoVertical, ssAutoBoth] then
|
|
Style := Style or WS_VSCROLL;
|
|
if FScrollBars in [ssHorizontal, ssBoth, ssAutoHorizontal, ssAutoBoth] then
|
|
Style := Style or WS_HSCROLL;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.DblClick;
|
|
var
|
|
dt, startTime, endTime: TDateTime;
|
|
begin
|
|
inherited;
|
|
// dvClickTimer.Enabled := false;
|
|
FMouseDown := false;
|
|
//FDragging := false;
|
|
|
|
// If the mouse was pressed down in the client area, then select the cell.
|
|
if not Focused then
|
|
SetFocus;
|
|
|
|
if ReadOnly then
|
|
begin
|
|
FMouseDownPoint := Point(0, 0);
|
|
exit;
|
|
end;
|
|
|
|
FActiveEvent := GetEventAtCoord(FMouseDownPoint.X, FMouseDownPoint.Y);
|
|
if (FActiveEvent <> nil) then
|
|
SpawnEventEditDialog(False)
|
|
else
|
|
begin
|
|
dt := GetDateTimeAtCoord(FMouseDownPoint.X);
|
|
if dt <> NO_DATE then
|
|
begin
|
|
startTime := trunc(dt);
|
|
endTime := startTime + 1.0;
|
|
ActiveEvent := Datastore.Resource.Schedule.AddEvent(
|
|
Datastore.GetNextID(EventsTableName),
|
|
startTime,
|
|
endTime
|
|
);
|
|
SpawnEventEditDialog(True);
|
|
end;
|
|
end;
|
|
FMouseDownPoint := Point(0, 0);
|
|
|
|
(*
|
|
|
|
if (Msg.XPos > dvRowHeadWidth - 9) and (Msg.YPos > dvColHeadHeight) then
|
|
begin
|
|
{ The mouse click landed inside the client area }
|
|
dvSetActiveRowByCoord(Point(Msg.XPos, Msg.YPos), True);
|
|
{ See if we hit an active event }
|
|
if (FActiveEvent <> nil) and (not ReadOnly) then begin
|
|
{ edit this event }
|
|
dvSpawnEventEditDialog(False);
|
|
end else if not ReadOnly then begin
|
|
if not CheckCreateResource then
|
|
Exit;
|
|
if (DataStore = nil) or (DataStore.Resource = nil) then
|
|
Exit;
|
|
{ otherwise, we must want to create a new event }
|
|
StartTime := trunc(FDisplayDate + ActiveCol)
|
|
+ dvLineMatrix[ActiveCol, ActiveRow].Time;
|
|
EndTime := StartTime + dvTimeIncSize * FRowLinesStep;
|
|
FActiveEvent := DataStore.Resource.Schedule.AddEvent(
|
|
DataStore.GetNextID(EventsTableName), StartTime, EndTime);
|
|
{ edit this new event }
|
|
dvSpawnEventEditDialog(True);
|
|
end;
|
|
end;
|
|
*)
|
|
end;
|
|
|
|
procedure TVpGanttView.DeleteActiveEvent(Prompt: Boolean);
|
|
var
|
|
DoIt: Boolean;
|
|
begin
|
|
if ReadOnly then
|
|
Exit;
|
|
if (FActiveEvent <> nil) and (not FActiveEvent.CanEdit) then
|
|
exit;
|
|
|
|
DoIt := not Prompt;
|
|
|
|
if FActiveEvent <> nil then begin
|
|
if Assigned(FOnDeletingEvent) then
|
|
begin
|
|
DoIt := true;
|
|
FOnDeletingEvent(self, FActiveEvent, DoIt);
|
|
end else
|
|
if Prompt then
|
|
DoIt := (MessageDlg(RSConfirmDeleteEvent + LineEnding2 + RSPermanent,
|
|
mtConfirmation, [mbYes, mbNo], 0) = mrYes);
|
|
|
|
if DoIt then begin
|
|
FActiveEvent.Deleted := true;
|
|
DataStore.PostEvents;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{$IF VP_LCL_SCALING <> 0}
|
|
procedure TVpGanttView.DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy;
|
|
const AXProportion, AYProportion: Double);
|
|
begin
|
|
inherited;
|
|
if AMode in [lapAutoAdjustWithoutHorizontalScrolling, lapAutoAdjustForDPI] then
|
|
begin
|
|
ColWidth := round(ColWidth * AXProportion);
|
|
FixedColWidth := round(FixedColWidth * AXProportion);
|
|
TextMargin := round(TextMargin * AXProportion);
|
|
end;
|
|
end;
|
|
{$IFEND}
|
|
|
|
function TVpGanttView.DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean;
|
|
begin
|
|
Result := inherited DoMouseWheelDown(Shift, MousePos);
|
|
if not Result then begin
|
|
if Shift = [] then
|
|
ScrollVertical(1)
|
|
else if Shift = [ssCtrl] then
|
|
ScrollHorizontal(1)
|
|
else
|
|
exit;
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
function TVpGanttView.DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean;
|
|
begin
|
|
Result := inherited DoMouseWheelUp(Shift, MousePos);
|
|
if not Result then begin
|
|
if Shift = [] then
|
|
ScrollVertical(-1)
|
|
else if Shift = [ssCtrl] then
|
|
ScrollHorizontal(-1)
|
|
else
|
|
exit;
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.DoOnResize;
|
|
var
|
|
emptyRows, emptyCols: Integer;
|
|
begin
|
|
inherited;
|
|
|
|
if (FRowHeight > 0) and (Length(FEventRecords) > 0) then
|
|
begin
|
|
VisibleRows := CalcVisibleRows(ClientHeight, FTotalColHeaderHeight, FRowHeight);
|
|
emptyRows := VisibleRows - (Length(FEventRecords) - FTopRow);
|
|
if emptyRows > 0 then
|
|
ScrollVertical(-emptyRows);
|
|
|
|
VisibleCols := CalcVisibleCols(ClientWidth, FFixedColWidth, FColWidth);
|
|
emptyCols := VisibleCols - (Length(FDayRecords) - FLeftCol);
|
|
if emptyCols > 0 then
|
|
ScrollHorizontal(-emptyCols);
|
|
end;
|
|
|
|
Invalidate;
|
|
end;
|
|
|
|
function TVpGanttView.GetColAtCoord(X: Integer): Integer;
|
|
begin
|
|
Result := (X - FixedColWidth) div FColWidth + FLeftCol;
|
|
end;
|
|
|
|
{ Defines the initial size of the control. }
|
|
class function TVpGanttView.GetControlClassDefaultSize: TSize;
|
|
begin
|
|
Result.CX := 300;
|
|
Result.CY := 200;
|
|
end;
|
|
|
|
function TVpGanttView.GetControlType: TVpItemType;
|
|
begin
|
|
Result := itGanttView;
|
|
end;
|
|
|
|
function TVpGanttView.GetDateOfCol(ACol: Integer): TDateTime;
|
|
begin
|
|
Result := FStartDate + ACol;
|
|
end;
|
|
|
|
function TVpGanttView.GetDateTimeAtCoord(X: Integer): TDateTime;
|
|
var
|
|
days: double;
|
|
begin
|
|
days := (X - FixedColWidth) / FColWidth + FLeftCol;
|
|
if (days >= 0) and (days < NumDays) then
|
|
Result := FStartDate + days
|
|
else
|
|
Result := NO_DATE;
|
|
end;
|
|
|
|
function TVpGanttView.GetDateFormat(AIndex: Integer): String;
|
|
begin
|
|
Result := FDateFormat[AIndex];
|
|
end;
|
|
|
|
function TVpGanttView.GetDayRec(AIndex: Integer): TVpGanttDayRec;
|
|
begin
|
|
Result := FDayRecords[AIndex];
|
|
end;
|
|
|
|
function TVpGanttView.GetEventAtCoord(X, Y: Integer): TVpEvent;
|
|
var
|
|
idx: Integer;
|
|
eventRec: TVpGanttEventRec;
|
|
dt: TDateTime;
|
|
begin
|
|
Result := nil;
|
|
dt := GetDateTimeAtCoord(X);
|
|
if (dt = -1) or (FRowHeight = 0) then
|
|
exit;
|
|
idx := GetRowAtCoord(Y);
|
|
if (idx >= 0) and (idx < NumEvents) then
|
|
begin
|
|
eventRec := FEventRecords[idx];
|
|
Result := eventRec.Event;
|
|
if Result.AllDayEvent then
|
|
begin
|
|
if (dt < trunc(Result.StartTime)) or (dt > trunc(Result.EndTime) + 1) then
|
|
Result := nil;
|
|
end else
|
|
if (dt < Result.StartTime) or (dt > Result.EndTime) then
|
|
Result := nil;
|
|
end;
|
|
end;
|
|
|
|
{ Determines the date when the earliest event starts, and the date when the
|
|
latest event ends.
|
|
Stores them in the internal variables FStartdate and FEndDate. }
|
|
procedure TVpGanttView.GetEventDateRange;
|
|
var
|
|
i: Integer;
|
|
event: TVpEvent;
|
|
d: TDateTime;
|
|
begin
|
|
if (Datastore = nil) or (Datastore.Resource = nil) or (Datastore.Resource.Schedule.EventCount = 0) then
|
|
begin
|
|
FFirstDate := NO_DATE;
|
|
FLastDate := NO_DATE;
|
|
end else
|
|
begin
|
|
event := Datastore.Resource.Schedule.GetEvent(0);
|
|
FFirstDate := trunc(event.StartTime);
|
|
FLastDate := -99999;
|
|
for i := 0 to Datastore.Resource.Schedule.EventCount-1 do
|
|
begin
|
|
event := Datastore.Resource.Schedule.GetEvent(i);
|
|
d := trunc(event.EndTime);
|
|
if d > FLastDate then FLastDate := d;
|
|
end;
|
|
end;
|
|
|
|
if FStartDate = 0 then
|
|
FStartDate := FFirstDate;
|
|
if FEndDate = 0 then
|
|
FEndDate := FLastDate;
|
|
end;
|
|
|
|
function TVpGanttView.GetEventOfRow(ARow: Integer): TVpEvent;
|
|
begin
|
|
Result := EventRecords[ARow].Event;
|
|
end;
|
|
|
|
function TVpGanttView.GetEventRec(AIndex: Integer): TVpGanttEventRec;
|
|
begin
|
|
Result := FEventRecords[AIndex];
|
|
end;
|
|
|
|
function TVpGanttView.GetMonthRec(AIndex: Integer): TVpGanttMonthRec;
|
|
begin
|
|
Result := FMonthRecords[AIndex];
|
|
end;
|
|
|
|
{ Determines the number days between the first and last Gantt event. This is
|
|
the number of day columns in the view. }
|
|
function TVpGanttView.GetNumDays: Integer;
|
|
begin
|
|
if (FStartDate <> NO_DATE) then
|
|
Result := trunc(FEndDate) - trunc(FStartDate) + 1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
{ Determines the number of events (= rows) to be displayed in the GanttView. }
|
|
function TVpGanttView.GetNumEvents: Integer;
|
|
begin
|
|
if (Datastore <> nil) and (Datastore.Resource <> nil) then
|
|
Result := Datastore.Resource.Schedule.EventCount
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
{ Determines the number of months (complete or partial) between the first and
|
|
last Gantt event. }
|
|
function TVpGanttView.GetNumMonths: Integer;
|
|
var
|
|
dm1, dm2: Integer;
|
|
y1, m1, d1: Word;
|
|
y2, m2, d2: Word;
|
|
begin
|
|
if (FStartDate <> NO_DATE) then
|
|
begin
|
|
DecodeDate(FStartDate, y1, m1, d1);
|
|
DecodeDate(FEndDate, y2, m2, d2);
|
|
if (y1 = y2) then
|
|
Result := m2 - m1 + 1
|
|
else
|
|
Result := 13 - m1 + m2 + (y2 - y1 - 1)*12;
|
|
end else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TVpGanttView.GetRowAtCoord(Y: Integer): Integer;
|
|
begin
|
|
Result := (Y - FTotalColHeaderHeight) div FRowHeight + FTopRow;
|
|
end;
|
|
|
|
function TVpGanttView.GetRowOfEvent(AEvent: TVpEvent): Integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to High(FEventRecords) do
|
|
if FEventRecords[i].Event = AEvent then
|
|
begin
|
|
Result := i;
|
|
exit;
|
|
end;
|
|
Result := -1;
|
|
end;
|
|
|
|
{ If the component is being dropped on a form at designtime, then
|
|
automatically hook up to the first datastore component found. }
|
|
procedure TVpGanttView.HookUp;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if csDesigning in ComponentState then
|
|
for I := 0 to pred(Owner.ComponentCount) do begin
|
|
if (Owner.Components[I] is TVpCustomDataStore) then begin
|
|
DataStore := TVpCustomDataStore(Owner.Components[I]);
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.Init;
|
|
begin
|
|
CalcRowHeight;
|
|
CalcColHeaderHeight;
|
|
|
|
GetEventDateRange;
|
|
FColCount := GetNumDays;
|
|
FRowCount := GetNumEvents;
|
|
|
|
PopulateDayRecords;
|
|
PopulateMonthRecords;
|
|
PopulateEventRecords;
|
|
end;
|
|
|
|
function TVpGanttView.IsEventOnDate(AEvent: TVpEvent; ADate: TDateTime): Boolean;
|
|
var
|
|
tEv1, tEv2: TDateTime;
|
|
begin
|
|
if AEvent <> nil then
|
|
begin
|
|
tEv1 := trunc(AEvent.StartTime);
|
|
tEv2 := trunc(AEvent.EndTime);
|
|
Result := (tEv1 <= ADate) and (tEv2 >= ADate);
|
|
end else
|
|
Result := false;
|
|
end;
|
|
|
|
function TVpGanttView.IsHoliday(ADate: TDate; out AHolidayName: String): Boolean;
|
|
begin
|
|
AHolidayName := '';
|
|
if Assigned(FOnHoliday) then
|
|
FOnHoliday(Self, ADate, AHolidayName);
|
|
Result := AHolidayName <> '';
|
|
end;
|
|
|
|
procedure TVpGanttView.KeyDown(var Key: Word; Shift: TShiftState);
|
|
|
|
procedure ScrollCols(ADelta: Integer);
|
|
begin
|
|
SetActiveCol(FActiveCol + ADelta);
|
|
if FActiveCol <= FLeftCol then
|
|
ScrollHorizontal(FActiveCol - FLeftCol)
|
|
else
|
|
if FActiveCol >= FLeftCol + FVisibleCols then
|
|
ScrollHorizontal(FActiveCol - (FLeftCol + FVisibleCols) + 1);
|
|
end;
|
|
|
|
procedure ScrollRows(ADelta: Integer);
|
|
begin
|
|
SetActiveRow(FActiveRow + ADelta);
|
|
if FActiveRow <= FTopRow then
|
|
ScrollVertical(FActiveRow - FTopRow)
|
|
else
|
|
if FActiveRow >= FTopRow + FVisibleRows then
|
|
ScrollVertical(FActiveRow - (FTopRow + FVisibleRows) + 1);
|
|
end;
|
|
|
|
var
|
|
P: TPoint;
|
|
begin
|
|
inherited;
|
|
case Key of
|
|
VK_LEFT:
|
|
ScrollCols(-1);
|
|
VK_RIGHT:
|
|
ScrollCols(1);
|
|
VK_DOWN:
|
|
ScrollRows(1);
|
|
VK_UP:
|
|
ScrollRows(-1);
|
|
VK_HOME:
|
|
if Shift = [ssCtrl] then
|
|
begin
|
|
ActiveCol := 0;
|
|
FLeftCol := 0;
|
|
end else
|
|
if Shift = [ssCtrl, ssShift] then
|
|
begin
|
|
ActiveCol := 0;
|
|
ActiveRow := 0;
|
|
FLeftCol := 0;
|
|
FTopRow := 0;
|
|
end else
|
|
if Shift = [] then
|
|
ScrollCols(-FVisibleCols);
|
|
VK_END:
|
|
if Shift = [ssCtrl] then
|
|
begin
|
|
ActiveCol := ColCount-1;
|
|
ScrollHorizontal(FLeftCol + FVisibleCols);
|
|
end else
|
|
if Shift = [ssCtrl, ssShift] then
|
|
begin
|
|
ActiveCol := ColCount-1;
|
|
ActiveRow := RowCount-1;
|
|
FLeftCol := ColCount - FVisibleCols;
|
|
FTopRow := RowCount - FVisibleRows;
|
|
end else
|
|
ScrollCols(FVisibleCols);
|
|
VK_NEXT:
|
|
if Shift = [ssCtrl] then // ctrl + page down
|
|
begin
|
|
ActiveRow := RowCount - 1;
|
|
ScrollRows(MaxInt);
|
|
end else
|
|
ScrollRows(FVisibleRows); // page down
|
|
VK_PRIOR:
|
|
if Shift = [ssCtrl] then // ctrl + page up
|
|
begin
|
|
ActiveRow := 0;
|
|
ScrollRows(-MaxInt);
|
|
end else
|
|
ScrollRows(-FVisibleRows); // page up
|
|
VK_F10, VK_APPS:
|
|
if (ssShift in Shift) then
|
|
begin
|
|
P := GetClientOrigin;
|
|
P.X := P.X + FDayRecords[FActiveCol].Rect.Right;
|
|
P.Y := P.Y + FDayRecords[FActiveCol].Rect.Top;
|
|
PopupMenu.Popup(P.X + 10, P.Y + 10);
|
|
end;
|
|
VK_RETURN:
|
|
PopupEditEvent(Self);
|
|
VK_INSERT:
|
|
PopupAddEvent(Self);
|
|
VK_DELETE:
|
|
DeleteActiveEvent(true);
|
|
else
|
|
exit;
|
|
end;
|
|
Invalidate;
|
|
Key := 0;
|
|
end;
|
|
|
|
function TVpGanttView.IsStoredColWidth: Boolean;
|
|
begin
|
|
Result := FColWidth <> DEFAULT_COLWIDTH;
|
|
end;
|
|
|
|
function TVpGanttView.IsStoredDateFormat(AIndex: Integer): Boolean;
|
|
begin
|
|
case AIndex of
|
|
0: Result := FDateFormat[0] <> DEFAULT_DAYFORMAT;
|
|
1: Result := FDateFormat[1] <> DEFAULT_MONTHFORMAT;
|
|
2: Result := FDateFormat[2] <> DEFAULT_MONTHFORMAT_SHORT;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.LoadLanguage;
|
|
var
|
|
item: TMenuItem;
|
|
begin
|
|
for item in FDefaultPopup.Items do
|
|
if item is TVpMenuItem then
|
|
TVpMenuItem(item).Translate;
|
|
end;
|
|
|
|
procedure TVpGanttView.LinkHandler(Sender: TComponent;
|
|
NotificationType: TVpNotificationType; const Value: Variant);
|
|
begin
|
|
FInLinkHandler := true;
|
|
try
|
|
case NotificationType of
|
|
neDateChange : SetActiveDate(Value);
|
|
neDataStoreChange : Invalidate;
|
|
neInvalidate : Invalidate;
|
|
end;
|
|
finally
|
|
FInLinkHandler := false;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.Loaded;
|
|
begin
|
|
inherited;
|
|
FLoaded := true;
|
|
Populate;
|
|
end;
|
|
|
|
procedure TVpGanttView.MouseDown(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer);
|
|
var
|
|
dt: TDateTime;
|
|
begin
|
|
inherited MouseDown(Button, Shift, X, Y);
|
|
|
|
if not Focused then
|
|
SetFocus;
|
|
|
|
FMouseDownPoint := Point(X, Y);
|
|
FActiveCol := GetColAtCoord(X);
|
|
FActiveRow := GetRowAtCoord(Y);
|
|
SetActiveEvent(GetEventAtCoord(X, Y));
|
|
dt := GetDateTimeAtCoord(X);
|
|
if dt <> NO_DATE then
|
|
SetActiveDate(dt);
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TVpGanttView.MouseEnter;
|
|
begin
|
|
FMouseEvent := nil;
|
|
end;
|
|
|
|
procedure TVpGanttView.MouseLeave;
|
|
begin
|
|
HideHintWindow;
|
|
end;
|
|
|
|
|
|
procedure TVpGanttView.MouseMove(Shift: TShiftState; X, Y: Integer);
|
|
var
|
|
event: TVpEvent;
|
|
begin
|
|
inherited MouseMove(Shift, X, Y);
|
|
if ShowHint then
|
|
begin
|
|
event := GetEventAtCoord(X, Y);
|
|
if event = nil then
|
|
HideHintWindow
|
|
else
|
|
if FMouseEvent <> event then begin
|
|
ShowHintWindow(Point(X, Y), event);
|
|
FMouseEvent := event;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.Paint;
|
|
begin
|
|
RenderToCanvas(
|
|
Canvas, // Paint Canvas
|
|
Rect(0, 0, Width, Height), // Paint Rectangle
|
|
ra0, // Rotation angle: none
|
|
1, // Scale
|
|
FStartDate, // Date
|
|
-1, // Start At
|
|
-1, // End At
|
|
gr30Min, // Granularity
|
|
False // Display Only
|
|
);
|
|
SetVScrollPos;
|
|
SetHScrollPos;
|
|
end;
|
|
|
|
procedure TVpGanttView.Populate;
|
|
begin
|
|
if DataStore <> nil then
|
|
DataStore.Date := FActiveDate;
|
|
end;
|
|
|
|
// Populates the array of TVpGanttRec records containing the date of each day
|
|
// cell and the *unscrolled* cell rectangle coordinates.
|
|
procedure TVpGanttView.PopulateDayRecords;
|
|
var
|
|
i: Integer;
|
|
x1, y1, x2, y2: Integer;
|
|
begin
|
|
SetLength(FDayRecords, GetNumDays);
|
|
x1 := FixedColWidth;
|
|
y1 := FMonthColHeaderHeight;
|
|
y2 := FTotalColHeaderHeight;
|
|
for i := 0 to High(FDayRecords) do
|
|
begin
|
|
x2 := x1 + ColWidth;
|
|
FDayRecords[i].Rect := Rect(x1, y1, x2, y2);
|
|
FDayRecords[i].Date := FStartDate + i;
|
|
x1 := x2;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.PopulateEventRecords;
|
|
var
|
|
event: TVpEvent;
|
|
i: Integer;
|
|
xh1, xh2, y1, xe1, xe2, y2: Integer;
|
|
t1, t2: TDateTime;
|
|
totalWidth: Integer;
|
|
list: TFPList;
|
|
begin
|
|
SetLength(FEventRecords, GetNumEvents);
|
|
if (Datastore = nil) or (DataStore.Resource = nil) then
|
|
exit;
|
|
|
|
list := TFPList.Create;
|
|
try
|
|
// Sort events by date/time
|
|
for i := 0 to Datastore.Resource.Schedule.EventCount-1 do
|
|
list.Add(Datastore.Resource.Schedule.GetEvent(i));
|
|
list.Sort(@CompareEvents);
|
|
|
|
xh1 := 0;
|
|
xh2 := FixedColWidth;
|
|
y1 := FTotalColHeaderHeight;
|
|
totalWidth := GetNumDays * ColWidth;
|
|
for i := 0 to High(FEventRecords) do
|
|
begin
|
|
event := TVpEvent(list[i]);
|
|
if event.AllDayEvent then
|
|
begin
|
|
t1 := trunc(event.StartTime);
|
|
t2 := trunc(event.EndTime) + 1;
|
|
if frac(event.EndTime) = 0 then t2 := t2 + 1;
|
|
end else
|
|
begin
|
|
t1 := event.StartTime;
|
|
t2 := event.EndTime;
|
|
end;
|
|
y2 := y1 + FRowHeight;
|
|
xe1 := round((t1 - FStartDate) / numDays * totalWidth) + FixedColWidth;
|
|
xe2 := round((t2 - FStartDate) / numDays * totalWidth) + FixedColWidth;
|
|
if xe1 = xe2 then xe2 := xe1 + 1;
|
|
FEventRecords[i].Event := event;
|
|
FEventRecords[i].Caption := event.Description;
|
|
FEventRecords[i].HeadRect := Rect(xh1, y1, xh2, y2);
|
|
FEventRecords[i].EventRect := Rect(xe1, y1, xe2, y2);
|
|
if event = FActiveEvent then
|
|
FActiveRow := i;
|
|
y1 := y2;
|
|
end;
|
|
|
|
finally
|
|
list.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.PopulateMonthRecords;
|
|
var
|
|
i, n: Integer;
|
|
x1, y1, x2, y2: Integer;
|
|
dm: TDateTime;
|
|
ndays: Integer;
|
|
begin
|
|
n := GetNumMonths;
|
|
SetLength(FMonthRecords, n);
|
|
if (Datastore = nil) or (Datastore.Resource = nil) then
|
|
exit;
|
|
|
|
x1 := FixedColWidth;
|
|
y1 := 0;
|
|
y2 := FTotalColHeaderHeight;
|
|
|
|
if n > 1 then
|
|
begin
|
|
dm := FStartDate;
|
|
for i := 0 to n - 1 do
|
|
begin
|
|
if i = 0 then begin
|
|
nDays := DaysInMonth(dm) - DayOf(dm) + 1;
|
|
dm := StartOfTheMonth(dm);
|
|
end else
|
|
if i = n-1 then
|
|
nDays := DayOf(FEndDate)
|
|
else
|
|
nDays := DaysInMonth(dm);
|
|
if dm + nDays > FEndDate then
|
|
nDays := trunc(FEndDate) - trunc(dm) + 1;
|
|
x2 := x1 + nDays * ColWidth;
|
|
FMonthRecords[i].Rect := Rect(x1, y1, x2, y2);
|
|
FMonthRecords[i].Date := dm;
|
|
dm := IncMonth(dm, 1);
|
|
x1 := x2;
|
|
end;
|
|
end else
|
|
begin
|
|
nDays := DayOf(FEndDate) - DayOf(FStartDate) + 1;
|
|
x2 := x1 + nDays * ColWidth;
|
|
FMonthRecords[0].Rect := Rect(x1, y1, x2, y2);
|
|
FMonthRecords[0].Date := FStartDate;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.RenderToCanvas(RenderCanvas: TCanvas; RenderIn: TRect;
|
|
Angle: TVpRotationAngle; Scale: Extended; RenderDate: TDateTime;
|
|
StartLine, StopLine: Integer; UseGran: TVpGranularity; DisplayOnly: Boolean);
|
|
var
|
|
painter: TVpGanttViewPainter;
|
|
begin
|
|
FPainting := true;
|
|
painter := TVpGanttViewPainter.Create(Self, RenderCanvas);
|
|
try
|
|
painter.RenderToCanvas(RenderIn, Angle, Scale, RenderDate, StartLine,
|
|
StopLine, UseGran, DisplayOnly);
|
|
finally
|
|
painter.Free;
|
|
FPainting := false;
|
|
end;
|
|
end;
|
|
|
|
{$IF VP_LCL_SCALING = 2}
|
|
procedure TVpGanttView.FixDesignFontsPPI(const ADesignTimePPI: Integer);
|
|
begin
|
|
inherited;
|
|
DoFixDesignFontPPI(ColHeaderAttributes.MonthFont, ADesignTimePPI);
|
|
DoFixDesignFontPPI(ColHeaderAttributes.DayFont, ADesignTimePPI);
|
|
DoFixDesignFontPPI(RowHeaderAttributes.EventFont, ADesignTimePPI);
|
|
end;
|
|
|
|
procedure TVpGanttView.ScaleFontsPPI(const AToPPI: Integer;
|
|
const AProportion: Double);
|
|
begin
|
|
inherited;
|
|
DoScaleFontPPI(ColHeaderAttributes.MonthFont, AToPPI, AProportion);
|
|
DoScaleFontPPI(ColHeaderAttributes.DayFont, AToPPI, AProportion);
|
|
DoScaleFontPPI(RowHeaderAttributes.EventFont, AToPPI, AProportion);
|
|
end;
|
|
{$ELSEIF VP_LCL_SCALING = 1}
|
|
procedure TVpGantView.ScaleFontsPPI(const AProportion: Double);
|
|
begin
|
|
inherited;
|
|
DoScaleFontPPI(ColHeaderAttributes.MonthFont, AProportion);
|
|
DoScaleFontPPI(ColHeaderAttributes.DayFont, AProportion);
|
|
DoScaleFontPPI(RowHeadAttributes.EventFont, AProportion);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TVpGanttView.ScrollDateIntoView(ADate: TDateTime);
|
|
begin
|
|
if (FStartDate = 0) or (FStartDate = NO_DATE) then
|
|
exit;
|
|
|
|
if ADate < FStartDate then
|
|
begin
|
|
FStartDate := trunc(ADate);
|
|
FColCount := GetNumDays;
|
|
SetLeftCol(-MaxInt);
|
|
end else
|
|
if ADate > FEndDate then
|
|
begin
|
|
FEndDate := trunc(ADate);
|
|
FColCount := GetNumDays;
|
|
SetLeftCol(FColCount - 1 - FVisibleCols);
|
|
end else
|
|
if ADate < FStartDate + FLeftCol then
|
|
SetLeftCol(trunc(ADate) - trunc(FStartDate))
|
|
else
|
|
if ADate > FStartDate + VisibleCols then
|
|
SetLeftCol(trunc(ADate) - VisibleCols)
|
|
else
|
|
exit;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TVpGanttView.ScrollHorizontal(ANumCols: Integer);
|
|
begin
|
|
SetLeftCol(FLeftCol + ANumCols);
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TVpGanttView.ScrollRowIntoView(ARow: Integer);
|
|
begin
|
|
if (ARow < TopRow) or (ARow >= TopRow + FVisibleRows) then
|
|
SetTopRow(ARow - FVisibleRows div 2)
|
|
end;
|
|
|
|
procedure TVpGanttView.ScrollVertical(ANumRows: Integer);
|
|
begin
|
|
SetTopRow(FTopRow + ANumRows);
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetActiveCol(AValue: Integer);
|
|
var
|
|
R: TRect = (Left:0; Top:0; Right:0; Bottom:0);
|
|
eventRect, dayRect: TRect;
|
|
dt: TDateTime;
|
|
event: TVpEvent;
|
|
begin
|
|
if AValue <= 0 then
|
|
FActiveCol := 0
|
|
else if AValue >= ColCount then
|
|
FActiveCol := ColCount - 1
|
|
else
|
|
FActiveCol := AValue;
|
|
|
|
dt := DayRecords[FActiveCol].Date;
|
|
dayRect := DayRecords[FActiveCol].Rect;
|
|
|
|
event := EventRecords[FActiveRow].Event;
|
|
eventRect := EventRecords[FActiveRow].EventRect;
|
|
dayRect.Top := eventRect.Top;
|
|
dayRect.Bottom := eventRect.Bottom;
|
|
|
|
if IntersectRect(R, dayRect, eventRect) then
|
|
SetActiveEvent(event)
|
|
else
|
|
SetActiveEvent(nil);
|
|
|
|
SetActiveDate(dt);
|
|
end;
|
|
|
|
procedure TVpGanttView.SetActiveDate(AValue: TDateTime);
|
|
begin
|
|
if FActiveDate <> trunc(AValue) then begin
|
|
FActiveDate := trunc(AValue);
|
|
|
|
if FLoaded then
|
|
Populate;
|
|
|
|
ScrollDateIntoView(FActiveDate);
|
|
FActiveCol := trunc(FActiveDate) - trunc(FStartDate);
|
|
Invalidate;
|
|
|
|
if (not FInLinkHandler) and (ControlLink <> nil) then
|
|
ControlLink.Notify(self, neDateChange, FActiveDate);
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetActiveEvent(AValue: TVpEvent);
|
|
begin
|
|
if FActiveEvent <> AValue then
|
|
begin
|
|
FActiveEvent := AValue;
|
|
if FActiveEvent <> nil then
|
|
begin
|
|
FActiveRow := GetRowOfEvent(FActiveEvent);
|
|
ScrollRowIntoView(FActiveRow);
|
|
end;
|
|
end;
|
|
UpdatePopupMenuState;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetActiveRow(AValue: Integer);
|
|
var
|
|
R: TRect = (Left:0; Top:0; Right:0; Bottom:0);
|
|
eventRect, dayRect: TRect;
|
|
event: TVpEvent;
|
|
dt: TDateTime;
|
|
begin
|
|
if AValue < 0 then
|
|
FActiveRow := 0
|
|
else if AValue >= RowCount then
|
|
FActiveRow := RowCount - 1
|
|
else
|
|
FActiveRow := AValue;
|
|
|
|
event := EventRecords[FActiveRow].Event;
|
|
eventRect := EventRecords[FActiveRow].EventRect;
|
|
dt := DayRecords[FActiveCol].Date;
|
|
dayRect := DayRecords[FActiveCol].Rect;
|
|
dayRect.Top := eventRect.Top;
|
|
dayRect.Bottom := eventRect.Bottom;
|
|
|
|
if IntersectRect(R, dayRect, eventRect) then
|
|
SetActiveEvent(event)
|
|
else
|
|
SetActiveEvent(nil);
|
|
|
|
SetActiveDate(dt);
|
|
end;
|
|
|
|
procedure TVpGanttView.SetColor(Value: TColor);
|
|
begin
|
|
if FColor <> Value then begin
|
|
FColor := Value;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetColWidth(AValue: Integer);
|
|
begin
|
|
if FColWidth <> AValue then
|
|
begin
|
|
FColWidth := AValue;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetDateFormat(AIndex: Integer; AValue: String);
|
|
begin
|
|
if FDateFormat[AIndex] <> AValue then
|
|
begin
|
|
FDateFormat[AIndex] := AValue;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetDrawingStyle(AValue: TVpDrawingStyle);
|
|
begin
|
|
if FDrawingStyle <> AValue then
|
|
begin
|
|
FDrawingStyle := AValue;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetFixedColWidth(AValue: Integer);
|
|
begin
|
|
if FFixedColWidth <> AValue then
|
|
begin
|
|
FFixedColWidth := AValue;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetHolidayColor(AValue: TColor);
|
|
begin
|
|
if FHolidayColor <> AValue then
|
|
begin
|
|
FHolidayColor := AValue;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetHScrollPos;
|
|
var
|
|
scrollInfo: TScrollInfo;
|
|
begin
|
|
if not HandleAllocated then
|
|
Exit;
|
|
with scrollInfo do
|
|
begin
|
|
cbSize := SizeOf(scrollInfo);
|
|
fMask := SIF_RANGE or SIF_PAGE or SIF_POS;
|
|
nMin := 0;
|
|
nMax := FColCount;
|
|
if FVisibleCols >= FColCount then
|
|
nPage := nMax
|
|
else
|
|
nPage := FVisibleCols;
|
|
if FLeftCol = pred(ColCount) - VisibleCols then
|
|
nPos := ColCount
|
|
else
|
|
nPos := FLeftCol;
|
|
nTrackPos := nPos;
|
|
end;
|
|
SetScrollInfo(Handle, SB_HORZ, scrollInfo, True);
|
|
end;
|
|
|
|
procedure TVpGanttView.SetLeftCol(AValue: Integer);
|
|
begin
|
|
if AValue <> FLeftCol then begin
|
|
if AValue + FVisibleCols >= FColCount then begin
|
|
FLeftCol := FColCount - FVisibleCols;
|
|
if FLeftCol < 0 then
|
|
FLeftCol := 0;
|
|
// Prevent the control from hanging at the right
|
|
if (AValue < FLeftCol) and (AValue > 0) then
|
|
FLeftCol := AValue;
|
|
end
|
|
else if AValue < 0 then
|
|
FLeftCol := 0
|
|
else
|
|
FLeftCol := AValue;
|
|
Invalidate;
|
|
SetHScrollPos;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetLineColor(AValue: TColor);
|
|
begin
|
|
if FLineColor <> AValue then begin
|
|
FLineColor := AValue;
|
|
Repaint;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetOptions(AValue: TVpGanttViewOptions);
|
|
begin
|
|
if FOptions <> AValue then
|
|
begin
|
|
FOptions := AValue;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetSpecialDayMode(AValue: TVpGanttSpecialDayMode);
|
|
begin
|
|
if FSpecialDayMode <> AValue then
|
|
begin
|
|
FSpecialDayMode := AValue;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetTextMargin(AValue: Integer);
|
|
begin
|
|
if FTextMargin <> AValue then
|
|
begin
|
|
FTextMargin := AValue;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetTopRow(AValue: Integer);
|
|
begin
|
|
if AValue <> FTopRow then begin
|
|
if AValue + FVisibleRows >= RowCount then begin
|
|
FTopRow := FRowCount - FVisibleRows;
|
|
if FTopRow < 0 then
|
|
FTopRow := 0;
|
|
// Prevent the control from hanging at the bottom
|
|
if (AValue < FTopRow) and (AValue > 0) then
|
|
FTopRow := AValue;
|
|
end
|
|
else if AValue < 0 then
|
|
FTopRow := 0
|
|
else
|
|
FTopRow:= AValue;
|
|
Invalidate;
|
|
SetVScrollPos;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetVScrollPos;
|
|
var
|
|
scrollInfo: TScrollInfo;
|
|
begin
|
|
if not HandleAllocated then
|
|
Exit;
|
|
with scrollInfo do
|
|
begin
|
|
cbSize := SizeOf(scrollInfo);
|
|
fMask := SIF_RANGE or SIF_PAGE or SIF_POS;
|
|
nMin := 0;
|
|
nMax := FRowCount;
|
|
if FVisibleRows >= FRowCount then
|
|
nPage := nMax
|
|
else
|
|
nPage := FVisibleRows;
|
|
if FTopRow = pred(RowCount) - VisibleRows then
|
|
nPos := FRowCount
|
|
else
|
|
nPos := FTopRow;
|
|
nTrackPos := nPos;
|
|
end;
|
|
SetScrollInfo(Handle, SB_VERT, scrollInfo, True);
|
|
end;
|
|
|
|
procedure TVpGanttView.SetWeekendColor(AValue: TColor);
|
|
begin
|
|
if FWeekendColor <> AValue then
|
|
begin
|
|
FWeekendColor := AValue;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.SpawnEventEditDialog(IsNewEvent: Boolean);
|
|
var
|
|
AllowIt: Boolean;
|
|
EventDlg : TVpEventEditDialog;
|
|
begin
|
|
if (DataStore = nil) or (DataStore.Resource = nil) or ReadOnly then
|
|
Exit;
|
|
|
|
AllowIt := false;
|
|
if Assigned(FOwnerEditEvent) then
|
|
FOwnerEditEvent(self, FActiveEvent, IsNewEvent, DataStore.Resource, AllowIt)
|
|
else begin
|
|
EventDlg := TVpEventEditDialog.Create(nil);
|
|
try
|
|
EventDlg.DataStore := DataStore;
|
|
AllowIt := EventDlg.Execute(FActiveEvent);
|
|
finally
|
|
EventDlg.Free;
|
|
end;
|
|
end;
|
|
|
|
if AllowIt then begin
|
|
FActiveEvent.Changed := true;
|
|
DataStore.PostEvents;
|
|
|
|
// The new or edited event may be at a different position in the grid.
|
|
// --> Re-read the events to sort them, find the new active row/col and
|
|
// scroll them into view
|
|
PopulateEventRecords;
|
|
SetActiveDate(FActiveEvent.StartTime);
|
|
ScrollRowIntoView(FActiveRow);
|
|
|
|
if IsNewEvent and Assigned(FOnAddEvent) then
|
|
FOnAddEvent(self, FActiveEvent);
|
|
if not IsNewEvent and Assigned(FOnModifyEvent) then
|
|
FOnModifyEvent(self, FActiveEvent);
|
|
end else begin
|
|
if IsNewEvent then begin
|
|
FActiveEvent.Deleted := true;
|
|
DataStore.PostEvents;
|
|
SetActiveEvent(nil);
|
|
end;
|
|
end;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TVpGanttView.WMHScroll(var Msg: TLMHScroll);
|
|
begin
|
|
case Msg.ScrollCode of
|
|
SB_LINELEFT : ScrollHorizontal(-1);
|
|
SB_LINERIGHT : ScrollHorizontal(1);
|
|
SB_PAGELEFT : ScrollHorizontal(-FVisibleCols);
|
|
SB_PAGERIGHT : ScrollHorizontal(FVisibleCols);
|
|
SB_THUMBPOSITION, SB_THUMBTRACK : SetLeftCol(Msg.Pos);
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.WMVScroll(var Msg: TLMVScroll);
|
|
begin
|
|
case Msg.ScrollCode of
|
|
SB_LINEUP : ScrollVertical(-1);
|
|
SB_LINEDOWN : ScrollVertical(1);
|
|
SB_PAGEUP : ScrollVertical(-FVisibleRows);
|
|
SB_PAGEDOWN : ScrollVertical(FVisibleRows);
|
|
SB_THUMBPOSITION, SB_THUMBTRACK : SetTopRow(Msg.Pos);
|
|
end;
|
|
end;
|
|
|
|
|
|
{ Hint support }
|
|
|
|
procedure TVpGanttView.ShowHintWindow(APoint: TPoint; AEvent: TVpEvent);
|
|
var
|
|
txt: String;
|
|
begin
|
|
HideHintWindow;
|
|
case FHintMode of
|
|
hmPlannerHint:
|
|
begin
|
|
if (AEvent = nil) or (Datastore = nil) or (Datastore.Resource = nil) then
|
|
exit;
|
|
txt := BuildEventString(AEvent, true);
|
|
end;
|
|
hmComponentHint:
|
|
txt := FComponentHint;
|
|
end;
|
|
if (txt <> '') and not (csDesigning in ComponentState) then
|
|
begin
|
|
Hint := txt;
|
|
Application.Hint := Hint;
|
|
Application.ActivateHint(ClientToScreen(APoint), true);
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.HideHintWindow;
|
|
begin
|
|
Application.CancelHint;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetHint(const AValue: TTranslateString);
|
|
begin
|
|
inherited;
|
|
if FHintMode = hmComponentHint then
|
|
FComponentHint := AValue;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetHintMode(const AValue: TVpHintMode);
|
|
begin
|
|
if AValue = FHintMode then
|
|
exit;
|
|
FHintMode := AValue;
|
|
if FHintMode = hmPlannerHint then
|
|
FComponentHint := Hint;
|
|
end;
|
|
|
|
|
|
{ Popup menu }
|
|
|
|
function TVpGanttView.GetPopupMenu: TPopupMenu;
|
|
begin
|
|
if FExternalPopup = nil then
|
|
Result := FDefaultPopup
|
|
else
|
|
Result := FExternalPopup;
|
|
end;
|
|
|
|
procedure TVpGanttView.SetPopupMenu(AValue: TPopupMenu);
|
|
begin
|
|
if (AValue = nil) or (AValue = FDefaultPopup) then
|
|
FExternalPopup := nil
|
|
else
|
|
FExternalPopup := AValue;
|
|
end;
|
|
|
|
procedure TVpGanttView.InitializeDefaultPopup;
|
|
var
|
|
NewItem: TVpMenuItem;
|
|
canEdit: Boolean;
|
|
begin
|
|
canEdit := (FActiveEvent <> nil) and FActiveEvent.CanEdit;
|
|
FDefaultPopup.Items.Clear;
|
|
|
|
if RSPopupAddEvent <> '' then begin // Add
|
|
NewItem := TVpMenuItem.Create(Self);
|
|
NewItem.Kind := mikAddEvent;
|
|
NewItem.OnClick := @PopupAddEvent;
|
|
NewItem.Tag := 0;
|
|
FDefaultPopup.Items.Add(NewItem);
|
|
end;
|
|
|
|
if RSPopupEditEvent <> '' then begin // Edit
|
|
NewItem := TVpMenuItem.Create(Self);
|
|
NewItem.Kind := mikEditEvent;
|
|
NewItem.Enabled := canEdit;
|
|
NewItem.OnClick := @PopupEditEvent;
|
|
NewItem.Tag := 1;
|
|
FDefaultPopup.Items.Add(NewItem);
|
|
end;
|
|
|
|
if RSPopupDeleteEvent <> '' then begin // Delete
|
|
NewItem := TVpMenuItem.Create(Self);
|
|
NewItem.Kind := mikDeleteEvent;
|
|
NewItem.Enabled := canEdit;
|
|
NewItem.OnClick := @PopupDeleteEvent;
|
|
NewItem.Tag := 1;
|
|
FDefaultPopup.Items.Add(NewItem);
|
|
end;
|
|
end;
|
|
|
|
procedure TVpGanttView.PopupAddEvent(Sender: TObject);
|
|
var
|
|
startTime: TDateTime;
|
|
endTime: TDateTime;
|
|
begin
|
|
if ReadOnly or (not CheckCreateResource) or
|
|
(not Assigned(DataStore)) or (not Assigned(DataStore.Resource))
|
|
then
|
|
Exit;
|
|
|
|
// Create the new event as an all-day event for the clicked day.
|
|
startTime := trunc(FActiveDate);
|
|
endTime := startTime + 1 - OneMilliSecond;
|
|
FActiveEvent := DataStore.Resource.Schedule.AddEvent(
|
|
DataStore.GetNextID(EventsTableName),
|
|
StartTime,
|
|
EndTime
|
|
);
|
|
FActiveEvent.AllDayEvent := true;
|
|
|
|
// Edit this new event
|
|
SpawnEventEditDialog(True);
|
|
end;
|
|
|
|
procedure TVpGanttView.PopupDeleteEvent(Sender: TObject);
|
|
begin
|
|
if ReadOnly then
|
|
Exit;
|
|
Invalidate;
|
|
if FActiveEvent <> nil then
|
|
DeleteActiveEvent(True);
|
|
end;
|
|
|
|
procedure TVpGanttView.PopupEditEvent(Sender: TObject);
|
|
begin
|
|
if ReadOnly then
|
|
Exit;
|
|
Invalidate;
|
|
if FActiveEvent <> nil then
|
|
// edit this event
|
|
SpawnEventEditDialog(false);
|
|
end;
|
|
|
|
procedure TVpGanttView.UpdatePopupMenuState;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if Assigned(FActiveEvent) then
|
|
begin
|
|
for i := 0 to FDefaultPopup.Items.Count - 1 do
|
|
FDefaultPopup.Items[i].Enabled := True;
|
|
end else
|
|
for i := 0 to FDefaultPopup.Items.Count - 1 do
|
|
if (FDefaultPopup.Items[i].Tag = 1) or (ReadOnly) then
|
|
FDefaultPopup.Items[i].Enabled := False;
|
|
end;
|
|
|
|
end.
|
|
|