git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.DevExpressVCL@29 05c56307-c608-d34a-929d-697000501d7a
18700 lines
562 KiB
ObjectPascal
18700 lines
562 KiB
ObjectPascal
|
|
{*******************************************************************}
|
|
{ }
|
|
{ Developer Express Visual Component Library }
|
|
{ ExpressMasterView main components }
|
|
{ }
|
|
{ Copyright (c) 1999-2008 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 EXPRESSMASTERVIEW 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 dxMasterView;
|
|
|
|
{$I cxVer.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Messages, Classes,{$IFDEF DELPHI6} Variants,{$ENDIF} Controls, DB,
|
|
Graphics, Forms;
|
|
|
|
const
|
|
dxMVCustomizationFormRowCount = 12;
|
|
dxMVPreviewLeftIndent = 20;
|
|
dxMVPreviewMaxLineCount = 3;
|
|
dxMVPreviewRightIndent = 5;
|
|
|
|
dxMVColumnDefaultMinWidth = 20;
|
|
dxMVColumnDefaultMaxWidth = 10000;
|
|
dxMVColumnDefaultMaxRowCount = 100;
|
|
|
|
type
|
|
PBoolArray = ^TBoolArray;
|
|
TBoolArray = array[0..MaxInt div SizeOf(Boolean) - 1] of Boolean;
|
|
PBRUSH = ^HBRUSH;
|
|
{$IFNDEF DELPHI5}
|
|
PColor = ^TColor;
|
|
{$ENDIF}
|
|
PFont = ^TFont;
|
|
PIntArray = ^TIntArray;
|
|
TIntArray = array[0..MaxInt div SizeOf(Integer) - 1] of Integer;
|
|
|
|
TdxMasterViewStyle = class;
|
|
TdxMasterViewStyleClass = class of TdxMasterViewStyle;
|
|
TdxMasterViewColumn = class;
|
|
TdxMasterViewColumnClass = class of TdxMasterViewColumn;
|
|
TdxMasterViewLayout = class;
|
|
TdxMasterViewLevel = class;
|
|
TdxMasterViewNode = class;
|
|
TdxMasterView = class;
|
|
|
|
TdxMasterViewNodeType = (ntData, ntCaption, ntGroup);
|
|
TdxMasterViewNodeTypes = set of TdxMasterViewNodeType;
|
|
|
|
TdxMVDesignerRefreshCode = (rcName, rcLevels, rcColumns, rcData, rcStyles, rcEnables);
|
|
TdxMVDesignerRefreshCodes = set of TdxMVDesignerRefreshCode;
|
|
|
|
TCurDesigner =
|
|
{$IFDEF DELPHI6}IUnknown{$ELSE}{$IFDEF DELPHI4}IDesigner{$ELSE}TDesigner{$ENDIF}{$ENDIF};
|
|
|
|
TdxMVDesigner = class
|
|
public
|
|
procedure Changed(Control: TdxMasterView; RefreshCodes: TdxMVDesignerRefreshCodes); virtual; abstract;
|
|
procedure Hide(Control: TdxMasterView); virtual; abstract;
|
|
function UniqueName(Control: TdxMasterView; const BaseName: string): string; virtual; abstract;
|
|
procedure Show(Control: TdxMasterView; ADesigner: TCurDesigner); virtual; abstract;
|
|
end;
|
|
|
|
TdxMasterViewDataLink = class(TDataLink)
|
|
private
|
|
FFreezeCount: Integer;
|
|
FLevel: TdxMasterViewLevel;
|
|
function GetFrozen: Boolean;
|
|
protected
|
|
procedure ActiveChanged; override;
|
|
procedure DataSetChanged; override;
|
|
procedure DataSetScrolled(Distance: Integer); override;
|
|
procedure EditingChanged; override;
|
|
procedure LayoutChanged; override;
|
|
procedure RecordChanged(Field: TField); override;
|
|
public
|
|
constructor Create(ALevel: TdxMasterViewLevel);
|
|
function Freeze: Integer;
|
|
procedure Unfreeze;
|
|
property FreezeCount: Integer read FFreezeCount;
|
|
property Frozen: Boolean read GetFrozen;
|
|
end;
|
|
|
|
TdxMasterViewStyleValue = (svAnotherColor, svColor, svFont);
|
|
TdxMasterViewStyleValues = set of TdxMasterViewStyleValue;
|
|
TdxMasterViewStyleConsumeType =
|
|
(sctHeader, sctContent, sctFooter, sctPreview, sctCaption, sctGroup,
|
|
sctGroupByBox, sctHighlight, sctInactive);
|
|
TdxMasterViewStyleConsumeTypes = set of TdxMasterViewStyleConsumeType;
|
|
|
|
PdxMasterViewStyleConsumerRec = ^TdxMasterViewStyleConsumerRec;
|
|
TdxMasterViewStyleConsumerRec = record
|
|
Consumer: TComponent;
|
|
ConsumeTypes: TdxMasterViewStyleConsumeTypes;
|
|
end;
|
|
|
|
TdxMasterViewStyle = class(TComponent)
|
|
private
|
|
FAnotherBrush: HBRUSH;
|
|
FAnotherColor: TColor;
|
|
FAssignedValues: TdxMasterViewStyleValues;
|
|
FBrush: HBRUSH;
|
|
FColor: TColor;
|
|
FControl: TdxMasterView;
|
|
FConsumers: TList;
|
|
FFont: TFont;
|
|
function GetConsumerRec(Index: Integer): PdxMasterViewStyleConsumerRec;
|
|
function GetConsumerCount: Integer;
|
|
function GetIndex: Integer;
|
|
procedure SetAnotherColor(Value: TColor);
|
|
procedure SetAssignedValues(Value: TdxMasterViewStyleValues);
|
|
procedure SetColor(Value: TColor);
|
|
procedure SetFont(Value: TFont);
|
|
procedure SetIndex(Value: Integer);
|
|
function IsAnotherColorStored: Boolean;
|
|
function IsColorStored: Boolean;
|
|
function IsFontStored: Boolean;
|
|
procedure FontChanged(Sender: TObject);
|
|
protected
|
|
procedure SetName(const NewName: TComponentName); override;
|
|
procedure SetParentComponent(AParent: TComponent); override;
|
|
procedure AddConsumeType(AConsumer: TComponent; AConsumeType: TdxMasterViewStyleConsumeType);
|
|
procedure Changed(Values: TdxMasterViewStyleValues);
|
|
function IndexOfConsumer(Consumer: TComponent): Integer;
|
|
procedure RemoveConsumeType(AConsumer: TComponent; AConsumeType: TdxMasterViewStyleConsumeType);
|
|
procedure SysColorChanged; virtual;
|
|
property ConsumerCount: Integer read GetConsumerCount;
|
|
property ConsumerRecs[Index: Integer]: PdxMasterViewStyleConsumerRec read GetConsumerRec;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
function GetParentComponent: TComponent; override;
|
|
function HasParent: Boolean; override;
|
|
property AnotherBrush: HBRUSH read FAnotherBrush;
|
|
property Brush: HBRUSH read FBrush;
|
|
property Control: TdxMasterView read FControl;
|
|
property Index: Integer read GetIndex write SetIndex;
|
|
published
|
|
property AnotherColor: TColor read FAnotherColor write SetAnotherColor
|
|
stored IsAnotherColorStored;
|
|
property Color: TColor read FColor write SetColor stored IsColorStored;
|
|
property Font: TFont read FFont write SetFont stored IsFontStored;
|
|
property AssignedValues: TdxMasterViewStyleValues read FAssignedValues
|
|
write SetAssignedValues default []; // must be loaded after all
|
|
end;
|
|
|
|
TdxMasterViewColumnAssignedValue =
|
|
(cvAlignment, cvCaption, cvFooterAlignment, cvHeaderAlignment, cvSummaryFieldName, cvWidth);
|
|
TdxMasterViewColumnAssignedValues = set of TdxMasterViewColumnAssignedValue;
|
|
TdxMasterViewHPart = (hpOne, hpAll);
|
|
TdxMasterViewVPart = (vpGroupByBox, vpHeader, vpContent, vpFooter, vpAll, vpAllAndBelow);
|
|
TdxMasterViewSortOrder = (soNone, soAscending, soDescending);
|
|
TdxMasterViewSummaryType = (stNone, stSum, stMin, stMax, stCount, stAverage);
|
|
|
|
TdxMasterViewColumnOption =
|
|
(coGrouping, coHidden, coHorSizing, coMoving, coSorting, coVerSizing,
|
|
coShowCaption);
|
|
TdxMasterViewColumnOptions = set of TdxMasterViewColumnOption;
|
|
|
|
TdxMVColumnGetStyleEvent = procedure(Sender: TdxMasterViewColumn;
|
|
Node: TdxMasterViewNode; var NewStyle: TdxMasterViewStyle) of object;
|
|
TdxMVSummaryEvent = procedure(Sender: TdxMasterViewColumn;
|
|
Node: TdxMasterViewNode; DataSet: TDataSet; var Value: Extended) of object;
|
|
|
|
TdxMasterViewColumn = class(TComponent)
|
|
private
|
|
FAddInWidth: Integer;
|
|
FAlignment: TAlignment;
|
|
FAssignedValues: TdxMasterViewColumnAssignedValues;
|
|
FCaption: string;
|
|
FColIndex: Integer;
|
|
FContentStyle: TdxMasterViewStyle;
|
|
FField: TField;
|
|
FFieldName: string;
|
|
FFooterAlignment: TAlignment;
|
|
FFooterStyle: TdxMasterViewStyle;
|
|
FHeaderAlignment: TAlignment;
|
|
FHeaderGlyph: TBitmap;
|
|
FHeaderGlyphAlignment: TAlignment;
|
|
FHeaderStyle: TdxMasterViewStyle;
|
|
FLeftColumns: TList;
|
|
FLevel: TdxMasterViewLevel;
|
|
FLoadedGroupIndex: Integer;
|
|
FLoadedSortIndex: Integer;
|
|
FLogicalOffset: Integer;
|
|
FMaxRowCount: Integer;
|
|
FMaxWidth: Integer;
|
|
FMinRowCount: Integer;
|
|
FMinWidth: Integer;
|
|
FMultiLine: Boolean;
|
|
FOptions: TdxMasterViewColumnOptions;
|
|
FPressed: Boolean;
|
|
FRightColumns: TList;
|
|
FRowCount: Integer;
|
|
FRowIndex: Integer;
|
|
FLeaveSortOrder: Boolean;
|
|
FSortOrder: TdxMasterViewSortOrder;
|
|
FSummaryField: TField;
|
|
FSummaryFieldName: string;
|
|
FSummaryFormat: string;
|
|
FSummaryType: TdxMasterViewSummaryType;
|
|
FVisible: Boolean;
|
|
FVisibleWidth: Integer;
|
|
FWidth: Integer;
|
|
|
|
FOnAfterCalcSummary: TdxMVSummaryEvent;
|
|
FOnBeforeCalcSummary: TdxMVSummaryEvent;
|
|
FOnCalcSummary: TdxMVSummaryEvent;
|
|
FOnGetContentStyle: TdxMVColumnGetStyleEvent;
|
|
FOnGetFooterStyle: TdxMVColumnGetStyleEvent;
|
|
FOnGetHeaderStyle: TdxMVColumnGetStyleEvent;
|
|
|
|
function GetAlignment: TAlignment;
|
|
function GetCaption: string;
|
|
function GetColIndex: Integer;
|
|
function GetContentAnotherBrush: HBRUSH;
|
|
function GetContentAnotherColor: TColor;
|
|
function GetContentBrush: HBRUSH;
|
|
function GetContentColor: TColor;
|
|
function GetContentFont: TFont;
|
|
function GetControl: TdxMasterView;
|
|
function GetFooterAlignment: TAlignment;
|
|
function GetFooterBrush: HBRUSH;
|
|
function GetFooterColor: TColor;
|
|
function GetFooterFont: TFont;
|
|
function GetGroupIndex: Integer;
|
|
function GetHeaderAlignment: TAlignment;
|
|
function GetHeaderBrush: HBRUSH;
|
|
function GetHeaderColor: TColor;
|
|
function GetHeaderFont: TFont;
|
|
function GetHidden: Boolean;
|
|
function GetIndex: Integer;
|
|
function GetIsDestroying: Boolean;
|
|
function GetIsLoading: Boolean;
|
|
function GetLastInRow: Boolean;
|
|
function GetLogicalOffset: Integer;
|
|
// function GetMaxLogicalOffset: Integer;
|
|
function GetMinLogicalOffset: Integer;
|
|
function GetNonScaledLogicalOffset: Integer;
|
|
// function GetNonScaledOffset: Integer;
|
|
function GetNonScaledWidth: Integer;
|
|
function GetOffset: Integer;
|
|
function GetRowIndex: Integer;
|
|
function GetSortIndex: Integer;
|
|
function GetSummaryField: TField;
|
|
function GetSummaryFieldName: string;
|
|
function GetSummaryIndex: Integer;
|
|
function GetVisibleIndex: Integer;
|
|
function GetVisibleMaxWidth: Integer;
|
|
function GetVisibleMinWidth: Integer;
|
|
function GetVisibleWidth: Integer;
|
|
procedure SetAlignment(Value: TAlignment);
|
|
procedure SetAssignedValues(Value: TdxMasterViewColumnAssignedValues);
|
|
procedure SetCaption(Value: string);
|
|
procedure SetColIndex(Value: Integer);
|
|
procedure SetContentStyle(Value: TdxMasterViewStyle);
|
|
procedure SetField(Value: TField);
|
|
procedure SetFieldInternally(Value: TField);
|
|
procedure SetFieldName(Value: string);
|
|
procedure SetFooterAlignment(Value: TAlignment);
|
|
procedure SetFooterStyle(Value: TdxMasterViewStyle);
|
|
procedure SetGroupIndex(Value: Integer);
|
|
procedure SetHeaderAlignment(Value: TAlignment);
|
|
procedure SetHeaderGlyph(Value: TBitmap);
|
|
procedure SetHeaderGlyphAlignment(Value: TAlignment);
|
|
procedure SetHeaderStyle(Value: TdxMasterViewStyle);
|
|
procedure SetIndex(Value: Integer);
|
|
procedure SetInternalVisibleWidth(Value: Integer);
|
|
procedure SetMaxRowCount(Value: Integer);
|
|
procedure SetMaxWidth(Value: Integer);
|
|
procedure SetMinRowCount(Value: Integer);
|
|
procedure SetMinWidth(Value: Integer);
|
|
procedure SetMultiLine(Value: Boolean);
|
|
procedure SetOptions(Value: TdxMasterViewColumnOptions);
|
|
procedure SetPressed(Value: Boolean);
|
|
procedure SetRowCount(Value: Integer);
|
|
procedure SetRowIndex(Value: Integer);
|
|
procedure SetSortIndex(Value: Integer);
|
|
procedure SetSortOrder(Value: TdxMasterViewSortOrder);
|
|
procedure SetSummaryField(Value: TField);
|
|
procedure SetSummaryFieldInternally(Value: TField);
|
|
procedure SetSummaryFieldName(Value: string);
|
|
procedure SetSummaryFormat(Value: string);
|
|
procedure SetSummaryType(Value: TdxMasterViewSummaryType);
|
|
procedure SetVisible(Value: Boolean);
|
|
procedure SetVisibleWidth(Value: Integer);
|
|
procedure SetWidth(Value: Integer);
|
|
|
|
procedure CheckRowCount(var Value: Integer);
|
|
procedure CheckVisibleWidthValue(var Value: Integer);
|
|
procedure CheckWidthValue(var Value: Integer);
|
|
function FindField: TField;
|
|
function FindSummaryField: TField;
|
|
procedure HeaderGlyphChanged(Sender: TObject);
|
|
function IsAlignmentStored: Boolean;
|
|
function IsCaptionStored: Boolean;
|
|
function IsFooterAlignmentStored: Boolean;
|
|
function IsHeaderAlignmentStored: Boolean;
|
|
function IsSummaryFieldNameStored: Boolean;
|
|
function IsWidthLinked: Boolean;
|
|
function IsWidthStored: Boolean;
|
|
procedure ReadLeaveSortOrder(Reader: TReader);
|
|
procedure WriteLeaveSortOrder(Writer: TWriter);
|
|
protected
|
|
procedure DefineProperties(Filer: TFiler); override;
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
procedure SetName(const NewName: TComponentName); override;
|
|
procedure SetParentComponent(AParent: TComponent); override;
|
|
|
|
function CanGrouping(Index: Integer): Boolean;
|
|
function CanHiding: Boolean;
|
|
function CanMoving: Boolean;
|
|
function CanHorSizing: Boolean;
|
|
function CanSorting: Boolean;
|
|
function CanVerSizing: Boolean;
|
|
procedure ColumnChanged(HardRefresh: Boolean;
|
|
HPart: TdxMasterViewHPart; VPart: TdxMasterViewVPart);
|
|
procedure ContentStyleChanged(Values: TdxMasterViewStyleValues);
|
|
function DefaultAlignment: TAlignment;
|
|
function DefaultCaption: string;
|
|
function DefaultHeaderAlignment: TAlignment;
|
|
function DefaultWidth: Integer;
|
|
procedure DoAfterCalcSummary(Node: TdxMasterViewNode; DataSet: TDataSet;
|
|
var Value: Extended); virtual;
|
|
procedure DoBeforeCalcSummary(Node: TdxMasterViewNode; DataSet: TDataSet;
|
|
var Value: Extended); virtual;
|
|
procedure DoCalcSummary(Node: TdxMasterViewNode; DataSet: TDataSet;
|
|
var Value: Extended); virtual;
|
|
procedure DrawSortMark(DC: HDC; var ARect: TRect);
|
|
procedure DrawHeader(DC: HDC; var ARect: TRect; Node: TdxMasterViewNode); virtual;
|
|
procedure DrawContent(DC: HDC; var ARect: TRect; Node: TdxMasterViewNode); virtual;
|
|
procedure DrawFooter(DC: HDC; var ARect: TRect; Node: TdxMasterViewNode); virtual;
|
|
procedure FooterStyleChanged(Values: TdxMasterViewStyleValues);
|
|
function GetFooterText(Node: TdxMasterViewNode): string;
|
|
function GetGroupByBoxBounds(Node: TdxMasterViewNode): TRect;
|
|
function GetGroupDisplayText(Node: TdxMasterViewNode): string; virtual;
|
|
function GetHeaderBestFitWidth(DC: HDC; CheckSortOrderMark: Boolean): Integer;
|
|
function GetHeaderBounds(Node: TdxMasterViewNode): TRect;
|
|
function GetHeaderHeight: Integer;
|
|
function GetContentBounds(Node: TdxMasterViewNode): TRect;
|
|
function GetFooterBounds(Node: TdxMasterViewNode): TRect;
|
|
procedure HeaderStyleChanged(Values: TdxMasterViewStyleValues);
|
|
|
|
property AddInWidth: Integer read FAddInWidth;
|
|
property Hidden: Boolean read GetHidden;
|
|
property InternalVisibleWidth: Integer read FVisibleWidth write SetInternalVisibleWidth;
|
|
property IsDestroying: Boolean read GetIsDestroying;
|
|
property IsLoading: Boolean read GetIsLoading;
|
|
property LastInRow: Boolean read GetLastInRow;
|
|
property LogicalOffset: Integer read GetLogicalOffset;
|
|
// property MaxLogicalOffset: Integer read GetMaxLogicalOffset;
|
|
property MinLogicalOffset: Integer read GetMinLogicalOffset;
|
|
property NonScaledLogicalOffset: Integer read GetNonScaledLogicalOffset;
|
|
// property NonScaledOffset: Integer read GetNonScaledOffset;
|
|
property NonScaledWidth: Integer read GetNonScaledWidth;
|
|
property Offset: Integer read GetOffset;
|
|
property Pressed: Boolean read FPressed write SetPressed;
|
|
property SummaryIndex: Integer read GetSummaryIndex;
|
|
property VisibleMaxWidth: Integer read GetVisibleMaxWidth;
|
|
property VisibleMinWidth: Integer read GetVisibleMinWidth;
|
|
|
|
property HeaderBrush: HBRUSH read GetHeaderBrush;
|
|
property HeaderColor: TColor read GetHeaderColor;
|
|
property HeaderFont: TFont read GetHeaderFont;
|
|
property ContentAnotherBrush: HBRUSH read GetContentAnotherBrush;
|
|
property ContentAnotherColor: TColor read GetContentAnotherColor;
|
|
property ContentBrush: HBRUSH read GetContentBrush;
|
|
property ContentColor: TColor read GetContentColor;
|
|
property ContentFont: TFont read GetContentFont;
|
|
property FooterBrush: HBRUSH read GetFooterBrush;
|
|
property FooterColor: TColor read GetFooterColor;
|
|
property FooterFont: TFont read GetFooterFont;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
procedure ChangeWidth(Value: Integer; AdjustLinkedColumns: Boolean);
|
|
function GetParentComponent: TComponent; override;
|
|
function HasParent: Boolean; override;
|
|
|
|
procedure ApplyBestFit;
|
|
function GetBestFitWidth: Integer;
|
|
function GetFooterValue(Node: TdxMasterViewNode): Extended;
|
|
|
|
property AssignedValues: TdxMasterViewColumnAssignedValues read FAssignedValues
|
|
write SetAssignedValues;
|
|
property Control: TdxMasterView read GetControl;
|
|
property Field: TField read FField write SetField;
|
|
property Index: Integer read GetIndex write SetIndex;
|
|
property Level: TdxMasterViewLevel read FLevel;
|
|
property SummaryField: TField read GetSummaryField write SetSummaryField;
|
|
property VisibleIndex: Integer read GetVisibleIndex;
|
|
property VisibleWidth: Integer read GetVisibleWidth write SetVisibleWidth;
|
|
published
|
|
property Alignment: TAlignment read GetAlignment write SetAlignment stored IsAlignmentStored;
|
|
property Caption: string read GetCaption write SetCaption stored IsCaptionStored;
|
|
property ContentStyle: TdxMasterViewStyle read FContentStyle write SetContentStyle;
|
|
property FieldName: string read FFieldName write SetFieldName;
|
|
property FooterAlignment: TAlignment read GetFooterAlignment write SetFooterAlignment
|
|
stored IsFooterAlignmentStored;
|
|
property FooterStyle: TdxMasterViewStyle read FFooterStyle write SetFooterStyle;
|
|
property GroupIndex: Integer read GetGroupIndex write SetGroupIndex default -1;
|
|
property HeaderAlignment: TAlignment read GetHeaderAlignment write SetHeaderAlignment
|
|
stored IsHeaderAlignmentStored;
|
|
property HeaderGlyph: TBitmap read FHeaderGlyph write SetHeaderGlyph;
|
|
property HeaderGlyphAlignment: TAlignment read FHeaderGlyphAlignment
|
|
write SetHeaderGlyphAlignment default taLeftJustify;
|
|
property HeaderStyle: TdxMasterViewStyle read FHeaderStyle write SetHeaderStyle;
|
|
property MaxRowCount: Integer read FMaxRowCount write SetMaxRowCount
|
|
default dxMVColumnDefaultMaxRowCount;
|
|
property MaxWidth: Integer read FMaxWidth write SetMaxWidth
|
|
default dxMVColumnDefaultMaxWidth;
|
|
property MinRowCount: Integer read FMinRowCount write SetMinRowCount default 1;
|
|
property MinWidth: Integer read FMinWidth write SetMinWidth
|
|
default dxMVColumnDefaultMinWidth;
|
|
property MultiLine: Boolean read FMultiLine write SetMultiLine default False;
|
|
property Options: TdxMasterViewColumnOptions read FOptions write SetOptions
|
|
default [coGrouping, coHorSizing, coMoving, coSorting, coVerSizing, coShowCaption];
|
|
|
|
property RowIndex: Integer read GetRowIndex write SetRowIndex; // must be before RowCount
|
|
property ColIndex: Integer read GetColIndex write SetColIndex;
|
|
property RowCount: Integer read FRowCount write SetRowCount default 1;
|
|
|
|
property SortIndex: Integer read GetSortIndex write SetSortIndex default -1;
|
|
property SortOrder: TdxMasterViewSortOrder read FSortOrder write SetSortOrder default soNone;
|
|
property SummaryFieldName: string read GetSummaryFieldName write SetSummaryFieldName
|
|
stored IsSummaryFieldNameStored;
|
|
property SummaryFormat: string read FSummaryFormat write SetSummaryFormat;
|
|
property SummaryType: TdxMasterViewSummaryType read FSummaryType write SetSummaryType
|
|
default stNone;
|
|
property Visible: Boolean read FVisible write SetVisible default True;
|
|
property Width: Integer read FWidth write SetWidth stored IsWidthStored;
|
|
|
|
property OnAfterCalcSummary: TdxMVSummaryEvent read FOnAfterCalcSummary
|
|
write FOnAfterCalcSummary;
|
|
property OnBeforeCalcSummary: TdxMVSummaryEvent read FOnBeforeCalcSummary
|
|
write FOnBeforeCalcSummary;
|
|
property OnCalcSummary: TdxMVSummaryEvent read FOnCalcSummary write FOnCalcSummary;
|
|
property OnGetContentStyle: TdxMVColumnGetStyleEvent read FOnGetContentStyle
|
|
write FOnGetContentStyle;
|
|
property OnGetFooterStyle: TdxMVColumnGetStyleEvent read FOnGetFooterStyle
|
|
write FOnGetFooterStyle;
|
|
property OnGetHeaderStyle: TdxMVColumnGetStyleEvent read FOnGetHeaderStyle
|
|
write FOnGetHeaderStyle;
|
|
end;
|
|
|
|
TdxMasterViewLayout = class
|
|
private
|
|
FContentNonScaledWidths: PIntArray;
|
|
FContentWidths: PIntArray;
|
|
FHeaderWidthAssigned: PBoolArray;
|
|
FHeaderWidths: PIntArray;
|
|
FHorizontal: Boolean;
|
|
FLevel: TdxMasterViewLevel;
|
|
FLines: TList;
|
|
FRowCount: Integer;
|
|
FUpdateLockCount: Integer;
|
|
FVisibleWidth: Integer;
|
|
function GetColLogicalOffset(ACol: Integer): Integer;
|
|
function GetColOffset(ACol: Integer): Integer;
|
|
function GetColumn(ARow, ACol: Integer): TdxMasterViewColumn;
|
|
function GetColWidth(ACol: Integer): Integer;
|
|
function GetContentDynamicMaxWidth(ACol: Integer): Integer;
|
|
function GetContentDynamicMinWidth(ACol: Integer): Integer;
|
|
function GetContentMaxWidth(ACol: Integer): Integer;
|
|
function GetContentMinWidth(ACol: Integer): Integer;
|
|
function GetContentNonScaledWidth(ACol: Integer): Integer;
|
|
function GetContentWidth(ACol: Integer): Integer;
|
|
function GetCount: Integer;
|
|
function GetHeaderDynamicMaxWidth(ACol: Integer): Integer;
|
|
function GetHeaderDynamicMinWidth(ACol: Integer): Integer;
|
|
function GetHeaderMaxWidth(ACol: Integer): Integer;
|
|
function GetHeaderMinWidth(ACol: Integer): Integer;
|
|
function GetHeaderWidth(ACol: Integer): Integer;
|
|
function GetHeaderWidthAssigned(ACol: Integer): Boolean;
|
|
function GetItem(Index: Integer): TList;
|
|
// function GetMaxWidth: Integer;
|
|
function GetMinWidth: Integer;
|
|
function GetNonScaledWidth: Integer;
|
|
function GetVisibleWidth: Integer;
|
|
procedure SetContentInternalVisibleWidth(ACol, Value: Integer);
|
|
procedure SetContentWidth(ACol, Value: Integer);
|
|
procedure SetCount(Value: Integer);
|
|
procedure SetHeaderWidth(ACol, Value: Integer);
|
|
procedure SetHeaderWidthAssigned(ACol: Integer; Value: Boolean);
|
|
protected
|
|
function AreNeighbours(Column1, Column2: TdxMasterViewColumn;
|
|
ExactResult: Boolean): Boolean;
|
|
procedure CalcAddInWidths;
|
|
procedure CalcColWidths;
|
|
procedure CalcLogicalOffsets(Mode: Byte);
|
|
procedure CalcNeighbours;
|
|
procedure CalcOptimizedValues;
|
|
procedure CalcVisibleWidth;
|
|
procedure CheckColumnsWidths(FixedColumn: TdxMasterViewColumn);
|
|
procedure CheckCount;
|
|
procedure Clear;
|
|
procedure ClearOptimizedValues;
|
|
function ColFromX(X: Integer): Integer;
|
|
procedure CreateColArrays;
|
|
procedure Delete(Index: Integer);
|
|
procedure DestroyColArrays;
|
|
function HasLeftNeighbours(AColumn: TdxMasterViewColumn; AList: TList;
|
|
ExactResult: Boolean): Boolean;
|
|
// function HasLinkedColumns(AColumn: TdxMasterViewColumn; AList: TList): Boolean;
|
|
function HasRightNeighbours(AColumn: TdxMasterViewColumn; AList: TList;
|
|
ExactResult: Boolean): Boolean;
|
|
procedure HeaderWidthChanged;
|
|
procedure Insert(Index, ACount: Integer);
|
|
procedure InsertAtPos(ARow, APos: Integer; AColumn: TdxMasterViewColumn);
|
|
procedure InsertColumn(ARow, ACol: Integer; AColumn: TdxMasterViewColumn);
|
|
procedure InsertColumnAtPos(ARow, APos: Integer; AColumn: TdxMasterViewColumn);
|
|
procedure InternalRemoveFreeSpace;
|
|
procedure RemoveColumn(AColumn: TdxMasterViewColumn);
|
|
procedure RetrieveLastColumns(AList: TList);
|
|
function GetNearestCol(ARow, AOffset: Integer): Integer;
|
|
function GetNearestRow(ACol, ARow: Integer): Integer;
|
|
procedure RequireCount(ACount: Integer);
|
|
procedure ViewModeChanged;
|
|
|
|
property ContentInternalVisibleWidths[ACol: Integer]: Integer
|
|
write SetContentInternalVisibleWidth;
|
|
public
|
|
constructor Create(ALevel: TdxMasterViewLevel);
|
|
destructor Destroy; override;
|
|
procedure BeginUpdate;
|
|
procedure CancelUpdate;
|
|
procedure ChangeCol(AColumn: TdxMasterViewColumn; ACol: Integer);
|
|
procedure ChangeHeaderWidth(ACol: Integer; Value: Integer; FixCol: Boolean);
|
|
procedure ChangeRow(AColumn: TdxMasterViewColumn; ARow: Integer; FixedPos: Boolean);
|
|
procedure ChangeRowAndRowCount(AColumn: TdxMasterViewColumn; ARow, ARowCount: Integer;
|
|
FixedPos: Boolean);
|
|
procedure ChangeRowCount(AColumn: TdxMasterViewColumn; ARowCount: Integer);
|
|
procedure EndUpdate;
|
|
function GetBestFitWidth(ACol: Integer): Integer;
|
|
function IndexOf(AColumn: TdxMasterViewColumn; ALine: Integer): Integer;
|
|
function IsColumnFirst(AColumn: TdxMasterViewColumn): Boolean;
|
|
function IsColumnLast(AColumn: TdxMasterViewColumn): Boolean;
|
|
function OneOnLine(AColumn: TdxMasterViewColumn): Boolean;
|
|
procedure RemoveFreeSpace;
|
|
|
|
property ColLogicalOffsets[ACol: Integer]: Integer read GetColLogicalOffset;
|
|
property ColOffsets[ACol: Integer]: Integer read GetColOffset;
|
|
property Columns[ARow, ACol: Integer]: TdxMasterViewColumn read GetColumn;
|
|
property ColWidths[ACol: Integer]: Integer read GetColWidth;
|
|
property ContentDynamicMaxWidths[ACol: Integer]: Integer read GetContentDynamicMaxWidth;
|
|
property ContentDynamicMinWidths[ACol: Integer]: Integer read GetContentDynamicMinWidth;
|
|
property ContentMaxWidths[ACol: Integer]: Integer read GetContentMaxWidth;
|
|
property ContentMinWidths[ACol: Integer]: Integer read GetContentMinWidth;
|
|
property ContentNonScaledWidths[ACol: Integer]: Integer read GetContentNonScaledWidth;
|
|
property ContentWidths[ACol: Integer]: Integer read GetContentWidth write SetContentWidth;
|
|
property Count: Integer read GetCount write SetCount;
|
|
property HeaderDynamicMaxWidths[ACol: Integer]: Integer read GetHeaderDynamicMaxWidth;
|
|
property HeaderDynamicMinWidths[ACol: Integer]: Integer read GetHeaderDynamicMinWidth;
|
|
property HeaderMaxWidths[ACol: Integer]: Integer read GetHeaderMaxWidth;
|
|
property HeaderMinWidths[ACol: Integer]: Integer read GetHeaderMinWidth;
|
|
property HeaderWidthAssigned[ACol: Integer]: Boolean read GetHeaderWidthAssigned
|
|
write SetHeaderWidthAssigned;
|
|
property HeaderWidths[ACol: Integer]: Integer read GetHeaderWidth write SetHeaderWidth;
|
|
property Horizontal: Boolean read FHorizontal;
|
|
property Items[Index: Integer]: TList read GetItem; default;
|
|
// property MaxWidth: Integer read GetMaxWidth;
|
|
property MinWidth: Integer read GetMinWidth;
|
|
property NonScaledWidth: Integer read GetNonScaledWidth;
|
|
property RowCount: Integer read FRowCount;
|
|
property VisibleWidth: Integer read FVisibleWidth;
|
|
end;
|
|
|
|
TdxMasterViewLevelOptionBehavior = (lobDblClkExpanding);
|
|
TdxMasterViewLevelOptionsBehavior = set of TdxMasterViewLevelOptionBehavior;
|
|
|
|
TdxMasterViewLevelOptionCustomize =
|
|
(locColumnMoving, locColumnHiding, locColumnHorSizing, locColumnVerSizing,
|
|
locColumnSorting, locColumnGrouping, locHideColumnOnGrouping,
|
|
locShowColumnOnUngrouping);
|
|
TdxMasterViewLevelOptionsCustomize = set of TdxMasterViewLevelOptionCustomize;
|
|
|
|
TdxMasterViewLevelOptionCustomizeBox =
|
|
(loxCaption, loxColumns, loxFooter, loxGrid, loxGridWithPreview, loxGroupByBox,
|
|
loxHeader, loxHeaderOptions, loxOccupyRestSpace, loxPreview, loxViewMode);
|
|
TdxMasterViewLevelOptionsCustomizeBox = set of TdxMasterViewLevelOptionCustomizeBox;
|
|
|
|
TdxMasterViewLevelOptionDB =
|
|
(lodAllowDelete, lodAllowInsert, lodConfirmDelete, lodDeleteOnlyChildless,
|
|
lodDontFilterRecords, lodSmartLoad, lodSmartRefresh, lodSmartReload);
|
|
TdxMasterViewLevelOptionsDB = set of TdxMasterViewLevelOptionDB;
|
|
|
|
TdxMasterViewLevelOptionHeader =
|
|
(lohForFirstNode, lohForFirstVisibleNode, lohAfterExpandedNode);
|
|
TdxMasterViewLevelOptionsHeader = set of TdxMasterViewLevelOptionHeader;
|
|
|
|
TdxMasterViewLevelOptionView =
|
|
(lovCaption, lovFooter, lovGrid, lovGridWithPreview, lovGroupByBox,
|
|
lovHeader, lovNoButtonsWhenNoChildren, lovOccupyRestSpace, lovPreview);
|
|
TdxMasterViewLevelOptionsView = set of TdxMasterViewLevelOptionView;
|
|
|
|
PdxMVLevels = ^TdxMVLevels;
|
|
TdxMVLevels = array[0..MaxInt div SizeOf(TdxMasterViewLevel) - 1] of
|
|
{$IFDEF CBUILDER3}TComponent{$ELSE}TdxMasterViewLevel{$ENDIF};
|
|
TdxMasterViewViewMode = (vmHorizontal, vmVertical);
|
|
|
|
TdxMVChangeGroupingEvent = procedure(Sender: TdxMasterViewLevel; Column: TdxMasterViewColumn;
|
|
GroupIndex: Integer; var Allow: Boolean) of object;
|
|
TdxMVColumnEvent = procedure(Sender: TdxMasterViewLevel; Column: TdxMasterViewColumn) of object;
|
|
TdxMVColumnAllowEvent = procedure(Sender: TdxMasterViewLevel; Column: TdxMasterViewColumn;
|
|
var Allow: Boolean) of object;
|
|
TdxMVFilterRecordEvent = procedure(Sender: TdxMasterViewLevel;
|
|
const AID, AKeyValue: Variant; var Accept: Boolean) of object;
|
|
TdxMVGetFooterCellTextEvent = procedure(Sender: TdxMasterViewLevel;
|
|
Node: TdxMasterViewNode; Column: TdxMasterViewColumn; var Text: string) of object;
|
|
TdxMVGetPreviewLineCountEvent = procedure(Sender: TdxMasterViewLevel;
|
|
Node: TdxMasterViewNode; var LineCount: Integer) of object;
|
|
TdxMVGetPreviewTextEvent = procedure(Sender: TdxMasterViewLevel;
|
|
Node: TdxMasterViewNode; var Text: string) of object;
|
|
TdxMVLevelGetStyleEvent = procedure(Sender: TdxMasterViewLevel;
|
|
Node: TdxMasterViewNode; Column: TdxMasterViewColumn;
|
|
var NewStyle: TdxMasterViewStyle) of object;
|
|
TdxMVNodeEvent = procedure(Sender: TdxMasterViewLevel; Node: TdxMasterViewNode) of object;
|
|
TdxMVNodeAllowEvent = procedure(Sender: TdxMasterViewLevel; Node: TdxMasterViewNode;
|
|
var Allow: Boolean) of object;
|
|
|
|
TdxMasterViewLevel = class(TComponent)
|
|
private
|
|
FAbsoluteIndex: Integer;
|
|
FAssignWidthsLockCount: Integer;
|
|
FBeforeLoadActiveRecord: Integer;
|
|
FBeforeLoadBOF: Boolean;
|
|
FBeforeLoadBookmark: Pointer;
|
|
FBeforeLoadEOF: Boolean;
|
|
FCanUseSmartReload: Boolean;
|
|
FCaption: string;
|
|
FCaptionStyle: TdxMasterViewStyle;
|
|
FColumns: TList;
|
|
FContentStyle: TdxMasterViewStyle;
|
|
FControl: TdxMasterView;
|
|
FCursorBeforeLoading: TCursor;
|
|
FDataChanging: Boolean;
|
|
FDataChangingLockCount: Integer;
|
|
FDataLink: TdxMasterViewDataLink;
|
|
FDeleteConfirmCaptionText: string;
|
|
FDeleteConfirmText: string;
|
|
FDetailKey: string;
|
|
FDetailKeyFields: TList;
|
|
FEditingNode: TdxMasterViewNode;
|
|
FFirstVisibleNode: TdxMasterViewNode;
|
|
FFirstVisibleNodeWithData: TdxMasterViewNode;
|
|
FFooterStyle: TdxMasterViewStyle;
|
|
FGridLinesBrush: HBRUSH;
|
|
FGridLinesPen: HPEN;
|
|
FGridLinesColor: TColor;
|
|
FGroupByBoxStyle: TdxMasterViewStyle;
|
|
FGroupColumns: TList;
|
|
FGroupStyle: TdxMasterViewStyle;
|
|
FHeaderStyle: TdxMasterViewStyle;
|
|
FHorizontal: Boolean;
|
|
FID: string;
|
|
FIDFields: TList;
|
|
FIndex: Integer;
|
|
FIsInsertMode: Boolean;
|
|
FItems: TList;
|
|
FLayout: TdxMasterViewLayout;
|
|
FLevelSeparatorBrush: HBRUSH;
|
|
FLevelSeparatorColor: TColor;
|
|
FLevelSeparatorWidth: Integer;
|
|
FLoadingLockCount: Integer;
|
|
FLoadLockCount: Integer;
|
|
FMasterKey: string;
|
|
FMasterKeyFields: TList;
|
|
FMultipleDeleteConfirmText: string;
|
|
FOptionsBehavior: TdxMasterViewLevelOptionsBehavior;
|
|
FOptionsCustomize: TdxMasterViewLevelOptionsCustomize;
|
|
FOptionsCustomizeBox: TdxMasterViewLevelOptionsCustomizeBox;
|
|
FOptionsDB: TdxMasterViewLevelOptionsDB;
|
|
FOptionsHeader: TdxMasterViewLevelOptionsHeader;
|
|
FOptionsView: TdxMasterViewLevelOptionsView;
|
|
FParent: TdxMasterViewLevel;
|
|
FParentCount: Integer;
|
|
FParents: PdxMVLevels;
|
|
FPreviewDC: HDC;
|
|
FPreviewField: TField;
|
|
FPreviewFieldName: string;
|
|
FPreviewLeftIndent: Integer;
|
|
FPreviewLineCount: Integer;
|
|
FPreviewMaxLength: Integer;
|
|
FPreviewMaxLineCount: Integer;
|
|
FPreviewPrevFont: HFONT;
|
|
FPreviewRightIndent: Integer;
|
|
FPreviewStyle: TdxMasterViewStyle;
|
|
FRowSeparatorBrush: HBRUSH;
|
|
FRowSeparatorColor: TColor;
|
|
FRowSeparatorWidth: Integer;
|
|
FSortedColumns: TList;
|
|
FSortingLockCount: Integer;
|
|
FSummaryColumns: TList;
|
|
FViewMode: TdxMasterViewViewMode;
|
|
FVisible: Boolean;
|
|
FVisibleColumns: TList;
|
|
|
|
FHeaderHeight, FContentHeight, FFooterHeight,
|
|
FHeaderRealHeight, FContentRealHeight,
|
|
FCaptionHeight, FGroupHeight, FGroupByBoxTextHeight: Integer;
|
|
FLineWidth, FExtLineWidth: Integer;
|
|
|
|
// for GetParentNode function
|
|
GPNGroupValue, GPNFindingValue, GPNCurValue: Variant;
|
|
GPNDisplayText, GPNS1, GPNS2: string;
|
|
GPNCanUseAnsiCompareStrOnGrouping, GPNCanUseCaseInsensitiveGrouping,
|
|
GPNFindingValueIsNull, GPNCurValueIsNull, GPNReverseOrder: Boolean;
|
|
GPNParentNode: TdxMasterViewNode;
|
|
|
|
FOnChangeGrouping: TdxMVChangeGroupingEvent;
|
|
FOnCollapsed: TdxMVNodeEvent;
|
|
FOnCollapsing: TdxMVNodeAllowEvent;
|
|
FOnColumnSorted: TdxMVColumnEvent;
|
|
FOnColumnSorting: TdxMVColumnAllowEvent;
|
|
FOnDeleteNode: TdxMVNodeEvent;
|
|
FOnExpanded: TdxMVNodeEvent;
|
|
FOnExpanding: TdxMVNodeAllowEvent;
|
|
FOnFilterRecord: TdxMVFilterRecordEvent;
|
|
FOnGetCaptionStyle: TdxMVLevelGetStyleEvent;
|
|
FOnGetContentStyle: TdxMVLevelGetStyleEvent;
|
|
FOnGetFooterCellText: TdxMVGetFooterCellTextEvent;
|
|
FOnGetFooterStyle: TdxMVLevelGetStyleEvent;
|
|
FOnGetGroupByBoxStyle: TdxMVLevelGetStyleEvent;
|
|
FOnGetGroupStyle: TdxMVLevelGetStyleEvent;
|
|
FOnGetHeaderStyle: TdxMVLevelGetStyleEvent;
|
|
FOnGetPreviewLineCount: TdxMVGetPreviewLineCountEvent;
|
|
FOnGetPreviewStyle: TdxMVLevelGetStyleEvent;
|
|
FOnGetPreviewText: TdxMVGetPreviewTextEvent;
|
|
FOnHideColumn: TdxMVColumnEvent;
|
|
FOnShowColumn: TdxMVColumnEvent;
|
|
FOnWidthChanged: TNotifyEvent;
|
|
|
|
function GetActive: Boolean;
|
|
function GetCaptionBrush: HBRUSH;
|
|
function GetCaptionColor: TColor;
|
|
function GetCaptionFont: TFont;
|
|
function GetColumn(Index: Integer): TdxMasterViewColumn;
|
|
function GetColumnCount: Integer;
|
|
function GetContentAnotherBrush: HBRUSH;
|
|
function GetContentAnotherColor: TColor;
|
|
function GetContentBrush: HBRUSH;
|
|
function GetContentColor: TColor;
|
|
function GetContentFont: TFont;
|
|
function GetCount: Integer;
|
|
function GetDataSet: TDataSet;
|
|
function GetDataSource: TDataSource;
|
|
function GetDetailKeyField(Index: Integer): TField;
|
|
function GetDetailKeyFieldCount: Integer;
|
|
function GetDontFilterRecords: Boolean;
|
|
function GetFooterBrush: HBRUSH;
|
|
function GetFooterColor: TColor;
|
|
function GetFooterFont: TFont;
|
|
function GetGroupBrush: HBRUSH;
|
|
function GetGroupByBoxBrush: HBRUSH;
|
|
function GetGroupByBoxColor: TColor;
|
|
function GetGroupByBoxFont: TFont;
|
|
function GetGroupByBoxFontColor: TColor;
|
|
function GetGroupByBoxHeight: Integer;
|
|
function GetGroupColor: TColor;
|
|
function GetGroupColumn(Index: Integer): TdxMasterViewColumn;
|
|
function GetGroupColumnCount: Integer;
|
|
function GetGroupFont: TFont;
|
|
function GetHasChildren: Boolean;
|
|
function GetHeaderBrush: HBRUSH;
|
|
function GetHeaderColor: TColor;
|
|
function GetHeaderFont: TFont;
|
|
function GetHeaderRestSpaceBrush: HBRUSH;
|
|
function GetHeaderRestSpaceColor: TColor;
|
|
function GetIDField(Index: Integer): TField;
|
|
function GetIDFieldCount: Integer;
|
|
function GetIndent: Integer;
|
|
function GetIsDestroying: Boolean;
|
|
function GetIsFirst: Boolean;
|
|
function GetIsLast: Boolean;
|
|
function GetIsLoading: Boolean;
|
|
function GetIsTop: Boolean;
|
|
function GetItem(Index: Integer): TdxMasterViewLevel;
|
|
function GetMasterKeyField(Index: Integer): TField;
|
|
function GetMasterKeyFieldCount: Integer;
|
|
function GetNonScaledWidth: Integer;
|
|
function GetOccupyRestSpace: Boolean;
|
|
{$IFDEF CBUILDER3}
|
|
function GetParent(Index: Integer): TdxMasterViewLevel;
|
|
{$ENDIF}
|
|
function GetPreviewAnotherBrush: HBRUSH;
|
|
function GetPreviewAnotherColor: TColor;
|
|
function GetPreviewBrush: HBRUSH;
|
|
function GetPreviewColor: TColor;
|
|
function GetPreviewColorAssigned: Boolean;
|
|
function GetPreviewFont: TFont;
|
|
function GetPreviewFontAssigned: Boolean;
|
|
function GetPreviewFontColor: TColor;
|
|
function GetRowCount: Integer;
|
|
function GetShowCaption: Boolean;
|
|
function GetShowFooter: Boolean;
|
|
function GetShowGrid: Boolean;
|
|
function GetShowGridWithPreview: Boolean;
|
|
function GetShowGroupByBox: Boolean;
|
|
function GetShowHeader: Boolean;
|
|
function GetShowPreview: Boolean;
|
|
function GetSmartLoad: Boolean;
|
|
function GetSmartReload: Boolean;
|
|
function GetSortedColumn(Index: Integer): TdxMasterViewColumn;
|
|
function GetSortedColumnCount: Integer;
|
|
function GetVisibleColumn(Index: Integer): TdxMasterViewColumn;
|
|
function GetVisibleColumnCount: Integer;
|
|
function GetVisibleRowCount: Integer;
|
|
function GetVisibleWidth: Integer;
|
|
procedure SetCaption(const Value: string);
|
|
procedure SetCaptionStyle(Value: TdxMasterViewStyle);
|
|
procedure SetColumn(Index: Integer; Value: TdxMasterViewColumn);
|
|
procedure SetContentStyle(Value: TdxMasterViewStyle);
|
|
procedure SetDataSource(Value: TDataSource);
|
|
procedure SetDetailKey(const Value: string);
|
|
procedure SetFooterStyle(Value: TdxMasterViewStyle);
|
|
procedure SetGridLinesColor(Value: TColor);
|
|
procedure SetGroupByBoxStyle(Value: TdxMasterViewStyle);
|
|
procedure SetGroupStyle(Value: TdxMasterViewStyle);
|
|
procedure SetHeaderStyle(Value: TdxMasterViewStyle);
|
|
procedure SetID(Value: string);
|
|
procedure SetMasterKey(const Value: string);
|
|
procedure SetOptionsDB(Value: TdxMasterViewLevelOptionsDB);
|
|
procedure SetOptionsHeader(Value: TdxMasterViewLevelOptionsHeader);
|
|
procedure SetOptionsView(Value: TdxMasterViewLevelOptionsView);
|
|
procedure SetPreviewField(Value: TField);
|
|
procedure SetPreviewFieldInternally(Value: TField);
|
|
procedure SetPreviewFieldName(Value: string);
|
|
procedure SetPreviewLeftIndent(Value: Integer);
|
|
procedure SetPreviewLineCount(Value: Integer);
|
|
procedure SetPreviewMaxLength(Value: Integer);
|
|
procedure SetPreviewMaxLineCount(Value: Integer);
|
|
procedure SetPreviewRightIndent(Value: Integer);
|
|
procedure SetPreviewStyle(Value: TdxMasterViewStyle);
|
|
procedure SetRowSeparatorColor(Value: TColor);
|
|
procedure SetRowSeparatorWidth(Value: Integer);
|
|
procedure SetLevelSeparatorColor(Value: TColor);
|
|
procedure SetLevelSeparatorWidth(Value: Integer);
|
|
procedure SetViewMode(Value: TdxMasterViewViewMode);
|
|
procedure SetVisibleColumn(Index: Integer; Value: TdxMasterViewColumn);
|
|
|
|
function IsDeleteConfirmCaptionTextStored: Boolean;
|
|
function IsDeleteConfirmTextStored: Boolean;
|
|
function IsMultipleDeleteConfirmTextStored: Boolean;
|
|
procedure ReadHeaderWidths(Reader: TReader);
|
|
procedure WriteHeaderWidths(Writer: TWriter);
|
|
|
|
procedure AddColumn(AColumn: TdxMasterViewColumn);
|
|
procedure RemoveColumn(AColumn: TdxMasterViewColumn);
|
|
procedure AddItem(Value: TdxMasterViewLevel);
|
|
procedure RemoveItem(Value: TdxMasterViewLevel);
|
|
function FindPreviewField: TField;
|
|
procedure FontsChanged;
|
|
procedure DeleteNodes;
|
|
procedure RefreshDetailKeyFieldsList;
|
|
procedure RefreshIDFieldsList;
|
|
procedure RefreshMasterKeyFieldsList;
|
|
procedure RefreshVisibleColumnsList;
|
|
procedure SummaryColumnsChanged(AColumn: TdxMasterViewColumn; Operation: TOperation);
|
|
protected
|
|
procedure DefineProperties(Filer: TFiler); override;
|
|
procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
|
|
procedure Loaded; override;
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
procedure SetName(const NewName: TComponentName); override;
|
|
procedure SetParentComponent(AParent: TComponent); override;
|
|
|
|
procedure ActiveChanged;
|
|
procedure AfterPaint;
|
|
procedure AssignColumnWidths;
|
|
procedure BeforePaint;
|
|
procedure BeginLoad;
|
|
procedure BeginLoading;
|
|
procedure CalcDefaultWidths(Column: TdxMasterViewColumn);
|
|
procedure CalcLineWidth;
|
|
procedure CalcParents;
|
|
procedure CalcRealHeights;
|
|
procedure DestroySummaries(NodeTypes: TdxMasterViewNodeTypes);
|
|
procedure EndLoad(RecalcInfo: Boolean);
|
|
procedure EndLoading;
|
|
procedure LoadingComplete;
|
|
|
|
procedure CalcPreviewLineCount(DC: HDC; const S: string; Width: Integer;
|
|
Node: TdxMasterViewNode; var Height: Integer);
|
|
function CanDelete: Boolean;
|
|
function CanGrouping(Column: TdxMasterViewColumn; Index: Integer): Boolean;
|
|
function CanHorSizing: Boolean;
|
|
function CanInsert: Boolean;
|
|
function CanSmartRefresh: Boolean;
|
|
function CanSorting(Column: TdxMasterViewColumn): Boolean;
|
|
procedure CaptionStyleChanged(Values: TdxMasterViewStyleValues);
|
|
procedure ChangeGrouping(Column: TdxMasterViewColumn; AIndex: Integer);
|
|
procedure ChangeSorting(Column: TdxMasterViewColumn;
|
|
ASortOrder: TdxMasterViewSortOrder; ASortIndex: Integer);
|
|
procedure ContentStyleChanged(Values: TdxMasterViewStyleValues);
|
|
procedure DataChanged;
|
|
procedure DoAfterCollapse(Node: TdxMasterViewNode);
|
|
procedure DoAfterExpand(Node: TdxMasterViewNode);
|
|
function DoBeforeCollapse(Node: TdxMasterViewNode): Boolean;
|
|
function DoBeforeExpand(Node: TdxMasterViewNode): Boolean;
|
|
procedure DoGetContentStyle(Node: TdxMasterViewNode; Column: TdxMasterViewColumn;
|
|
var NewStyle: TdxMasterViewStyle); virtual;
|
|
procedure DoGetFooterCellText(Node: TdxMasterViewNode; Column: TdxMasterViewColumn;
|
|
var Text: string);
|
|
procedure DoHideColumn(Column: TdxMasterViewColumn);
|
|
procedure DoNodeDeleted(Node: TdxMasterViewNode);
|
|
procedure DoShowColumn(Column: TdxMasterViewColumn);
|
|
procedure DoSorting;
|
|
procedure DrawIndent(DC: HDC; const ARect: TRect; Node: TdxMasterViewNode);
|
|
procedure DrawGroupByBox(DC: HDC; const ARect: TRect; Node: TdxMasterViewNode);
|
|
procedure DrawHeader(DC: HDC; const ARect: TRect; Node: TdxMasterViewNode);
|
|
procedure DrawContent(DC: HDC; const ARect: TRect; Node: TdxMasterViewNode);
|
|
procedure DrawFooter(DC: HDC; const ARect: TRect; Node: TdxMasterViewNode);
|
|
procedure EditingChanged;
|
|
procedure FooterStyleChanged(Values: TdxMasterViewStyleValues);
|
|
function GetCurDetailKeyValue: Variant;
|
|
function GetCurIDValue: Variant;
|
|
function GetCurKeyValue: Variant;
|
|
function GetCurMasterKeyValue: Variant;
|
|
function GetCurPreviewText(Node: TdxMasterViewNode): string;
|
|
function GetParentNode(Root, Node: TdxMasterViewNode;
|
|
FirstIndex, AvailIndex: PInteger; RestItems: TList;
|
|
CheckRoot: Boolean): TdxMasterViewNode;
|
|
procedure GroupByBoxStyleChanged(Values: TdxMasterViewStyleValues);
|
|
procedure GroupStyleChanged(Values: TdxMasterViewStyleValues);
|
|
function HasExpandButton: Boolean;
|
|
function HasGrid: Boolean;
|
|
//function HasAsChild(Level: TdxMasterViewLevel): Boolean;
|
|
function HasAsParent(Level: TdxMasterViewLevel): Boolean;
|
|
procedure HeaderStyleChanged(Values: TdxMasterViewStyleValues);
|
|
function IndexOfParent(Level: TdxMasterViewLevel): Integer;
|
|
procedure LayoutChanged;
|
|
procedure LevelChanged(HardRefresh: Boolean);
|
|
function LoadDataOnExpand: Boolean;
|
|
procedure MakeVisibleColumnsSortedList(List: TList);
|
|
procedure PreviewChanged;
|
|
procedure PreviewStyleChanged(Values: TdxMasterViewStyleValues);
|
|
procedure RecordChanged(Field: TField);
|
|
procedure RemoveFreeSpace;
|
|
procedure RestoreVisibleColumnsPlaces(var List: TList);
|
|
procedure SaveVisibleColumnsPlaces(var List: TList);
|
|
procedure FreeVisibleColumnsPlaces(var List: TList);
|
|
procedure SyncPos;
|
|
procedure UncheckTriedToExpand;
|
|
procedure WidthChanged;
|
|
procedure WidthChangedEx;
|
|
|
|
property Active: Boolean read GetActive;
|
|
property DataLink: TdxMasterViewDataLink read FDataLink;
|
|
property IsLoading: Boolean read GetIsLoading;
|
|
|
|
property CaptionHeight: Integer read FCaptionHeight;
|
|
property ContentHeight: Integer read FContentHeight;
|
|
property ContentRealHeight: Integer read FContentRealHeight;
|
|
property ExtLineWidth: Integer read FExtLineWidth;
|
|
property FooterHeight: Integer read FFooterHeight;
|
|
property GroupByBoxHeight: Integer read GetGroupByBoxHeight;
|
|
property GroupByBoxTextHeight: Integer read FGroupByBoxTextHeight;
|
|
property GroupHeight: Integer read FGroupHeight;
|
|
property HeaderHeight: Integer read FHeaderHeight;
|
|
property HeaderRealHeight: Integer read FHeaderRealHeight;
|
|
property Indent: Integer read GetIndent;
|
|
property IsDestroying: Boolean read GetIsDestroying;
|
|
property LineWidth: Integer read FLineWidth;
|
|
property NonScaledWidth: Integer read GetNonScaledWidth;
|
|
property VisibleWidth: Integer read GetVisibleWidth;
|
|
|
|
property Horizontal: Boolean read FHorizontal;
|
|
property ParentCount: Integer read FParentCount;
|
|
{$IFDEF CBUILDER3}
|
|
property Parents[Index: Integer]: TdxMasterViewLevel read GetParent;
|
|
{$ELSE}
|
|
property Parents: PdxMVLevels read FParents;
|
|
{$ENDIF}
|
|
property RowCount: Integer read GetRowCount;
|
|
property VisibleRowCount: Integer read GetVisibleRowCount;
|
|
|
|
property GridLinesBrush: HBRUSH read FGridLinesBrush;
|
|
property GridLinesPen: HPEN read FGridLinesPen;
|
|
property LevelSeparatorBrush: HBRUSH read FLevelSeparatorBrush;
|
|
property RowSeparatorBrush: HBRUSH read FRowSeparatorBrush;
|
|
|
|
property DontFilterRecords: Boolean read GetDontFilterRecords;
|
|
property OccupyRestSpace: Boolean read GetOccupyRestSpace;
|
|
property ShowCaption: Boolean read GetShowCaption;
|
|
property ShowFooter: Boolean read GetShowFooter;
|
|
property ShowGrid: Boolean read GetShowGrid;
|
|
property ShowGridWithPreview: Boolean read GetShowGridWithPreview;
|
|
property ShowGroupByBox: Boolean read GetShowGroupByBox;
|
|
property ShowHeader: Boolean read GetShowHeader;
|
|
property ShowPreview: Boolean read GetShowPreview;
|
|
property SmartLoad: Boolean read GetSmartLoad;
|
|
property SmartReload: Boolean read GetSmartReload;
|
|
|
|
property HeaderBrush: HBRUSH read GetHeaderBrush;
|
|
property HeaderColor: TColor read GetHeaderColor;
|
|
property HeaderFont: TFont read GetHeaderFont;
|
|
property HeaderRestSpaceBrush: HBRUSH read GetHeaderRestSpaceBrush;
|
|
property HeaderRestSpaceColor: TColor read GetHeaderRestSpaceColor;
|
|
property ContentAnotherBrush: HBRUSH read GetContentAnotherBrush;
|
|
property ContentAnotherColor: TColor read GetContentAnotherColor;
|
|
property ContentBrush: HBRUSH read GetContentBrush;
|
|
property ContentColor: TColor read GetContentColor;
|
|
property ContentFont: TFont read GetContentFont;
|
|
property FooterBrush: HBRUSH read GetFooterBrush;
|
|
property FooterColor: TColor read GetFooterColor;
|
|
property FooterFont: TFont read GetFooterFont;
|
|
property PreviewAnotherBrush: HBRUSH read GetPreviewAnotherBrush;
|
|
property PreviewAnotherColor: TColor read GetPreviewAnotherColor;
|
|
property PreviewBrush: HBRUSH read GetPreviewBrush;
|
|
property PreviewColor: TColor read GetPreviewColor;
|
|
property PreviewColorAssigned: Boolean read GetPreviewColorAssigned;
|
|
property PreviewFont: TFont read GetPreviewFont;
|
|
property PreviewFontAssigned: Boolean read GetPreviewFontAssigned;
|
|
property PreviewFontColor: TColor read GetPreviewFontColor;
|
|
property CaptionBrush: HBRUSH read GetCaptionBrush;
|
|
property CaptionColor: TColor read GetCaptionColor;
|
|
property CaptionFont: TFont read GetCaptionFont;
|
|
property GroupBrush: HBRUSH read GetGroupBrush;
|
|
property GroupColor: TColor read GetGroupColor;
|
|
property GroupFont: TFont read GetGroupFont;
|
|
property GroupByBoxBrush: HBRUSH read GetGroupByBoxBrush;
|
|
property GroupByBoxColor: TColor read GetGroupByBoxColor;
|
|
property GroupByBoxFont: TFont read GetGroupByBoxFont;
|
|
property GroupByBoxFontColor: TColor read GetGroupByBoxFontColor;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
function GetParentComponent: TComponent; override;
|
|
function HasParent: Boolean; override;
|
|
|
|
function Add: TdxMasterViewLevel;
|
|
procedure BeginAssignWidths;
|
|
procedure BeginDataChanging;
|
|
procedure BeginLayout;
|
|
procedure BeginSorting;
|
|
procedure CancelAssignWidths;
|
|
procedure CancelDataChanging;
|
|
procedure CancelLayout;
|
|
procedure CancelSorting;
|
|
procedure Clear;
|
|
procedure ClearSorting(ExceptionalColumn: TdxMasterViewColumn);
|
|
function ColumnByFieldName(const AFieldName: string): TdxMasterViewColumn;
|
|
function ColumnByName(const AName: string): TdxMasterViewColumn;
|
|
procedure CreateAllColumns;
|
|
function CreateColumn(AColumnClass: TdxMasterViewColumnClass): TdxMasterViewColumn;
|
|
procedure DestroyColumns;
|
|
procedure EndAssignWidths;
|
|
procedure EndDataChanging;
|
|
procedure EndLayout;
|
|
procedure EndSorting;
|
|
|
|
property AbsoluteIndex: Integer read FAbsoluteIndex;
|
|
property CanUseSmartReload: Boolean read FCanUseSmartReload write FCanUseSmartReload;
|
|
property ColumnCount: Integer read GetColumnCount;
|
|
property Columns[Index: Integer]: TdxMasterViewColumn read GetColumn write SetColumn;
|
|
property Control: TdxMasterView read FControl;
|
|
property Count: Integer read GetCount;
|
|
property DataSet: TDataSet read GetDataSet;
|
|
property DetailKeyFieldCount: Integer read GetDetailKeyFieldCount;
|
|
property DetailKeyFields[Index: Integer]: TField read GetDetailKeyField;
|
|
property GroupColumnCount: Integer read GetGroupColumnCount;
|
|
property GroupColumns[Index: Integer]: TdxMasterViewColumn read GetGroupColumn;
|
|
property HasChildren: Boolean read GetHasChildren;
|
|
property IDFieldCount: Integer read GetIDFieldCount;
|
|
property IDFields[Index: Integer]: TField read GetIDField;
|
|
property Index: Integer read FIndex;
|
|
property IsFirst: Boolean read GetIsFirst;
|
|
property IsLast: Boolean read GetIsLast;
|
|
property IsTop: Boolean read GetIsTop;
|
|
property Items[Index: Integer]: TdxMasterViewLevel read GetItem; default;
|
|
property Layout: TdxMasterViewLayout read FLayout;
|
|
property MasterKeyFieldCount: Integer read GetMasterKeyFieldCount;
|
|
property MasterKeyFields[Index: Integer]: TField read GetMasterKeyField;
|
|
property Parent: TdxMasterViewLevel read FParent;
|
|
property PreviewField: TField read FPreviewField write SetPreviewField;
|
|
property SortedColumnCount: Integer read GetSortedColumnCount;
|
|
property SortedColumns[Index: Integer]: TdxMasterViewColumn read GetSortedColumn;
|
|
property Visible: Boolean read FVisible;
|
|
property VisibleColumnCount: Integer read GetVisibleColumnCount;
|
|
property VisibleColumns[Index: Integer]: TdxMasterViewColumn
|
|
read GetVisibleColumn write SetVisibleColumn;
|
|
|
|
procedure GetContentParams(Node: TdxMasterViewNode; Column: TdxMasterViewColumn;
|
|
ABrush: PBRUSH; ATextColor, ABkColor: PColor; AFont: PFont; CheckSelected: Boolean);
|
|
procedure GetFooterParams(Node: TdxMasterViewNode; Column: TdxMasterViewColumn;
|
|
ABrush: PBRUSH; ATextColor, ABkColor: PColor; AFont: PFont);
|
|
procedure GetGroupByBoxParams(Node: TdxMasterViewNode;
|
|
ABrush: PBRUSH; ATextColor, ABkColor: PColor; AFont: PFont);
|
|
procedure GetHeaderParams(Node: TdxMasterViewNode; Column: TdxMasterViewColumn;
|
|
ABrush, ARestSpaceBrush: PBRUSH; ATextColor, ABkColor: PColor; AFont: PFont);
|
|
procedure GetPreviewParams(Node: TdxMasterViewNode;
|
|
ABrush: PBRUSH; ATextColor, ABkColor: PColor; AFont: PFont);
|
|
published
|
|
property Caption: string read FCaption write SetCaption;
|
|
property CaptionStyle: TdxMasterViewStyle read FCaptionStyle write SetCaptionStyle;
|
|
property ContentStyle: TdxMasterViewStyle read FContentStyle write SetContentStyle;
|
|
property DataSource: TDataSource read GetDataSource write SetDataSource;
|
|
property DeleteConfirmCaptionText: string read FDeleteConfirmCaptionText
|
|
write FDeleteConfirmCaptionText stored IsDeleteConfirmCaptionTextStored;
|
|
property DeleteConfirmText: string read FDeleteConfirmText write FDeleteConfirmText
|
|
stored IsDeleteConfirmTextStored;
|
|
property DetailKey: string read FDetailKey write SetDetailKey;
|
|
property FooterStyle: TdxMasterViewStyle read FFooterStyle write SetFooterStyle;
|
|
property GridLinesColor: TColor read FGridLinesColor write SetGridLinesColor
|
|
default clBtnShadow;
|
|
property GroupByBoxStyle: TdxMasterViewStyle read FGroupByBoxStyle
|
|
write SetGroupByBoxStyle;
|
|
property GroupStyle: TdxMasterViewStyle read FGroupStyle write SetGroupStyle;
|
|
property HeaderStyle: TdxMasterViewStyle read FHeaderStyle write SetHeaderStyle;
|
|
property ID: string read FID write SetID;
|
|
property LevelSeparatorColor: TColor read FLevelSeparatorColor
|
|
write SetLevelSeparatorColor default clWindowText{!};
|
|
property LevelSeparatorWidth: Integer read FLevelSeparatorWidth
|
|
write SetLevelSeparatorWidth default 0;
|
|
property MasterKey: string read FMasterKey write SetMasterKey;
|
|
property MultipleDeleteConfirmText: string read FMultipleDeleteConfirmText
|
|
write FMultipleDeleteConfirmText stored IsMultipleDeleteConfirmTextStored;
|
|
property OptionsBehavior: TdxMasterViewLevelOptionsBehavior read FOptionsBehavior
|
|
write FOptionsBehavior default [lobDblClkExpanding];
|
|
property OptionsCustomize: TdxMasterViewLevelOptionsCustomize read FOptionsCustomize
|
|
write FOptionsCustomize default [locColumnMoving, locColumnHorSizing,
|
|
locColumnVerSizing, locColumnSorting, locColumnGrouping, locShowColumnOnUngrouping];
|
|
property OptionsCustomizeBox: TdxMasterViewLevelOptionsCustomizeBox read FOptionsCustomizeBox
|
|
write FOptionsCustomizeBox default [loxCaption, loxColumns, loxGrid,
|
|
loxGroupByBox, loxHeader, loxViewMode];
|
|
property OptionsDB: TdxMasterViewLevelOptionsDB read FOptionsDB
|
|
write SetOptionsDB default [lodConfirmDelete, lodSmartLoad, lodSmartReload];
|
|
property OptionsHeader: TdxMasterViewLevelOptionsHeader read FOptionsHeader
|
|
write SetOptionsHeader default [lohForFirstNode, lohForFirstVisibleNode, lohAfterExpandedNode];
|
|
property OptionsView: TdxMasterViewLevelOptionsView read FOptionsView write SetOptionsView
|
|
default [lovGrid, lovGridWithPreview, lovHeader, lovOccupyRestSpace];
|
|
property PreviewFieldName: string read FPreviewFieldName write SetPreviewFieldName;
|
|
property PreviewLeftIndent: Integer read FPreviewLeftIndent write SetPreviewLeftIndent
|
|
default dxMVPreviewLeftIndent;
|
|
property PreviewLineCount: Integer read FPreviewLineCount write SetPreviewLineCount
|
|
default 0;
|
|
property PreviewMaxLength: Integer read FPreviewMaxLength write SetPreviewMaxLength
|
|
default 0;
|
|
property PreviewMaxLineCount: Integer read FPreviewMaxLineCount write SetPreviewMaxLineCount
|
|
default dxMVPreviewMaxLineCount;
|
|
property PreviewRightIndent: Integer read FPreviewRightIndent write SetPreviewRightIndent
|
|
default dxMVPreviewRightIndent;
|
|
property PreviewStyle: TdxMasterViewStyle read FPreviewStyle write SetPreviewStyle;
|
|
property RowSeparatorColor: TColor read FRowSeparatorColor write SetRowSeparatorColor
|
|
default clBtnShadow;
|
|
property RowSeparatorWidth: Integer read FRowSeparatorWidth write SetRowSeparatorWidth
|
|
default 0;
|
|
property ViewMode: TdxMasterViewViewMode read FViewMode write SetViewMode default vmHorizontal;
|
|
|
|
property OnChangeGrouping: TdxMVChangeGroupingEvent read FOnChangeGrouping
|
|
write FOnChangeGrouping;
|
|
property OnCollapsed: TdxMVNodeEvent read FOnCollapsed write FOnCollapsed;
|
|
property OnCollapsing: TdxMVNodeAllowEvent read FOnCollapsing write FOnCollapsing;
|
|
property OnColumnSorted: TdxMVColumnEvent read FOnColumnSorted write FOnColumnSorted;
|
|
property OnColumnSorting: TdxMVColumnAllowEvent read FOnColumnSorting
|
|
write FOnColumnSorting;
|
|
property OnDeleteNode: TdxMVNodeEvent read FOnDeleteNode write FOnDeleteNode;
|
|
property OnExpanded: TdxMVNodeEvent read FOnExpanded write FOnExpanded;
|
|
property OnExpanding: TdxMVNodeAllowEvent read FOnExpanding write FOnExpanding;
|
|
property OnFilterRecord: TdxMVFilterRecordEvent read FOnFilterRecord write FOnFilterRecord;
|
|
property OnGetCaptionStyle: TdxMVLevelGetStyleEvent read FOnGetCaptionStyle
|
|
write FOnGetCaptionStyle;
|
|
property OnGetContentStyle: TdxMVLevelGetStyleEvent read FOnGetContentStyle
|
|
write FOnGetContentStyle;
|
|
property OnGetFooterCellText: TdxMVGetFooterCellTextEvent read FOnGetFooterCellText
|
|
write FOnGetFooterCellText;
|
|
property OnGetFooterStyle: TdxMVLevelGetStyleEvent read FOnGetFooterStyle
|
|
write FOnGetFooterStyle;
|
|
property OnGetGroupByBoxStyle: TdxMVLevelGetStyleEvent read FOnGetGroupByBoxStyle
|
|
write FOnGetGroupByBoxStyle;
|
|
property OnGetGroupStyle: TdxMVLevelGetStyleEvent read FOnGetGroupStyle
|
|
write FOnGetGroupStyle;
|
|
property OnGetHeaderStyle: TdxMVLevelGetStyleEvent read FOnGetHeaderStyle
|
|
write FOnGetHeaderStyle;
|
|
property OnGetPreviewLineCount: TdxMVGetPreviewLineCountEvent read FOnGetPreviewLineCount
|
|
write FOnGetPreviewLineCount;
|
|
property OnGetPreviewStyle: TdxMVLevelGetStyleEvent read FOnGetPreviewStyle
|
|
write FOnGetPreviewStyle;
|
|
property OnGetPreviewText: TdxMVGetPreviewTextEvent read FOnGetPreviewText
|
|
write FOnGetPreviewText;
|
|
property OnHideColumn: TdxMVColumnEvent read FOnHideColumn write FOnHideColumn;
|
|
property OnShowColumn: TdxMVColumnEvent read FOnShowColumn write FOnShowColumn;
|
|
property OnWidthChanged: TNotifyEvent read FOnWidthChanged write FOnWidthChanged;
|
|
end;
|
|
|
|
PdxMasterViewNodeList = ^TdxMasterViewNodeList;
|
|
TdxMasterViewNodeList = array[0..MaxListSize - 1] of TdxMasterViewNode;
|
|
TdxMasterViewListSortCompare = function (Item1, Item2: TdxMasterViewNode): Integer;
|
|
TdxMasterViewListMode = (lmItems, lmAbsoluteItems, lmSelectedItems);
|
|
|
|
TdxMasterViewList = class
|
|
private
|
|
FCapacity: Integer;
|
|
FCount: Integer;
|
|
FDeletionLockCount: Integer;
|
|
FInsertionLockCount: Integer;
|
|
FList: PdxMasterViewNodeList;
|
|
FMode: TdxMasterViewListMode;
|
|
FNewCount, FPrevCount: Integer;
|
|
FOwner: TdxMasterViewNode;
|
|
function Get(Index: Integer): TdxMasterViewNode;
|
|
procedure Put(Index: Integer; Item: TdxMasterViewNode);
|
|
procedure SetCapacity(NewCapacity: Integer);
|
|
procedure SetCount(NewCount: Integer);
|
|
protected
|
|
procedure Grow;
|
|
public
|
|
constructor Create(AOwner: TdxMasterViewNode; AMode: TdxMasterViewListMode);
|
|
destructor Destroy; override;
|
|
function Add(Item: TdxMasterViewNode): Integer;
|
|
procedure BeginDeletion; // these two optimization's methods must not intersect
|
|
procedure BeginInsertion;
|
|
procedure Clear;
|
|
procedure CopyTo(List: TList);
|
|
procedure Delete(Index: Integer);
|
|
procedure EndDeletion;
|
|
procedure EndInsertion;
|
|
class procedure Error(const Msg: string; Data: Integer);
|
|
function First: TdxMasterViewNode;
|
|
function IndexOf(Item: TdxMasterViewNode): Integer;
|
|
procedure Insert(Index: Integer; Item: TdxMasterViewNode);
|
|
function Last: TdxMasterViewNode;
|
|
procedure Move(CurIndex, NewIndex: Integer);
|
|
function Remove(Item: TdxMasterViewNode): Integer;
|
|
procedure Sort(Compare: TdxMasterViewListSortCompare;
|
|
TopBound, BottomBound: Integer);
|
|
|
|
property Capacity: Integer read FCapacity write SetCapacity;
|
|
property Count: Integer read FCount write SetCount;
|
|
property Items[Index: Integer]: TdxMasterViewNode read Get write Put; default;
|
|
property List: PdxMasterViewNodeList read FList;
|
|
property Owner: TdxMasterViewNode read FOwner;
|
|
end;
|
|
|
|
TdxMasterViewNodeViewInfoOption = (vioClipped);
|
|
TdxMasterViewNodeViewInfoOptions = set of TdxMasterViewNodeViewInfoOption;
|
|
TdxMasterViewNodeViewInfo = record
|
|
Bounds: TRect;
|
|
Width: Integer;
|
|
GroupByBoxSize: Integer;
|
|
HeaderSize: Integer;
|
|
PreviewSize: Integer;
|
|
FooterSize: Integer;
|
|
EndLevelCount: Integer;
|
|
EndLevelData: Integer;
|
|
Options: TdxMasterViewNodeViewInfoOptions;
|
|
LevelIndex: Integer;
|
|
end;
|
|
|
|
PdxMVSortingValues = ^TdxMVSortingValues;
|
|
TdxMVSortingValues = array[0..MaxInt div SizeOf(PVariant) - 1] of PVariant;
|
|
PdxMVSortingData = ^TdxMVSortingData;
|
|
TdxMVSortingData = array[0..MaxInt div SizeOf(PdxMVSortingValues) - 1] of PdxMVSortingValues;
|
|
PdxMVSummaryValues = ^TdxMVSummaryValues;
|
|
TdxMVSummaryValues = array[0..MaxInt div SizeOf(Extended) - 1] of Extended;
|
|
PdxMVSummaries = ^TdxMVSummaries;
|
|
TdxMVSummaries = array[0..MaxInt div SizeOf(PdxMVSummaryValues) - 1] of PdxMVSummaryValues;
|
|
|
|
TdxMasterViewNode = class
|
|
private
|
|
FAbsoluteIndex: Integer;
|
|
FControl: TdxMasterView; //change to FLevel.Control? (4 times slower)
|
|
FData: Pointer;
|
|
FExpanded: Boolean;
|
|
FGroupIndex: Integer;
|
|
FID: Variant;
|
|
FIndex: Integer;
|
|
FItems: TdxMasterViewList;
|
|
FKeyValue: Variant;
|
|
FLevel: TdxMasterViewLevel;
|
|
FNodeType: TdxMasterViewNodeType;
|
|
FParentNode: TdxMasterViewNode;
|
|
FPreviewText: string;
|
|
FSelectedIndex: Integer;
|
|
FSummaries: PdxMVSummaries;
|
|
FSummariesInitialized: Boolean;
|
|
FTriedToExpand: Boolean;
|
|
FValues: TStrings;
|
|
FViewInfo: TdxMasterViewNodeViewInfo;
|
|
|
|
function GetBounds: TRect;
|
|
function GetContentBounds: TRect;
|
|
function GetContentBoundsWithoutPreview: TRect;
|
|
function GetCount: Integer;
|
|
function GetCountInLevel(ALevel: TdxMasterViewLevel): Integer;
|
|
function GetFirst: TdxMasterViewNode;
|
|
function GetFirstInLevel(ALevel: TdxMasterViewLevel): TdxMasterViewNode;
|
|
function GetFocused: Boolean;
|
|
function GetFooterBounds: TRect;
|
|
function GetFullBounds: TRect;
|
|
function GetFullContentBounds: TRect;
|
|
function GetFullFooterBounds: TRect;
|
|
function GetFullGroupByBoxBounds: TRect;
|
|
function GetFullHeaderBounds: TRect;
|
|
function GetGroupByBoxBounds: TRect;
|
|
function GetGroupByBoxColumnBounds(Index: Integer): TRect;
|
|
function GetGroupIndex: Integer;
|
|
function GetHasChildren: Boolean;
|
|
function GetHeaderBounds: TRect;
|
|
function GetHeaderColBounds(Index: Integer): TRect;
|
|
function GetHeaderRowBounds(Index: Integer): TRect;
|
|
function GetHorizontal: Boolean;
|
|
function GetIsEditing: Boolean;
|
|
function GetIsFirst: Boolean;
|
|
function GetIsFirstInLevel: Boolean;
|
|
function GetIsLast: Boolean;
|
|
function GetIsLastInLevel: Boolean;
|
|
function GetItem(Index: Integer): TdxMasterViewNode;
|
|
function GetLast: TdxMasterViewNode;
|
|
function GetLastInLevel(ALevel: TdxMasterViewLevel): TdxMasterViewNode;
|
|
function GetLeftSpaceBounds: TRect;
|
|
function GetNodeWithSummaryData(ALevel: TdxMasterViewLevel): TdxMasterViewNode;
|
|
function GetParentNodes(Index: Integer): TdxMasterViewNode;
|
|
function GetParentNodeWithData: TdxMasterViewNode;
|
|
function GetPreviewBounds: TRect;
|
|
function GetRightSpaceBounds: TRect;
|
|
function GetSelected: Boolean;
|
|
function GetString(Index: Integer): string;
|
|
function GetSubFooterBounds(AParentIndex: Integer): TRect;
|
|
function GetValue(Index: Integer): Variant;
|
|
function GetValueCount: Integer;
|
|
function GetVisible: Boolean;
|
|
procedure SetExpanded(Value: Boolean);
|
|
procedure SetFocused(Value: Boolean);
|
|
procedure SetSelected(Value: Boolean);
|
|
|
|
procedure AddItem(AIndex: Integer; Value: TdxMasterViewNode);
|
|
procedure RemoveItem(Value: TdxMasterViewNode);
|
|
procedure SetHasLevelSeparator(var EndLevelData: Integer; ALevelParentIndex: Integer);
|
|
procedure SetHasRowSeparator(var EndLevelData: Integer; ALevelParentIndex: Integer);
|
|
protected
|
|
function Add(ALevel: TdxMasterViewLevel; AIndex: Integer;
|
|
ANodeType: TdxMasterViewNodeType; const AID, AKeyValue: Variant): TdxMasterViewNode;
|
|
procedure AddToList(ALevel: TdxMasterViewLevel;
|
|
OtherNodesList, GroupNodesList: TList; ProcessRoot: Boolean);
|
|
procedure AddVisibleToList(List: TdxMasterViewList);
|
|
function CanDelete: Boolean;
|
|
function CanExpand: Boolean;
|
|
procedure ChangeExpanded(Value: Boolean);
|
|
procedure CheckChildNodes(ALevel: TdxMasterViewLevel;
|
|
NeedCheckParentNodes: Boolean);
|
|
procedure CheckExpanded;
|
|
procedure CheckParentNodes;
|
|
procedure Clear;
|
|
procedure ClearValues;
|
|
function ContainsDataInChildren(ALevel: TdxMasterViewLevel): Boolean;
|
|
procedure DoSmartLoadChanged(ALevel: TdxMasterViewLevel);
|
|
procedure DoSorting(ALevel: TdxMasterViewLevel);
|
|
procedure Draw(DC: HDC);
|
|
function GetAvailIndex(AChildLevelIndex: Integer): Integer;
|
|
function GetLastSubChild: TdxMasterViewNode;
|
|
function GetLevelIndex: Integer;
|
|
function HasDataInChildren(ALevel: TdxMasterViewLevel): Boolean;
|
|
function InSelectedPeriod: Boolean;
|
|
procedure Invalidate(Column: TdxMasterViewColumn; VPart: TdxMasterViewVPart);
|
|
procedure MoveData(ALevel: TdxMasterViewLevel; FromIndex, ToIndex: Integer);
|
|
procedure NodeChanged(HardRefresh: Boolean);
|
|
procedure Sync;
|
|
procedure SyncPos;
|
|
procedure UpdateData(UpdateSelf, UpdateChildren, UpdateOther: Boolean);
|
|
procedure UpdateDataForLevel(ALevel: TdxMasterViewLevel);
|
|
|
|
procedure CreateSummaries;
|
|
procedure DestroySummaries;
|
|
procedure CheckSummaries;
|
|
procedure InitializeSummaries(ALevel: TdxMasterViewLevel);
|
|
procedure CalcSummaries(UseRealData: Boolean);
|
|
procedure FinalizeSummaries(ALevel: TdxMasterViewLevel);
|
|
|
|
function BeginLevel(var Size: Integer): Boolean;
|
|
function EndLevel(var Size, EndLevelCount, EndLevelData: Integer): Boolean;
|
|
function HasExpandButton: Boolean;
|
|
function HasFooter(AParentIndex: Integer): Boolean;
|
|
function HasGroupByBox(var Size: Integer): Boolean;
|
|
function HasHeader(ATopIndex: Integer; var Size: Integer): Boolean;
|
|
function HasLevelSeparator(ALevelParentIndex: Integer): Boolean;
|
|
function HasPreview: Boolean;
|
|
function HasRowSeparator(ALevelParentIndex: Integer): Boolean;
|
|
function HasSummariesData: Boolean;
|
|
function CalcViewInfo(const ATopIndex: Integer; const R: TRect;
|
|
const AIndent, AWidth: Integer; var AFooterSize: Integer; const StoreInfo: Boolean): Integer;
|
|
procedure ClearViewInfo;
|
|
function ContentColIndexFromX(X: Integer): Integer;
|
|
function ContentRowIndexFromY(Y: Integer): Integer;
|
|
function FooterColIndexFromX(AParentIndex: Integer; X: Integer): Integer;
|
|
function FooterRowIndexFromY(AParentIndex: Integer; Y: Integer): Integer;
|
|
function HeaderColIndexFromX(X: Integer): Integer;
|
|
function HeaderRowIndexFromY(Y: Integer): Integer;
|
|
function InternalHeaderRowIndexFromY(Y: Integer): Integer;
|
|
function ShowExpandButton: Boolean;
|
|
|
|
property NodesWithSummaryData[ALevel: TdxMasterViewLevel]: TdxMasterViewNode
|
|
read GetNodeWithSummaryData;
|
|
|
|
property Bounds: TRect read GetBounds;
|
|
property ContentBounds: TRect read GetContentBounds;
|
|
property ContentBoundsWithoutPreview: TRect read GetContentBoundsWithoutPreview;
|
|
property FooterBounds: TRect read GetFooterBounds;
|
|
property FullBounds: TRect read GetFullBounds;
|
|
property FullContentBounds: TRect read GetFullContentBounds;
|
|
property FullFooterBounds: TRect read GetFullFooterBounds;
|
|
property FullGroupByBoxBounds: TRect read GetFullGroupByBoxBounds;
|
|
property FullHeaderBounds: TRect read GetFullHeaderBounds;
|
|
property GroupByBoxBounds: TRect read GetGroupByBoxBounds;
|
|
property GroupByBoxColumnBounds[Index: Integer]: TRect read GetGroupByBoxColumnBounds;
|
|
property HeaderBounds: TRect read GetHeaderBounds;
|
|
property HeaderColBounds[Index: Integer]: TRect read GetHeaderColBounds;
|
|
property HeaderRowBounds[Index: Integer]: TRect read GetHeaderRowBounds;
|
|
property LeftSpaceBounds: TRect read GetLeftSpaceBounds;
|
|
property PreviewBounds: TRect read GetPreviewBounds;
|
|
property RightSpaceBounds: TRect read GetRightSpaceBounds;
|
|
property SubFooterBounds[AParentIndex: Integer]: TRect read GetSubFooterBounds;
|
|
property ViewInfo: TdxMasterViewNodeViewInfo read FViewInfo;
|
|
public
|
|
constructor Create(AControl: TdxMasterView; ALevel: TdxMasterViewLevel;
|
|
AParentNode: TdxMasterViewNode; AIndex: Integer;
|
|
ANodeType: TdxMasterViewNodeType; const AID, AKeyValue: Variant);
|
|
destructor Destroy; override;
|
|
procedure Collapse(Recurse: Boolean);
|
|
procedure Delete;
|
|
procedure Expand(Recurse: Boolean);
|
|
function FindChildren: Boolean;
|
|
function GetParentNode(ALevel: TdxMasterViewLevel;
|
|
OnlyDataNodes: Boolean): TdxMasterViewNode;
|
|
procedure MakeVisible;
|
|
procedure LoadChildren(Recurse: Boolean);
|
|
function NodeFromID(ALevel: TdxMasterViewLevel; const AID: Variant): TdxMasterViewNode;
|
|
function NodeFromKeyValue(ALevel: TdxMasterViewLevel; AChildIndex: Integer;
|
|
const AKeyValue: Variant): TdxMasterViewNode;
|
|
|
|
property AbsoluteIndex: Integer read FAbsoluteIndex;
|
|
property Control: TdxMasterView read FControl;
|
|
property Count: Integer read GetCount;
|
|
property CountInLevel[ALevel: TdxMasterViewLevel]: Integer read GetCountInLevel;
|
|
property Data: Pointer read FData write FData;
|
|
property Expanded: Boolean read FExpanded write SetExpanded;
|
|
property First: TdxMasterViewNode read GetFirst;
|
|
property FirstInLevel[ALevel: TdxMasterViewLevel]: TdxMasterViewNode read GetFirstInLevel;
|
|
property Focused: Boolean read GetFocused write SetFocused;
|
|
property GroupIndex: Integer read FGroupIndex;
|
|
property GroupValue: Variant read FKeyValue;
|
|
property GroupValueText: Variant read FID;
|
|
property HasChildren: Boolean read GetHasChildren;
|
|
property Horizontal: Boolean read GetHorizontal;
|
|
property ID: Variant read FID;
|
|
property Index: Integer read FIndex;
|
|
property IsEditing: Boolean read GetIsEditing;
|
|
property IsFirst: Boolean read GetIsFirst;
|
|
property IsFirstInLevel: Boolean read GetIsFirstInLevel;
|
|
property IsLast: Boolean read GetIsLast;
|
|
property IsLastInLevel: Boolean read GetIsLastInLevel;
|
|
property Items[Index: Integer]: TdxMasterViewNode read GetItem; default;
|
|
property ItemsList: TdxMasterViewList read FItems;
|
|
property KeyValue: Variant read FKeyValue;
|
|
property Last: TdxMasterViewNode read GetLast;
|
|
property LastInLevel[ALevel: TdxMasterViewLevel]: TdxMasterViewNode read GetLastInLevel;
|
|
property Level: TdxMasterViewLevel read FLevel;
|
|
property NodeType: TdxMasterViewNodeType read FNodeType;
|
|
property ParentNode: TdxMasterViewNode read FParentNode;
|
|
property ParentNodes[Index: Integer]: TdxMasterViewNode read GetParentNodes;
|
|
property ParentNodeWithData: TdxMasterViewNode read GetParentNodeWithData;
|
|
property PreviewText: string read FPreviewText write FPreviewText;
|
|
property Selected: Boolean read GetSelected write SetSelected;
|
|
property SelectedIndex: Integer read FSelectedIndex;
|
|
property StringCount: Integer read GetValueCount;
|
|
property Strings[Index: Integer]: string read GetString;
|
|
property ValueCount: Integer read GetValueCount;
|
|
property Values[Index: Integer]: Variant read GetValue;
|
|
property Visible: Boolean read GetVisible;
|
|
end;
|
|
|
|
TdxMasterViewDragDetect = (ddNone, ddDrag, ddCancel);
|
|
TdxMasterViewDragSource = (dsHeader, dsGroupByBox, dsCustomizingForm);
|
|
TdxMasterViewDirection = (dirNone, dirLeft, dirUp, dirRight, dirDown);
|
|
TdxMasterViewHitTestCode = (htNone, htLeftSpace, htRightSpace, htIndent, htGroupByBox,
|
|
htHeader, htHeaderLeftEdge, htHeaderRightEdge, htHeaderTopEdge, htHeaderBottomEdge,
|
|
htContent, htExpandButton, htContentLeftEdge, htContentRightEdge, htPreview,
|
|
htFooter, htCustomizationForm, htOther);
|
|
TdxMasterViewState =
|
|
(mvsCtrlClick, mvsIndentClick, mvsAnchorSelected, mvsSelectPeriod,
|
|
mvsColumnSizing, mvsColumnMoving, mvsScrolling);
|
|
TdxMasterViewStates = set of TdxMasterViewState;
|
|
|
|
TdxMasterViewOptionBehavior =
|
|
(mobAnsiCompareStrOnGrouping, mobAnsiCompareStrOnSorting,
|
|
mobCaseInsensitiveGrouping, mobCaseInsensitiveSorting, mobMultiSelect,
|
|
mobShowHourGlassCursor, mobStoreInIniFile, mobStoreInRegistry,
|
|
mobUseIndent);
|
|
TdxMasterViewOptionsBehavior = set of TdxMasterViewOptionBehavior;
|
|
|
|
TdxMasterViewOptionDB = (modSyncMove);
|
|
TdxMasterViewOptionsDB = set of TdxMasterViewOptionDB;
|
|
|
|
TdxMasterViewOptionView =
|
|
(movAnimation, movAutoColumnWidth, movDrawEndEllipsis, movHideFocusRect,
|
|
movHideSelection, movKeepColumnWidths,
|
|
movTransparentDragAndDrop, movUseBitmap, movUseBitmapToDrawPreview);
|
|
TdxMasterViewOptionsView = set of TdxMasterViewOptionView;
|
|
|
|
TdxMasterViewRegIniFileMode = (riIniFile, riRegistry);
|
|
|
|
TdxMVScrollBars = (sbAuto, sbHorizontal, sbVertical, sbBoth, sbNone);
|
|
|
|
TdxMVColumnMovingEvent = procedure(Sender: TdxMasterView; Column: TdxMasterViewColumn;
|
|
P: TPoint; RowIndex, ColIndex: Integer; InsertIntoNewRow: Boolean;
|
|
var Accept: Boolean) of object;
|
|
TdxMVCustomizingEvent = procedure(Sender: TdxMasterView; Showing: Boolean) of object;
|
|
TdxMVFocusNodeEvent = procedure(Sender: TdxMasterView; PrevNode,
|
|
CurNode: TdxMasterViewNode) of object;
|
|
TdxMVLevelEvent = procedure(Sender: TdxMasterView; Level: TdxMasterViewLevel) of object;
|
|
TdxMVSelectNodeEvent = procedure(Sender: TdxMasterView; Node: TdxMasterViewNode;
|
|
var Allow: Boolean) of object;
|
|
|
|
TdxMasterView = class(TCustomControl)
|
|
private
|
|
FAbsoluteItems: TdxMasterViewList;
|
|
FAbsoluteLevels: TList;
|
|
FAnimation: Boolean;
|
|
FArrowsColor: TColor;
|
|
FBitmap: TBitmap;
|
|
FBtnHighlightPen: HPEN;
|
|
FBtnShadowPen: HPEN;
|
|
FCalculatingScrollableWidth: Boolean;
|
|
FCustomizationForm: TWinControl;
|
|
FCustomizationFormPos: TPoint;
|
|
FCustomizationFormRowCount: Integer;
|
|
FCustomizing: Boolean;
|
|
FDontInvalidate: Boolean;
|
|
FFocusedNode: TdxMasterViewNode;
|
|
FFrozen: Boolean;
|
|
FHighlightStyle: TdxMasterViewStyle;
|
|
FInactiveStyle: TdxMasterViewStyle;
|
|
FIniFileName: string;
|
|
FItems: TdxMasterViewNode;
|
|
FLastMousePos: TPoint;
|
|
FLastPartVisibleItemCount: Integer;
|
|
FLastSelectedNode: TdxMasterViewNode;
|
|
FLastVisibleItemCount: Integer;
|
|
FLayoutLockCount: Integer;
|
|
FLeftPos: Integer;
|
|
FLevels: TdxMasterViewLevel;
|
|
FMovingColumn: TdxMasterViewColumn;
|
|
FMovingColumnNode: TdxMasterViewNode;
|
|
FOptionsBehavior: TdxMasterViewOptionsBehavior;
|
|
FOptionsDB: TdxMasterViewOptionsDB;
|
|
FOptionsView: TdxMasterViewOptionsView;
|
|
FPainting: Boolean;
|
|
FPrevTopNode: TdxMasterViewNode;
|
|
FRegistryPath: string;
|
|
FScrollableWidth: Integer;
|
|
FScrollBars: TdxMVScrollBars;
|
|
FScrollTimer: UINT;
|
|
FSelectedItems: TdxMasterViewList;
|
|
FSelectionAnchor: TdxMasterViewNode;
|
|
FSelectionLockCount: Integer;
|
|
FSizingColumn: TdxMasterViewColumn;
|
|
FSortingColumnCount: Integer;
|
|
FSortingData: PdxMVSortingData;
|
|
FSortingDesc: PBoolArray;
|
|
FState: TdxMasterViewStates;
|
|
FStyles: TList;
|
|
FTopNode: TdxMasterViewNode;
|
|
FTopNodeChangeLockCount: Integer;
|
|
FUpdateLockCount: Integer;
|
|
FUpdatingData: Boolean;
|
|
|
|
// for sorting
|
|
SortV1, SortV2: PVariant;
|
|
SortS1, SortS2: string;
|
|
|
|
FOnAfterColumnMoving: TdxMVColumnMovingEvent;
|
|
FOnAfterUpdateData: TdxMVLevelEvent;
|
|
FOnBeforeColumnMoving: TdxMVColumnMovingEvent;
|
|
FOnBeforeFocusNode: TdxMVSelectNodeEvent;
|
|
FOnBeforeUpdateData: TdxMVLevelEvent;
|
|
FOnColumnMoving: TdxMVColumnMovingEvent;
|
|
FOnCustomizing: TdxMVCustomizingEvent;
|
|
FOnFocusNode: TdxMVFocusNodeEvent;
|
|
FOnLeftPosChanged: TNotifyEvent;
|
|
FOnSelectNode: TdxMVSelectNodeEvent;
|
|
FOnSelectionChanged: TNotifyEvent;
|
|
FOnTopNodeChanged: TNotifyEvent;
|
|
|
|
function GetAbsoluteItemCount: Integer;
|
|
function GetAbsoluteItem(Index: Integer): TdxMasterViewNode;
|
|
function GetAbsoluteLevelCount: Integer;
|
|
function GetAbsoluteLevel(Index: Integer): TdxMasterViewLevel;
|
|
function GetAnimation: Boolean;
|
|
function GetAutoColumnWidth: Boolean;
|
|
function GetCustomizationFormLevel: TdxMasterViewLevel;
|
|
function GetFocusedIndex: Integer;
|
|
function GetHasFocus: Boolean;
|
|
function GetHighlightBrush: HBRUSH;
|
|
function GetHighlightColor: TColor;
|
|
function GetHighlightFontColor: TColor;
|
|
function GetInactiveBrush: HBRUSH;
|
|
function GetInactiveColor: TColor;
|
|
function GetInactiveFocusBrush: HBRUSH;
|
|
function GetInactiveFocusColor: TColor;
|
|
function GetInactiveFontColor: TColor;
|
|
function GetIsDesigning: Boolean;
|
|
function GetIsDestroying: Boolean;
|
|
function GetIsLoading: Boolean;
|
|
function GetMultiSelect: Boolean;
|
|
function GetPartVisibleItemCount: Integer;
|
|
function GetSelectedItem(Index: Integer): TdxMasterViewNode;
|
|
function GetSelectedItemCount: Integer;
|
|
function GetShowHourGlassCursor: Boolean;
|
|
function GetStyle(Index: Integer): TdxMasterViewStyle;
|
|
function GetStyleCount: Integer;
|
|
function GetSyncMove: Boolean;
|
|
function GetTopIndex: Integer;
|
|
function GetTransparentDragAndDrop: Boolean;
|
|
function GetUseIndent: Boolean;
|
|
function GetVisibleItemCount: Integer;
|
|
function GetWidthForColumns: Integer;
|
|
procedure SetCanUseSmartReload(Value: Boolean);
|
|
procedure SetCustomizationFormLevel(Value: TdxMasterViewLevel);
|
|
procedure SetCustomizationFormRowCount(Value: Integer);
|
|
procedure SetCustomizing(Value: Boolean);
|
|
procedure SetFocusedIndex(Value: Integer);
|
|
procedure SetFocusedNode(Value: TdxMasterViewNode);
|
|
procedure SetHighlightStyle(Value: TdxMasterViewStyle);
|
|
procedure SetInactiveStyle(Value: TdxMasterViewStyle);
|
|
procedure SetLeftPos(Value: Integer);
|
|
procedure SetOptionsBehavior(Value: TdxMasterViewOptionsBehavior);
|
|
procedure SetOptionsDB(Value: TdxMasterViewOptionsDB);
|
|
procedure SetOptionsView(Value: TdxMasterViewOptionsView);
|
|
procedure SetScrollBars(Value: TdxMVScrollBars);
|
|
procedure SetTopIndex(Value: Integer);
|
|
procedure SetTopNode(Value: TdxMasterViewNode);
|
|
|
|
procedure AddStyle(AStyle: TdxMasterViewStyle);
|
|
procedure RemoveStyle(AStyle: TdxMasterViewStyle);
|
|
|
|
procedure AddSelectedItem(ANode: TdxMasterViewNode);
|
|
procedure RemoveSelectedItem(ANode: TdxMasterViewNode);
|
|
procedure ClearSelectedItems;
|
|
|
|
procedure CreateScrollTimer(Direction: TdxMasterViewDirection);
|
|
procedure DestroyScrollTimer;
|
|
|
|
procedure WMCaptureChanged(var Message: TMessage); message WM_CAPTURECHANGED;
|
|
procedure WMDestroy(var Message: TMessage); message WM_DESTROY;
|
|
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
|
|
procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
|
|
procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
|
|
procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
|
|
procedure WMMouseActivate(var Message: TWMMouseActivate); message WM_MOUSEACTIVATE;
|
|
procedure WMMouseWheel(var Message: TMessage); message WM_MOUSEWHEEL;
|
|
procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
|
|
procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
|
|
procedure WMNCPaint(var Message: TWMNCPaint); message WM_NCPAINT;
|
|
procedure WMSetCursor(var Message: TWMSetCursor); message WM_SETCURSOR;
|
|
procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
|
|
procedure WMSize(var Message: TWMSize); message WM_SIZE;
|
|
procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
|
|
procedure WMWindowPosChanged(var Message: TWMWindowPosChanged); message WM_WINDOWPOSCHANGED;
|
|
procedure CMDesignHitTest(var Message: TCMDesignHitTest); message CM_DESIGNHITTEST;
|
|
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
|
|
procedure CMSysColorChange(var Message: TMessage); message CM_SYSCOLORCHANGE;
|
|
protected
|
|
procedure CreateParams(var Params: TCreateParams); override;
|
|
procedure CreateWnd; override;
|
|
procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
|
|
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
|
|
procedure Loaded; override;
|
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
|
|
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
|
|
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
procedure Paint; override;
|
|
procedure SetName(const NewName: TComponentName); override;
|
|
procedure WndProc(var Message: TMessage); override;
|
|
|
|
procedure BeginAnimation;
|
|
procedure EndAnimation;
|
|
procedure BeforePaint;
|
|
procedure AfterPaint;
|
|
procedure BeginTopNodeChange;
|
|
procedure EndTopNodeChange;
|
|
property BtnHighlightPen: HPEN read FBtnHighlightPen;
|
|
property BtnShadowPen: HPEN read FBtnShadowPen;
|
|
|
|
procedure CalcScrollableWidth(CallingLevel: TdxMasterViewLevel);
|
|
procedure CalcViewInfo(ATopIndex: Integer; AHeight: Integer;
|
|
var AVisibleItemCount, APartVisibleItemCount: Integer; CalcNodesViewInfo: Boolean);
|
|
procedure AssignColumnWidths;
|
|
function GetAnimatableHeight: Integer;
|
|
procedure SetScrollBarsInfo(var AVisibleItemCount, APartVisibleItemCount: Integer);
|
|
procedure WidthChanged;
|
|
|
|
function CanScroll(Direction: TdxMasterViewDirection): Boolean;
|
|
function CheckLeftPos(Value: Integer): Integer;
|
|
function CheckTopIndex(Value: Integer): Integer;
|
|
procedure CheckFocusedNode;
|
|
procedure DestroyStyles;
|
|
procedure DoAfterUpdateData(Level: TdxMasterViewLevel); virtual;
|
|
procedure DoBeforeUpdateData(Level: TdxMasterViewLevel); virtual;
|
|
procedure DoColumnMoving(Node: TdxMasterViewNode; Column: TdxMasterViewColumn;
|
|
const InitialP: TPoint; DragSource: TdxMasterViewDragSource);
|
|
procedure DoColumnHorSizing(Column: TdxMasterViewColumn; ContentSizing: Boolean);
|
|
procedure DoColumnVerSizing(Node: TdxMasterViewNode; Column: TdxMasterViewColumn;
|
|
Edge: TdxMasterViewHitTestCode);
|
|
procedure DoNodeDeleted(Node: TdxMasterViewNode); virtual;
|
|
procedure DoScrolling;
|
|
procedure DoSelectionChanged; virtual;
|
|
function DoSelectNode(Node: TdxMasterViewNode): Boolean;
|
|
procedure DoSorting;
|
|
procedure DoTopNodeChanged; virtual;
|
|
procedure HighlightStyleChanged(Values: TdxMasterViewStyleValues);
|
|
procedure InactiveStyleChanged(Values: TdxMasterViewStyleValues);
|
|
|
|
function CanFocusNode(Node: TdxMasterViewNode): Boolean;
|
|
procedure ChangeFocusedIndex(Value: Integer);
|
|
function GetFirstNodeFromVisible(Level: TdxMasterViewLevel): TdxMasterViewNode;
|
|
function GetLastNodeFromVisible(Level: TdxMasterViewLevel): TdxMasterViewNode;
|
|
function GetNextNode(Value: TdxMasterViewNode; OnSameLevel: Boolean): TdxMasterViewNode;
|
|
function GetPrevNode(Value: TdxMasterViewNode; OnSameLevel: Boolean): TdxMasterViewNode;
|
|
procedure ShowPrevPage(CurTopIndex: Integer; OnSameLevel: Boolean);
|
|
procedure ShowNextPage(CurBottomIndex: Integer; OnSameLevel: Boolean);
|
|
procedure Scroll(Direction: TdxMasterViewDirection);
|
|
procedure RefreshAbsoluteItems;
|
|
procedure RefreshAbsoluteLevels;
|
|
procedure SelectPeriod(ToNode: TdxMasterViewNode);
|
|
procedure InvalidateSelection;
|
|
|
|
procedure Modified;
|
|
|
|
procedure Freeze;
|
|
function FreezeDataSet(ALevel: TdxMasterViewLevel): Integer;
|
|
procedure Unfreeze;
|
|
procedure UnfreezeDataSet(ALevel: TdxMasterViewLevel);
|
|
property Frozen: Boolean read FFrozen;
|
|
|
|
property Animation: Boolean read GetAnimation;
|
|
property AutoColumnWidth: Boolean read GetAutoColumnWidth;
|
|
property HasFocus: Boolean read GetHasFocus;
|
|
property IsDesigning: Boolean read GetIsDesigning;
|
|
property IsDestroying: Boolean read GetIsDestroying;
|
|
property IsLoading: Boolean read GetIsLoading;
|
|
property MultiSelect: Boolean read GetMultiSelect;
|
|
property ScrollableWidth: Integer read FScrollableWidth;
|
|
property ShowHourGlassCursor: Boolean read GetShowHourGlassCursor;
|
|
property SyncMove: Boolean read GetSyncMove;
|
|
property TransparentDragAndDrop: Boolean read GetTransparentDragAndDrop;
|
|
property UseIndent: Boolean read GetUseIndent;
|
|
property WidthForColumns: Integer read GetWidthForColumns;
|
|
|
|
property HighlightBrush: HBRUSH read GetHighlightBrush;
|
|
property HighlightColor: TColor read GetHighlightColor;
|
|
property HighlightFontColor: TColor read GetHighlightFontColor;
|
|
property InactiveBrush: HBRUSH read GetInactiveBrush;
|
|
property InactiveColor: TColor read GetInactiveColor;
|
|
property InactiveFocusColor: TColor read GetInactiveFocusColor;
|
|
property InactiveFocusBrush: HBRUSH read GetInactiveFocusBrush;
|
|
property InactiveFontColor: TColor read GetInactiveFontColor;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Invalidate; override;
|
|
procedure DrawText(const DrawDC: HDC; var ARect: TRect;
|
|
const Font: TFont; const Brush: HBRUSH; const TextColor, BkColor: TColor;
|
|
const Alignment: TAlignment; const Text: string;
|
|
const FillBackground, MakeRightSpace, AllowUseBitmap, MultiLine: Boolean);
|
|
function GetSelectionParams(Node: TdxMasterViewNode;
|
|
ABrush: PBRUSH; ATextColor, ABkColor: PColor): Boolean;
|
|
procedure PrepareBitmap(const AWidth, AHeight: Integer);
|
|
|
|
property AbsoluteItemsList: TdxMasterViewList read FAbsoluteItems;
|
|
property Bitmap: TBitmap read FBitmap write FBitmap;
|
|
property SelectedItemsList: TdxMasterViewList read FSelectedItems;
|
|
|
|
procedure ApplyBestFit(Level: TdxMasterViewLevel; Column: TdxMasterViewColumn);
|
|
procedure BeginLayout;
|
|
procedure BeginSelection;
|
|
procedure BeginUpdate;
|
|
procedure CancelLayout;
|
|
procedure CancelUpdate;
|
|
procedure ClearSelection;
|
|
function CreateStyle(AStyleClass: TdxMasterViewStyleClass): TdxMasterViewStyle;
|
|
procedure DeleteSelection;
|
|
procedure EndLayout;
|
|
procedure EndSelection;
|
|
procedure EndUpdate;
|
|
procedure FocusNode(Node: TdxMasterViewNode; ChangeSelection: Boolean);
|
|
procedure FullCollapse;
|
|
procedure FullExpand;
|
|
function GetHitTestInfo(const P: TPoint; var Node: TdxMasterViewNode;
|
|
var Column: TdxMasterViewColumn; var RowIndex, ColIndex: Integer): TdxMasterViewHitTestCode;
|
|
procedure LoadFromRegIniFile(const AFileName: string; AMode: TdxMasterViewRegIniFileMode);
|
|
function NodeFromID(ALevel: TdxMasterViewLevel; const AID: Variant): TdxMasterViewNode;
|
|
function NodeFromKeyValue(ALevel: TdxMasterViewLevel; AChildIndex: Integer;
|
|
const AKeyValue: Variant): TdxMasterViewNode;
|
|
procedure SaveToRegIniFile(const AFileName: string; AMode: TdxMasterViewRegIniFileMode);
|
|
procedure SelectItems(FromIndex, ToIndex: Integer; Select: Boolean);
|
|
procedure ShowFocusedNode;
|
|
procedure UpdateData;
|
|
|
|
property AbsoluteItemCount: Integer read GetAbsoluteItemCount;
|
|
property AbsoluteItems[Index: Integer]: TdxMasterViewNode read GetAbsoluteItem;
|
|
property AbsoluteLevelCount: Integer read GetAbsoluteLevelCount;
|
|
property AbsoluteLevels[Index: Integer]: TdxMasterViewLevel read GetAbsoluteLevel;
|
|
property CanUseSmartReload: Boolean write SetCanUseSmartReload;
|
|
property CustomizationForm: TWinControl read FCustomizationForm;
|
|
property CustomizationFormLevel: TdxMasterViewLevel read GetCustomizationFormLevel
|
|
write SetCustomizationFormLevel;
|
|
property CustomizationFormPos: TPoint read FCustomizationFormPos write FCustomizationFormPos;
|
|
property Customizing: Boolean read FCustomizing write SetCustomizing;
|
|
property FocusedIndex: Integer read GetFocusedIndex write SetFocusedIndex;
|
|
property FocusedNode: TdxMasterViewNode read FFocusedNode write SetFocusedNode;
|
|
property Items: TdxMasterViewNode read FItems;
|
|
property LeftPos: Integer read FLeftPos write SetLeftPos;
|
|
property Levels: TdxMasterViewLevel read FLevels;
|
|
property MovingColumn: TdxMasterViewColumn read FMovingColumn;
|
|
property MovingColumnNode: TdxMasterViewNode read FMovingColumnNode;
|
|
property PartVisibleItemCount: Integer read GetPartVisibleItemCount;
|
|
property SelectedItemCount: Integer read GetSelectedItemCount;
|
|
property SelectedItems[Index: Integer]: TdxMasterViewNode read GetSelectedItem;
|
|
property State: TdxMasterViewStates read FState;
|
|
property StyleCount: Integer read GetStyleCount;
|
|
property Styles[Index: Integer]: TdxMasterViewStyle read GetStyle;
|
|
property TopIndex: Integer read GetTopIndex write SetTopIndex;
|
|
property TopNode: TdxMasterViewNode read FTopNode write SetTopNode;
|
|
property SizingColumn: TdxMasterViewColumn read FSizingColumn;
|
|
property VisibleItemCount: Integer read GetVisibleItemCount;
|
|
published
|
|
property Align;
|
|
property Color;
|
|
property DragCursor;
|
|
property DragMode;
|
|
property Enabled;
|
|
property Font;
|
|
property ParentColor default False;
|
|
property ParentFont;
|
|
property ParentShowHint;
|
|
property PopupMenu;
|
|
property ShowHint;
|
|
property TabOrder;
|
|
property TabStop default True;
|
|
property Visible;
|
|
{$IFDEF DELPHI4}
|
|
property Anchors;
|
|
property Constraints;
|
|
property DragKind;
|
|
{$ENDIF}
|
|
|
|
property ArrowsColor: TColor read FArrowsColor write FArrowsColor default clLime;
|
|
property CustomizationFormRowCount: Integer read FCustomizationFormRowCount
|
|
write SetCustomizationFormRowCount default dxMVCustomizationFormRowCount;
|
|
property HighlightStyle: TdxMasterViewStyle read FHighlightStyle write SetHighlightStyle;
|
|
property InactiveStyle: TdxMasterViewStyle read FInactiveStyle write SetInactiveStyle;
|
|
property IniFileName: string read FIniFileName write FIniFileName;
|
|
property OptionsBehavior: TdxMasterViewOptionsBehavior read FOptionsBehavior
|
|
write SetOptionsBehavior default [mobUseIndent];
|
|
property OptionsDB: TdxMasterViewOptionsDB read FOptionsDB write SetOptionsDB
|
|
default [modSyncMove];
|
|
property OptionsView: TdxMasterViewOptionsView read FOptionsView write SetOptionsView
|
|
default [movAnimation, movHideFocusRect, movKeepColumnWidths,
|
|
movTransparentDragAndDrop, movUseBitmapToDrawPreview];
|
|
property RegistryPath: string read FRegistryPath write FRegistryPath;
|
|
property ScrollBars: TdxMVScrollBars read FScrollBars write SetScrollBars
|
|
default sbAuto;
|
|
|
|
property OnClick;
|
|
property OnDblClick;
|
|
property OnDragDrop;
|
|
property OnDragOver;
|
|
property OnEndDrag;
|
|
property OnEnter;
|
|
property OnExit;
|
|
property OnKeyDown;
|
|
property OnKeyPress;
|
|
property OnKeyUp;
|
|
property OnMouseDown;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
property OnStartDrag;
|
|
{$IFDEF DELPHI4}
|
|
property OnEndDock;
|
|
property OnStartDock;
|
|
{$ENDIF}
|
|
{$IFDEF DELPHI5}
|
|
property OnContextPopup;
|
|
{$ENDIF}
|
|
|
|
property OnAfterColumnMoving: TdxMVColumnMovingEvent read FOnAfterColumnMoving
|
|
write FOnAfterColumnMoving;
|
|
//property OnAfterUpdateData: TdxMVLevelEvent read FOnAfterUpdateData write FOnAfterUpdateData;
|
|
property OnBeforeColumnMoving: TdxMVColumnMovingEvent read FOnBeforeColumnMoving
|
|
write FOnBeforeColumnMoving;
|
|
property OnBeforeFocusNode: TdxMVSelectNodeEvent read FOnBeforeFocusNode write FOnBeforeFocusNode;
|
|
//property OnBeforeUpdateData: TdxMVLevelEvent read FOnBeforeUpdateData
|
|
// write FOnBeforeUpdateData;
|
|
property OnColumnMoving: TdxMVColumnMovingEvent read FOnColumnMoving write FOnColumnMoving;
|
|
property OnCustomizing: TdxMVCustomizingEvent read FOnCustomizing write FOnCustomizing;
|
|
property OnFocusNode: TdxMVFocusNodeEvent read FOnFocusNode write FOnFocusNode;
|
|
property OnLeftPosChanged: TNotifyEvent read FOnLeftPosChanged write FOnLeftPosChanged;
|
|
property OnSelectNode: TdxMVSelectNodeEvent read FOnSelectNode write FOnSelectNode;
|
|
property OnSelectionChanged: TNotifyEvent read FOnSelectionChanged write FOnSelectionChanged;
|
|
property OnTopNodeChanged: TNotifyEvent read FOnTopNodeChanged write FOnTopNodeChanged;
|
|
end;
|
|
|
|
function DragDetect(Wnd: HWND): TdxMasterViewDragDetect;
|
|
|
|
var
|
|
dxMVDesigner: TdxMVDesigner;
|
|
|
|
dxMVGroupByBoxText: string;
|
|
|
|
function dxMasterViewColumnClass(Index: Integer): TdxMasterViewColumnClass;
|
|
function dxMasterViewColumnCount: Integer;
|
|
procedure dxMasterViewRegisterColumn(AColumnClass: TdxMasterViewColumnClass);
|
|
procedure dxMasterViewUnregisterColumn(AColumnClass: TdxMasterViewColumnClass);
|
|
|
|
procedure TransparentDraw(const DrawDC: HDC; var FullRect: TRect;
|
|
const Alignment: TAlignment; const Brush: HBRUSH; const ABitmap: TBitmap);
|
|
|
|
implementation
|
|
|
|
{$R dxMasterView.res}
|
|
|
|
uses
|
|
Consts,{$IFDEF DELPHI6} RTLConsts,{$ENDIF} Buttons, SysUtils, StdCtrls,
|
|
ExtCtrls, CheckLst, IniFiles, Registry, dxMasterViewStrs;
|
|
|
|
const
|
|
MaxExtended = 1.1E4932;
|
|
MinExtended = -MaxExtended;
|
|
|
|
crdxMasterViewMirror = 1501;
|
|
crdxMasterViewFullScroll = 1502;
|
|
crdxMasterViewHorScroll = 1503;
|
|
crdxMasterViewVerScroll = 1504;
|
|
crdxMasterViewUpScroll = 1505;
|
|
crdxMasterViewRightScroll = 1506;
|
|
crdxMasterViewDownScroll = 1507;
|
|
crdxMasterViewLeftScroll = 1508;
|
|
crdxMasterViewHorSize = 1509;
|
|
crdxMasterViewVerSize = 1512;
|
|
crdxMasterViewRemove = 1510;
|
|
crdxMasterViewNoDrop = 1511;
|
|
|
|
DefaultLineWidth = 1;
|
|
ExpandButtonIndent = 3;
|
|
ExpandButtonSize = 12;
|
|
LevelIndent = ExpandButtonIndent + ExpandButtonSize + ExpandButtonIndent;
|
|
ColumnSizingZoneWidth = 4;
|
|
InsertZoneWidth = 10;
|
|
|
|
HScrollDelta = 10;
|
|
ScrollTimeStep = 70;
|
|
ScrollLeftTimerId = 1;
|
|
ScrollUpTimerId = 2;
|
|
ScrollRightTimerId = 3;
|
|
ScrollDownTimerId = 4;
|
|
ColumnMovingHScrollZone = 15;
|
|
|
|
AnimationOriginalStep = 1;
|
|
AnimationIncreaseStepDivisor1 = 100; // collapse (TopIndex = PrevTopIndex)
|
|
AnimationIncreaseStepDivisor2 = 40; // collapse (TopIndex <> PrevTopIndex)
|
|
AnimationIncreaseStepDivisor3 = 100; // expand
|
|
|
|
SortOrderMarkZoneWidth = 16;
|
|
SortOrderMarkWidth = 8;
|
|
SortOrderMarkHeight = 7;
|
|
|
|
GroupByBoxLeftOffset = 8;
|
|
GroupByBoxTopOffset = 8;
|
|
GroupByBoxHorOffset = 4;
|
|
GroupByBoxVerOffset = 0;
|
|
GroupByBoxColumnWidth = 100;
|
|
GroupByBoxLineColor = clBtnText;
|
|
|
|
LeftHitTests = [htLeftSpace, htIndent, htExpandButton];
|
|
HeaderHitTests = [htHeader..htHeaderBottomEdge];
|
|
ContentHitTests = [htContent, htContentLeftEdge, htContentRightEdge];
|
|
|
|
type
|
|
TDummyDataSet = class(TDataSet);
|
|
|
|
PRegColumnRecord = ^TRegColumnRecord;
|
|
TRegColumnRecord = record
|
|
ColumnClass: TdxMasterViewColumnClass;
|
|
end;
|
|
|
|
var
|
|
RegColumnList: TList;
|
|
|
|
function dxMasterViewColumnClass(Index: Integer): TdxMasterViewColumnClass;
|
|
begin
|
|
Result := PRegColumnRecord(RegColumnList[Index])^.ColumnClass;
|
|
end;
|
|
|
|
function dxMasterViewColumnCount: Integer;
|
|
begin
|
|
Result := RegColumnList.Count;
|
|
end;
|
|
|
|
procedure dxMasterViewRegisterColumn(AColumnClass: TdxMasterViewColumnClass);
|
|
var
|
|
RegColumnRecord: PRegColumnRecord;
|
|
begin
|
|
New(RegColumnRecord);
|
|
with RegColumnRecord^ do
|
|
begin
|
|
ColumnClass := AColumnClass;
|
|
end;
|
|
RegColumnList.Add(RegColumnRecord);
|
|
RegisterClass(AColumnClass);
|
|
end;
|
|
|
|
procedure dxMasterViewUnregisterColumn(AColumnClass: TdxMasterViewColumnClass);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to dxMasterViewColumnCount - 1 do
|
|
if dxMasterViewColumnClass(I) = AColumnClass then
|
|
begin
|
|
Dispose(PRegColumnRecord(RegColumnList[I]));
|
|
RegColumnList.Delete(I);
|
|
UnregisterClass(AColumnClass);
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
function DragDetect(Wnd: HWND): TdxMasterViewDragDetect;
|
|
var
|
|
NoDragZone: TRect;
|
|
P: TPoint;
|
|
Msg: TMsg;
|
|
begin
|
|
Result := ddCancel;
|
|
|
|
GetCursorPos(P);
|
|
with NoDragZone, P do
|
|
begin
|
|
Right := 2 * GetSystemMetrics(SM_CXDRAG);
|
|
Bottom := 2 * GetSystemMetrics(SM_CYDRAG);
|
|
Left := X - Right div 2;
|
|
Top := Y - Bottom div 2;
|
|
Inc(Right, Left);
|
|
Inc(Bottom, Top);
|
|
end;
|
|
|
|
SetCapture(Wnd);
|
|
try
|
|
while GetCapture = Wnd do
|
|
begin
|
|
case Integer(GetMessage(Msg, 0, 0, 0)) of
|
|
-1: Break;
|
|
0: begin
|
|
PostQuitMessage(Msg.wParam);
|
|
Break;
|
|
end;
|
|
end;
|
|
try
|
|
case Msg.message of
|
|
WM_KEYDOWN, WM_KEYUP:
|
|
if Msg.wParam = VK_ESCAPE then Break;
|
|
WM_MOUSEMOVE:
|
|
begin
|
|
P := SmallPointToPoint(TSmallPoint(Msg.lParam));
|
|
ClientToScreen(Msg.hwnd, P);
|
|
if not PtInRect(NoDragZone, P) then
|
|
begin
|
|
Result := ddDrag;
|
|
Break;
|
|
end;
|
|
end;
|
|
WM_LBUTTONUP:
|
|
begin
|
|
Result := ddNone;
|
|
Break;
|
|
end;
|
|
end;
|
|
finally
|
|
TranslateMessage(Msg);
|
|
DispatchMessage(Msg);
|
|
end;
|
|
end;
|
|
finally
|
|
if GetCapture = Wnd then ReleaseCapture;
|
|
end;
|
|
end;
|
|
|
|
procedure CalcFontSize(AFont: TFont; var Size: TSize);
|
|
var
|
|
DC: HDC;
|
|
PrevFont: HFONT;
|
|
begin
|
|
DC := GetDC(0);
|
|
PrevFont := SelectObject(DC, AFont.Handle);
|
|
GetTextExtentPoint{32}(DC, 'Qq', 2, Size);
|
|
SelectObject(DC, PrevFont);
|
|
ReleaseDC(0, DC);
|
|
Size.cx := Size.cx div 2;
|
|
end;
|
|
|
|
procedure DrawExpandButton(DC: HDC; const ARect: TRect; BkBrush: HBRUSH;
|
|
Expanded, Enabled: Boolean);
|
|
var
|
|
X, Y: Integer;
|
|
R: TRect;
|
|
CrossBrush: HBRUSH;
|
|
|
|
procedure DrawCross;
|
|
begin
|
|
FillRect(DC, Rect(X - 2, Y, X + 3, Y + 1), CrossBrush);
|
|
if not Expanded then
|
|
FillRect(DC, Rect(X, Y - 2, X + 1, Y + 3), CrossBrush);
|
|
end;
|
|
|
|
begin
|
|
with ARect do
|
|
begin
|
|
X := (Left + Right - ExpandButtonSize) div 2;
|
|
Y := (Top + Bottom - ExpandButtonSize) div 2;
|
|
FillRect(DC, Rect(Left, Top, Right, Y), BkBrush);
|
|
FillRect(DC, Rect(Left, Y + ExpandButtonSize, Right, Bottom), BkBrush);
|
|
FillRect(DC, Rect(Left, Y, X, Y + ExpandButtonSize), BkBrush);
|
|
FillRect(DC, Rect(X + ExpandButtonSize, Y, Right, Y + ExpandButtonSize), BkBrush);
|
|
end;
|
|
with R do
|
|
begin
|
|
Left := X;
|
|
Top := Y;
|
|
Right := Left + ExpandButtonSize;
|
|
Bottom := Top + ExpandButtonSize;
|
|
DrawEdge(DC, R, BDR_RAISEDINNER, BF_LEFT or BF_TOP);
|
|
DrawEdge(DC, R, BDR_RAISEDOUTER, BF_RIGHT or BF_BOTTOM);
|
|
InflateRect(R, -1, -1);
|
|
DrawEdge(DC, R, BDR_RAISEDINNER, BF_RIGHT or BF_BOTTOM);
|
|
Dec(Right);
|
|
Dec(Bottom);
|
|
FillRect(DC, R, COLOR_BTNFACE + 1);
|
|
X := (Left + Right - 1) div 2;
|
|
Y := (Top + Bottom - 1) div 2;
|
|
if Enabled then
|
|
begin
|
|
CrossBrush := COLOR_BTNTEXT + 1;
|
|
DrawCross;
|
|
end
|
|
else
|
|
begin
|
|
Inc(X);
|
|
Inc(Y);
|
|
CrossBrush := COLOR_BTNHIGHLIGHT + 1;
|
|
DrawCross;
|
|
Dec(X);
|
|
Dec(Y);
|
|
CrossBrush := COLOR_BTNSHADOW + 1;
|
|
DrawCross;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TransparentDraw(const DrawDC: HDC; var FullRect: TRect;
|
|
const Alignment: TAlignment; const Brush: HBRUSH; const ABitmap: TBitmap);
|
|
const
|
|
ROP_DSPDxax = $00E20746;
|
|
var
|
|
BW, BH, X, Y: Integer;
|
|
DC, MaskDC: HDC;
|
|
B, MaskB: HBITMAP;
|
|
ATextColor, ABackColor: COLORREF;
|
|
ABrush: HBRUSH;
|
|
begin
|
|
with FullRect do
|
|
begin
|
|
BW := ABitmap.Width;
|
|
BH := ABitmap.Height;
|
|
case Alignment of
|
|
taLeftJustify:
|
|
X := Left;
|
|
taRightJustify:
|
|
X := Right - BW;
|
|
else
|
|
X := (Left + Right - BW) div 2;
|
|
end;
|
|
if X < Left then X := Left;
|
|
if X + BW > Right then BW := Right - X;
|
|
case Alignment of
|
|
taLeftJustify:
|
|
Left := X + BW;
|
|
taRightJustify:
|
|
Right := X;
|
|
end;
|
|
Y := (Top + Bottom - BH) div 2;
|
|
if Y < Top then Y := Top;
|
|
if Y + BH > Bottom then BH := Bottom - Y;
|
|
|
|
DC := CreateCompatibleDC(DrawDC);
|
|
B := CreateCompatibleBitmap(DrawDC, BW, BH);
|
|
B := SelectObject(DC, B);
|
|
try
|
|
BitBlt(DC, 0, 0, BW, BH, ABitmap.Canvas.Handle, 0, 0, SRCCOPY);
|
|
|
|
MaskDC := CreateCompatibleDC(DrawDC);
|
|
MaskB := CreateBitmap(BW, BH, 1, 1, nil);
|
|
MaskB := SelectObject(MaskDC, MaskB);
|
|
try
|
|
ABackColor := SetBkColor(DC, ColorToRGB(ABitmap.TransparentColor));
|
|
BitBlt(MaskDC, 0, 0, BW, BH, DC, 0, 0, SRCCOPY);
|
|
|
|
ATextColor := SetTextColor(DC, 0);
|
|
SetBkColor(DC, $FFFFFF);
|
|
ABrush := SelectObject(DC, Brush);
|
|
BitBlt(DC, 0, 0, BW, BH, MaskDC, 0, 0, ROP_DSPDxax);
|
|
SelectObject(DC, ABrush);
|
|
SetTextColor(DC, ATextColor);
|
|
SetBkColor(DC, ABackColor);
|
|
finally
|
|
DeleteObject(SelectObject(MaskDC, MaskB));
|
|
DeleteDC(MaskDC);
|
|
end;
|
|
|
|
BitBlt(DrawDC, X, Y, BW, BH, DC, 0, 0, SRCCOPY);
|
|
finally
|
|
DeleteObject(SelectObject(DC, B));
|
|
DeleteDC(DC);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure DrawDowned(DC: HDC; const R: TRect);
|
|
begin
|
|
with R do
|
|
BitBlt(DC, Left, Top, Right - Left, Bottom - Top, 0, 0, 0, DSTINVERT);
|
|
end;
|
|
|
|
procedure ProcessPaintMessages(Wnd: HWND);
|
|
const
|
|
MessageCount = 4;
|
|
Messages: array[0..MessageCount - 1] of UINT =
|
|
(WM_NCCALCSIZE, WM_NCPAINT, WM_ERASEBKGND, WM_PAINT);
|
|
var
|
|
Exists: Boolean;
|
|
I: Integer;
|
|
Msg: TMsg;
|
|
begin
|
|
repeat
|
|
for I := 0 to MessageCount - 1 do
|
|
begin
|
|
Exists := PeekMessage(Msg, Wnd, Messages[I], Messages[I], PM_REMOVE);
|
|
if Exists then
|
|
begin
|
|
DispatchMessage(Msg);
|
|
Break;
|
|
end;
|
|
end;
|
|
until not Exists;
|
|
UpdateWindow(Wnd);
|
|
end;
|
|
|
|
function IsBetween(N, N1, N2: TdxMasterViewNode): Boolean;
|
|
var
|
|
I, M1, M2: Integer;
|
|
begin
|
|
if (N1 = nil) or (N2 = nil) then Result := False
|
|
else
|
|
begin
|
|
I := N.AbsoluteIndex;
|
|
M1 := N1.AbsoluteIndex;
|
|
M2 := N2.AbsoluteIndex;
|
|
if M1 < M2 then Result := (M1 <= I) and (I <= M2)
|
|
else Result := (M2 <= I) and (I <= M1);
|
|
end;
|
|
end;
|
|
|
|
function VarAnsiUpperCase(const V: Variant): Variant;
|
|
begin
|
|
if VarIsNull(V) or VarIsEmpty(V) then
|
|
Result := V
|
|
else
|
|
Result := AnsiUpperCase(V);
|
|
end;
|
|
|
|
function VarAreEqual(const V1, V2: Variant): Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if not VarIsArray(V1) then
|
|
if VarIsEmpty(V1) or VarIsEmpty(V2) then
|
|
Result := False
|
|
else
|
|
try
|
|
Result := V1 = V2
|
|
except
|
|
Result := False
|
|
end
|
|
else
|
|
begin
|
|
Result := True;
|
|
for I := 0 to VarArrayHighBound(V1, 1) do
|
|
try
|
|
if V1[I] <> V2[I] then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
except
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function VarCompare(const V1, V2: Variant): Integer;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if VarIsArray(V1) and VarIsArray(V2) then
|
|
begin
|
|
Result := 0;
|
|
for I := 0 to VarArrayHighBound(V1, 1) do
|
|
begin
|
|
if V1[I] < V2[I] then Result := -1
|
|
else
|
|
if V1[I] = V2[I] then Continue
|
|
else Result := 1;
|
|
Break;
|
|
end;
|
|
end
|
|
else
|
|
if VarIsArray(V1) then Result := 1
|
|
else
|
|
if VarIsArray(V2) then Result := -1
|
|
else
|
|
if VarIsEmpty(V1) then
|
|
if VarIsEmpty(V2) then Result := 0
|
|
else Result := -1
|
|
else
|
|
if VarIsEmpty(V2) then Result := 1
|
|
else
|
|
if V1 < V2 then Result := -1
|
|
else
|
|
if V1 = V2 then Result := 0
|
|
else Result := 1
|
|
end;
|
|
|
|
{ TdxMVRegIniFile }
|
|
|
|
type
|
|
TCurIniFile = {$IFDEF DELPHI4}TMemIniFile{$ELSE}TIniFile{$ENDIF};
|
|
|
|
TdxMVRegIniFile = class
|
|
private
|
|
FIniFile: TCurIniFile;
|
|
FMode: TdxMasterViewRegIniFileMode;
|
|
FRegIniFile: TRegIniFile;
|
|
public
|
|
constructor Create(AFileName: string; AMode: TdxMasterViewRegIniFileMode);
|
|
destructor Destroy; override;
|
|
function ReadBool(const Section, Ident: string; Default: Boolean): Boolean;
|
|
function ReadInteger(const Section, Ident: string; Default: Longint): Longint;
|
|
function SectionExists(const Section: string): Boolean;
|
|
function ValueExists(const Section, Ident: string): Boolean;
|
|
procedure WriteBool(const Section, Ident: string; Value: Boolean);
|
|
procedure WriteInteger(const Section, Ident: string; Value: Longint);
|
|
end;
|
|
|
|
constructor TdxMVRegIniFile.Create(AFileName: string; AMode: TdxMasterViewRegIniFileMode);
|
|
begin
|
|
inherited Create;
|
|
if FMode = riRegistry then
|
|
begin
|
|
if AFileName[1] <> '\' then AFileName := '\' + AFileName;
|
|
if AFileName[Length(AFileName)] = '\' then
|
|
Delete(AFileName, Length(AFileName), 1);
|
|
end;
|
|
FMode := AMode;
|
|
case FMode of
|
|
riIniFile:
|
|
FIniFile := TCurIniFile.Create(AFileName);
|
|
riRegistry:
|
|
FRegIniFile := TRegIniFile.Create(AFileName);
|
|
end;
|
|
end;
|
|
|
|
destructor TdxMVRegIniFile.Destroy;
|
|
begin
|
|
case FMode of
|
|
riIniFile:
|
|
begin
|
|
{$IFDEF DELPHI4}
|
|
FIniFile.UpdateFile;
|
|
{$ENDIF}
|
|
FIniFile.Free;
|
|
end;
|
|
riRegistry:
|
|
FRegIniFile.Free;
|
|
end;
|
|
inherited;
|
|
end;
|
|
|
|
function TdxMVRegIniFile.ReadBool(const Section, Ident: string; Default: Boolean): Boolean;
|
|
begin
|
|
Result := Default;
|
|
case FMode of
|
|
riIniFile:
|
|
Result := FIniFile.ReadBool(Section, Ident, Default);
|
|
riRegistry:
|
|
Result := FRegIniFile.ReadBool(Section, Ident, Default);
|
|
end;
|
|
end;
|
|
|
|
function TdxMVRegIniFile.ReadInteger(const Section, Ident: string; Default: Longint): Longint;
|
|
begin
|
|
Result := Default;
|
|
case FMode of
|
|
riIniFile:
|
|
Result := FIniFile.ReadInteger(Section, Ident, Default);
|
|
riRegistry:
|
|
Result := FRegIniFile.ReadInteger(Section, Ident, Default);
|
|
end;
|
|
end;
|
|
|
|
function TdxMVRegIniFile.SectionExists(const Section: string): Boolean;
|
|
var
|
|
S: TStrings;
|
|
begin
|
|
S := TStringList.Create;
|
|
try
|
|
case FMode of
|
|
riIniFile:
|
|
FIniFile.ReadSection(Section, S);
|
|
riRegistry:
|
|
FRegIniFile.ReadSection(Section, S);
|
|
end;
|
|
finally
|
|
Result := S.Count <> 0;
|
|
S.Free;
|
|
end;
|
|
end;
|
|
|
|
function TdxMVRegIniFile.ValueExists(const Section, Ident: string): Boolean;
|
|
var
|
|
S: TStrings;
|
|
begin
|
|
S := TStringList.Create;
|
|
try
|
|
case FMode of
|
|
riIniFile:
|
|
FIniFile.ReadSection(Section, S);
|
|
riRegistry:
|
|
FRegIniFile.ReadSection(Section, S);
|
|
end;
|
|
finally
|
|
Result := S.IndexOf(Ident) <> -1;
|
|
S.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMVRegIniFile.WriteBool(const Section, Ident: string; Value: Boolean);
|
|
begin
|
|
case FMode of
|
|
riIniFile:
|
|
FIniFile.WriteBool(Section, Ident, Value);
|
|
riRegistry:
|
|
FRegIniFile.WriteBool(Section, Ident, Value);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMVRegIniFile.WriteInteger(const Section, Ident: string; Value: Longint);
|
|
begin
|
|
case FMode of
|
|
riIniFile:
|
|
FIniFile.WriteInteger(Section, Ident, Value);
|
|
riRegistry:
|
|
FRegIniFile.WriteInteger(Section, Ident, Value);
|
|
end;
|
|
end;
|
|
|
|
{ TFlatComboBox }
|
|
|
|
type
|
|
TFlatComboBox = class(TComboBox)
|
|
private
|
|
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
|
|
protected
|
|
procedure CreateParams(var Params: TCreateParams); override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
end;
|
|
|
|
constructor TFlatComboBox.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
Style := csDropDownList;
|
|
end;
|
|
|
|
procedure TFlatComboBox.WMPaint(var Message: TWMPaint);
|
|
const
|
|
Borders: array[Boolean] of Integer = (BDR_RAISEDINNER, BDR_SUNKENOUTER);
|
|
Pushes: array[Boolean] of Integer = (0, DFCS_PUSHED);
|
|
var
|
|
DC: HDC;
|
|
R: TRect;
|
|
begin
|
|
inherited;
|
|
DC := GetDC(Handle);
|
|
|
|
R := ClientRect;
|
|
InflateRect(R, -1, -1);
|
|
FrameRect(DC, R, GetSysColorBrush(COLOR_BTNFACE));
|
|
|
|
InflateRect(R, -1, -1);
|
|
with R do
|
|
begin
|
|
Left := Right - GetSystemMetrics(SM_CXVSCROLL);
|
|
FillRect(DC, Rect(Left, Top, Left + 1, Bottom), COLOR_BTNFACE + 1);
|
|
Inc(Left);
|
|
end;
|
|
DrawEdge(DC, R, Borders[DroppedDown], BF_RECT);
|
|
|
|
InflateRect(R, -1, -1);
|
|
with R do
|
|
IntersectClipRect(DC, Left, Top, Right, Bottom);
|
|
InflateRect(R, 2, 2);
|
|
DrawFrameControl(DC, R, DFC_SCROLL,
|
|
DFCS_SCROLLCOMBOBOX or DFCS_FLAT or Pushes[DroppedDown]);
|
|
|
|
ReleaseDC(Handle, DC);
|
|
end;
|
|
|
|
procedure TFlatComboBox.CreateParams(var Params: TCreateParams);
|
|
begin
|
|
inherited;
|
|
with Params do
|
|
begin
|
|
Style := WS_CHILD or CBS_DROPDOWNLIST;
|
|
ExStyle := 0;
|
|
end;
|
|
end;
|
|
|
|
{ TChangePageButton }
|
|
|
|
type
|
|
TChangePageButton = class(TSpeedButton)
|
|
private
|
|
procedure WMCancelMode(var Message: TWMCancelMode); message WM_CANCELMODE;
|
|
protected
|
|
procedure Paint; override;
|
|
end;
|
|
|
|
procedure TChangePageButton.WMCancelMode(var Message: TWMCancelMode);
|
|
begin
|
|
inherited;
|
|
if not Down then
|
|
begin
|
|
FState := bsUp;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TChangePageButton.Paint;
|
|
var
|
|
DC: HDC;
|
|
R: TRect;
|
|
PrevFont: HFONT;
|
|
begin
|
|
if FState = bsUp then
|
|
begin
|
|
DC := Canvas.Handle;
|
|
R := ClientRect;
|
|
DrawEdge(DC, R, BDR_RAISEDINNER, BF_RECT);
|
|
InflateRect(R, -1, -1);
|
|
FillRect(DC, R, COLOR_BTNFACE + 1);
|
|
SetBkMode(DC, Windows.TRANSPARENT);
|
|
PrevFont := SelectObject(DC, Font.Handle);
|
|
DrawText(DC, PChar(Caption), Length(Caption), R,
|
|
DT_SINGLELINE or DT_CENTER or DT_VCENTER);
|
|
SelectObject(DC, PrevFont);
|
|
SetBkMode(DC, OPAQUE);
|
|
end
|
|
else
|
|
inherited;
|
|
end;
|
|
|
|
{ TColumnsListBox }
|
|
|
|
type
|
|
TColumnsListBox = class(TListBox)
|
|
private
|
|
procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
|
|
procedure WMNCPaint(var Message: TWMNCPaint); message WM_NCPAINT;
|
|
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
|
|
procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
|
|
protected
|
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
|
|
public
|
|
Control: TdxMasterView;
|
|
constructor Create(AOwner: TComponent); override;
|
|
end;
|
|
|
|
constructor TColumnsListBox.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
BorderStyle := bsNone;
|
|
Color := clBtnFace;
|
|
Sorted := True;
|
|
Style := lbOwnerDrawFixed;
|
|
end;
|
|
|
|
procedure TColumnsListBox.WMNCCalcSize(var Message: TWMNCCalcSize);
|
|
begin
|
|
inherited;
|
|
InflateRect(Message.CalcSize_Params^.rgrc[0], -1, -1);
|
|
end;
|
|
|
|
procedure TColumnsListBox.WMNCPaint(var Message: TWMNCPaint);
|
|
var
|
|
R: TRect;
|
|
DC: HDC;
|
|
begin
|
|
inherited;
|
|
GetWindowRect(Handle, R);
|
|
OffsetRect(R, -R.Left, -R.Top);
|
|
DC := GetWindowDC(Handle);
|
|
DrawEdge(DC, R, BDR_SUNKENOUTER, BF_RECT);
|
|
ReleaseDC(Handle, DC);
|
|
end;
|
|
|
|
procedure TColumnsListBox.WMPaint(var Message: TWMPaint);
|
|
var
|
|
DC: HDC;
|
|
PS: TPaintStruct;
|
|
S: string;
|
|
R: TRect;
|
|
PrevTextColor: COLORREF;
|
|
PrevBkMode: Integer;
|
|
PrevFont: HFONT;
|
|
begin
|
|
if Items.Count = 0 then
|
|
begin
|
|
if Message.DC = 0 then DC := BeginPaint(Handle, PS)
|
|
else DC := Message.DC;
|
|
R := ClientRect;
|
|
S := LoadStr(dxsMVCBNoFields);
|
|
PrevTextColor := SetTextColor(DC, GetSysColor(COLOR_BTNSHADOW));
|
|
PrevBkMode := SetBkMode(DC, TRANSPARENT);
|
|
PrevFont := SelectObject(DC, Font.Handle);
|
|
Windows.DrawText(DC, PChar(S), Length(S), R, DT_SINGLELINE or DT_CENTER or DT_VCENTER);
|
|
SelectObject(DC, PrevFont);
|
|
SetBkMode(DC, PrevBkMode);
|
|
SetTextColor(DC, PrevTextColor);
|
|
if Message.DC = 0 then EndPaint(Handle, PS);
|
|
end
|
|
else
|
|
inherited;
|
|
end;
|
|
|
|
procedure TColumnsListBox.CNDrawItem(var Message: TWMDrawItem);
|
|
var
|
|
R: TRect;
|
|
S: string;
|
|
PrevTextColor: COLORREF;
|
|
PrevBkMode: Integer;
|
|
begin
|
|
with Message.DrawItemStruct^ do
|
|
if Integer(itemID) >= 0 then
|
|
begin
|
|
R := rcItem;
|
|
DrawEdge(hDC, R, BDR_RAISEDINNER, BF_RECT);
|
|
InflateRect(R, -1, -1);
|
|
FillRect(hDC, R, COLOR_BTNFACE + 1);
|
|
InflateRect(R, -2, 0);
|
|
S := TdxMasterViewColumn(itemData).Caption;
|
|
PrevTextColor := SetTextColor(hDC, GetSysColor(COLOR_BTNTEXT));
|
|
PrevBkMode := SetBkMode(hDC, TRANSPARENT);
|
|
Windows.DrawText(hDC, PChar(S), Length(S), R,
|
|
DT_SINGLELINE or DT_VCENTER or DT_END_ELLIPSIS);
|
|
SetBkMode(hDC, PrevBkMode);
|
|
SetTextColor(hDC, PrevTextColor);
|
|
if itemState and ODS_SELECTED <> 0 then
|
|
with rcItem do
|
|
BitBlt(hDC, Left, Top, Right - Left, Bottom - Top, 0, 0, 0, DSTINVERT);
|
|
end;
|
|
end;
|
|
|
|
procedure TColumnsListBox.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
inherited;
|
|
if (Button = mbLeft) and (ItemAtPos(Point(X, Y), True) <> -1) and
|
|
(DragDetect(Handle) = ddDrag) then
|
|
Control.DoColumnMoving(nil, TdxMasterViewColumn(Items.Objects[ItemIndex]),
|
|
Point(-1, -1), dsCustomizingForm);
|
|
end;
|
|
|
|
{ TOptionsListBox }
|
|
|
|
type
|
|
TOptionsListBox = class(TCheckListBox)
|
|
private
|
|
procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
|
|
procedure WMNCPaint(var Message: TWMNCPaint); message WM_NCPAINT;
|
|
protected
|
|
procedure ClickCheck; override;
|
|
public
|
|
Level: TdxMasterViewLevel;
|
|
constructor Create(AOwner: TComponent); override;
|
|
end;
|
|
|
|
constructor TOptionsListBox.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
BorderStyle := bsNone;
|
|
Color := clBtnFace;
|
|
end;
|
|
|
|
procedure TOptionsListBox.WMNCCalcSize(var Message: TWMNCCalcSize);
|
|
begin
|
|
inherited;
|
|
InflateRect(Message.CalcSize_Params^.rgrc[0], -2, -2);
|
|
end;
|
|
|
|
procedure TOptionsListBox.WMNCPaint(var Message: TWMNCPaint);
|
|
var
|
|
R: TRect;
|
|
DC: HDC;
|
|
begin
|
|
inherited;
|
|
GetWindowRect(Handle, R);
|
|
OffsetRect(R, -R.Left, -R.Top);
|
|
DC := GetWindowDC(Handle);
|
|
DrawEdge(DC, R, EDGE_ETCHED, BF_RECT);
|
|
ReleaseDC(Handle, DC);
|
|
end;
|
|
|
|
procedure TOptionsListBox.ClickCheck;
|
|
var
|
|
S: string;
|
|
I: Integer;
|
|
|
|
procedure XorOptionsView(Option: TdxMasterViewLevelOptionView);
|
|
begin
|
|
with Level do
|
|
if Option in OptionsView then
|
|
OptionsView := OptionsView - [Option]
|
|
else
|
|
OptionsView := OptionsView + [Option];
|
|
end;
|
|
|
|
procedure XorOptionsHeader(Option: TdxMasterViewLevelOptionHeader);
|
|
begin
|
|
with Level do
|
|
if Option in OptionsHeader then
|
|
OptionsHeader := OptionsHeader - [Option]
|
|
else
|
|
OptionsHeader := OptionsHeader + [Option];
|
|
end;
|
|
|
|
begin
|
|
inherited;
|
|
S := Items[ItemIndex];
|
|
for I := dxsMVCBOptionCaption to dxsMVCBOptionViewMode do
|
|
if S = LoadStr(I) then Break;
|
|
with Level do
|
|
case I - dxsMVBase of
|
|
08: XorOptionsView(lovCaption);
|
|
09: XorOptionsView(lovFooter);
|
|
10: XorOptionsView(lovGrid);
|
|
11: XorOptionsView(lovGridWithPreview);
|
|
12: XorOptionsView(lovGroupByBox);
|
|
13: XorOptionsView(lovHeader);
|
|
14: XorOptionsHeader(lohForFirstNode);
|
|
15: XorOptionsHeader(lohForFirstVisibleNode);
|
|
16: XorOptionsHeader(lohAfterExpandedNode);
|
|
17: XorOptionsView(lovOccupyRestSpace);
|
|
18: XorOptionsView(lovPreview);
|
|
19:
|
|
if ViewMode = vmHorizontal then
|
|
ViewMode := vmVertical
|
|
else
|
|
ViewMode := vmHorizontal;
|
|
end;
|
|
end;
|
|
|
|
{ TdxMVCustomizationForm }
|
|
|
|
type
|
|
TdxMVCustomizationForm = class(TWinControl)
|
|
private
|
|
FActiveLevel: TdxMasterViewLevel;
|
|
ListBoxTop, ListBoxBottom: Integer;
|
|
procedure SetActiveLevel(Value: TdxMasterViewLevel);
|
|
|
|
procedure cmbLevelsClick(Sender: TObject);
|
|
procedure btnChangePageClick(Sender: TObject);
|
|
|
|
procedure WMActivate(var Message: TWMActivate); message WM_ACTIVATE;
|
|
procedure WMClose(var Message: TWMClose); message WM_CLOSE;
|
|
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
|
|
procedure WMMove(var Message: TWMMove); message WM_MOVE;
|
|
procedure WMNCCreate(var Message: TWMNCCreate); message WM_NCCREATE;
|
|
protected
|
|
procedure CreateParams(var Params: TCreateParams); override;
|
|
public
|
|
cmbLevels: TComboBox;
|
|
pnlChangePage: TPanel;
|
|
btnColumns, btnOptions: TChangePageButton;
|
|
lbColumns: TColumnsListBox;
|
|
clbOptions: TOptionsListBox;
|
|
Control: TdxMasterView;
|
|
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
function MouseInBounds(P: TPoint): Boolean;
|
|
procedure RefreshColumnsListBox(FocusedColumn: TdxMasterViewColumn);
|
|
procedure RefreshOptions;
|
|
|
|
property ActiveLevel: TdxMasterViewLevel read FActiveLevel write SetActiveLevel;
|
|
end;
|
|
|
|
var
|
|
WndProcHandlers: TList;
|
|
WndProcHookHandle: HHOOK;
|
|
|
|
function dxMVCustFormWndProcHook(Code: Integer; wParam: WParam; lParam: LParam): LRESULT; stdcall;
|
|
const
|
|
Flags: array[Boolean] of Integer = (SWP_HIDEWINDOW, SWP_SHOWWINDOW);
|
|
var
|
|
I: Integer;
|
|
Wnd, ParentWnd: HWND;
|
|
|
|
function GetParentFormHandle(Wnd: HWND): HWND;
|
|
begin
|
|
Result := Wnd;
|
|
while not (FindControl(Result) is TCustomForm) and (GetParent(Result) <> 0) do
|
|
Result := GetParent(Result);
|
|
end;
|
|
|
|
begin
|
|
with PCWPStruct(lParam)^ do
|
|
if message = WM_ACTIVATE then
|
|
for I := 0 to WndProcHandlers.Count - 1 do
|
|
begin
|
|
Wnd := TWinControl(WndProcHandlers[I]).Handle;
|
|
ParentWnd := GetParentFormHandle(Wnd);
|
|
if (hwnd = ParentWnd) and (Windows.HWND(lParam) <> Wnd) or
|
|
(hwnd = Wnd) and (Windows.HWND(lParam) <> ParentWnd) then
|
|
SetWindowPos(Wnd, 0, 0, 0, 0, 0,
|
|
SWP_NOZORDER or SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or
|
|
Flags[LOWORD(wParam) <> WA_INACTIVE]);
|
|
end;
|
|
Result := CallNextHookEx(WndProcHookHandle, Code, wParam, lParam);
|
|
end;
|
|
|
|
procedure RegisterWndProcHandler(CustForm: TWinControl);
|
|
begin
|
|
WndProcHandlers.Add(CustForm);
|
|
if WndProcHookHandle = 0 then
|
|
WndProcHookHandle :=
|
|
SetWindowsHookEx(WH_CALLWNDPROC, dxMVCustFormWndProcHook, 0, GetCurrentThreadId);
|
|
end;
|
|
|
|
procedure UnregisterWndProcHandler(CustForm: TWinControl);
|
|
begin
|
|
WndProcHandlers.Remove(CustForm);
|
|
if (WndProcHandlers.Count = 0) and (WndProcHookHandle <> 0) then
|
|
begin
|
|
UnhookWindowsHookEx(WndProcHookHandle);
|
|
WndProcHookHandle := 0;
|
|
end;
|
|
end;
|
|
|
|
constructor TdxMVCustomizationForm.Create(AOwner: TComponent);
|
|
var
|
|
Size: TPoint;
|
|
D, W, T, I: Integer;
|
|
Level: TdxMasterViewLevel;
|
|
R: TRect;
|
|
|
|
function GetSymbolSize: TPoint;
|
|
var
|
|
DC: HDC;
|
|
PrevFont: HFONT;
|
|
begin
|
|
DC := GetDC(0);
|
|
PrevFont := SelectObject(DC, Font.Handle);
|
|
GetTextExtentPoint{32}(DC, '0', 1, TSize(Result));
|
|
SelectObject(DC, PrevFont);
|
|
ReleaseDC(0, DC);
|
|
end;
|
|
|
|
begin
|
|
Control := TdxMasterView(AOwner);
|
|
inherited;
|
|
Visible := False;
|
|
Caption := LoadStr(dxsMVCBCaption);
|
|
Font := Control.Font;
|
|
|
|
Size := GetSymbolSize;
|
|
D := Size.Y div 6;
|
|
W := 32 * Size.X;
|
|
T := D;
|
|
|
|
cmbLevels := TFlatComboBox.Create(Self);
|
|
with cmbLevels do
|
|
begin
|
|
Parent := Self;
|
|
for I := 0 to Control.AbsoluteLevelCount - 1 do
|
|
begin
|
|
Level := Control.AbsoluteLevels[I];
|
|
if Level.OptionsCustomizeBox <> [] then
|
|
Items.AddObject(Level.Caption, Level);
|
|
end;
|
|
DropDownCount := Items.Count;
|
|
if Items.Count > 1 then
|
|
begin
|
|
SetBounds(D, T, W, 10);
|
|
OnClick := cmbLevelsClick;
|
|
ShowWindow(Handle, SW_SHOW);
|
|
Inc(T, Height + 2 * D);
|
|
end;
|
|
end;
|
|
|
|
pnlChangePage := TPanel.Create(Self);
|
|
with pnlChangePage do
|
|
begin
|
|
Parent := Self;
|
|
BevelOuter := bvNone;
|
|
SetBounds(D, T, W, 12 * D);
|
|
btnColumns := TChangePageButton.Create(Self);
|
|
with btnColumns do
|
|
begin
|
|
Caption := LoadStr(dxsMVCBColumns);
|
|
Flat := True;
|
|
GroupIndex := 1;
|
|
Down := True;
|
|
Parent := pnlChangePage;
|
|
SetBounds(0, 0, (W - 2 * D) div 2, Parent.Height);
|
|
OnClick := btnChangePageClick;
|
|
end;
|
|
btnOptions := TChangePageButton.Create(Self);
|
|
with btnOptions do
|
|
begin
|
|
Caption := LoadStr(dxsMVCBOptions);
|
|
Flat := True;
|
|
GroupIndex := 1;
|
|
Parent := pnlChangePage;
|
|
SetBounds(btnColumns.Width + 2 * D, 0,
|
|
W - btnColumns.Width - 2 * D, Parent.Height);
|
|
OnClick := btnChangePageClick;
|
|
end;
|
|
end;
|
|
Inc(T, pnlChangePage.Height + 2 * D);
|
|
|
|
ListBoxTop := T;
|
|
lbColumns := TColumnsListBox.Create(Self);
|
|
with lbColumns do
|
|
begin
|
|
Control := Self.Control;
|
|
Parent := Self;
|
|
ItemHeight := Size.Y + 2 + 2 * 2;
|
|
SetBounds(D, T, W, 2 + Control.CustomizationFormRowCount * ItemHeight);
|
|
ListBoxBottom := BoundsRect.Bottom;
|
|
end;
|
|
|
|
clbOptions := TOptionsListBox.Create(Self);
|
|
with clbOptions do
|
|
begin
|
|
Parent := Self;
|
|
BoundsRect := lbColumns.BoundsRect;
|
|
end;
|
|
|
|
Width := 100;
|
|
Height := 100;
|
|
with lbColumns.BoundsRect do
|
|
begin
|
|
ClientWidth := Right + D;
|
|
ClientHeight := Bottom + D;
|
|
end;
|
|
|
|
if cmbLevels.Items.Count <> 0 then
|
|
ActiveLevel := TdxMasterViewLevel(cmbLevels.Items.Objects[0]);
|
|
|
|
if Control.CustomizationFormPos.X = -1 then
|
|
begin
|
|
GetWindowRect(Control.Handle, R);
|
|
Left := R.Right - Width;
|
|
Top := R.Bottom - Height;
|
|
end
|
|
else
|
|
with Control.CustomizationFormPos do
|
|
begin
|
|
Left := X;
|
|
Top := Y;
|
|
end;
|
|
|
|
Visible := True;
|
|
ShowWindow(Handle, SW_SHOW);
|
|
|
|
RegisterWndProcHandler(Self);
|
|
end;
|
|
|
|
destructor TdxMVCustomizationForm.Destroy;
|
|
begin
|
|
UnregisterWndProcHandler(Self);
|
|
|
|
Destroying;
|
|
Control.Customizing := False;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TdxMVCustomizationForm.SetActiveLevel(Value: TdxMasterViewLevel);
|
|
const
|
|
Visibilities: array[Boolean] of Integer = (SW_HIDE, SW_SHOW);
|
|
var
|
|
ShowColumns, ShowOptions: Boolean;
|
|
T: Integer;
|
|
begin
|
|
if FActiveLevel <> Value then
|
|
begin
|
|
FActiveLevel := Value;
|
|
with cmbLevels do
|
|
ItemIndex := Items.IndexOfObject(Value);
|
|
|
|
ShowColumns := loxColumns in FActiveLevel.OptionsCustomizeBox;
|
|
ShowOptions := FActiveLevel.OptionsCustomizeBox - [loxColumns] <> [];
|
|
ShowWindow(pnlChangePage.Handle, Visibilities[ShowColumns and ShowOptions]);
|
|
if ShowColumns and ShowOptions then
|
|
T := ListBoxTop
|
|
else
|
|
T := pnlChangePage.BoundsRect.Top;
|
|
if ShowColumns then
|
|
begin
|
|
with lbColumns do
|
|
SetBounds(Left, T, Width, ListBoxBottom - T);
|
|
RefreshColumnsListBox(nil);
|
|
end;
|
|
if ShowOptions then
|
|
begin
|
|
with clbOptions do
|
|
SetBounds(Left, T, Width, ListBoxBottom - T);
|
|
RefreshOptions;
|
|
end;
|
|
|
|
ShowColumns := ShowColumns and (btnColumns.Down or not ShowOptions);
|
|
ShowOptions := ShowOptions and (btnOptions.Down or not ShowColumns);
|
|
ShowWindow(lbColumns.Handle, Visibilities[ShowColumns]);
|
|
ShowWindow(clbOptions.Handle, Visibilities[ShowOptions]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMVCustomizationForm.cmbLevelsClick(Sender: TObject);
|
|
begin
|
|
with cmbLevels do
|
|
ActiveLevel := TdxMasterViewLevel(Items.Objects[ItemIndex]);
|
|
end;
|
|
|
|
procedure TdxMVCustomizationForm.btnChangePageClick(Sender: TObject);
|
|
begin
|
|
if btnColumns.Down then
|
|
begin
|
|
ShowWindow(lbColumns.Handle, SW_SHOW);
|
|
ShowWindow(clbOptions.Handle, SW_HIDE);
|
|
end
|
|
else
|
|
begin
|
|
ShowWindow(clbOptions.Handle, SW_SHOW);
|
|
ShowWindow(lbColumns.Handle, SW_HIDE);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMVCustomizationForm.WMActivate(var Message: TWMActivate);
|
|
begin
|
|
inherited;
|
|
if (Message.Active <> WA_INACTIVE) and (GetFocus = Handle) then
|
|
Windows.SetFocus(lbColumns.Handle);
|
|
end;
|
|
|
|
procedure TdxMVCustomizationForm.WMClose(var Message: TWMClose);
|
|
begin
|
|
inherited;
|
|
Free;
|
|
end;
|
|
|
|
procedure TdxMVCustomizationForm.WMEraseBkgnd(var Message: TWMEraseBkgnd);
|
|
begin
|
|
FillRect(Message.DC, ClientRect, COLOR_BTNFACE + 1);
|
|
Message.Result := 1;
|
|
end;
|
|
|
|
procedure TdxMVCustomizationForm.WMMove(var Message: TWMMove);
|
|
var
|
|
R: TRect;
|
|
begin
|
|
inherited;
|
|
if IsWindowVisible(Handle) then
|
|
begin
|
|
GetWindowRect(Handle, R);
|
|
Control.CustomizationFormPos := R.TopLeft;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMVCustomizationForm.WMNCCreate(var Message: TWMNCCreate);
|
|
var
|
|
SysMenu: HMENU;
|
|
begin
|
|
inherited;
|
|
SysMenu := GetSystemMenu(Handle, False);
|
|
DeleteMenu(SysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
|
|
DeleteMenu(SysMenu, SC_MINIMIZE, MF_BYCOMMAND);
|
|
DeleteMenu(SysMenu, SC_SIZE, MF_BYCOMMAND);
|
|
DeleteMenu(SysMenu, SC_RESTORE, MF_BYCOMMAND);
|
|
end;
|
|
|
|
procedure TdxMVCustomizationForm.CreateParams(var Params: TCreateParams);
|
|
begin
|
|
inherited;
|
|
with Params do
|
|
begin
|
|
Style := WS_POPUP or WS_CLIPCHILDREN or WS_CLIPSIBLINGS or WS_CAPTION or WS_SYSMENU;
|
|
ExStyle := WS_EX_TOOLWINDOW or WS_EX_DLGMODALFRAME or WS_EX_CONTROLPARENT;
|
|
WindowClass.Style := CS_SAVEBITS;
|
|
WndParent := Control.Handle;
|
|
end;
|
|
end;
|
|
|
|
function TdxMVCustomizationForm.MouseInBounds(P: TPoint): Boolean;
|
|
begin
|
|
Windows.ClientToScreen(Control.Handle, P);
|
|
Result := PtInRect(BoundsRect, P);
|
|
end;
|
|
|
|
procedure TdxMVCustomizationForm.RefreshColumnsListBox(FocusedColumn: TdxMasterViewColumn);
|
|
var
|
|
PrevFocusedColumn: TObject;
|
|
I: Integer;
|
|
AColumn: TdxMasterViewColumn;
|
|
begin
|
|
with lbColumns, Items do
|
|
begin
|
|
if ItemIndex = -1 then
|
|
PrevFocusedColumn := nil
|
|
else
|
|
PrevFocusedColumn := Items.Objects[ItemIndex];
|
|
BeginUpdate;
|
|
try
|
|
Clear;
|
|
for I := 0 to ActiveLevel.ColumnCount - 1 do
|
|
begin
|
|
AColumn := ActiveLevel.Columns[I];
|
|
if not AColumn.Hidden and not AColumn.Visible then
|
|
AddObject(AColumn.Caption, AColumn);
|
|
end;
|
|
if FocusedColumn <> nil then
|
|
ItemIndex := IndexOfObject(FocusedColumn)
|
|
else
|
|
if PrevFocusedColumn <> nil then
|
|
ItemIndex := IndexOfObject(PrevFocusedColumn);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMVCustomizationForm.RefreshOptions;
|
|
begin
|
|
with ActiveLevel, clbOptions, Items do
|
|
begin
|
|
Level := ActiveLevel;
|
|
BeginUpdate;
|
|
try
|
|
Clear;
|
|
if loxViewMode in OptionsCustomizeBox then
|
|
Checked[Add(LoadStr(dxsMVCBOptionViewMode))] := Horizontal;
|
|
if loxCaption in OptionsCustomizeBox then
|
|
Checked[Add(LoadStr(dxsMVCBOptionCaption))] := ShowCaption;
|
|
if loxGroupByBox in OptionsCustomizeBox then
|
|
Checked[Add(LoadStr(dxsMVCBOptionGroupByBox))] := ShowGroupByBox;
|
|
if loxHeader in OptionsCustomizeBox then
|
|
Checked[Add(LoadStr(dxsMVCBOptionHeader))] := ShowHeader;
|
|
if loxHeaderOptions in OptionsCustomizeBox then
|
|
begin
|
|
Checked[Add(LoadStr(dxsMVCBOptionHeaderForFirstNode))] :=
|
|
lohForFirstNode in OptionsHeader;
|
|
Checked[Add(LoadStr(dxsMVCBOptionHeaderForFirstVisibleNode))] :=
|
|
lohForFirstVisibleNode in OptionsHeader;
|
|
Checked[Add(LoadStr(dxsMVCBOptionHeaderAfterExpandedNode))] :=
|
|
lohAfterExpandedNode in OptionsHeader;
|
|
end;
|
|
if loxGrid in OptionsCustomizeBox then
|
|
Checked[Add(LoadStr(dxsMVCBOptionGrid))] := ShowGrid;
|
|
if loxGridWithPreview in OptionsCustomizeBox then
|
|
Checked[Add(LoadStr(dxsMVCBOptionGridWithPreview))] := ShowGridWithPreview;
|
|
if loxPreview in OptionsCustomizeBox then
|
|
Checked[Add(LoadStr(dxsMVCBOptionPreview))] := ShowPreview;
|
|
if loxFooter in OptionsCustomizeBox then
|
|
Checked[Add(LoadStr(dxsMVCBOptionFooter))] := ShowFooter;
|
|
if loxOccupyRestSpace in OptionsCustomizeBox then
|
|
Checked[Add(LoadStr(dxsMVCBOptionOccupyRestSpace))] := OccupyRestSpace;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TdxMasterViewDataLink }
|
|
|
|
constructor TdxMasterViewDataLink.Create(ALevel: TdxMasterViewLevel);
|
|
begin
|
|
inherited Create;
|
|
{$IFDEF DELPHI5}
|
|
VisualControl := True;
|
|
{$ENDIF}
|
|
FLevel := ALevel;
|
|
end;
|
|
|
|
function TdxMasterViewDataLink.GetFrozen: Boolean;
|
|
begin
|
|
Result := FFreezeCount > 0;
|
|
end;
|
|
|
|
procedure TdxMasterViewDataLink.ActiveChanged;
|
|
begin
|
|
FLevel.ActiveChanged;
|
|
end;
|
|
|
|
procedure TdxMasterViewDataLink.DataSetChanged;
|
|
begin
|
|
if not Frozen then
|
|
FLevel.DataChanged
|
|
else
|
|
Unfreeze;
|
|
end;
|
|
|
|
procedure TdxMasterViewDataLink.DataSetScrolled(Distance: Integer);
|
|
begin
|
|
if not Frozen then
|
|
FLevel.SyncPos
|
|
else
|
|
Unfreeze;
|
|
end;
|
|
|
|
procedure TdxMasterViewDataLink.EditingChanged;
|
|
begin
|
|
FLevel.EditingChanged;
|
|
end;
|
|
|
|
procedure TdxMasterViewDataLink.LayoutChanged;
|
|
begin
|
|
FLevel.LayoutChanged;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TdxMasterViewDataLink.RecordChanged(Field: TField);
|
|
begin
|
|
FLevel.RecordChanged(Field);
|
|
end;
|
|
|
|
function TdxMasterViewDataLink.Freeze: Integer;
|
|
begin
|
|
Inc(FFreezeCount);
|
|
Result := FFreezeCount;
|
|
end;
|
|
|
|
procedure TdxMasterViewDataLink.Unfreeze;
|
|
begin
|
|
if FFreezeCount > 0 then Dec(FFreezeCount);
|
|
end;
|
|
|
|
{ TdxMasterViewStyle }
|
|
|
|
constructor TdxMasterViewStyle.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
FAnotherColor := clNone;
|
|
FColor := clNone;
|
|
FConsumers := TList.Create;
|
|
FFont := TFont.Create;
|
|
FFont.OnChange := FontChanged;
|
|
end;
|
|
|
|
destructor TdxMasterViewStyle.Destroy;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if FControl <> nil then FControl.RemoveStyle(Self);
|
|
if FBrush <> 0 then DeleteObject(FBrush);
|
|
if FAnotherBrush <> 0 then DeleteObject(FAnotherBrush);
|
|
FFont.Free;
|
|
for I := ConsumerCount - 1 downto 0 do
|
|
begin
|
|
Dispose(ConsumerRecs[I]);
|
|
FConsumers.Delete(I);
|
|
end;
|
|
FConsumers.Free;
|
|
FConsumers := nil;
|
|
inherited;
|
|
end;
|
|
|
|
function TdxMasterViewStyle.GetConsumerRec(Index: Integer): PdxMasterViewStyleConsumerRec;
|
|
begin
|
|
Result := PdxMasterViewStyleConsumerRec(FConsumers[Index]);
|
|
end;
|
|
|
|
function TdxMasterViewStyle.GetConsumerCount: Integer;
|
|
begin
|
|
Result := FConsumers.Count;
|
|
end;
|
|
|
|
function TdxMasterViewStyle.GetIndex: Integer;
|
|
begin
|
|
Result := FControl.FStyles.IndexOf(Self);
|
|
end;
|
|
|
|
procedure TdxMasterViewStyle.SetAnotherColor(Value: TColor);
|
|
begin
|
|
if FAnotherColor <> Value then
|
|
begin
|
|
FAnotherColor := Value;
|
|
if FAnotherBrush <> 0 then DeleteObject(FAnotherBrush);
|
|
if FAnotherColor = clNone then
|
|
begin
|
|
FAnotherBrush := 0;
|
|
AssignedValues := AssignedValues - [svAnotherColor];
|
|
end
|
|
else
|
|
begin
|
|
FAnotherBrush := CreateSolidBrush(ColorToRGB(FAnotherColor));
|
|
if svAnotherColor in AssignedValues then
|
|
Changed([svAnotherColor])
|
|
else
|
|
AssignedValues := AssignedValues + [svAnotherColor];
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewStyle.SetAssignedValues(Value: TdxMasterViewStyleValues);
|
|
var
|
|
PrevValue: TdxMasterViewStyleValues;
|
|
begin
|
|
if FAnotherColor = clNone then Exclude(Value, svAnotherColor);
|
|
if FColor = clNone then Exclude(Value, svColor);
|
|
if FAssignedValues <> Value then
|
|
begin
|
|
PrevValue := FAssignedValues;
|
|
FAssignedValues := Value;
|
|
Byte(PrevValue) := Byte(PrevValue) xor Byte(Value);
|
|
Changed(PrevValue);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewStyle.SetColor(Value: TColor);
|
|
begin
|
|
if FColor <> Value then
|
|
begin
|
|
FColor := Value;
|
|
if FBrush <> 0 then DeleteObject(FBrush);
|
|
if FColor = clNone then
|
|
begin
|
|
FBrush := 0;
|
|
AssignedValues := AssignedValues - [svColor];
|
|
end
|
|
else
|
|
begin
|
|
FBrush := CreateSolidBrush(ColorToRGB(FColor));
|
|
if svColor in AssignedValues then
|
|
Changed([svColor])
|
|
else
|
|
AssignedValues := AssignedValues + [svColor];
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewStyle.SetFont(Value: TFont);
|
|
begin
|
|
FFont.Assign(Value);
|
|
end;
|
|
|
|
procedure TdxMasterViewStyle.SetIndex(Value: Integer);
|
|
begin
|
|
if Value < 0 then Value := 0;
|
|
if Value >= FControl.StyleCount then Value := FControl.StyleCount - 1;
|
|
if Index <> Value then
|
|
FControl.FStyles.Move(Index, Value);
|
|
end;
|
|
|
|
function TdxMasterViewStyle.IsAnotherColorStored: Boolean;
|
|
begin
|
|
Result := svAnotherColor in FAssignedValues;
|
|
end;
|
|
|
|
function TdxMasterViewStyle.IsColorStored: Boolean;
|
|
begin
|
|
Result := svColor in FAssignedValues;
|
|
end;
|
|
|
|
function TdxMasterViewStyle.IsFontStored: Boolean;
|
|
begin
|
|
Result := svFont in FAssignedValues;
|
|
end;
|
|
|
|
procedure TdxMasterViewStyle.FontChanged(Sender: TObject);
|
|
begin
|
|
if svFont in AssignedValues then
|
|
Changed([svFont])
|
|
else
|
|
AssignedValues := AssignedValues + [svFont];
|
|
end;
|
|
|
|
procedure TdxMasterViewStyle.SetName(const NewName: TComponentName);
|
|
begin
|
|
inherited;
|
|
if dxMVDesigner <> nil then dxMVDesigner.Changed(FControl, [rcStyles]);
|
|
end;
|
|
|
|
procedure TdxMasterViewStyle.SetParentComponent(AParent: TComponent);
|
|
begin
|
|
if AParent is TdxMasterView then
|
|
TdxMasterView(AParent).AddStyle(Self);
|
|
end;
|
|
|
|
procedure TdxMasterViewStyle.AddConsumeType(AConsumer: TComponent;
|
|
AConsumeType: TdxMasterViewStyleConsumeType);
|
|
var
|
|
I: Integer;
|
|
ConsumerRec: PdxMasterViewStyleConsumerRec;
|
|
begin
|
|
I := IndexOfConsumer(AConsumer);
|
|
if I = -1 then
|
|
begin
|
|
New(ConsumerRec);
|
|
with ConsumerRec^ do
|
|
begin
|
|
Consumer := AConsumer;
|
|
ConsumeTypes := [AConsumeType];
|
|
end;
|
|
FConsumers.Add(ConsumerRec);
|
|
AConsumer.FreeNotification(Self);
|
|
end
|
|
else
|
|
Include(ConsumerRecs[I]^.ConsumeTypes, AConsumeType);
|
|
end;
|
|
|
|
procedure TdxMasterViewStyle.Changed(Values: TdxMasterViewStyleValues);
|
|
var
|
|
I: Integer;
|
|
ConsumerRec: PdxMasterViewStyleConsumerRec;
|
|
begin
|
|
for I := 0 to ConsumerCount - 1 do
|
|
begin
|
|
ConsumerRec := ConsumerRecs[I];
|
|
with ConsumerRec^ do
|
|
if Consumer is TdxMasterViewColumn then
|
|
with TdxMasterViewColumn(Consumer) do
|
|
begin
|
|
if sctHeader in ConsumeTypes then HeaderStyleChanged(Values);
|
|
if sctContent in ConsumeTypes then ContentStyleChanged(Values);
|
|
if sctFooter in ConsumeTypes then FooterStyleChanged(Values);
|
|
end
|
|
else
|
|
if Consumer is TdxMasterViewLevel then
|
|
with TdxMasterViewLevel(Consumer) do
|
|
begin
|
|
if sctHeader in ConsumeTypes then HeaderStyleChanged(Values);
|
|
if sctContent in ConsumeTypes then ContentStyleChanged(Values);
|
|
if sctFooter in ConsumeTypes then FooterStyleChanged(Values);
|
|
if sctPreview in ConsumeTypes then PreviewStyleChanged(Values);
|
|
if sctCaption in ConsumeTypes then CaptionStyleChanged(Values);
|
|
if sctGroup in ConsumeTypes then GroupStyleChanged(Values);
|
|
if sctGroupByBox in ConsumeTypes then GroupByBoxStyleChanged(Values);
|
|
end
|
|
else
|
|
if Consumer is TdxMasterView then
|
|
with TdxMasterView(Consumer) do
|
|
begin
|
|
if sctHighlight in ConsumeTypes then HighlightStyleChanged(Values);
|
|
if sctInactive in ConsumeTypes then InactiveStyleChanged(Values);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewStyle.IndexOfConsumer(Consumer: TComponent): Integer;
|
|
begin
|
|
if FConsumers <> nil then
|
|
for Result := 0 to ConsumerCount - 1 do
|
|
if ConsumerRecs[Result]^.Consumer = Consumer then Exit;
|
|
Result := -1;
|
|
end;
|
|
|
|
procedure TdxMasterViewStyle.RemoveConsumeType(AConsumer: TComponent;
|
|
AConsumeType: TdxMasterViewStyleConsumeType);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
I := IndexOfConsumer(AConsumer);
|
|
if I = -1 then Exit;
|
|
with ConsumerRecs[I]^ do
|
|
begin
|
|
Exclude(ConsumeTypes, AConsumeType);
|
|
if ConsumeTypes = [] then
|
|
begin
|
|
Dispose(ConsumerRecs[I]);
|
|
FConsumers.Delete(I);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewStyle.SysColorChanged;
|
|
|
|
procedure RecreateBrush(var ABrush: HBRUSH; AColor: TColor);
|
|
begin
|
|
DeleteObject(ABrush);
|
|
ABrush := CreateSolidBrush(ColorToRGB(AColor));
|
|
end;
|
|
|
|
begin
|
|
if svColor in AssignedValues then
|
|
RecreateBrush(FBrush, FColor);
|
|
if svAnotherColor in AssignedValues then
|
|
RecreateBrush(FAnotherBrush, FAnotherColor);
|
|
end;
|
|
|
|
procedure TdxMasterViewStyle.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TdxMasterViewStyle then
|
|
begin
|
|
AnotherColor := TdxMasterViewStyle(Source).AnotherColor;
|
|
Color := TdxMasterViewStyle(Source).Color;
|
|
Font := TdxMasterViewStyle(Source).Font;
|
|
AssignedValues := TdxMasterViewStyle(Source).AssignedValues;
|
|
end
|
|
else
|
|
inherited;
|
|
end;
|
|
|
|
function TdxMasterViewStyle.GetParentComponent: TComponent;
|
|
begin
|
|
Result := FControl;
|
|
end;
|
|
|
|
function TdxMasterViewStyle.HasParent: Boolean;
|
|
begin
|
|
Result := FControl <> nil;
|
|
end;
|
|
|
|
{ TdxMasterViewColumn }
|
|
|
|
constructor TdxMasterViewColumn.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
FColIndex := -1;
|
|
FHeaderGlyph := TBitmap.Create;
|
|
FHeaderGlyph.OnChange := HeaderGlyphChanged;
|
|
FLeftColumns := TList.Create;
|
|
FLoadedGroupIndex := -1;
|
|
FLoadedSortIndex := -1;
|
|
FLogicalOffset := -1;
|
|
FMinRowCount := 1;
|
|
FMinWidth := dxMVColumnDefaultMinWidth;
|
|
FMaxRowCount := dxMVColumnDefaultMaxRowCount;
|
|
FMaxWidth := dxMVColumnDefaultMaxWidth;
|
|
FOptions :=
|
|
[coGrouping , coHorSizing, coMoving, coSorting, coVerSizing, coShowCaption];
|
|
FRightColumns := TList.Create;
|
|
FRowIndex := -1;
|
|
FRowCount := 1;
|
|
FVisible := True;
|
|
end;
|
|
|
|
destructor TdxMasterViewColumn.Destroy;
|
|
begin
|
|
Destroying;
|
|
HeaderStyle := nil;
|
|
ContentStyle := nil;
|
|
FooterStyle := nil;
|
|
FLevel.RemoveColumn(Self);
|
|
FRightColumns.Free;
|
|
FLeftColumns.Free;
|
|
FHeaderGlyph.Free;
|
|
inherited;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetAlignment: TAlignment;
|
|
begin
|
|
if cvAlignment in FAssignedValues then
|
|
Result := FAlignment
|
|
else
|
|
Result := DefaultAlignment;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetCaption: string;
|
|
begin
|
|
if cvCaption in FAssignedValues then
|
|
Result := FCaption
|
|
else
|
|
Result := DefaultCaption;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetColIndex: Integer;
|
|
begin
|
|
if FVisible and (FLevel.ViewMode = vmHorizontal) then
|
|
Result := FLevel.Layout.IndexOf(Self, FRowIndex)
|
|
else
|
|
Result := FColIndex;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetContentAnotherBrush: HBRUSH;
|
|
begin
|
|
if (ContentStyle <> nil) and (svAnotherColor in ContentStyle.AssignedValues) then
|
|
Result := ContentStyle.AnotherBrush
|
|
else
|
|
Result := FLevel.ContentAnotherBrush;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetContentAnotherColor: TColor;
|
|
begin
|
|
if (ContentStyle <> nil) and (svAnotherColor in ContentStyle.AssignedValues) then
|
|
Result := ContentStyle.AnotherColor
|
|
else
|
|
Result := FLevel.ContentAnotherColor;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetContentBrush: HBRUSH;
|
|
begin
|
|
if (ContentStyle <> nil) and (svColor in ContentStyle.AssignedValues) then
|
|
Result := ContentStyle.Brush
|
|
else
|
|
Result := FLevel.ContentBrush;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetContentColor: TColor;
|
|
begin
|
|
if (ContentStyle <> nil) and (svColor in ContentStyle.AssignedValues) then
|
|
Result := ContentStyle.Color
|
|
else
|
|
Result := FLevel.ContentColor;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetContentFont: TFont;
|
|
begin
|
|
if (ContentStyle <> nil) and (svFont in ContentStyle.AssignedValues) then
|
|
Result := ContentStyle.Font
|
|
else
|
|
Result := FLevel.ContentFont;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetControl: TdxMasterView;
|
|
begin
|
|
Result := FLevel.Control;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetFooterAlignment: TAlignment;
|
|
begin
|
|
if cvFooterAlignment in FAssignedValues then
|
|
Result := FFooterAlignment
|
|
else
|
|
Result := DefaultAlignment;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetFooterBrush: HBRUSH;
|
|
begin
|
|
if (FooterStyle <> nil) and (svColor in FooterStyle.AssignedValues) then
|
|
Result := FooterStyle.Brush
|
|
else
|
|
Result := FLevel.FooterBrush;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetFooterColor: TColor;
|
|
begin
|
|
if (FooterStyle <> nil) and (svColor in FooterStyle.AssignedValues) then
|
|
Result := FooterStyle.Color
|
|
else
|
|
Result := FLevel.FooterColor;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetFooterFont: TFont;
|
|
begin
|
|
if (FooterStyle <> nil) and (svFont in FooterStyle.AssignedValues) then
|
|
Result := FooterStyle.Font
|
|
else
|
|
Result := FLevel.FooterFont;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetGroupIndex: Integer;
|
|
begin
|
|
Result := FLevel.FGroupColumns.IndexOf(Self);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetHeaderAlignment: TAlignment;
|
|
begin
|
|
if cvHeaderAlignment in FAssignedValues then Result := FHeaderAlignment
|
|
else Result := DefaultHeaderAlignment;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetHeaderBrush: HBRUSH;
|
|
begin
|
|
if (HeaderStyle <> nil) and (svColor in HeaderStyle.AssignedValues) then
|
|
Result := HeaderStyle.Brush
|
|
else
|
|
Result := FLevel.HeaderBrush;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetHeaderColor: TColor;
|
|
begin
|
|
if (HeaderStyle <> nil) and (svColor in HeaderStyle.AssignedValues) then
|
|
Result := HeaderStyle.Color
|
|
else
|
|
Result := FLevel.HeaderColor;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetHeaderFont: TFont;
|
|
begin
|
|
if (HeaderStyle <> nil) and (svFont in HeaderStyle.AssignedValues) then
|
|
Result := HeaderStyle.Font
|
|
else
|
|
Result := FLevel.HeaderFont;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetHidden: Boolean;
|
|
begin
|
|
Result := coHidden in FOptions;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetIndex: Integer;
|
|
begin
|
|
Result := FLevel.FColumns.IndexOf(Self);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetIsDestroying: Boolean;
|
|
begin
|
|
Result := csDestroying in ComponentState;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetIsLoading: Boolean;
|
|
begin
|
|
Result := (csLoading in ComponentState) or FLevel.IsLoading;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetLastInRow: Boolean;
|
|
begin
|
|
Result := ColIndex = FLevel.Layout[RowIndex].Count - 1;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetLogicalOffset: Integer;
|
|
var
|
|
List: TList;
|
|
I, AOffset: Integer;
|
|
begin
|
|
if FLogicalOffset = -1 then
|
|
begin
|
|
Result := 0;
|
|
if IsLoading {FLevel} then Exit;
|
|
if FLevel.Horizontal then
|
|
begin
|
|
if FRowIndex = -1 then Exit;
|
|
List := TList.Create;
|
|
try
|
|
if FLevel.Layout.HasLeftNeighbours(Self, List, False) then
|
|
for I := 0 to List.Count - 1 do
|
|
begin
|
|
with TdxMasterViewColumn(List[I]) do
|
|
AOffset := LogicalOffset + VisibleWidth;
|
|
if AOffset > Result then Result := AOffset;
|
|
end;
|
|
finally
|
|
List.Free;
|
|
end;
|
|
end
|
|
else
|
|
with FLevel, Layout do
|
|
begin
|
|
if FColIndex = -1 then Exit;
|
|
if HasExpandButton then Result := LevelIndent;
|
|
for I := 0 to ColIndex - 1 do
|
|
Inc(Result, HeaderWidths[I] + ContentWidths[I]);
|
|
end;
|
|
end
|
|
else
|
|
Result := FLogicalOffset;
|
|
end;
|
|
{
|
|
function TdxMasterViewColumn.GetMaxLogicalOffset: Integer;
|
|
var
|
|
List: TList;
|
|
I, AOffset: Integer;
|
|
begin
|
|
Result := 0;
|
|
if FRowIndex = -1 then Exit;
|
|
List := TList.Create;
|
|
try
|
|
if FLevel.Layout.HasLeftNeighbours(Self, List, True) then
|
|
for I := 0 to List.Count - 1 do
|
|
begin
|
|
with TdxMasterViewColumn(List[I]) do
|
|
AOffset := MaxLogicalOffset + VisibleMaxWidth;
|
|
if AOffset > Result then Result := AOffset;
|
|
end;
|
|
finally
|
|
List.Free;
|
|
end;
|
|
end;
|
|
}
|
|
function TdxMasterViewColumn.GetMinLogicalOffset: Integer;
|
|
var
|
|
List: TList;
|
|
I, AOffset: Integer;
|
|
begin
|
|
Result := 0;
|
|
if FRowIndex = -1 then Exit;
|
|
List := TList.Create;
|
|
try
|
|
if FLevel.Layout.HasLeftNeighbours(Self, List, False) then
|
|
for I := 0 to List.Count - 1 do
|
|
begin
|
|
with TdxMasterViewColumn(List[I]) do
|
|
AOffset := MinLogicalOffset + VisibleMinWidth;
|
|
if AOffset > Result then Result := AOffset;
|
|
end;
|
|
finally
|
|
List.Free;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetNonScaledLogicalOffset: Integer;
|
|
var
|
|
List: TList;
|
|
I, AOffset: Integer;
|
|
begin
|
|
Result := 0;
|
|
if FLevel.Horizontal then
|
|
begin
|
|
if FRowIndex = -1 then Exit;
|
|
List := TList.Create;
|
|
try
|
|
if FLevel.Layout.HasLeftNeighbours(Self, List, False) then
|
|
for I := 0 to List.Count - 1 do
|
|
begin
|
|
with TdxMasterViewColumn(List[I]) do
|
|
AOffset := NonScaledLogicalOffset + NonScaledWidth;
|
|
if AOffset > Result then Result := AOffset;
|
|
end;
|
|
finally
|
|
List.Free;
|
|
end;
|
|
end
|
|
else
|
|
with FLevel, Layout do
|
|
begin
|
|
if FColIndex = -1 then Exit;
|
|
if HasExpandButton then Result := LevelIndent;
|
|
for I := 0 to ColIndex - 1 do
|
|
Inc(Result, HeaderWidths[I] + ContentNonScaledWidths[I]);
|
|
end;
|
|
end;
|
|
{
|
|
function TdxMasterViewColumn.GetNonScaledOffset: Integer;
|
|
begin
|
|
Result := FLevel.Indent - Control.LeftPos + NonScaledLogicalOffset;
|
|
end;
|
|
}
|
|
function TdxMasterViewColumn.GetNonScaledWidth: Integer;
|
|
begin
|
|
Result := Width + AddInWidth;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetOffset: Integer;
|
|
begin
|
|
Result := FLevel.Indent - Control.LeftPos + LogicalOffset;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetRowIndex: Integer;
|
|
begin
|
|
if (FLevel.ViewMode = vmVertical) and FVisible then
|
|
Result := FLevel.Layout.IndexOf(Self, FColIndex) //!!!
|
|
else
|
|
Result := FRowIndex;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetSortIndex: Integer;
|
|
begin
|
|
Result := FLevel.FSortedColumns.IndexOf(Self);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetSummaryField: TField;
|
|
begin
|
|
if cvSummaryFieldName in FAssignedValues then
|
|
Result := FSummaryField
|
|
else
|
|
Result := Field;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetSummaryFieldName: string;
|
|
begin
|
|
if cvSummaryFieldName in FAssignedValues then
|
|
Result := FSummaryFieldName
|
|
else
|
|
Result := FieldName;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetSummaryIndex: Integer;
|
|
begin
|
|
Result := FLevel.FSummaryColumns.IndexOf(Self);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetVisibleIndex: Integer;
|
|
begin
|
|
if FLevel = nil then Result := -1
|
|
else Result := FLevel.FVisibleColumns.IndexOf(Self);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetVisibleMaxWidth: Integer;
|
|
begin
|
|
if coHorSizing in FOptions then
|
|
Result := MaxWidth + AddInWidth
|
|
else
|
|
Result := VisibleWidth;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetVisibleMinWidth: Integer;
|
|
begin
|
|
if coHorSizing in FOptions then
|
|
Result := MinWidth + AddInWidth
|
|
else
|
|
Result := VisibleWidth;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetVisibleWidth: Integer;
|
|
begin
|
|
if FVisible and (FVisibleWidth <> 0) then
|
|
Result := FVisibleWidth
|
|
else
|
|
Result := Width;
|
|
Inc(Result, FAddInWidth);
|
|
{ if Control.AutoColumnWidth and FVisible then
|
|
Result := FVisibleWidth
|
|
else
|
|
Result := Width;
|
|
Inc(Result, AddInWidth);}
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetAlignment(Value: TAlignment);
|
|
begin
|
|
if (Alignment <> Value) or IsLoading then
|
|
begin
|
|
FAlignment := Value;
|
|
AssignedValues := AssignedValues + [cvAlignment];
|
|
ColumnChanged(False, hpOne, vpContent);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetAssignedValues(Value: TdxMasterViewColumnAssignedValues);
|
|
var
|
|
PrevValue: TdxMasterViewColumnAssignedValues;
|
|
begin
|
|
if FAssignedValues <> Value then
|
|
begin
|
|
PrevValue := FAssignedValues;
|
|
FAssignedValues := Value;
|
|
if not (cvCaption in Value) then FCaption := '';
|
|
if not (cvSummaryFieldName in Value) then
|
|
begin
|
|
FSummaryField := nil;
|
|
FSummaryFieldName := '';
|
|
end;
|
|
if (cvWidth in Value) and not (cvWidth in PrevValue) and FVisible then
|
|
FLevel.WidthChanged
|
|
else
|
|
if not (cvWidth in Value) and
|
|
((cvWidth in PrevValue) or
|
|
FLevel.ShowHeader and ([cvCaption] * Value <> [cvCaption] * PrevValue)) then
|
|
FLevel.CalcDefaultWidths(Self);
|
|
ColumnChanged(
|
|
(cvSummaryFieldName in PrevValue) and not (cvSummaryFieldName in Value),
|
|
hpAll, vpAll);
|
|
// if dxMVDesigner <> nil then dxMVDesigner.Changed(Control, [rcEnables]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetCaption(Value: string);
|
|
const
|
|
HParts: array[Boolean] of TdxMasterViewHPart = (hpAll, hpOne);
|
|
begin
|
|
if Caption <> Value then
|
|
begin
|
|
FCaption := Value;
|
|
if not (cvCaption in FAssignedValues) then
|
|
AssignedValues := AssignedValues + [cvCaption]
|
|
else
|
|
if not (cvWidth in FAssignedValues) and FLevel.ShowHeader then
|
|
FLevel.CalcDefaultWidths(Self);
|
|
ColumnChanged(False, HParts[cvWidth in FAssignedValues], vpAll);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetColIndex(Value: Integer);
|
|
begin
|
|
FLevel.Layout.ChangeCol(Self, Value);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetContentStyle(Value: TdxMasterViewStyle);
|
|
begin
|
|
if FContentStyle <> Value then
|
|
begin
|
|
if FContentStyle <> nil then
|
|
FContentStyle.RemoveConsumeType(Self, sctContent);
|
|
FContentStyle := Value;
|
|
if FContentStyle <> nil then
|
|
FContentStyle.AddConsumeType(Self, sctContent);
|
|
ContentStyleChanged([]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetField(Value: TField);
|
|
begin
|
|
if FField <> Value then
|
|
begin
|
|
SetFieldInternally(Value);
|
|
if ([cvWidth, cvCaption] * FAssignedValues = []) {and FLevel.ShowHeader }then
|
|
FLevel.CalcDefaultWidths(Self);
|
|
FLevel.FCanUseSmartReload := False;
|
|
ColumnChanged(True, hpAll, vpAll);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetFieldInternally(Value: TField);
|
|
begin
|
|
if FField <> Value then
|
|
begin
|
|
FField := Value;
|
|
if FField <> nil then
|
|
begin
|
|
FField.FreeNotification(FLevel);
|
|
FFieldName := FField.FieldName;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetFieldName(Value: string);
|
|
begin
|
|
if FFieldName <> Value then
|
|
begin
|
|
FFieldName := Value;
|
|
SetField(FindField);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetFooterAlignment(Value: TAlignment);
|
|
begin
|
|
if (FooterAlignment <> Value) or IsLoading then
|
|
begin
|
|
FFooterAlignment := Value;
|
|
AssignedValues := AssignedValues + [cvFooterAlignment];
|
|
ColumnChanged(False, hpOne, vpFooter);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetFooterStyle(Value: TdxMasterViewStyle);
|
|
begin
|
|
if FFooterStyle <> Value then
|
|
begin
|
|
if FFooterStyle <> nil then
|
|
FFooterStyle.RemoveConsumeType(Self, sctFooter);
|
|
FFooterStyle := Value;
|
|
if FFooterStyle <> nil then
|
|
FFooterStyle.AddConsumeType(Self, sctFooter);
|
|
FooterStyleChanged([]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetGroupIndex(Value: Integer);
|
|
begin
|
|
if IsLoading then
|
|
FLoadedGroupIndex := Value
|
|
else
|
|
begin
|
|
if Value < -1 then Value := -1;
|
|
if Value > FLevel.GroupColumnCount then Value := FLevel.GroupColumnCount;
|
|
if (GroupIndex <> Value) and
|
|
(coGrouping in FOptions) {and
|
|
((coSorting in FOptions) or (Value = -1) or (FSortOrder <> soNone))} then
|
|
FLevel.ChangeGrouping(Self, Value);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetHeaderAlignment(Value: TAlignment);
|
|
begin
|
|
if HeaderAlignment <> Value then
|
|
begin
|
|
FHeaderAlignment := Value;
|
|
AssignedValues := AssignedValues + [cvHeaderAlignment];
|
|
ColumnChanged(False, hpOne, vpAll);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetHeaderGlyph(Value: TBitmap);
|
|
begin
|
|
FHeaderGlyph.Assign(Value);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetHeaderGlyphAlignment(Value: TAlignment);
|
|
begin
|
|
if FHeaderGlyphAlignment <> Value then
|
|
begin
|
|
FHeaderGlyphAlignment := Value;
|
|
ColumnChanged(False, hpOne, vpAll);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetHeaderStyle(Value: TdxMasterViewStyle);
|
|
begin
|
|
if FHeaderStyle <> Value then
|
|
begin
|
|
if FHeaderStyle <> nil then
|
|
FHeaderStyle.RemoveConsumeType(Self, sctHeader);
|
|
FHeaderStyle := Value;
|
|
if FHeaderStyle <> nil then
|
|
FHeaderStyle.AddConsumeType(Self, sctHeader);
|
|
HeaderStyleChanged([]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetIndex(Value: Integer);
|
|
begin
|
|
if Value < 0 then Value := 0;
|
|
if Value >= FLevel.ColumnCount then Value := FLevel.ColumnCount - 1;
|
|
if Index <> Value then
|
|
begin
|
|
Control.Items.MoveData(FLevel, Index, Value);
|
|
FLevel.FColumns.Move(Index, Value);
|
|
FLevel.RefreshVisibleColumnsList;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetInternalVisibleWidth(Value: Integer);
|
|
begin
|
|
CheckVisibleWidthValue(Value);
|
|
Dec(Value, AddInWidth);
|
|
FVisibleWidth := Value;
|
|
{ Dec(Value, AddInWidth);
|
|
CheckWidthValue(Value);
|
|
FVisibleWidth := Value;}
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetMaxRowCount(Value: Integer);
|
|
begin
|
|
if Value < FMinRowCount then Value := FMinRowCount;
|
|
if FMaxRowCount <> Value then
|
|
begin
|
|
FMaxRowCount := Value;
|
|
if FRowCount > FMaxRowCount then RowCount := FMaxRowCount;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetMaxWidth(Value: Integer);
|
|
begin
|
|
if Value < FMinWidth then Value := FMinWidth;
|
|
if FMaxWidth <> Value then
|
|
begin
|
|
FMaxWidth := Value;
|
|
if IsLoading then Exit;
|
|
if Width > FMaxWidth then
|
|
Width := FMaxWidth
|
|
else
|
|
if VisibleWidth > VisibleMaxWidth then
|
|
VisibleWidth := VisibleMaxWidth
|
|
else
|
|
if Control.AutoColumnWidth then FLevel.WidthChangedEx;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetMinRowCount(Value: Integer);
|
|
begin
|
|
if Value < 1 then Value := 1;
|
|
if Value > FMaxRowCount then Value := FMaxRowCount;
|
|
if FMinRowCount <> Value then
|
|
begin
|
|
FMinRowCount := Value;
|
|
if FRowCount < FMinRowCount then RowCount := FMinRowCount;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetMinWidth(Value: Integer);
|
|
begin
|
|
if Value < 0 then Value := 0;
|
|
if Value > FMaxWidth then Value := FMaxWidth;
|
|
if FMinWidth <> Value then
|
|
begin
|
|
FMinWidth := Value;
|
|
if IsLoading then Exit;
|
|
if Width < FMinWidth then
|
|
Width := FMinWidth
|
|
else
|
|
if VisibleWidth < VisibleMinWidth then
|
|
VisibleWidth := VisibleMinWidth
|
|
else
|
|
if Control.AutoColumnWidth then FLevel.WidthChangedEx;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetMultiLine(Value: Boolean);
|
|
begin
|
|
if FMultiLine <> Value then
|
|
begin
|
|
FMultiLine := Value;
|
|
ColumnChanged(False, hpOne, vpContent);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetOptions(Value: TdxMasterViewColumnOptions);
|
|
const
|
|
HParts: array[Boolean] of TdxMasterViewHPart = (hpAll, hpOne);
|
|
var
|
|
ChangedValues: TdxMasterViewColumnOptions;
|
|
begin
|
|
if FOptions <> Value then
|
|
begin
|
|
Byte(ChangedValues) := Byte(Value) xor Byte(FOptions);
|
|
FOptions := Value;
|
|
if (coHidden in ChangedValues) and Control.Customizing then
|
|
TdxMVCustomizationForm(Control.CustomizationForm).RefreshColumnsListBox(nil);
|
|
if coShowCaption in ChangedValues then
|
|
begin
|
|
if not (cvWidth in FAssignedValues) and FLevel.ShowHeader then
|
|
FLevel.CalcDefaultWidths(Self);
|
|
ColumnChanged(False, HParts[cvWidth in FAssignedValues], vpAll);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetPressed(Value: Boolean);
|
|
begin
|
|
if FPressed <> Value then
|
|
begin
|
|
FPressed := Value;
|
|
ColumnChanged(False, hpOne, vpHeader);
|
|
if FLevel.ShowGroupByBox then
|
|
ColumnChanged(False, hpOne, vpGroupByBox);
|
|
if Control <> nil then Control.Update;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetRowCount(Value: Integer);
|
|
begin
|
|
FLevel.Layout.ChangeRowCount(Self, Value);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetRowIndex(Value: Integer);
|
|
begin
|
|
FLevel.Layout.ChangeRow(Self, Value, False);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetSortIndex(Value: Integer);
|
|
begin
|
|
if IsLoading then
|
|
FLoadedSortIndex := Value
|
|
else
|
|
begin
|
|
if FSortOrder = soNone then Exit;
|
|
if Value < 0 then Value := 0;
|
|
if Value > FLevel.SortedColumnCount - 1 then
|
|
Value := FLevel.SortedColumnCount - 1;
|
|
if SortIndex <> Value then
|
|
FLevel.ChangeSorting(Self, FSortOrder, Value);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetSortOrder(Value: TdxMasterViewSortOrder);
|
|
begin
|
|
if IsLoading then
|
|
FSortOrder := Value
|
|
else
|
|
if (FSortOrder <> Value) and (coSorting in FOptions) then
|
|
FLevel.ChangeSorting(Self, Value, SortIndex);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetSummaryField(Value: TField);
|
|
begin
|
|
if SummaryField <> Value then
|
|
begin
|
|
SetSummaryFieldInternally(Value);
|
|
FLevel.FCanUseSmartReload := False;
|
|
ColumnChanged(True, hpAll, vpAll);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetSummaryFieldInternally(Value: TField);
|
|
begin
|
|
if SummaryField <> Value then
|
|
begin
|
|
FSummaryField := Value;
|
|
if FSummaryField <> nil then
|
|
begin
|
|
FSummaryField.FreeNotification(FLevel);
|
|
SummaryFieldName := FSummaryField.FieldName;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetSummaryFieldName(Value: string);
|
|
begin
|
|
if SummaryFieldName <> Value then
|
|
begin
|
|
FSummaryFieldName := Value;
|
|
AssignedValues := AssignedValues + [cvSummaryFieldName];
|
|
SetSummaryField(FindSummaryField);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetSummaryFormat(Value: string);
|
|
begin
|
|
if FSummaryFormat <> Value then
|
|
begin
|
|
FSummaryFormat := Value;
|
|
ColumnChanged(False, hpOne, vpFooter);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetSummaryType(Value: TdxMasterViewSummaryType);
|
|
begin
|
|
if FSummaryType <> Value then
|
|
begin
|
|
FSummaryType := Value;
|
|
FLevel.SummaryColumnsChanged(Self, TOperation(Value = stNone));
|
|
ColumnChanged(True, hpAll, vpAll);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetVisible(Value: Boolean);
|
|
begin
|
|
if FVisible <> Value then
|
|
begin
|
|
if not Value and not IsLoading then
|
|
begin
|
|
ColumnChanged(False, hpAll, vpAll);
|
|
if FLevel.Horizontal then
|
|
FColIndex := ColIndex
|
|
else
|
|
FRowIndex := RowIndex;
|
|
end;
|
|
FVisible := Value;
|
|
FLevel.RefreshVisibleColumnsList;
|
|
if Value then
|
|
FLevel.Layout.InsertColumn(FRowIndex, FColIndex, Self)
|
|
else
|
|
FLevel.Layout.RemoveColumn(Self);
|
|
if IsLoading then Exit;
|
|
if (HeaderStyle <> nil) and (svFont in HeaderStyle.AssignedValues) then
|
|
HeaderStyleChanged([svFont]);
|
|
if (ContentStyle <> nil) and (svFont in ContentStyle.AssignedValues) then
|
|
ContentStyleChanged([svFont]);
|
|
if (FooterStyle <> nil) and (svFont in FooterStyle.AssignedValues) then
|
|
FooterStyleChanged([svFont]);
|
|
FLevel.WidthChanged;
|
|
if Value then ColumnChanged(False, hpAll, vpAll);
|
|
if Control <> nil then
|
|
if Control.Customizing then
|
|
TdxMVCustomizationForm(Control.CustomizationForm).RefreshColumnsListBox(Self);
|
|
if FVisible then
|
|
FLevel.DoShowColumn(Self)
|
|
else
|
|
FLevel.DoHideColumn(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetVisibleWidth(Value: Integer);
|
|
begin
|
|
CheckVisibleWidthValue(Value);
|
|
if VisibleWidth <> Value then
|
|
ChangeWidth(Value - AddInWidth, True);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetWidth(Value: Integer);
|
|
begin
|
|
CheckWidthValue(Value);
|
|
if Width <> Value then
|
|
ChangeWidth(Value, False);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.CheckRowCount(var Value: Integer);
|
|
begin
|
|
if Value < FMinRowCount then Value := FMinRowCount;
|
|
if Value > FMaxRowCount then Value := FMaxRowCount;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.CheckVisibleWidthValue(var Value: Integer);
|
|
begin
|
|
if Value < VisibleMinWidth then Value := VisibleMinWidth;
|
|
if Value > VisibleMaxWidth then Value := VisibleMaxWidth;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.CheckWidthValue(var Value: Integer);
|
|
begin
|
|
if Value < FMinWidth then Value := FMinWidth;
|
|
if Value > FMaxWidth then Value := FMaxWidth;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.FindField: TField;
|
|
begin
|
|
if (FFieldName <> '') and (FLevel.DataSet <> nil) then
|
|
Result := FLevel.DataSet.FindField(FFieldName)
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.FindSummaryField: TField;
|
|
begin
|
|
if cvSummaryFieldName in FAssignedValues then
|
|
if (FSummaryFieldName <> '') and (FLevel.DataSet <> nil) then
|
|
Result := FLevel.DataSet.FindField(FSummaryFieldName)
|
|
else
|
|
Result := nil
|
|
else
|
|
Result := Field;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.HeaderGlyphChanged(Sender: TObject);
|
|
const
|
|
HParts: array[Boolean] of TdxMasterViewHPart = (hpAll, hpOne);
|
|
begin
|
|
if not (cvWidth in FAssignedValues) and FLevel.ShowHeader then
|
|
FLevel.CalcDefaultWidths(Self);
|
|
ColumnChanged(False, HParts[cvWidth in FAssignedValues], vpAll);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.IsAlignmentStored: Boolean;
|
|
begin
|
|
Result := (cvAlignment in FAssignedValues) and (FAlignment <> DefaultAlignment);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.IsCaptionStored: Boolean;
|
|
begin
|
|
Result := (cvCaption in FAssignedValues) and (FCaption <> DefaultCaption);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.IsFooterAlignmentStored: Boolean;
|
|
begin
|
|
Result := (cvFooterAlignment in FAssignedValues) and
|
|
(FFooterAlignment <> DefaultAlignment);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.IsHeaderAlignmentStored: Boolean;
|
|
begin
|
|
Result := (cvHeaderAlignment in FAssignedValues) and
|
|
(FHeaderAlignment <> DefaultHeaderAlignment);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.IsSummaryFieldNameStored: Boolean;
|
|
begin
|
|
Result := (cvSummaryFieldName in FAssignedValues) and
|
|
(FSummaryFieldName <> FFieldName);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.IsWidthLinked: Boolean;
|
|
begin
|
|
Result := VisibleWidth = FLevel.Layout.ContentWidths[ColIndex];
|
|
end;
|
|
|
|
function TdxMasterViewColumn.IsWidthStored: Boolean;
|
|
begin
|
|
Result := (cvWidth in FAssignedValues) and (FWidth <> DefaultWidth);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.ReadLeaveSortOrder(Reader: TReader);
|
|
begin
|
|
FLeaveSortOrder := Reader.ReadBoolean;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.WriteLeaveSortOrder(Writer: TWriter);
|
|
begin
|
|
Writer.WriteBoolean(FLeaveSortOrder);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.DefineProperties(Filer: TFiler);
|
|
begin
|
|
inherited;
|
|
Filer.DefineProperty('LeaveSortOrder', ReadLeaveSortOrder, WriteLeaveSortOrder,
|
|
FLeaveSortOrder);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.Notification(AComponent: TComponent;
|
|
Operation: TOperation);
|
|
begin
|
|
inherited;
|
|
if (Operation = opRemove) and (AComponent is TdxMasterViewStyle) then
|
|
begin
|
|
if HeaderStyle = AComponent then HeaderStyle := nil;
|
|
if ContentStyle = AComponent then ContentStyle := nil;
|
|
if FooterStyle = AComponent then FooterStyle := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetName(const NewName: TComponentName);
|
|
begin
|
|
inherited;
|
|
if dxMVDesigner <> nil then dxMVDesigner.Changed(Control, [rcColumns]);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.SetParentComponent(AParent: TComponent);
|
|
begin
|
|
if AParent is TdxMasterViewLevel then
|
|
TdxMasterViewLevel(AParent).AddColumn(Self);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.CanGrouping(Index: Integer): Boolean;
|
|
begin
|
|
Result := (coGrouping in FOptions) and FLevel.CanGrouping(Self, Index);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.CanHiding: Boolean;
|
|
begin
|
|
Result := FVisible and not Hidden and (FLevel.VisibleColumnCount > 1) and
|
|
((locColumnHiding in FLevel.OptionsCustomize) or
|
|
Control.Customizing or Control.IsDesigning);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.CanMoving: Boolean;
|
|
begin
|
|
Result :=
|
|
(locColumnMoving in FLevel.OptionsCustomize) and (coMoving in FOptions);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.CanHorSizing: Boolean;
|
|
begin
|
|
Result := FLevel.CanHorSizing and
|
|
(coHorSizing in FOptions) and (FMinWidth <> FMaxWidth);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.CanSorting: Boolean;
|
|
begin
|
|
Result := (coSorting in FOptions) and FLevel.CanSorting(Self);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.CanVerSizing: Boolean;
|
|
begin
|
|
Result := (locColumnVerSizing in FLevel.OptionsCustomize) and
|
|
(coVerSizing in FOptions) and (FMinRowCount <> FMaxRowCount);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.ColumnChanged(HardRefresh: Boolean;
|
|
HPart: TdxMasterViewHPart; VPart: TdxMasterViewVPart);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if not FLevel.Active or IsDestroying or IsLoading then Exit;
|
|
if HardRefresh then
|
|
FLevel.LevelChanged(HardRefresh)
|
|
else
|
|
if (FVisible or (VPart = vpGroupByBox)) and
|
|
(Control <> nil) and (FLevel.FLayout.FUpdateLockCount = 0) then
|
|
with Control do
|
|
if (FUpdateLockCount = 0) and HandleAllocated then
|
|
for I := TopIndex to TopIndex + PartVisibleItemCount - 1 do
|
|
with AbsoluteItems[I] do
|
|
if Level = Self.Level then
|
|
if HPart = hpOne then
|
|
Invalidate(Self, VPart)
|
|
else
|
|
Invalidate(nil, VPart)
|
|
else
|
|
if Level.HasAsParent(Self.Level) then
|
|
Invalidate(nil, vpFooter);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.ContentStyleChanged(Values: TdxMasterViewStyleValues);
|
|
begin
|
|
if (Values = []) or (svFont in Values) then
|
|
FLevel.ContentStyleChanged([svFont]);
|
|
ColumnChanged(False, hpOne, vpContent);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.DefaultAlignment: TAlignment;
|
|
begin
|
|
if Field = nil then
|
|
Result := taLeftJustify
|
|
else
|
|
Result := Field.Alignment;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.DefaultCaption: string;
|
|
begin
|
|
if Field = nil then
|
|
Result := FieldName
|
|
else
|
|
Result := Field.DisplayName;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.DefaultHeaderAlignment: TAlignment;
|
|
begin
|
|
Result := taLeftJustify;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.DefaultWidth: Integer;
|
|
var
|
|
DC: HDC;
|
|
PrevFont: HFONT;
|
|
TM: TTextMetric;
|
|
Size: TSize;
|
|
W: Integer;
|
|
begin
|
|
if (FLevel = nil) or (Field = nil) then
|
|
Result := 64
|
|
else
|
|
begin
|
|
DC := GetDC(0);
|
|
PrevFont := SelectObject(DC, ContentFont.Handle);
|
|
GetTextMetrics(DC, TM);
|
|
GetTextExtentPoint{32}(DC, '0', 1, Size);
|
|
Result := Field.DisplayWidth * (Size.cx - TM.tmOverhang) + TM.tmOverhang + 4;
|
|
if FLevel.ShowHeader then
|
|
begin
|
|
W := GetHeaderBestFitWidth(DC, False);
|
|
if W > Result then Result := W;
|
|
end;
|
|
SelectObject(DC, PrevFont);
|
|
ReleaseDC(0, DC);
|
|
end;
|
|
CheckWidthValue(Result);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.DoAfterCalcSummary(Node: TdxMasterViewNode;
|
|
DataSet: TDataSet; var Value: Extended);
|
|
begin
|
|
if Assigned(FOnAfterCalcSummary) then
|
|
FOnAfterCalcSummary(Self, Node, DataSet, Value);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.DoBeforeCalcSummary(Node: TdxMasterViewNode;
|
|
DataSet: TDataSet; var Value: Extended);
|
|
begin
|
|
if Assigned(FOnBeforeCalcSummary) then
|
|
FOnBeforeCalcSummary(Self, Node, DataSet, Value);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.DoCalcSummary(Node: TdxMasterViewNode;
|
|
DataSet: TDataSet; var Value: Extended);
|
|
begin
|
|
if Assigned(FOnCalcSummary) then FOnCalcSummary(Self, Node, DataSet, Value);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.DrawSortMark(DC: HDC; var ARect: TRect);
|
|
var
|
|
Sign, X, Y: Integer;
|
|
PrevPen: HPEN;
|
|
begin
|
|
Dec(ARect.Right, SortOrderMarkZoneWidth);
|
|
|
|
Sign := 2 * Byte(FSortOrder = soAscending) - 1;
|
|
X := ARect.Right + SortOrderMarkZoneWidth div 2 - 1;
|
|
Y := (ARect.Top + ARect.Bottom - Sign * SortOrderMarkHeight) div 2 -
|
|
Byte(FSortOrder = soDescending);
|
|
|
|
PrevPen := SelectObject(DC, Control.BtnHighlightPen);
|
|
MoveToEx(DC, X + 4, Y + Sign * 5, nil);
|
|
LineTo(DC, X + 1, Y);
|
|
LineTo(DC, X + 4, Y + Sign * 6);
|
|
if FSortOrder = soDescending then SelectObject(DC, Control.BtnShadowPen);
|
|
LineTo(DC, X - 3, Y + Sign * 6);
|
|
if FSortOrder = soAscending then SelectObject(DC, Control.BtnShadowPen);
|
|
LineTo(DC, X, Y);
|
|
LineTo(DC, X - 3, Y + Sign * 7);
|
|
SelectObject(DC, PrevPen);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.DrawHeader(DC: HDC; var ARect: TRect; Node: TdxMasterViewNode);
|
|
var
|
|
ABrush: HBRUSH;
|
|
ATextColor, ABkColor: TColor;
|
|
AFont: TFont;
|
|
R: TRect;
|
|
ADC: HDC;
|
|
CanUseBitmap, FillBackground, MakeRightSpace: Boolean;
|
|
begin
|
|
FLevel.GetHeaderParams(Node, Self, @ABrush, nil, @ATextColor, @ABkColor, @AFont);
|
|
R := ARect;
|
|
CanUseBitmap :=
|
|
(movUseBitmap in Control.OptionsView) or not FHeaderGlyph.Empty;
|
|
with Control do
|
|
if CanUseBitmap then
|
|
begin
|
|
with R do
|
|
begin
|
|
OffsetRect(R, -Left, -Top);
|
|
PrepareBitmap(Right, Bottom);
|
|
end;
|
|
ADC := Bitmap.Canvas.Handle;
|
|
end
|
|
else
|
|
ADC := DC;
|
|
|
|
if not FHeaderGlyph.Empty then
|
|
begin
|
|
FillRect(ADC, R, ABrush);
|
|
TransparentDraw(ADC, R, FHeaderGlyphAlignment, ABrush, FHeaderGlyph);
|
|
FillBackground := False;
|
|
end
|
|
else
|
|
FillBackground := True;
|
|
MakeRightSpace := (FSortOrder = soNone) or
|
|
(ARect.Right - ARect.Left < SortOrderMarkZoneWidth);
|
|
if coShowCaption in FOptions then
|
|
Control.DrawText(ADC, R, AFont, ABrush, ATextColor, ABkColor,
|
|
HeaderAlignment, Caption, FillBackground, MakeRightSpace, False, False)
|
|
else
|
|
if FHeaderGlyph.Empty then FillRect(ADC, R, ABrush);
|
|
if not MakeRightSpace then DrawSortMark(ADC, R);
|
|
|
|
if CanUseBitmap then
|
|
with ARect do
|
|
BitBlt(DC, Left, Top, Right - Left, Bottom - Top, ADC, 0, 0, SRCCOPY);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.DrawContent(DC: HDC; var ARect: TRect; Node: TdxMasterViewNode);
|
|
var
|
|
ABrush: HBRUSH;
|
|
ATextColor, ABkColor: TColor;
|
|
AFont: TFont;
|
|
S: string;
|
|
begin
|
|
FLevel.GetContentParams(Node, Self, @ABrush, @ATextColor, @ABkColor, @AFont, True);
|
|
if FMultiLine and not VarIsNull(Node.Values[Index]) then
|
|
S := Node.Values[Index]
|
|
else
|
|
S := Node.Strings[Index];
|
|
Control.DrawText(DC, ARect, AFont, ABrush, ATextColor, ABkColor,
|
|
Alignment, S, True, True, True, FMultiLine);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.DrawFooter(DC: HDC; var ARect: TRect; Node: TdxMasterViewNode);
|
|
var
|
|
ABrush: HBRUSH;
|
|
ATextColor, ABkColor: TColor;
|
|
AFont: TFont;
|
|
begin
|
|
FLevel.GetFooterParams(Node, Self, @ABrush, @ATextColor, @ABkColor, @AFont);
|
|
Control.DrawText(DC, ARect, AFont, ABrush, ATextColor, ABkColor,
|
|
FooterAlignment, GetFooterText(Node), True, True, True, False);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.FooterStyleChanged(Values: TdxMasterViewStyleValues);
|
|
begin
|
|
if (Values = []) or (svFont in Values) then
|
|
FLevel.FooterStyleChanged([svFont]);
|
|
ColumnChanged(False, hpOne, vpFooter);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetFooterText(Node: TdxMasterViewNode): string;
|
|
const
|
|
SummaryFormats: array[Boolean, stSum..stAverage] of string =
|
|
(('0.00;-0.00', 'MIN=0.00;MIN=-0.00', 'MAX=0.00;MAX=-0.00', '0', 'AVG=0.00;AVG=-0.00'),
|
|
('', 'MIN=', 'MAX=', '0', 'AVG='));
|
|
var
|
|
Value: Extended;
|
|
IsDateTime: Boolean;
|
|
begin
|
|
if SummaryType = stNone then
|
|
Result := ''
|
|
else
|
|
begin
|
|
Value := GetFooterValue(Node);
|
|
IsDateTime :=
|
|
(SummaryField <> nil) and
|
|
(SummaryField.DataType in [ftDate, ftTime, ftDateTime]) and
|
|
(FSummaryType <> stCount);
|
|
if FSummaryFormat = '' then
|
|
Result := SummaryFormats[IsDateTime, FSummaryType]
|
|
else
|
|
Result := FSummaryFormat;
|
|
if IsDateTime then
|
|
case SummaryField.DataType of
|
|
ftDate: Result := Result + DateToStr(Value);
|
|
ftTime: Result := Result + TimeToStr(Value);
|
|
else
|
|
Result := Result + DateTimeToStr(Value);
|
|
end
|
|
else
|
|
Result := FormatFloat(Result, Value);
|
|
end;
|
|
FLevel.DoGetFooterCellText(Node, Self, Result);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetGroupByBoxBounds(Node: TdxMasterViewNode): TRect;
|
|
begin
|
|
Result := Node.GroupByBoxColumnBounds[GroupIndex];
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetGroupDisplayText(Node: TdxMasterViewNode): string;
|
|
begin
|
|
Result := Node.GroupValueText;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetHeaderBestFitWidth(DC: HDC; CheckSortOrderMark: Boolean): Integer;
|
|
var
|
|
PrevFont: HFONT;
|
|
Size: TSize;
|
|
begin
|
|
if coShowCaption in FOptions then
|
|
begin
|
|
PrevFont := SelectObject(DC, HeaderFont.Handle);
|
|
GetTextExtentPoint{32}(DC, PChar(Caption), Length(Caption), Size);
|
|
SelectObject(DC, PrevFont);
|
|
end
|
|
else
|
|
Size.cx := 0;
|
|
Result := 2 + Size.cx + 2;
|
|
if CheckSortOrderMark and (FSortOrder <> soNone) then
|
|
Inc(Result, SortOrderMarkZoneWidth - 2);
|
|
if not FHeaderGlyph.Empty then
|
|
if FHeaderAlignment <> taCenter then
|
|
Inc(Result, FHeaderGlyph.Width)
|
|
else
|
|
if (Caption = '') and (FHeaderGlyph.Width > Result) then
|
|
Result := FHeaderGlyph.Width;
|
|
Inc(Result, 1 + 1);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetHeaderBounds(Node: TdxMasterViewNode): TRect;
|
|
begin
|
|
if Node.NodeType = ntData then
|
|
begin
|
|
Result := Node.HeaderBounds;
|
|
with Result do
|
|
begin
|
|
Inc(Left, LogicalOffset);
|
|
if FLevel.Horizontal then
|
|
Right := Left + VisibleWidth
|
|
else
|
|
Right := Left + FLevel.Layout.HeaderWidths[ColIndex];
|
|
Inc(Top, RowIndex * FLevel.HeaderRealHeight);
|
|
Bottom := Top + RowCount * FLevel.HeaderRealHeight;
|
|
end;
|
|
end
|
|
else SetRectEmpty(Result);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetHeaderHeight: Integer;
|
|
var
|
|
Size: TSize;
|
|
begin
|
|
CalcFontSize(HeaderFont, Size);
|
|
Result := Size.cy + 2 + 2 * 2; // 19
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetContentBounds(Node: TdxMasterViewNode): TRect;
|
|
begin
|
|
if Node.NodeType = ntData then
|
|
begin
|
|
Result := Node.ContentBounds;
|
|
with Result do
|
|
begin
|
|
Inc(Left, LogicalOffset);
|
|
if not FLevel.Horizontal then
|
|
Inc(Left, FLevel.Layout.HeaderWidths[ColIndex]);
|
|
Right := Left + VisibleWidth;
|
|
Inc(Top, RowIndex * FLevel.ContentRealHeight);
|
|
Bottom := Top + RowCount * FLevel.ContentRealHeight;
|
|
end;
|
|
end
|
|
else
|
|
SetRectEmpty(Result);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetFooterBounds(Node: TdxMasterViewNode): TRect;
|
|
begin
|
|
Result := Node.SubFooterBounds[Node.Level.IndexOfParent(FLevel)];
|
|
if not IsRectEmpty(Result) then
|
|
with Result do
|
|
begin
|
|
Inc(Left, LogicalOffset);
|
|
if not FLevel.Horizontal then
|
|
Inc(Left, FLevel.Layout.HeaderWidths[ColIndex]);
|
|
Right := Left + VisibleWidth;
|
|
Inc(Top, RowIndex * FLevel.FooterHeight);
|
|
Bottom := Top + RowCount * FLevel.FooterHeight;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.HeaderStyleChanged(Values: TdxMasterViewStyleValues);
|
|
begin
|
|
if (Values = []) or (svFont in Values) then
|
|
FLevel.HeaderStyleChanged([svFont]);
|
|
ColumnChanged(False, hpOne, vpHeader);
|
|
if GroupIndex <> -1 then
|
|
FLevel.GroupByBoxStyleChanged(Values);
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.Assign(Source: TPersistent);
|
|
var
|
|
AColumn: TdxMasterViewColumn;
|
|
begin
|
|
if Source is TdxMasterViewColumn then
|
|
begin
|
|
AColumn := TdxMasterViewColumn(Source);
|
|
FLevel.BeginDataChanging;
|
|
try
|
|
AssignedValues := [];
|
|
if cvAlignment in AColumn.AssignedValues then
|
|
Alignment := AColumn.Alignment;
|
|
if cvCaption in AColumn.AssignedValues then
|
|
Caption := AColumn.Caption;
|
|
if cvFooterAlignment in AColumn.AssignedValues then
|
|
FooterAlignment := AColumn.FooterAlignment;
|
|
if cvHeaderAlignment in AColumn.AssignedValues then
|
|
HeaderAlignment := AColumn.HeaderAlignment;
|
|
if cvSummaryFieldName in AColumn.AssignedValues then
|
|
SummaryFieldName := AColumn.SummaryFieldName;
|
|
if cvWidth in AColumn.AssignedValues then
|
|
Width := AColumn.Width;
|
|
|
|
ContentStyle := AColumn.ContentStyle;
|
|
FieldName := AColumn.FieldName;
|
|
FooterStyle := AColumn.FooterStyle;
|
|
GroupIndex := AColumn.GroupIndex;
|
|
HeaderGlyph := AColumn.HeaderGlyph;
|
|
HeaderStyle := AColumn.HeaderStyle;
|
|
Index := AColumn.Index;
|
|
MaxRowCount := AColumn.MaxRowCount;
|
|
MaxWidth := AColumn.MaxWidth;
|
|
MinRowCount := AColumn.MinRowCount;
|
|
MinWidth := AColumn.MinWidth;
|
|
MultiLine := AColumn.MultiLine;
|
|
Options := AColumn.Options;
|
|
|
|
RowIndex := AColumn.RowIndex;
|
|
ColIndex := AColumn.ColIndex;
|
|
RowCount := AColumn.RowCount;
|
|
|
|
SortIndex := AColumn.SortIndex;
|
|
SortOrder := AColumn.SortOrder;
|
|
SummaryFormat := AColumn.SummaryFormat;
|
|
SummaryType := AColumn.SummaryType;
|
|
VisibleWidth := AColumn.VisibleWidth;
|
|
FLeaveSortOrder := AColumn.FLeaveSortOrder;
|
|
Visible := AColumn.Visible;
|
|
finally
|
|
FLevel.EndDataChanging;
|
|
end;
|
|
end
|
|
else
|
|
inherited;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.ChangeWidth(Value: Integer;
|
|
AdjustLinkedColumns: Boolean);
|
|
var
|
|
Delta: Integer;
|
|
NeedAssignWidths: Boolean;
|
|
|
|
function ChangeLinkedWidths: Boolean;
|
|
type
|
|
PBoolArray = ^TBoolArray;
|
|
TBoolArray = array[-1..MaxInt div (2 * SizeOf(Boolean))] of Boolean;
|
|
var
|
|
NewWidths: PIntArray;
|
|
ColumnLocked, ColumnProcessed, ColumnFixed: PBoolArray;
|
|
IsLast: Boolean;
|
|
I, W: Integer;
|
|
Column: TdxMasterViewColumn;
|
|
|
|
procedure SetFixedColumns(Column: TdxMasterViewColumn);
|
|
var
|
|
List: TList;
|
|
I: Integer;
|
|
begin
|
|
List := TList.Create;
|
|
try
|
|
FLevel.Layout.HasLeftNeighbours(Column, List, True);
|
|
for I := 0 to List.Count - 1 do
|
|
begin
|
|
ColumnFixed[TdxMasterViewColumn(List[I]).VisibleIndex] := True;
|
|
SetFixedColumns(List[I]);
|
|
end;
|
|
finally
|
|
List.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure ChangeWidth(Column: TdxMasterViewColumn; var Delta: Integer;
|
|
Direction: TdxMasterViewDirection);
|
|
var
|
|
VI, W, CheckW, CurDelta, I, ADelta: Integer;
|
|
NeedChangeSize: Boolean;
|
|
ListL, ListR, CollapsingList, ExpandingList: TList;
|
|
OppositeDirection: TdxMasterViewDirection;
|
|
|
|
function CanChangeSize(Column: TdxMasterViewColumn): Boolean;
|
|
var
|
|
List: TList;
|
|
I: Integer;
|
|
begin
|
|
Result := not ColumnLocked[Column.VisibleIndex];
|
|
if Result then
|
|
begin
|
|
List := TList.Create;
|
|
try
|
|
if FLevel.Layout.HasLeftNeighbours(Column, List, True) then
|
|
for I := 0 to List.Count - 1 do
|
|
begin
|
|
Result := CanChangeSize(List[I]);
|
|
if not Result then Break;
|
|
end;
|
|
finally
|
|
List.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if Column = nil then
|
|
VI := -1
|
|
else
|
|
VI := Column.VisibleIndex;
|
|
|
|
if ColumnLocked[VI] or ColumnProcessed[VI] then
|
|
begin
|
|
Delta := 0;
|
|
Exit;
|
|
end;
|
|
if ColumnFixed[VI] then
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
|
|
NeedChangeSize := (Column <> nil) and
|
|
(Control.AutoColumnWidth or (Direction = dirRight) and CanChangeSize(Column));
|
|
if NeedChangeSize then
|
|
begin
|
|
W := NewWidths[VI];
|
|
if Delta < 0 then
|
|
CheckW := Column.VisibleMinWidth
|
|
else
|
|
CheckW := Column.VisibleMaxWidth;
|
|
if (Delta < 0) and (W + Delta < CheckW) or
|
|
(Delta > 0) and (W + Delta > CheckW) then
|
|
CurDelta := CheckW - W
|
|
else
|
|
CurDelta := Delta;
|
|
Dec(Delta, CurDelta);
|
|
end
|
|
else
|
|
begin
|
|
CurDelta := 0;
|
|
ColumnProcessed[VI] := True;
|
|
end;
|
|
|
|
if VI <> -1 then Inc(NewWidths[VI], CurDelta);
|
|
|
|
ColumnLocked[VI] := True;
|
|
ListL := TList.Create;
|
|
ListR := TList.Create;
|
|
try
|
|
if Column <> nil then
|
|
with FLevel.Layout do
|
|
begin
|
|
HasLeftNeighbours(Column, ListL, True);
|
|
HasRightNeighbours(Column, ListR, True);
|
|
end;
|
|
if Direction = dirLeft then
|
|
begin
|
|
CollapsingList := ListL;
|
|
if Column = nil then
|
|
FLevel.Layout.RetrieveLastColumns(CollapsingList);
|
|
ExpandingList := ListR;
|
|
OppositeDirection := dirRight;
|
|
end
|
|
else
|
|
begin
|
|
CollapsingList := ListR;
|
|
if (CollapsingList.Count = 0) and
|
|
(Control.AutoColumnWidth or FLevel.OccupyRestSpace) then
|
|
CollapsingList.Add(nil);
|
|
ExpandingList := ListL;
|
|
OppositeDirection := dirLeft;
|
|
end;
|
|
for I := 0 to CollapsingList.Count - 1 do
|
|
begin
|
|
ADelta := -(Delta + CurDelta);
|
|
ChangeWidth(CollapsingList[I], ADelta, OppositeDirection);
|
|
if ADelta <> 0 then
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
end;
|
|
if Column = nil then Delta := 0;
|
|
if Delta <> 0 then
|
|
if (ExpandingList.Count = 0) and NeedChangeSize then
|
|
Result := False
|
|
else
|
|
begin
|
|
for I := 0 to ExpandingList.Count - 1 do
|
|
begin
|
|
ADelta := Delta;
|
|
ChangeWidth(ExpandingList[I], ADelta, Direction);
|
|
if ADelta <> 0 then
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
end;
|
|
Delta := 0;
|
|
end;
|
|
finally
|
|
ListR.Free;
|
|
ListL.Free;
|
|
ColumnLocked[VI] := False;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if FLevel.Horizontal then
|
|
begin
|
|
if Control.AutoColumnWidth and FLevel.Layout.OneOnLine(Self) then
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
Result := True;
|
|
IsLast := FLevel.Layout.IsColumnLast(Self);
|
|
|
|
GetMem(NewWidths, FLevel.VisibleColumnCount * SizeOf(Integer));
|
|
GetMem(ColumnLocked, (1 + FLevel.VisibleColumnCount) * SizeOf(Boolean));
|
|
GetMem(ColumnProcessed, (1 + FLevel.VisibleColumnCount) * SizeOf(Boolean));
|
|
GetMem(ColumnFixed, (1 + FLevel.VisibleColumnCount) * SizeOf(Boolean));
|
|
try
|
|
for I := -1 to FLevel.VisibleColumnCount - 1 do
|
|
begin
|
|
if I <> -1 then
|
|
NewWidths[I] := FLevel.VisibleColumns[I].VisibleWidth;
|
|
ColumnLocked[I] := False;
|
|
ColumnProcessed[I] := False;
|
|
ColumnFixed[I] := False;
|
|
end;
|
|
if not IsLast then SetFixedColumns(Self);
|
|
|
|
if IsLast and Control.AutoColumnWidth then
|
|
ChangeWidth(Self, Delta, dirLeft)
|
|
else
|
|
ChangeWidth(Self, Delta, dirRight);
|
|
if not Result then Exit;
|
|
|
|
for I := 0 to FLevel.VisibleColumnCount - 1 do
|
|
begin
|
|
Column := FLevel.VisibleColumns[I];
|
|
if Column <> Self then
|
|
with Column do
|
|
begin
|
|
W := NewWidths[I] - AddInWidth;
|
|
if Control.AutoColumnWidth or (VisibleWidth <> NewWidths[I]) then
|
|
Width := W
|
|
else
|
|
InternalVisibleWidth := NewWidths[I];
|
|
end;
|
|
end;
|
|
finally
|
|
FreeMem(ColumnFixed, (1 + FLevel.VisibleColumnCount) * SizeOf(Boolean));
|
|
FreeMem(ColumnProcessed, (1 + FLevel.VisibleColumnCount) * SizeOf(Boolean));
|
|
FreeMem(ColumnLocked, (1 + FLevel.VisibleColumnCount) * SizeOf(Boolean));
|
|
FreeMem(NewWidths, FLevel.VisibleColumnCount * SizeOf(Integer));
|
|
end;
|
|
end
|
|
else
|
|
with FLevel.Layout do
|
|
begin
|
|
{ Result := False;
|
|
for I := 0 to Items[ColIndex].Count - 1 do
|
|
with Columns[I, ColIndex] do
|
|
if (Value < MinWidth) or (Value > MaxWidth) then Exit;}
|
|
Result := True;
|
|
if Control.AutoColumnWidth then
|
|
begin
|
|
W := ContentDynamicMinWidths[ColIndex];
|
|
if Value < W then Value := W;
|
|
if ColIndex <> Count - 1 then
|
|
begin
|
|
W := ContentDynamicMaxWidths[ColIndex];
|
|
if Value > W then Value := W;
|
|
end;
|
|
Result := Self.Width <> Value;
|
|
if not Result then Exit;
|
|
FLevel.AssignColumnWidths;
|
|
end;
|
|
for I := 0 to Items[ColIndex].Count - 1 do
|
|
with Columns[I, ColIndex] do
|
|
if (RowIndex = I) and (coHorSizing in Options) then
|
|
Width := Value;
|
|
if Control.AutoColumnWidth then
|
|
begin
|
|
CalcColWidths;
|
|
CheckColumnsWidths(Self);
|
|
FLevel.AssignColumnWidths;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
CheckWidthValue(Value);
|
|
NeedAssignWidths := False;
|
|
try
|
|
if not IsLoading{FLevel} and
|
|
AdjustLinkedColumns and FVisible then
|
|
begin
|
|
Delta := Value - (VisibleWidth - AddInWidth);
|
|
NeedAssignWidths := True;
|
|
FLevel.BeginAssignWidths;
|
|
if not ChangeLinkedWidths then
|
|
begin
|
|
NeedAssignWidths := False;
|
|
FLevel.CancelAssignWidths;
|
|
Exit;
|
|
end;
|
|
end;
|
|
FWidth := Value;
|
|
FVisibleWidth := Value;
|
|
//InternalVisibleWidth := Value + AddInWidth;
|
|
if not (cvWidth in FAssignedValues) then
|
|
AssignedValues := AssignedValues + [cvWidth]
|
|
else
|
|
if FVisible then FLevel.WidthChanged;
|
|
finally
|
|
if NeedAssignWidths then FLevel.EndAssignWidths;
|
|
end;
|
|
ColumnChanged(False, hpAll, vpAll);
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetParentComponent: TComponent;
|
|
begin
|
|
Result := FLevel;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.HasParent: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
procedure TdxMasterViewColumn.ApplyBestFit;
|
|
var
|
|
Value: Integer;
|
|
begin
|
|
if Visible then
|
|
begin
|
|
if FLevel.Horizontal then
|
|
Value := GetBestFitWidth
|
|
else
|
|
Value := FLevel.Layout.GetBestFitWidth(ColIndex);
|
|
VisibleWidth := Value;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetBestFitWidth: Integer;
|
|
var
|
|
DC: HDC;
|
|
PrevFont: HFONT;
|
|
AIndex: Integer;
|
|
Size: TSize;
|
|
|
|
function GetTextWidth(const S: string): Integer;
|
|
begin
|
|
GetTextExtentPoint{32}(DC, PChar(S), Length(S), Size);
|
|
Result := 2 + Size.cx + 2;
|
|
end;
|
|
|
|
procedure CalcBestFit(Root: TdxMasterViewNode);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (Root.Level = FLevel) and (Root.NodeType = ntData) then
|
|
begin
|
|
I := FAddInWidth + GetTextWidth(Root.Strings[AIndex]) + FLevel.LineWidth;
|
|
if I > Result then Result := I;
|
|
end
|
|
else
|
|
for I := 0 to Root.Count - 1 do CalcBestFit(Root[I]);
|
|
end;
|
|
|
|
begin
|
|
DC := GetDC(0);
|
|
try
|
|
if FLevel.Horizontal then
|
|
Result := GetHeaderBestFitWidth(DC, True)
|
|
else
|
|
Result := 0;
|
|
AIndex := Index;
|
|
PrevFont := SelectObject(DC, ContentFont.Handle);
|
|
try
|
|
CalcBestFit(Control.FItems);
|
|
finally
|
|
SelectObject(DC, PrevFont);
|
|
end;
|
|
finally
|
|
ReleaseDC(0, DC);
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewColumn.GetFooterValue(Node: TdxMasterViewNode): Extended;
|
|
begin
|
|
with Node.NodesWithSummaryData[FLevel] do
|
|
Result := FSummaries[Byte(NodeType = ntData) * Self.FLevel.Index][SummaryIndex];
|
|
end;
|
|
|
|
{ TdxMasterViewLayout }
|
|
|
|
constructor TdxMasterViewLayout.Create(ALevel: TdxMasterViewLevel);
|
|
begin
|
|
inherited Create;
|
|
FLevel := ALevel;
|
|
FHorizontal := True;
|
|
FLines := TList.Create;
|
|
end;
|
|
|
|
destructor TdxMasterViewLayout.Destroy;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
DestroyColArrays;
|
|
for I := Count - 1 downto 0 do Items[I].Free;
|
|
FLines.Free;
|
|
inherited;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetColLogicalOffset(ACol: Integer): Integer;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := 0;
|
|
if FLevel.HasExpandButton then Inc(Result, LevelIndent);
|
|
for I := 0 to ACol - 1 do Inc(Result, ColWidths[I]);
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetColOffset(ACol: Integer): Integer;
|
|
begin
|
|
with FLevel do
|
|
Result := Indent - Control.LeftPos + ColLogicalOffsets[ACol];
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetColumn(ARow, ACol: Integer): TdxMasterViewColumn;
|
|
begin
|
|
if FHorizontal then
|
|
Result := TdxMasterViewColumn(TList(FLines[ARow])[ACol])
|
|
else
|
|
Result := TdxMasterViewColumn(TList(FLines[ACol])[ARow]);
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetColWidth(ACol: Integer): Integer;
|
|
begin
|
|
Result := HeaderWidths[ACol] + ContentWidths[ACol];
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetContentDynamicMaxWidth(ACol: Integer): Integer;
|
|
var
|
|
W, I: Integer;
|
|
begin
|
|
Result := ContentMaxWidths[ACol];
|
|
if FLevel.Control.AutoColumnWidth then
|
|
begin
|
|
W := VisibleWidth - ColLogicalOffsets[ACol] - HeaderWidths[ACol];
|
|
for I := Count - 1 downto ACol + 1 do
|
|
Dec(W, HeaderWidths[I] + ContentDynamicMinWidths[I]);
|
|
if W < Result then Result := W;
|
|
W := ContentDynamicMinWidths[ACol];
|
|
if Result < W then Result := W;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetContentDynamicMinWidth(ACol: Integer): Integer;
|
|
begin
|
|
Result := ContentMinWidths[ACol];
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetContentMaxWidth(ACol: Integer): Integer;
|
|
var
|
|
I, W: Integer;
|
|
begin
|
|
Result := MaxInt;
|
|
for I := 0 to Items[ACol].Count - 1 do
|
|
with Columns[I, ACol] do
|
|
begin
|
|
W := VisibleMaxWidth;
|
|
if (Result = MaxInt) or (W > Result) then Result := W;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetContentMinWidth(ACol: Integer): Integer;
|
|
var
|
|
I, W: Integer;
|
|
begin
|
|
Result := 0;
|
|
for I := 0 to Items[ACol].Count - 1 do
|
|
begin
|
|
W := Columns[I, ACol].VisibleMinWidth;
|
|
if W > Result then Result := W;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetContentNonScaledWidth(ACol: Integer): Integer;
|
|
begin
|
|
Result := FContentNonScaledWidths[ACol];
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetContentWidth(ACol: Integer): Integer;
|
|
begin
|
|
Result := FContentWidths[ACol];
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetCount: Integer;
|
|
begin
|
|
Result := FLines.Count;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetHeaderDynamicMaxWidth(ACol: Integer): Integer;
|
|
var
|
|
W, I: Integer;
|
|
begin
|
|
Result := HeaderMaxWidths[ACol];
|
|
if FLevel.Control.AutoColumnWidth and (VisibleWidth > MinWidth) then
|
|
begin
|
|
W := VisibleWidth - ColLogicalOffsets[ACol] - ContentMinWidths[ACol];
|
|
for I := Count - 1 downto ACol + 1 do
|
|
Dec(W, HeaderWidths[I] + ContentMinWidths[I]);
|
|
if W < Result then Result := W;
|
|
W := HeaderMinWidths[ACol];
|
|
if Result < W then Result := W;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetHeaderDynamicMinWidth(ACol: Integer): Integer;
|
|
begin
|
|
Result := HeaderMinWidths[ACol];
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetHeaderMaxWidth(ACol: Integer): Integer;
|
|
begin
|
|
Result := dxMVColumnDefaultMaxWidth;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetHeaderMinWidth(ACol: Integer): Integer;
|
|
begin
|
|
Result := dxMVColumnDefaultMinWidth;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetHeaderWidth(ACol: Integer): Integer;
|
|
begin
|
|
if FLevel.ShowHeader then
|
|
Result := FHeaderWidths[ACol]
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetHeaderWidthAssigned(ACol: Integer): Boolean;
|
|
begin
|
|
Result := FHeaderWidthAssigned[ACol];
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetItem(Index: Integer): TList;
|
|
begin
|
|
Result := TList(FLines[Index]);
|
|
end;
|
|
{
|
|
function TdxMasterViewLayout.GetMaxWidth: Integer;
|
|
var
|
|
I, AWidth: Integer;
|
|
begin
|
|
Result := 0;
|
|
for I := 0 to Count - 1 do
|
|
if Items[I].Count <> 0 then
|
|
begin
|
|
with Columns[I, Items[I].Count - 1] do
|
|
AWidth := MaxLogicalOffset + VisibleMaxWidth;
|
|
if AWidth > Result then Result := AWidth;
|
|
end;
|
|
end;
|
|
}
|
|
function TdxMasterViewLayout.GetMinWidth: Integer;
|
|
var
|
|
I, AWidth: Integer;
|
|
begin
|
|
Result := 0;
|
|
if FHorizontal then
|
|
for I := 0 to Count - 1 do
|
|
if Items[I].Count <> 0 then
|
|
begin
|
|
with Columns[I, Items[I].Count - 1] do
|
|
AWidth := MinLogicalOffset + VisibleMinWidth;
|
|
if AWidth > Result then Result := AWidth;
|
|
end
|
|
else
|
|
else
|
|
begin
|
|
if FLevel.HasExpandButton then Result := LevelIndent;
|
|
for I := 0 to Count - 1 do
|
|
Inc(Result, {HeaderMinWidths[I]}HeaderWidths[I]{!!!} + ContentMinWidths[I]);
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetNonScaledWidth: Integer;
|
|
var
|
|
I, AWidth: Integer;
|
|
begin
|
|
if not FHorizontal and FLevel.HasExpandButton then
|
|
Result := LevelIndent
|
|
else
|
|
Result := 0;
|
|
for I := 0 to Count - 1 do
|
|
if Items[I].Count <> 0 then
|
|
if FHorizontal then
|
|
begin
|
|
with Columns[I, Items[I].Count - 1] do
|
|
AWidth := NonScaledLogicalOffset + NonScaledWidth;
|
|
if AWidth > Result then Result := AWidth;
|
|
end
|
|
else
|
|
Inc(Result, HeaderWidths[I] + ContentNonScaledWidths[I]);
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetVisibleWidth: Integer;
|
|
var
|
|
AIndent: Integer;
|
|
begin
|
|
if FLevel.Control.AutoColumnWidth and (FLevel.VisibleColumnCount <> 0) then
|
|
begin
|
|
AIndent := FLevel.Indent;
|
|
Result := MinWidth;
|
|
if AIndent + Result < FLevel.Control.ClientWidth then
|
|
Result := FLevel.Control.ClientWidth - AIndent;
|
|
end
|
|
else
|
|
Result := GetNonScaledWidth;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.SetContentInternalVisibleWidth(ACol, Value: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if FContentWidths[ACol] <> Value then
|
|
for I := 0 to Items[ACol].Count - 1 do
|
|
with Columns[I, ACol] do
|
|
if RowIndex = I then
|
|
InternalVisibleWidth := Value;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.SetContentWidth(ACol, Value: Integer);
|
|
var
|
|
I, PrevWidth: Integer;
|
|
Changed: Boolean;
|
|
begin
|
|
if FContentWidths[ACol] <> Value then
|
|
begin
|
|
Changed := False;
|
|
FLevel.BeginAssignWidths;
|
|
try
|
|
for I := 0 to Items[ACol].Count - 1 do
|
|
with Columns[I, ACol] do
|
|
if RowIndex = I then
|
|
begin
|
|
PrevWidth := Width;
|
|
Width := Value;
|
|
Changed := Changed or (Width <> PrevWidth);
|
|
end;
|
|
finally
|
|
if Changed then FLevel.EndAssignWidths
|
|
else FLevel.CancelAssignWidths;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.SetCount(Value: Integer);
|
|
var
|
|
PrevCount, I: Integer;
|
|
PrevHeaderWidths: PIntArray;
|
|
PrevHeaderWidthAssigned: PBoolArray;
|
|
begin
|
|
if Value < 1 then Value := 1;
|
|
if Count <> Value then
|
|
begin
|
|
if Value > Count then
|
|
begin
|
|
PrevCount := Count;
|
|
PrevHeaderWidths := FHeaderWidths;
|
|
PrevHeaderWidthAssigned := FHeaderWidthAssigned;
|
|
if not FHorizontal then
|
|
begin
|
|
FHeaderWidths := nil;
|
|
FHeaderWidthAssigned := nil;
|
|
DestroyColArrays;
|
|
end;
|
|
for I := Count + 1 to Value do FLines.Add(TList.Create);
|
|
if FHorizontal then FRowCount := Count
|
|
else
|
|
begin
|
|
CreateColArrays;
|
|
Move(PrevHeaderWidths^, FHeaderWidths^, PrevCount * SizeOf(Integer));
|
|
Move(PrevHeaderWidthAssigned^, FHeaderWidthAssigned^, PrevCount * SizeOf(Boolean));
|
|
FreeMem(PrevHeaderWidths);
|
|
FreeMem(PrevHeaderWidthAssigned);
|
|
end;
|
|
end
|
|
else
|
|
for I := Count - 1 downto Value do Delete(I);
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.SetHeaderWidth(ACol, Value: Integer);
|
|
begin
|
|
ChangeHeaderWidth(ACol, Value, False);
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.SetHeaderWidthAssigned(ACol: Integer; Value: Boolean);
|
|
begin
|
|
if FHeaderWidthAssigned[ACol] <> Value then
|
|
begin
|
|
FHeaderWidthAssigned[ACol] := Value;
|
|
if not Value then HeaderWidthChanged;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.AreNeighbours(Column1, Column2: TdxMasterViewColumn;
|
|
ExactResult: Boolean): Boolean;
|
|
var
|
|
MinRow, MaxRow, I, I1, I2: Integer;
|
|
begin
|
|
if ExactResult then
|
|
Result := Column1.LogicalOffset + Column1.VisibleWidth = Column2.LogicalOffset
|
|
else
|
|
begin
|
|
if Column1.RowIndex > Column2.RowIndex then
|
|
MinRow := Column1.RowIndex
|
|
else
|
|
MinRow := Column2.RowIndex;
|
|
if Column1.RowIndex + Column1.RowCount < Column2.RowIndex + Column2.RowCount then
|
|
MaxRow := Column1.RowIndex + Column1.RowCount - 1
|
|
else
|
|
MaxRow := Column2.RowIndex + Column2.RowCount - 1;
|
|
Result := False;
|
|
for I := MinRow to MaxRow do
|
|
with Items[I] do
|
|
begin
|
|
I1 := IndexOf(Column1);
|
|
if I1 = -1 then Continue;
|
|
I2 := IndexOf(Column2);
|
|
if I2 = -1 then Continue;
|
|
if I1 + 1 <> I2 then Exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.CalcAddInWidths;
|
|
var
|
|
I: Integer;
|
|
Column: TdxMasterViewColumn;
|
|
begin
|
|
for I := 0 to FLevel.ColumnCount - 1 do
|
|
FLevel.Columns[I].FAddInWidth := 0;
|
|
if FLevel.HasExpandButton and FHorizontal then
|
|
for I := 0 to Count - 1 do
|
|
if Items[I].Count <> 0 then
|
|
begin
|
|
Column := Columns[I, 0];
|
|
if (Column.FAddInWidth = 0) and IsColumnFirst(Column) then
|
|
Column.FAddInWidth := LevelIndent;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.CalcColWidths;
|
|
var
|
|
DC: HDC;
|
|
I, J, W: Integer;
|
|
AHeaderWidthAssigned, AutoWidth: Boolean;
|
|
begin
|
|
FRowCount := 0;
|
|
AutoWidth := FLevel.Control.AutoColumnWidth;
|
|
DC := GetDC(0);
|
|
try
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
AHeaderWidthAssigned := HeaderWidthAssigned[I];
|
|
if not AHeaderWidthAssigned then
|
|
FHeaderWidths[I] := 0;
|
|
FContentNonScaledWidths[I] := 0;
|
|
FContentWidths[I] := 0;
|
|
J := Items[I].Count;
|
|
if J > FRowCount then FRowCount := J;
|
|
for J := 0 to J - 1 do
|
|
begin
|
|
if not AHeaderWidthAssigned then
|
|
begin
|
|
W := Columns[J, I].GetHeaderBestFitWidth(DC, True);
|
|
if W > FHeaderWidths[I] then FHeaderWidths[I] := W;
|
|
end;
|
|
W := Columns[J, I].NonScaledWidth;
|
|
if W > FContentNonScaledWidths[I] then FContentNonScaledWidths[I] := W;
|
|
if AutoWidth then
|
|
W := Columns[J, I].VisibleWidth;
|
|
if W > FContentWidths[I] then FContentWidths[I] := W;
|
|
end;
|
|
end;
|
|
finally
|
|
ReleaseDC(0, DC);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.CalcLogicalOffsets(Mode: Byte);
|
|
var
|
|
I, J: Integer;
|
|
begin
|
|
if Mode in [0, 1] then
|
|
for I := 0 to Count - 1 do
|
|
for J := 0 to Items[I].Count - 1 do
|
|
with TdxMasterViewColumn(Items[I][J]) do
|
|
FLogicalOffset := -1;
|
|
if Mode in [0, 2] then
|
|
for I := 0 to Count - 1 do
|
|
for J := 0 to Items[I].Count - 1 do
|
|
with TdxMasterViewColumn(Items[I][J]) do
|
|
if FLogicalOffset = -1 then
|
|
FLogicalOffset := LogicalOffset;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.CalcNeighbours;
|
|
var
|
|
I: Integer;
|
|
Column: TdxMasterViewColumn;
|
|
begin
|
|
for I := 0 to FLevel.VisibleColumnCount - 1 do
|
|
begin
|
|
Column := FLevel.VisibleColumns[I];
|
|
Column.FLeftColumns.Clear;
|
|
Column.FRightColumns.Clear;
|
|
if FHorizontal then
|
|
begin
|
|
HasLeftNeighbours(Column, Column.FLeftColumns, False);
|
|
HasRightNeighbours(Column, Column.FRightColumns, False);
|
|
end;
|
|
{ Column.FLeftColumns.Clear;
|
|
HasLeftNeighbours(Column, Column.FLeftColumns, False);
|
|
Column.FRightColumns.Clear;
|
|
HasRightNeighbours(Column, Column.FRightColumns, False);}
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.CalcOptimizedValues;
|
|
begin
|
|
CalcNeighbours;
|
|
CalcLogicalOffsets(0);
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.CalcVisibleWidth;
|
|
begin
|
|
if FLevel.Control.AutoColumnWidth and (FLevel.VisibleColumnCount <> 0) then
|
|
FVisibleWidth := FLevel.Control.ScrollableWidth - FLevel.Indent
|
|
else
|
|
FVisibleWidth := GetVisibleWidth;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.CheckColumnsWidths(FixedColumn: TdxMasterViewColumn);
|
|
|
|
procedure CheckColumnsAutoWidthsWhenHorizontal;
|
|
var
|
|
AColumns: TList;
|
|
NewWidths, FreeSpaces: PIntArray;
|
|
ColumnLocked: PBoolArray;
|
|
NonScaledSize, AvailableSpace, I, NonScaledOffset, NonScaledW, W, CheckW: Integer;
|
|
Column: TdxMasterViewColumn;
|
|
|
|
function GetAdvanceNewWidth: Integer;
|
|
begin
|
|
NonScaledOffset := Column.NonScaledLogicalOffset;
|
|
NonScaledW := Column.NonScaledWidth;
|
|
if OneOnLine(Column) then
|
|
Result := AvailableSpace
|
|
else
|
|
Result :=
|
|
MulDiv(NonScaledOffset + NonScaledW, AvailableSpace, NonScaledSize) -
|
|
MulDiv(NonScaledOffset, AvailableSpace, NonScaledSize);
|
|
end;
|
|
|
|
procedure ChangeWidth(Column: TdxMasterViewColumn; Delta: Integer;
|
|
Direction: TdxMasterViewDirection);
|
|
var
|
|
VI, W, CheckW, CurDelta, MaxW_L, MaxW_R, DeltaL, DeltaR, I: Integer;
|
|
ListL, ListR, CollapsingList, ExpandingList: TList;
|
|
OppositeDirection: TdxMasterViewDirection;
|
|
|
|
function FindMaxWidth(List: TList): Integer;
|
|
var
|
|
I, W: Integer;
|
|
begin
|
|
Result := 0;
|
|
for I := 0 to List.Count - 1 do
|
|
begin
|
|
W := TdxMasterViewColumn(List[I]).NonScaledWidth;
|
|
if W > Result then Result := W;
|
|
end;
|
|
end;
|
|
|
|
procedure CheckAvailableSpace(List: TList; Direction: TdxMasterViewDirection;
|
|
var Delta1, Delta2: Integer);
|
|
var
|
|
AvailSpace: Integer;
|
|
|
|
function FindAvailableSpace(List: TList): Integer;
|
|
var
|
|
AList: TList;
|
|
I, Space: Integer;
|
|
begin
|
|
Result := MaxInt;
|
|
AList := TList.Create;
|
|
try
|
|
for I := 0 to List.Count - 1 do
|
|
begin
|
|
if Direction = dirLeft then
|
|
HasLeftNeighbours(List[I], AList, True)
|
|
else
|
|
HasRightNeighbours(List[I], AList, True);
|
|
with TdxMasterViewColumn(List[I]) do
|
|
if CurDelta > 0 then
|
|
Space := NewWidths[VisibleIndex] - VisibleMinWidth
|
|
else
|
|
Space := VisibleMaxWidth - NewWidths[VisibleIndex];
|
|
Inc(Space, FindAvailableSpace(AList));
|
|
if Space < Result then Result := Space;
|
|
end;
|
|
finally
|
|
AList.Free;
|
|
if Result = MaxInt then Result := 0;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
AvailSpace := FindAvailableSpace(List);
|
|
if CurDelta < 0 then AvailSpace := -AvailSpace;
|
|
if (CurDelta > 0) and (Delta1 > AvailSpace) or
|
|
(CurDelta < 0) and (Delta1 < AvailSpace) then
|
|
begin
|
|
Inc(Delta2, Delta1 - AvailSpace);
|
|
Delta1 := AvailSpace;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
VI := Column.VisibleIndex;
|
|
if ColumnLocked[VI] then Exit;
|
|
|
|
if FreeSpaces[VI] * Delta > 0 then
|
|
CurDelta := Delta
|
|
else
|
|
begin
|
|
W := NewWidths[VI];
|
|
if Delta < 0 then
|
|
CheckW := Column.VisibleMinWidth
|
|
else
|
|
CheckW := Column.VisibleMaxWidth;
|
|
if (Delta < 0) and (W + Delta < CheckW) or
|
|
(Delta > 0) and (W + Delta > CheckW) then
|
|
CurDelta := CheckW - W
|
|
else
|
|
CurDelta := Delta;
|
|
end;
|
|
Dec(Delta, CurDelta);
|
|
|
|
Inc(NewWidths[VI], CurDelta);
|
|
if FreeSpaces[VI] <> 0 then
|
|
if (FreeSpaces[VI] + CurDelta) * FreeSpaces[VI] < 0 then
|
|
FreeSpaces[VI] := 0
|
|
else
|
|
Inc(FreeSpaces[VI], CurDelta);
|
|
|
|
ColumnLocked[VI] := True;
|
|
ListL := TList.Create;
|
|
ListR := TList.Create;
|
|
try
|
|
HasLeftNeighbours(Column, ListL, True);
|
|
HasRightNeighbours(Column, ListR, True);
|
|
if Direction = dirNone then
|
|
begin
|
|
MaxW_L := FindMaxWidth(ListL);
|
|
MaxW_R := FindMaxWidth(ListR);
|
|
DeltaL := MulDiv(CurDelta, MaxW_L, MaxW_L + MaxW_R);
|
|
DeltaR := CurDelta - DeltaL;
|
|
CheckAvailableSpace(ListL, dirLeft, DeltaL, DeltaR);
|
|
CheckAvailableSpace(ListR, dirRight, DeltaR, DeltaL);
|
|
for I := 0 to ListL.Count - 1 do
|
|
ChangeWidth(ListL[I], -DeltaL, dirLeft);
|
|
for I := 0 to ListR.Count - 1 do
|
|
ChangeWidth(ListR[I], -DeltaR, dirRight);
|
|
end
|
|
else
|
|
begin
|
|
if Direction = dirLeft then
|
|
begin
|
|
CollapsingList := ListR;
|
|
ExpandingList := ListL;
|
|
OppositeDirection := dirRight;
|
|
end
|
|
else
|
|
begin
|
|
CollapsingList := ListL;
|
|
ExpandingList := ListR;
|
|
OppositeDirection := dirLeft;
|
|
end;
|
|
for I := 0 to CollapsingList.Count - 1 do
|
|
ChangeWidth(CollapsingList[I], -(Delta + CurDelta), OppositeDirection);
|
|
if Delta <> 0 then
|
|
for I := 0 to ExpandingList.Count - 1 do
|
|
ChangeWidth(ExpandingList[I], Delta, Direction);
|
|
end;
|
|
finally
|
|
ListR.Free;
|
|
ListL.Free;
|
|
ColumnLocked[VI] := False;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if not FLevel.Visible then Exit;
|
|
|
|
AColumns := TList.Create;
|
|
AColumns.Count := FLevel.VisibleColumnCount;
|
|
Move(FLevel.FVisibleColumns.List^, AColumns.List^, AColumns.Count * SizeOf(Pointer));
|
|
|
|
GetMem(NewWidths, AColumns.Count * SizeOf(Integer));
|
|
GetMem(FreeSpaces, AColumns.Count * SizeOf(Integer));
|
|
GetMem(ColumnLocked, AColumns.Count * SizeOf(Boolean));
|
|
|
|
try
|
|
NonScaledSize := NonScaledWidth;
|
|
AvailableSpace := VisibleWidth;
|
|
|
|
for I := 0 to AColumns.Count - 1 do
|
|
begin
|
|
Column := AColumns[I];
|
|
W := GetAdvanceNewWidth;
|
|
CheckW := Column.VisibleMinWidth;
|
|
if W < CheckW then
|
|
FreeSpaces[I] := W - CheckW
|
|
else
|
|
begin
|
|
CheckW := Column.VisibleMaxWidth;
|
|
if W > CheckW then
|
|
FreeSpaces[I] := W - CheckW
|
|
else
|
|
FreeSpaces[I] := 0;
|
|
end;
|
|
NewWidths[I] := W;
|
|
end;
|
|
|
|
for I := 0 to AColumns.Count - 1 do
|
|
begin
|
|
Column := AColumns[I];
|
|
if FreeSpaces^[Column.VisibleIndex] <> 0 then
|
|
begin
|
|
FillChar(ColumnLocked^, AColumns.Count * SizeOf(Boolean), 0);
|
|
ChangeWidth(Column, -FreeSpaces[Column.VisibleIndex], dirNone);
|
|
end;
|
|
end;
|
|
|
|
for I := 0 to AColumns.Count - 1 do
|
|
TdxMasterViewColumn(AColumns[I]).InternalVisibleWidth := NewWidths[I];
|
|
finally
|
|
FreeMem(ColumnLocked, AColumns.Count * SizeOf(Boolean));
|
|
FreeMem(FreeSpaces, AColumns.Count * SizeOf(Integer));
|
|
FreeMem(NewWidths, AColumns.Count * SizeOf(Integer));
|
|
AColumns.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure CheckColumnsAutoWidthsWhenVertical;
|
|
var
|
|
NewWidths, ContentMinWidths: PIntArray;
|
|
NonScaledSize, AvailableSpace, FixedCol, FixedI1, FixedI2,
|
|
I, NonScaledOffset, NonScaledW, W, CheckW: Integer;
|
|
|
|
function ContentNonScaledOffset(const ACol: Integer): Integer;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := 0;
|
|
for I := 0 to ACol - 1 do
|
|
if NewWidths[I] = -1 then
|
|
Inc(Result, ContentNonScaledWidths[I]);
|
|
end;
|
|
|
|
function GetAdvanceNewWidth: Integer;
|
|
begin
|
|
NonScaledOffset := ContentNonScaledOffset(I);
|
|
NonScaledW := ContentNonScaledWidths[I];
|
|
if Count = 1 then
|
|
Result := AvailableSpace
|
|
else
|
|
Result :=
|
|
MulDiv(NonScaledOffset + NonScaledW, AvailableSpace, NonScaledSize) -
|
|
MulDiv(NonScaledOffset, AvailableSpace, NonScaledSize);
|
|
end;
|
|
|
|
procedure CheckWidths(ForMin: Boolean);
|
|
begin
|
|
I := 0;
|
|
NonScaledOffset := 0;
|
|
while I < Count do
|
|
begin
|
|
if NewWidths[I] = -1 then
|
|
begin
|
|
NonScaledW := ContentNonScaledWidths[I];
|
|
W :=
|
|
MulDiv(NonScaledOffset + NonScaledW, AvailableSpace, NonScaledSize) -
|
|
MulDiv(NonScaledOffset, AvailableSpace, NonScaledSize);
|
|
if ForMin then
|
|
CheckW := ContentMinWidths[I]
|
|
else
|
|
CheckW := ContentMaxWidths[I];
|
|
if ForMin and (W < CheckW) or not ForMin and (W > CheckW) then
|
|
begin
|
|
Dec(NonScaledSize, NonScaledW);
|
|
Dec(AvailableSpace, CheckW);
|
|
NewWidths[I] := CheckW;
|
|
I := 0;
|
|
NonScaledOffset := 0;
|
|
Continue;
|
|
end;
|
|
Inc(NonScaledOffset, NonScaledW);
|
|
end;
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if not FLevel.Visible then Exit;
|
|
|
|
GetMem(NewWidths, Count * SizeOf(Integer));
|
|
GetMem(ContentMinWidths, Count * SizeOf(Integer));
|
|
try
|
|
NonScaledSize := NonScaledWidth;
|
|
AvailableSpace := VisibleWidth;
|
|
if FLevel.HasExpandButton then
|
|
begin
|
|
Dec(NonScaledSize, LevelIndent);
|
|
Dec(AvailableSpace, LevelIndent);
|
|
end;
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
W := HeaderWidths[I];
|
|
Dec(NonScaledSize, W);
|
|
Dec(AvailableSpace, W);
|
|
ContentMinWidths[I] := Self.ContentMinWidths[I];
|
|
end;
|
|
if FixedColumn = nil then
|
|
FixedCol := -1
|
|
else
|
|
FixedCol := FixedColumn.ColIndex;
|
|
|
|
if (FixedCol <> -1) and (FixedCol = Count - 1) then
|
|
begin
|
|
FixedI1 := FixedCol;
|
|
FixedI2 := FixedCol;
|
|
end
|
|
else
|
|
begin
|
|
FixedI1 := 0;
|
|
FixedI2 := FixedCol;
|
|
end;
|
|
for I := 0 to Count - 1 do
|
|
if (FixedI1 <= I) and (I <= FixedI2) then
|
|
begin
|
|
NonScaledW := ContentNonScaledWidths[I];
|
|
W := ContentWidths[I];
|
|
Dec(NonScaledSize, NonScaledW);
|
|
Dec(AvailableSpace, W);
|
|
NewWidths[I] := W;
|
|
end
|
|
else
|
|
begin
|
|
W := GetAdvanceNewWidth;
|
|
CheckW := ContentMinWidths[I];
|
|
if W < CheckW then
|
|
begin
|
|
Dec(NonScaledSize, NonScaledW);
|
|
Dec(AvailableSpace, CheckW);
|
|
NewWidths[I] := CheckW;
|
|
end
|
|
else
|
|
NewWidths[I] := -1;
|
|
end;
|
|
|
|
CheckWidths(True);
|
|
CheckWidths(False);
|
|
|
|
NonScaledOffset := 0;
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
W := NewWidths[I];
|
|
if W = -1 then
|
|
begin
|
|
NonScaledW := ContentNonScaledWidths[I];
|
|
W :=
|
|
MulDiv(NonScaledOffset + NonScaledW, AvailableSpace, NonScaledSize) -
|
|
MulDiv(NonScaledOffset, AvailableSpace, NonScaledSize);
|
|
Inc(NonScaledOffset, NonScaledW);
|
|
end;
|
|
ContentInternalVisibleWidths[I] := W;
|
|
end;
|
|
finally
|
|
FreeMem(ContentMinWidths, Count * SizeOf(Integer));
|
|
FreeMem(NewWidths, Count * SizeOf(Integer));
|
|
end;
|
|
end;
|
|
|
|
procedure CheckColumnsFreeWidths(UseVisibleValues: Boolean);
|
|
var
|
|
List: TList;
|
|
I, J, K, MustBeOffset, FreeSpace, ASpace: Integer;
|
|
Column: TdxMasterViewColumn;
|
|
begin
|
|
if FHorizontal then
|
|
begin
|
|
List := TList.Create;
|
|
try
|
|
for I := 0 to Count - 1 do
|
|
for J := Items[I].Count - 1 downto 0 do
|
|
begin
|
|
Column := Columns[I, J];
|
|
if Column.RowIndex = I then
|
|
begin
|
|
with Column do
|
|
if UseVisibleValues then
|
|
MustBeOffset := LogicalOffset + VisibleWidth
|
|
else
|
|
MustBeOffset := NonScaledLogicalOffset + NonScaledWidth;
|
|
if HasRightNeighbours(Column, List, False) then
|
|
begin
|
|
FreeSpace := MaxInt;
|
|
for K := 0 to List.Count - 1 do
|
|
begin
|
|
with TdxMasterViewColumn(List[K]) do
|
|
if UseVisibleValues then
|
|
ASpace := LogicalOffset
|
|
else
|
|
ASpace := NonScaledLogicalOffset;
|
|
Dec(ASpace, MustBeOffset);
|
|
if ASpace < FreeSpace then FreeSpace := ASpace;
|
|
end;
|
|
end
|
|
else
|
|
if FLevel.OccupyRestSpace or UseVisibleValues then
|
|
FreeSpace := FVisibleWidth - MustBeOffset
|
|
else
|
|
FreeSpace := 0;
|
|
if UseVisibleValues then
|
|
ASpace := Column.VisibleWidth
|
|
else
|
|
ASpace := Column.NonScaledWidth;
|
|
Column.InternalVisibleWidth := ASpace + FreeSpace;
|
|
end;
|
|
end;
|
|
finally
|
|
List.Free;
|
|
end;
|
|
end
|
|
else
|
|
for I := 0 to Count - 1 do
|
|
for J := 0 to Items[I].Count - 1 do
|
|
with Columns[J, I] do
|
|
if RowIndex = J then
|
|
InternalVisibleWidth := ContentWidths[I];
|
|
end;
|
|
|
|
begin
|
|
if (FLevel.FAssignWidthsLockCount <> 0) and (FixedColumn = nil) or
|
|
(FUpdateLockCount <> 0) or FLevel.IsLoading then Exit;
|
|
CalcLogicalOffsets(1);
|
|
if FHorizontal then CalcAddInWidths;
|
|
CalcVisibleWidth;
|
|
if FLevel.Control.AutoColumnWidth then
|
|
if FHorizontal then
|
|
begin
|
|
CheckColumnsAutoWidthsWhenHorizontal;
|
|
CalcLogicalOffsets(2);
|
|
CheckColumnsFreeWidths(True);
|
|
end
|
|
else
|
|
begin
|
|
CheckColumnsAutoWidthsWhenVertical;
|
|
CalcColWidths;
|
|
CalcLogicalOffsets(2);
|
|
CheckColumnsFreeWidths(False);
|
|
end
|
|
else
|
|
begin
|
|
CheckColumnsFreeWidths(False);
|
|
CalcLogicalOffsets(2);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.CheckCount;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if FUpdateLockCount <> 0 then Exit;
|
|
for I := Count - 1 downto 0 do
|
|
if Items[I].Count = 0 then Delete(I)
|
|
else Break;
|
|
for I := 0 to Count - 1 do
|
|
if Items[0].Count = 0 then Delete(0)
|
|
else Break;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.Clear;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := Count - 1 downto 0 do Items[I].Clear;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.ClearOptimizedValues;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to FLevel.VisibleColumnCount - 1 do
|
|
with FLevel.VisibleColumns[I] do
|
|
begin
|
|
FLogicalOffset := -1;
|
|
FLeftColumns.Clear;
|
|
FRightColumns.Clear;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.ColFromX(X: Integer): Integer;
|
|
begin
|
|
if not FHorizontal then
|
|
for Result := 0 to Count - 1 do
|
|
if (ColOffsets[Result] <= X) and (X < ColOffsets[Result + 1]) then Exit;
|
|
Result := -1;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.CreateColArrays;
|
|
begin
|
|
GetMem(FContentNonScaledWidths, Count * SizeOf(Integer));
|
|
GetMem(FContentWidths, Count * SizeOf(Integer));
|
|
GetMem(FHeaderWidths, Count * SizeOf(Integer));
|
|
GetMem(FHeaderWidthAssigned, Count * SizeOf(Boolean));
|
|
FillChar(FHeaderWidthAssigned^, Count * SizeOf(Boolean), 0);
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.Delete(Index: Integer);
|
|
var
|
|
I, J: Integer;
|
|
begin
|
|
Items[Index].Free;
|
|
FLines.Delete(Index);
|
|
if FHorizontal then FRowCount := Count;
|
|
for I := Index to Count - 1 do
|
|
for J := 0 to Items[I].Count - 1 do
|
|
if FHorizontal then
|
|
with Columns[I, J] do
|
|
if FRowIndex = I + 1 then Dec(FRowIndex)
|
|
else
|
|
else
|
|
with Columns[J, I] do
|
|
if FColIndex = I + 1 then Dec(FColIndex);
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.DestroyColArrays;
|
|
begin
|
|
if FContentNonScaledWidths <> nil then
|
|
begin
|
|
FreeMem(FContentNonScaledWidths);
|
|
FContentNonScaledWidths := nil;
|
|
end;
|
|
if FContentWidths <> nil then
|
|
begin
|
|
FreeMem(FContentWidths);
|
|
FContentWidths := nil;
|
|
end;
|
|
if FHeaderWidths <> nil then
|
|
begin
|
|
FreeMem(FHeaderWidths);
|
|
FHeaderWidths := nil;
|
|
end;
|
|
if FHeaderWidthAssigned <> nil then
|
|
begin
|
|
FreeMem(FHeaderWidthAssigned);
|
|
FHeaderWidthAssigned := nil;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.HasLeftNeighbours(AColumn: TdxMasterViewColumn;
|
|
AList: TList; ExactResult: Boolean): Boolean;
|
|
var
|
|
I, J: Integer;
|
|
begin
|
|
if (AColumn.FLeftColumns.Count = 0) or ExactResult then
|
|
begin
|
|
Result := False;
|
|
if AList <> nil then AList.Clear;
|
|
for I := AColumn.RowIndex to AColumn.RowIndex + AColumn.RowCount - 1 do
|
|
begin
|
|
J := Items[I].IndexOf(AColumn);
|
|
if (J > 0) and AreNeighbours(Columns[I, J - 1], AColumn, ExactResult) then
|
|
begin
|
|
Result := True;
|
|
if AList = nil then Exit
|
|
else
|
|
if AList.IndexOf(Columns[I, J - 1]) = -1 then //!!!
|
|
AList.Add(Columns[I, J - 1]);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Result := True;
|
|
if AList <> nil then
|
|
with AColumn do
|
|
begin
|
|
AList.Count := FLeftColumns.Count;
|
|
Move(FLeftColumns.List^, AList.List^, FLeftColumns.Count * SizeOf(Pointer));
|
|
end;
|
|
end;
|
|
end;
|
|
{
|
|
function TdxMasterViewLayout.HasLinkedColumns(AColumn: TdxMasterViewColumn;
|
|
AList: TList): Boolean;
|
|
var
|
|
List, LinkedColumns: TList;
|
|
I, J: Integer;
|
|
begin
|
|
Result := False;
|
|
AList.Clear;
|
|
List := TList.Create;
|
|
LinkedColumns := TList.Create;
|
|
try
|
|
if HasRightNeighbours(AColumn, List, True) then
|
|
for I := 0 to List.Count - 1 do
|
|
if HasLeftNeighbours(List[I], LinkedColumns, True) then
|
|
begin
|
|
with AList do
|
|
Capacity := Capacity + LinkedColumns.Count;
|
|
for J := 0 to LinkedColumns.Count - 1 do
|
|
if LinkedColumns[J] <> AColumn then
|
|
AList.Add(LinkedColumns[J]);
|
|
end
|
|
else
|
|
else
|
|
if FLevel.OccupyRestSpace then
|
|
begin
|
|
RetrieveLastColumns(AList);
|
|
for I := AList.Count - 1 downto 0 do
|
|
if AList[I] = AColumn then AList.Delete(I);
|
|
end
|
|
else Exit;
|
|
finally
|
|
Result := AList.Count <> 0;
|
|
LinkedColumns.Free;
|
|
List.Free;
|
|
end;
|
|
end;
|
|
}
|
|
function TdxMasterViewLayout.HasRightNeighbours(AColumn: TdxMasterViewColumn;
|
|
AList: TList; ExactResult: Boolean): Boolean;
|
|
var
|
|
I, J: Integer;
|
|
begin
|
|
if (AColumn.FRightColumns.Count = 0) or ExactResult then
|
|
begin
|
|
Result := False;
|
|
if AList <> nil then AList.Clear;
|
|
for I := AColumn.RowIndex to AColumn.RowIndex + AColumn.RowCount - 1 do
|
|
begin
|
|
J := Items[I].IndexOf(AColumn);
|
|
if (J < Items[I].Count - 1) and
|
|
AreNeighbours(AColumn, Columns[I, J + 1], ExactResult) then
|
|
begin
|
|
Result := True;
|
|
if AList = nil then Exit
|
|
else
|
|
if AList.IndexOf(Columns[I, J + 1]) = -1 then //!!!
|
|
AList.Add(Columns[I, J + 1]);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Result := True;
|
|
if AList <> nil then
|
|
with AColumn do
|
|
begin
|
|
AList.Count := FRightColumns.Count;
|
|
Move(FRightColumns.List^, AList.List^, FRightColumns.Count * SizeOf(Pointer));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.HeaderWidthChanged;
|
|
begin
|
|
FLevel.WidthChangedEx;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.Insert(Index, ACount: Integer);
|
|
var
|
|
I, J: Integer;
|
|
PrevHeaderWidths: PIntArray;
|
|
PrevHeaderWidthAssigned: PBoolArray;
|
|
begin
|
|
for I := 0 to ACount - 1 do
|
|
FLines.Insert(Index, TList.Create);
|
|
for I := Count - 1 downto Index + ACount do
|
|
for J := 0 to Items[I].Count - 1 do
|
|
if FHorizontal then
|
|
with Columns[I, J] do
|
|
if FRowIndex = I - ACount then Inc(FRowIndex, ACount)
|
|
else
|
|
else
|
|
with Columns[J, I] do
|
|
if FColIndex = I - ACount then Inc(FColIndex, ACount);
|
|
|
|
if FHorizontal then FRowCount := Count
|
|
else
|
|
begin
|
|
PrevHeaderWidths := FHeaderWidths;
|
|
PrevHeaderWidthAssigned := FHeaderWidthAssigned;
|
|
FHeaderWidths := nil;
|
|
FHeaderWidthAssigned := nil;
|
|
DestroyColArrays;
|
|
CreateColArrays;
|
|
Move(PrevHeaderWidths^, FHeaderWidths^, Index * SizeOf(Integer));
|
|
Move(PrevHeaderWidthAssigned^, FHeaderWidthAssigned^, Index * SizeOf(Boolean));
|
|
I := Count - (Index + ACount);
|
|
Move(PrevHeaderWidths[Index], FHeaderWidths[Index + ACount],
|
|
I * SizeOf(Integer));
|
|
Move(PrevHeaderWidthAssigned[Index], FHeaderWidthAssigned[Index + ACount],
|
|
I * SizeOf(Boolean));
|
|
FreeMem(PrevHeaderWidths);
|
|
FreeMem(PrevHeaderWidthAssigned);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.InsertAtPos(ARow, APos: Integer; AColumn: TdxMasterViewColumn);
|
|
var
|
|
ACol{, AMinOffset, Delta, I, AvailSpace}: Integer;
|
|
begin
|
|
ACol := GetNearestCol(ARow, APos);
|
|
{ while ACol <> 0 do
|
|
begin
|
|
with Columns[ARow, ACol - 1] do
|
|
AMinOffset := MinLogicalOffset + VisibleMinWidth;
|
|
if AMinOffset <= APos then
|
|
begin
|
|
with Columns[ARow, ACol - 1] do
|
|
Delta := LogicalOffset + VisibleWidth - APos;
|
|
if Delta > 0 then
|
|
for I := ACol - 1 downto 0 do
|
|
begin
|
|
with Columns[ARow, I] do
|
|
AvailSpace := VisibleWidth - VisibleMinWidth;
|
|
if AvailSpace > Delta then AvailSpace := Delta;
|
|
with Columns[ARow, I] do
|
|
InternalVisibleWidth := VisibleWidth - AvailSpace;
|
|
Dec(Delta, AvailSpace);
|
|
if Delta = 0 then Break;
|
|
end;
|
|
Break;
|
|
end
|
|
else Dec(ACol);
|
|
end;}
|
|
Items[ARow].Insert(ACol, AColumn);
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.InsertColumn(ARow, ACol: Integer; AColumn: TdxMasterViewColumn);
|
|
var
|
|
I, Offset: Integer;
|
|
begin
|
|
// if not AColumn.Visible then Exit;
|
|
if FHorizontal then
|
|
begin
|
|
RequireCount(ARow + AColumn.RowCount);
|
|
if ACol > Items[ARow].Count then ACol := Items[ARow].Count;
|
|
Offset := -1;
|
|
BeginUpdate; //!!!
|
|
try
|
|
for I := ARow to ARow + AColumn.RowCount - 1 do
|
|
if I = ARow then Items[I].Insert(ACol, AColumn)
|
|
else
|
|
begin
|
|
if Offset = -1 then
|
|
Offset := AColumn.LogicalOffset;
|
|
InsertAtPos(I, Offset, AColumn);
|
|
end;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
RequireCount(ACol + 1);
|
|
ARow := GetNearestRow(ACol, ARow);
|
|
//if ARow > Items[ACol].Count then ARow := Items[ACol].Count;
|
|
BeginUpdate; //!!!
|
|
try
|
|
for I := ARow to ARow + AColumn.RowCount - 1 do
|
|
Items[ACol].Insert(I, AColumn);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.InsertColumnAtPos(ARow, APos: Integer; AColumn: TdxMasterViewColumn);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
// if not AColumn.Visible or not FHorizontal then Exit;
|
|
RequireCount(ARow + AColumn.RowCount);
|
|
for I := ARow to ARow + AColumn.RowCount - 1 do
|
|
InsertAtPos(I, APos, AColumn);
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.InternalRemoveFreeSpace;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := Count - 1 downto 0 do
|
|
if Items[I].Count = 0 then Delete(I);
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.RemoveColumn(AColumn: TdxMasterViewColumn);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
with AColumn do
|
|
if (RowIndex <> -1) and not IsLoading {FLevel} then
|
|
begin
|
|
Self.BeginUpdate;
|
|
try
|
|
if FHorizontal then
|
|
for I := RowIndex to RowIndex + RowCount - 1 do
|
|
Items[I].Remove(AColumn)
|
|
else
|
|
with Items[ColIndex] do
|
|
for I := RowIndex + RowCount - 1 downto RowIndex do
|
|
Delete(I);
|
|
finally
|
|
Self.EndUpdate;
|
|
end;
|
|
end;
|
|
// CheckCount;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.RetrieveLastColumns(AList: TList);
|
|
var
|
|
I: Integer;
|
|
Column: TdxMasterViewColumn;
|
|
begin
|
|
AList.Clear;
|
|
for I := 0 to Count - 1 do
|
|
if Items[I].Count <> 0 then
|
|
begin
|
|
Column := Items[I].Last;
|
|
if (AList.IndexOf(Column) = -1) and
|
|
not HasRightNeighbours(Column, nil, True) then
|
|
AList.Add(Column);
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetNearestCol(ARow, AOffset: Integer): Integer;
|
|
var
|
|
CurOffset, I: Integer;
|
|
begin
|
|
if ARow >= Count then Result := 0
|
|
else
|
|
begin
|
|
Result := Items[ARow].Count;
|
|
for I := 0 to Result - 1 do
|
|
begin
|
|
with Columns[ARow, I] do
|
|
CurOffset := LogicalOffset;
|
|
if AOffset <= CurOffset then
|
|
begin
|
|
Result := I;
|
|
Break;
|
|
end;
|
|
with Columns[ARow, I] do
|
|
Inc(CurOffset, VisibleWidth);
|
|
if AOffset < CurOffset then
|
|
begin
|
|
Result := I + 1;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetNearestRow(ACol, ARow: Integer): Integer;
|
|
var
|
|
ACount: Integer;
|
|
begin
|
|
if ACol >= Count then Result := 0
|
|
else
|
|
begin
|
|
ACount := Items[ACol].Count;
|
|
if ARow >= ACount then Result := ACount
|
|
else
|
|
begin
|
|
Result := ARow;
|
|
while (Result < ACount) and (Columns[Result, ACol].RowIndex <> Result) do
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.RequireCount(ACount: Integer);
|
|
begin
|
|
if ACount > Count then Count := ACount;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.ViewModeChanged;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FHorizontal := FLevel.Horizontal;
|
|
BeginUpdate;
|
|
try
|
|
for I := Count - 1 downto 1 do Delete(I);
|
|
if Count = 1 then Items[0].Clear;
|
|
if FHorizontal then
|
|
begin
|
|
FRowCount := Count;
|
|
for I := 0 to FLevel.VisibleColumnCount - 1 do
|
|
begin
|
|
FLevel.VisibleColumns[I].FRowIndex := 0;
|
|
InsertColumn(0, Items[0].Count, FLevel.VisibleColumns[I]);
|
|
end;
|
|
DestroyColArrays;
|
|
end
|
|
else
|
|
begin
|
|
for I := 0 to FLevel.VisibleColumnCount - 1 do
|
|
begin
|
|
FLevel.VisibleColumns[I].FColIndex := 0;
|
|
InsertColumn(Items[0].Count, 0, FLevel.VisibleColumns[I]);
|
|
end;
|
|
CreateColArrays;
|
|
end;
|
|
CalcAddInWidths;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.BeginUpdate;
|
|
begin
|
|
if FUpdateLockCount = 0 then ClearOptimizedValues;
|
|
Inc(FUpdateLockCount);
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.CancelUpdate;
|
|
begin
|
|
if FUpdateLockCount > 0 then
|
|
begin
|
|
Dec(FUpdateLockCount);
|
|
if FUpdateLockCount = 0 then CalcOptimizedValues;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.ChangeCol(AColumn: TdxMasterViewColumn; ACol: Integer);
|
|
var
|
|
ARow: Integer;
|
|
begin
|
|
if ACol < 0 then ACol := 0;
|
|
if AColumn.Visible and not FLevel.IsLoading then
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
ARow := AColumn.RowIndex;
|
|
RemoveColumn(AColumn);
|
|
if FHorizontal then
|
|
if ACol > Items[AColumn.RowIndex].Count then
|
|
ACol := Items[AColumn.RowIndex].Count
|
|
else
|
|
else
|
|
if ACol > Count then ACol := Count;
|
|
AColumn.FColIndex := ACol;
|
|
if FHorizontal then
|
|
ARow := AColumn.RowIndex
|
|
else
|
|
if ACol = Count then
|
|
ARow := 0
|
|
else
|
|
//ARow := Items[ACol].Count;
|
|
begin
|
|
if ARow < 0 then ARow := 0;
|
|
if ARow > Items[ACol].Count then
|
|
ARow := Items[ACol].Count;
|
|
end;
|
|
InsertColumn(ARow, ACol, AColumn);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end
|
|
else
|
|
AColumn.FColIndex := ACol;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.ChangeHeaderWidth(ACol: Integer; Value: Integer;
|
|
FixCol: Boolean);
|
|
var
|
|
MarginValue: Integer;
|
|
begin
|
|
MarginValue := HeaderMinWidths[ACol];
|
|
if Value < MarginValue then Value := MarginValue;
|
|
MarginValue := HeaderMaxWidths[ACol];
|
|
if Value > MarginValue then Value := MarginValue;
|
|
if FixCol then
|
|
begin
|
|
MarginValue := HeaderDynamicMinWidths[ACol];
|
|
if Value < MarginValue then Value := MarginValue;
|
|
MarginValue := HeaderDynamicMaxWidths[ACol];
|
|
if Value > MarginValue then Value := MarginValue;
|
|
end;
|
|
if FHeaderWidths[ACol] <> Value then
|
|
begin
|
|
FHeaderWidths[ACol] := Value;
|
|
HeaderWidthAssigned[ACol] := True;
|
|
if FixCol and (ACol > 0) and FLevel.Control.AutoColumnWidth then
|
|
begin
|
|
CheckColumnsWidths(Columns[0, ACol - 1]);
|
|
with FLevel do
|
|
begin
|
|
BeginAssignWidths;
|
|
try
|
|
AssignColumnWidths;
|
|
finally
|
|
CancelAssignWidths;
|
|
end;
|
|
end;
|
|
end;
|
|
HeaderWidthChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.ChangeRow(AColumn: TdxMasterViewColumn; ARow: Integer;
|
|
FixedPos: Boolean);
|
|
var
|
|
APos: Integer;
|
|
begin
|
|
if ARow < 0 then ARow := 0;
|
|
if AColumn.Visible and not FLevel.IsLoading then
|
|
begin
|
|
if FHorizontal and (ARow > Count) then
|
|
ARow := Count;
|
|
if AColumn.RowIndex <> ARow then
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
if FHorizontal then
|
|
if FixedPos then
|
|
APos := AColumn.LogicalOffset
|
|
else
|
|
APos := GetNearestCol(ARow, AColumn.LogicalOffset)
|
|
else
|
|
APos := AColumn.ColIndex;
|
|
RemoveColumn(AColumn);
|
|
if not FHorizontal then
|
|
ARow := GetNearestRow(APos, ARow);
|
|
AColumn.FRowIndex := ARow;
|
|
if FHorizontal and FixedPos then
|
|
InsertColumnAtPos(ARow, APos, AColumn)
|
|
else
|
|
InsertColumn(ARow, APos, AColumn);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
AColumn.FRowIndex := ARow;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.ChangeRowAndRowCount(AColumn: TdxMasterViewColumn;
|
|
ARow, ARowCount: Integer; FixedPos: Boolean);
|
|
var
|
|
APos: Integer;
|
|
begin
|
|
if ARow < 0 then ARow := 0;
|
|
AColumn.CheckRowCount(ARowCount);
|
|
if AColumn.Visible and not FLevel.IsLoading then
|
|
begin
|
|
if FHorizontal and (ARow > Count) then
|
|
ARow := Count;
|
|
if (AColumn.RowIndex <> ARow) or (AColumn.RowCount <> ARowCount) then
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
if FHorizontal then
|
|
if FixedPos then
|
|
APos := AColumn.LogicalOffset
|
|
else
|
|
APos := GetNearestCol(ARow, AColumn.LogicalOffset)
|
|
else
|
|
APos := AColumn.ColIndex;
|
|
RemoveColumn(AColumn);
|
|
if not FHorizontal then
|
|
ARow := GetNearestRow(APos, ARow);
|
|
with AColumn do
|
|
begin
|
|
FRowIndex := ARow;
|
|
FRowCount := ARowCount;
|
|
end;
|
|
if FHorizontal and FixedPos then
|
|
InsertColumnAtPos(ARow, APos, AColumn)
|
|
else
|
|
InsertColumn(ARow, APos, AColumn);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
with AColumn do
|
|
begin
|
|
FRowIndex := ARow;
|
|
FRowCount := ARowCount;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.ChangeRowCount(AColumn: TdxMasterViewColumn; ARowCount: Integer);
|
|
var
|
|
I, AOffset: Integer;
|
|
begin
|
|
with AColumn do
|
|
begin
|
|
CheckRowCount(ARowCount);
|
|
if RowCount <> ARowCount then
|
|
begin
|
|
if Visible and not FLevel.IsLoading then
|
|
begin
|
|
Self.BeginUpdate;
|
|
try
|
|
if ARowCount < RowCount then
|
|
for I := RowIndex + RowCount - 1 downto RowIndex + ARowCount do
|
|
if FHorizontal then
|
|
Self.Items[I].Remove(AColumn)
|
|
else
|
|
Self.Items[ColIndex].Delete(I)
|
|
else
|
|
begin
|
|
if FHorizontal then
|
|
begin
|
|
RequireCount(RowIndex + ARowCount);
|
|
AOffset := LogicalOffset;
|
|
end
|
|
else
|
|
AOffset := 0;
|
|
for I := RowIndex + RowCount to RowIndex + ARowCount - 1 do
|
|
if FHorizontal then
|
|
Self.InsertAtPos(I, AOffset, AColumn)
|
|
else
|
|
Self.Items[ColIndex].Insert(I, AColumn);
|
|
end;
|
|
FRowCount := ARowCount;
|
|
finally
|
|
Self.EndUpdate;
|
|
end;
|
|
end
|
|
else
|
|
FRowCount := ARowCount;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.EndUpdate;
|
|
begin
|
|
if FUpdateLockCount > 0 then
|
|
begin
|
|
Dec(FUpdateLockCount);
|
|
if FUpdateLockCount = 0 then
|
|
begin
|
|
if FHorizontal then
|
|
CheckCount
|
|
else
|
|
InternalRemoveFreeSpace;
|
|
FLevel.WidthChangedEx;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.GetBestFitWidth(ACol: Integer): Integer;
|
|
var
|
|
I, AValue: Integer;
|
|
begin
|
|
Result := 0;
|
|
for I := 0 to Items[ACol].Count - 1 do
|
|
with Columns[I, ACol] do
|
|
if RowIndex = I then
|
|
begin
|
|
AValue := GetBestFitWidth;
|
|
if AValue > Result then Result := AValue;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.IndexOf(AColumn: TdxMasterViewColumn; ALine: Integer): Integer;
|
|
begin
|
|
if (ALine < 0) or (ALine >= Count) then
|
|
Result := -1
|
|
else
|
|
Result := TList(FLines[ALine]).IndexOf(AColumn);
|
|
end;
|
|
|
|
function TdxMasterViewLayout.IsColumnFirst(AColumn: TdxMasterViewColumn): Boolean;
|
|
begin
|
|
if FHorizontal then
|
|
Result := not HasLeftNeighbours(AColumn, nil, True)
|
|
else
|
|
Result := AColumn.RowIndex = 0;//IndexOf(AColumn, AColumn.ColIndex) = 0;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.IsColumnLast(AColumn: TdxMasterViewColumn): Boolean;
|
|
begin
|
|
if FHorizontal then
|
|
Result := not HasRightNeighbours(AColumn, nil, True)
|
|
else
|
|
with AColumn do
|
|
Result := RowIndex + RowCount = Self.Items[ColIndex].Count;
|
|
end;
|
|
|
|
function TdxMasterViewLayout.OneOnLine(AColumn: TdxMasterViewColumn): Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if FHorizontal then
|
|
begin
|
|
Result := False;
|
|
with AColumn do
|
|
for I := RowIndex to RowIndex + RowCount - 1 do
|
|
if Self.Items[I].Count <> 1 then Exit;
|
|
Result := True;
|
|
end
|
|
else
|
|
with AColumn do
|
|
Result := RowCount = Self.Items[ColIndex].Count;
|
|
end;
|
|
|
|
procedure TdxMasterViewLayout.RemoveFreeSpace;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
InternalRemoveFreeSpace;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
{ TdxMasterViewLevel }
|
|
|
|
constructor TdxMasterViewLevel.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
FAbsoluteIndex := -1;
|
|
FCanUseSmartReload := True;
|
|
FColumns := TList.Create;
|
|
FDataLink := TdxMasterViewDataLink.Create(Self);
|
|
FDeleteConfirmCaptionText := LoadStr(dxsMVDeleteConfirmCaptionText);
|
|
FDeleteConfirmText := LoadStr(dxsMVDeleteConfirmText);
|
|
FDetailKeyFields := TList.Create;
|
|
FExtLineWidth := DefaultLineWidth;
|
|
FGridLinesColor := clBtnShadow;
|
|
FGroupColumns := TList.Create;
|
|
FHorizontal := True;
|
|
FIDFields := TList.Create;
|
|
FIndex := -1;
|
|
FItems := TList.Create;
|
|
FLayout := TdxMasterViewLayout.Create(Self);
|
|
FLevelSeparatorColor := clWindowText;
|
|
FLineWidth := DefaultLineWidth;
|
|
FMasterKeyFields := TList.Create;
|
|
FMultipleDeleteConfirmText := LoadStr(dxsMVMultipleDeleteConfirmText);
|
|
FOptionsBehavior :=
|
|
[lobDblClkExpanding];
|
|
FOptionsCustomize :=
|
|
[locColumnMoving, locColumnHorSizing, locColumnVerSizing, locColumnSorting,
|
|
locColumnGrouping, locShowColumnOnUngrouping];
|
|
FOptionsCustomizeBox :=
|
|
[loxCaption, loxColumns, loxGrid, loxGroupByBox, loxHeader, loxViewMode];
|
|
FOptionsDB :=
|
|
[lodConfirmDelete, lodSmartLoad, lodSmartReload];
|
|
FOptionsHeader :=
|
|
[lohForFirstNode, lohForFirstVisibleNode, lohAfterExpandedNode];
|
|
FOptionsView :=
|
|
[lovGrid, lovGridWithPreview, lovHeader, lovOccupyRestSpace];
|
|
FPreviewLeftIndent := dxMVPreviewLeftIndent;
|
|
FPreviewMaxLineCount := dxMVPreviewMaxLineCount;
|
|
FPreviewRightIndent := dxMVPreviewRightIndent;
|
|
FRowSeparatorColor := clBtnShadow;
|
|
FSortedColumns := TList.Create;
|
|
FSummaryColumns := TList.Create;
|
|
FVisibleColumns := TList.Create;
|
|
CalcParents;
|
|
end;
|
|
|
|
destructor TdxMasterViewLevel.Destroy;
|
|
begin
|
|
Destroying;
|
|
if FParent <> nil then FParent.RemoveItem(Self);
|
|
DestroyColumns;
|
|
Clear;
|
|
HeaderStyle := nil;
|
|
ContentStyle := nil;
|
|
FooterStyle := nil;
|
|
PreviewStyle := nil;
|
|
CaptionStyle := nil;
|
|
GroupStyle := nil;
|
|
GroupByBoxStyle := nil;
|
|
if FParents <> nil then
|
|
begin
|
|
FreeMem(FParents, FParentCount * SizeOf(TdxMasterViewLevel));
|
|
FParentCount := 0;
|
|
FParents := nil;
|
|
end;
|
|
FMasterKeyFields.Free;
|
|
FLayout.Free;
|
|
FIDFields.Free;
|
|
FGroupColumns.Free;
|
|
FDetailKeyFields.Free;
|
|
FDataLink.Free;
|
|
FVisibleColumns.Free;
|
|
FSummaryColumns.Free;
|
|
FSortedColumns.Free;
|
|
FItems.Free;
|
|
FColumns.Free;
|
|
inherited;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetActive: Boolean;
|
|
begin
|
|
Result :=
|
|
(FParent = nil) or
|
|
(DataSet <> nil) and DataSet.Active and (IDFieldCount <> 0) and
|
|
(DontFilterRecords or
|
|
(DetailKeyFieldCount <> 0) and (DetailKeyFieldCount = MasterKeyFieldCount));
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetCaptionBrush: HBRUSH;
|
|
begin
|
|
if (CaptionStyle <> nil) and (svColor in CaptionStyle.AssignedValues) then
|
|
Result := CaptionStyle.Brush
|
|
else
|
|
Result := GetSysColorBrush(COLOR_BTNFACE);//FControl.CaptionBrush;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetCaptionColor: TColor;
|
|
begin
|
|
if (CaptionStyle <> nil) and (svColor in CaptionStyle.AssignedValues) then
|
|
Result := CaptionStyle.Color
|
|
else
|
|
Result := clBtnFace;//FControl.CaptionColor;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetCaptionFont: TFont;
|
|
begin
|
|
if (CaptionStyle <> nil) and (svFont in CaptionStyle.AssignedValues) then
|
|
Result := CaptionStyle.Font
|
|
else
|
|
Result := FControl.Font;//FControl.CaptionFont;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetColumn(Index: Integer): TdxMasterViewColumn;
|
|
begin
|
|
Result := TdxMasterViewColumn(FColumns[Index]);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetColumnCount: Integer;
|
|
begin
|
|
Result := FColumns.Count;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetContentAnotherBrush: HBRUSH;
|
|
begin
|
|
if (ContentStyle <> nil) and (svAnotherColor in ContentStyle.AssignedValues) then
|
|
Result := ContentStyle.AnotherBrush
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetContentAnotherColor: TColor;
|
|
begin
|
|
if (ContentStyle <> nil) and (svAnotherColor in ContentStyle.AssignedValues) then
|
|
Result := ContentStyle.AnotherColor
|
|
else
|
|
Result := clNone;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetContentBrush: HBRUSH;
|
|
begin
|
|
if (ContentStyle <> nil) and (svColor in ContentStyle.AssignedValues) then
|
|
Result := ContentStyle.Brush
|
|
else
|
|
Result := FControl.Brush.Handle;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetContentColor: TColor;
|
|
begin
|
|
if (ContentStyle <> nil) and (svColor in ContentStyle.AssignedValues) then
|
|
Result := ContentStyle.Color
|
|
else
|
|
Result := FControl.Color;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetContentFont: TFont;
|
|
begin
|
|
if (ContentStyle <> nil) and (svFont in ContentStyle.AssignedValues) then
|
|
Result := ContentStyle.Font
|
|
else
|
|
Result := FControl.Font;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetCount: Integer;
|
|
begin
|
|
Result := FItems.Count;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetDataSet: TDataSet;
|
|
begin
|
|
Result := FDataLink.DataSet;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetDataSource: TDataSource;
|
|
begin
|
|
Result := FDataLink.DataSource;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetDetailKeyField(Index: Integer): TField;
|
|
begin
|
|
Result := TField(FDetailKeyFields[Index]);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetDetailKeyFieldCount: Integer;
|
|
begin
|
|
Result := FDetailKeyFields.Count;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetDontFilterRecords: Boolean;
|
|
begin
|
|
Result := IsTop or (lodDontFilterRecords in FOptionsDB);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetFooterBrush: HBRUSH;
|
|
begin
|
|
if (FooterStyle <> nil) and (svColor in FooterStyle.AssignedValues) then
|
|
Result := FooterStyle.Brush
|
|
else
|
|
Result := GetSysColorBrush(COLOR_BTNFACE);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetFooterColor: TColor;
|
|
begin
|
|
if (FooterStyle <> nil) and (svColor in FooterStyle.AssignedValues) then
|
|
Result := FooterStyle.Color
|
|
else
|
|
Result := clBtnFace;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetFooterFont: TFont;
|
|
begin
|
|
if (FooterStyle <> nil) and (svFont in FooterStyle.AssignedValues) then
|
|
Result := FooterStyle.Font
|
|
else
|
|
Result := FControl.Font;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetGroupBrush: HBRUSH;
|
|
begin
|
|
if (GroupStyle <> nil) and (svColor in GroupStyle.AssignedValues) then
|
|
Result := GroupStyle.Brush
|
|
else
|
|
Result := GetSysColorBrush(COLOR_BTNFACE);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetGroupByBoxBrush: HBRUSH;
|
|
begin
|
|
if (GroupByBoxStyle <> nil) and (svColor in GroupByBoxStyle.AssignedValues) then
|
|
Result := GroupByBoxStyle.Brush
|
|
else
|
|
Result := GetSysColorBrush(COLOR_BTNSHADOW);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetGroupByBoxColor: TColor;
|
|
begin
|
|
if (GroupByBoxStyle <> nil) and (svColor in GroupByBoxStyle.AssignedValues) then
|
|
Result := GroupByBoxStyle.Color
|
|
else
|
|
Result := clBtnShadow;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetGroupByBoxFont: TFont;
|
|
begin
|
|
if (GroupByBoxStyle <> nil) and (svFont in GroupByBoxStyle.AssignedValues) then
|
|
Result := GroupByBoxStyle.Font
|
|
else
|
|
Result := FControl.Font;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetGroupByBoxFontColor: TColor;
|
|
begin
|
|
if (GroupByBoxStyle <> nil) and (svFont in GroupByBoxStyle.AssignedValues) then
|
|
Result := GroupByBoxStyle.Font.Color
|
|
else
|
|
Result := clBtnFace;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetGroupByBoxHeight: Integer;
|
|
begin
|
|
Result := GroupColumnCount;
|
|
if Result = 0 then
|
|
Result := 2 * GroupByBoxTopOffset + GroupByBoxTextHeight
|
|
else
|
|
Result := 2 * GroupByBoxTopOffset +
|
|
HeaderRealHeight div 2 * (Result + 1) + Byte(Odd(HeaderRealHeight)) +
|
|
(Result - 1) * GroupByBoxVerOffset;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetGroupColor: TColor;
|
|
begin
|
|
if (GroupStyle <> nil) and (svColor in GroupStyle.AssignedValues) then
|
|
Result := GroupStyle.Color
|
|
else
|
|
Result := clBtnFace;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetGroupColumn(Index: Integer): TdxMasterViewColumn;
|
|
begin
|
|
Result := FGroupColumns[Index];
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetGroupColumnCount: Integer;
|
|
begin
|
|
Result := FGroupColumns.Count;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetGroupFont: TFont;
|
|
begin
|
|
if (GroupStyle <> nil) and (svFont in GroupStyle.AssignedValues) then
|
|
Result := GroupStyle.Font
|
|
else
|
|
Result := FControl.Font;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetHasChildren: Boolean;
|
|
begin
|
|
Result := FItems.Count <> 0;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetHeaderBrush: HBRUSH;
|
|
begin
|
|
if (HeaderStyle <> nil) and (svColor in HeaderStyle.AssignedValues) then
|
|
Result := HeaderStyle.Brush
|
|
else
|
|
Result := GetSysColorBrush(COLOR_BTNFACE);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetHeaderColor: TColor;
|
|
begin
|
|
if (HeaderStyle <> nil) and (svColor in HeaderStyle.AssignedValues) then
|
|
Result := HeaderStyle.Color
|
|
else
|
|
Result := clBtnFace;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetHeaderFont: TFont;
|
|
begin
|
|
if (HeaderStyle <> nil) and (svFont in HeaderStyle.AssignedValues) then
|
|
Result := HeaderStyle.Font
|
|
else
|
|
Result := FControl.Font;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetHeaderRestSpaceBrush: HBRUSH;
|
|
begin
|
|
if (HeaderStyle <> nil) and (svAnotherColor in HeaderStyle.AssignedValues) then
|
|
Result := HeaderStyle.AnotherBrush
|
|
else
|
|
Result := GetSysColorBrush(COLOR_BTNSHADOW);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetHeaderRestSpaceColor: TColor;
|
|
begin
|
|
if (HeaderStyle <> nil) and (svAnotherColor in HeaderStyle.AssignedValues) then
|
|
Result := HeaderStyle.AnotherColor
|
|
else
|
|
Result := clBtnShadow;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetIDField(Index: Integer): TField;
|
|
begin
|
|
Result := TField(FIDFields[Index]);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetIDFieldCount: Integer;
|
|
begin
|
|
Result := FIDFields.Count;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetIndent: Integer;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := 0;
|
|
for I := ParentCount - 2 downto 0 do
|
|
with Parents[I] do
|
|
begin
|
|
if ShowCaption then
|
|
Inc(Result, LevelIndent + ExtLineWidth);
|
|
Inc(Result, GroupColumnCount * (LevelIndent + ExtLineWidth));
|
|
if I = 0 then Break;
|
|
Inc(Result, LevelIndent + ExtLineWidth + LevelSeparatorWidth);
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetIsDestroying: Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := csDestroying in ComponentState;
|
|
if not Result then
|
|
for I := 1 to ParentCount - 1 do
|
|
begin
|
|
Result := csDestroying in Parents[I].ComponentState;
|
|
if Result then Break;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetIsFirst: Boolean;
|
|
begin
|
|
Result := Index = 0;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetIsLast: Boolean;
|
|
begin
|
|
Result := Index = FParent.Count - 1;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetIsLoading: Boolean;
|
|
begin
|
|
Result := (csLoading in ComponentState) or (FLoadingLockCount <> 0);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetIsTop: Boolean;
|
|
begin
|
|
Result := FParent.Parent = nil;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetItem(Index: Integer): TdxMasterViewLevel;
|
|
begin
|
|
Result := FItems[Index];
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetMasterKeyField(Index: Integer): TField;
|
|
begin
|
|
Result := TField(FMasterKeyFields[Index]);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetMasterKeyFieldCount: Integer;
|
|
begin
|
|
Result := FMasterKeyFields.Count;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetNonScaledWidth: Integer;
|
|
begin
|
|
Result := FLayout.NonScaledWidth;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetOccupyRestSpace: Boolean;
|
|
begin
|
|
Result := lovOccupyRestSpace in FOptionsView;
|
|
end;
|
|
|
|
{$IFDEF CBUILDER3}
|
|
function TdxMasterViewLevel.GetParent(Index: Integer): TdxMasterViewLevel;
|
|
begin
|
|
Result := TdxMasterViewLevel(FParents^[Index]);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function TdxMasterViewLevel.GetPreviewAnotherBrush: HBRUSH;
|
|
begin
|
|
if (PreviewStyle <> nil) and (svAnotherColor in PreviewStyle.AssignedValues) then
|
|
Result := PreviewStyle.AnotherBrush
|
|
else
|
|
Result := ContentAnotherBrush;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetPreviewAnotherColor: TColor;
|
|
begin
|
|
if (PreviewStyle <> nil) and (svAnotherColor in PreviewStyle.AssignedValues) then
|
|
Result := PreviewStyle.AnotherColor
|
|
else
|
|
Result := ContentAnotherColor;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetPreviewBrush: HBRUSH;
|
|
begin
|
|
if (PreviewStyle <> nil) and (svColor in PreviewStyle.AssignedValues) then
|
|
Result := PreviewStyle.Brush
|
|
else
|
|
Result := ContentBrush;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetPreviewColor: TColor;
|
|
begin
|
|
if PreviewColorAssigned then
|
|
Result := PreviewStyle.Color
|
|
else
|
|
Result := ContentColor;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetPreviewColorAssigned: Boolean;
|
|
begin
|
|
Result := (PreviewStyle <> nil) and (svColor in PreviewStyle.AssignedValues);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetPreviewFont: TFont;
|
|
begin
|
|
if PreviewFontAssigned then
|
|
Result := PreviewStyle.Font
|
|
else
|
|
Result := ContentFont;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetPreviewFontAssigned: Boolean;
|
|
begin
|
|
Result := (PreviewStyle <> nil) and (svFont in PreviewStyle.AssignedValues);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetPreviewFontColor: TColor; //!!!
|
|
begin
|
|
if PreviewFontAssigned then
|
|
Result := PreviewStyle.Font.Color
|
|
else
|
|
Result := clBlue;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetRowCount: Integer;
|
|
begin
|
|
Result := FLayout.RowCount;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetShowCaption: Boolean;
|
|
begin
|
|
Result := lovCaption in FOptionsView;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetShowFooter: Boolean;
|
|
begin
|
|
Result := lovFooter in FOptionsView;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetShowGrid: Boolean;
|
|
begin
|
|
Result := lovGrid in FOptionsView;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetShowGridWithPreview: Boolean;
|
|
begin
|
|
Result := lovGridWithPreview in FOptionsView;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetShowGroupByBox: Boolean;
|
|
begin
|
|
Result := lovGroupByBox in FOptionsView;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetShowHeader: Boolean;
|
|
begin
|
|
Result := lovHeader in FOptionsView;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetShowPreview: Boolean;
|
|
begin
|
|
Result := lovPreview in FOptionsView;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetSmartLoad: Boolean;
|
|
begin
|
|
Result := lodSmartLoad in FOptionsDB;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetSmartReload: Boolean;
|
|
begin
|
|
Result := (lodSmartReload in FOptionsDB) and FCanUseSmartReload;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetSortedColumn(Index: Integer): TdxMasterViewColumn;
|
|
begin
|
|
Result := TdxMasterViewColumn(FSortedColumns[Index]);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetSortedColumnCount: Integer;
|
|
begin
|
|
Result := FSortedColumns.Count;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetVisibleColumn(Index: Integer): TdxMasterViewColumn;
|
|
begin
|
|
Result := TdxMasterViewColumn(FVisibleColumns[Index]);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetVisibleColumnCount: Integer;
|
|
begin
|
|
Result := FVisibleColumns.Count;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetVisibleRowCount: Integer;
|
|
begin
|
|
Result := FLayout.RowCount;
|
|
if Result = 0 then Result := 1;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetVisibleWidth: Integer;
|
|
begin
|
|
Result := FLayout.VisibleWidth;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetCaptionStyle(Value: TdxMasterViewStyle);
|
|
begin
|
|
if FCaptionStyle <> Value then
|
|
begin
|
|
if FCaptionStyle <> nil then
|
|
FCaptionStyle.RemoveConsumeType(Self, sctCaption);
|
|
FCaptionStyle := Value;
|
|
if FCaptionStyle <> nil then
|
|
FCaptionStyle.AddConsumeType(Self, sctCaption);
|
|
CaptionStyleChanged([]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetColumn(Index: Integer; Value: TdxMasterViewColumn);
|
|
begin
|
|
Columns[Index].Assign(Value);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetCaption(const Value: string);
|
|
begin
|
|
if FCaption <> Value then
|
|
begin
|
|
FCaption := Value;
|
|
if ShowCaption then LevelChanged(False);
|
|
if dxMVDesigner <> nil then dxMVDesigner.Changed(FControl, [rcLevels]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetContentStyle(Value: TdxMasterViewStyle);
|
|
begin
|
|
if FContentStyle <> Value then
|
|
begin
|
|
if FContentStyle <> nil then
|
|
FContentStyle.RemoveConsumeType(Self, sctContent);
|
|
FContentStyle := Value;
|
|
if FContentStyle <> nil then
|
|
FContentStyle.AddConsumeType(Self, sctContent);
|
|
ContentStyleChanged([]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetDataSource(Value: TDataSource);
|
|
var
|
|
PrevActive: Boolean;
|
|
begin
|
|
if DataSource <> Value then
|
|
begin
|
|
PrevActive := Active;
|
|
FDataLink.DataSource := Value;
|
|
if Value <> nil then Value.FreeNotification(Self);
|
|
if PrevActive or Active then
|
|
begin
|
|
FCanUseSmartReload := False;
|
|
LevelChanged(True);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetDetailKey(const Value: string);
|
|
var
|
|
PrevActive: Boolean;
|
|
begin
|
|
if FDetailKey <> Value then
|
|
begin
|
|
PrevActive := Active;
|
|
FDetailKey := Value;
|
|
RefreshDetailKeyFieldsList;
|
|
if PrevActive or Active then
|
|
begin
|
|
FCanUseSmartReload := False;
|
|
LevelChanged(True);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetFooterStyle(Value: TdxMasterViewStyle);
|
|
begin
|
|
if FFooterStyle <> Value then
|
|
begin
|
|
if FFooterStyle <> nil then
|
|
FFooterStyle.RemoveConsumeType(Self, sctFooter);
|
|
FFooterStyle := Value;
|
|
if FFooterStyle <> nil then
|
|
FFooterStyle.AddConsumeType(Self, sctFooter);
|
|
FooterStyleChanged([]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetGridLinesColor(Value: TColor);
|
|
begin
|
|
if FGridLinesColor <> Value then
|
|
begin
|
|
FGridLinesColor := Value;
|
|
LevelChanged(False);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetGroupByBoxStyle(Value: TdxMasterViewStyle);
|
|
begin
|
|
if FGroupByBoxStyle <> Value then
|
|
begin
|
|
if FGroupByBoxStyle <> nil then
|
|
FGroupByBoxStyle.RemoveConsumeType(Self, sctGroupByBox);
|
|
FGroupByBoxStyle := Value;
|
|
if FGroupByBoxStyle <> nil then
|
|
FGroupByBoxStyle.AddConsumeType(Self, sctGroupByBox);
|
|
GroupByBoxStyleChanged([]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetGroupStyle(Value: TdxMasterViewStyle);
|
|
begin
|
|
if FGroupStyle <> Value then
|
|
begin
|
|
if FGroupStyle <> nil then
|
|
FGroupStyle.RemoveConsumeType(Self, sctGroup);
|
|
FGroupStyle := Value;
|
|
if FGroupStyle <> nil then
|
|
FGroupStyle.AddConsumeType(Self, sctGroup);
|
|
GroupStyleChanged([]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetHeaderStyle(Value: TdxMasterViewStyle);
|
|
begin
|
|
if FHeaderStyle <> Value then
|
|
begin
|
|
if FHeaderStyle <> nil then
|
|
FHeaderStyle.RemoveConsumeType(Self, sctHeader);
|
|
FHeaderStyle := Value;
|
|
if FHeaderStyle <> nil then
|
|
FHeaderStyle.AddConsumeType(Self, sctHeader);
|
|
HeaderStyleChanged([]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetID(Value: string);
|
|
var
|
|
PrevActive: Boolean;
|
|
begin
|
|
if FID <> Value then
|
|
begin
|
|
PrevActive := Active;
|
|
FID := Value;
|
|
RefreshIDFieldsList;
|
|
if PrevActive or Active then
|
|
begin
|
|
FCanUseSmartReload := False;
|
|
LevelChanged(True);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetLevelSeparatorColor(Value: TColor);
|
|
begin
|
|
if FLevelSeparatorColor <> Value then
|
|
begin
|
|
FLevelSeparatorColor := Value;
|
|
if FLevelSeparatorWidth <> 0 then LevelChanged(False);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetLevelSeparatorWidth(Value: Integer);
|
|
begin
|
|
if Value < 0 then Value := 0;
|
|
if FLevelSeparatorWidth <> Value then
|
|
begin
|
|
FLevelSeparatorWidth := Value;
|
|
LevelChanged(False);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetMasterKey(const Value: string);
|
|
var
|
|
PrevActive: Boolean;
|
|
begin
|
|
if FMasterKey <> Value then
|
|
begin
|
|
PrevActive := Active;
|
|
FMasterKey := Value;
|
|
RefreshMasterKeyFieldsList;
|
|
if not IsTop then
|
|
with FParent do
|
|
begin
|
|
FCanUseSmartReload := False;
|
|
LevelChanged(True);
|
|
end;
|
|
if PrevActive or Active then
|
|
begin
|
|
FCanUseSmartReload := False;
|
|
LevelChanged(True);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetOptionsDB(Value: TdxMasterViewLevelOptionsDB);
|
|
var
|
|
ChangedValues: TdxMasterViewLevelOptionsDB;
|
|
begin
|
|
if FOptionsDB <> Value then
|
|
begin
|
|
Byte(ChangedValues) := Byte(Value) xor Byte(FOptionsDB);
|
|
|
|
FOptionsDB := Value;
|
|
|
|
if lodDontFilterRecords in ChangedValues then
|
|
begin
|
|
FCanUseSmartReload := False;
|
|
LevelChanged(True);
|
|
end;
|
|
|
|
if lodSmartLoad in ChangedValues then
|
|
if FControl <> nil then
|
|
with FControl do
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
Items.DoSmartLoadChanged(Self);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetOptionsHeader(Value: TdxMasterViewLevelOptionsHeader);
|
|
begin
|
|
if FOptionsHeader <> Value then
|
|
begin
|
|
FOptionsHeader := Value;
|
|
LevelChanged(False);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetOptionsView(Value: TdxMasterViewLevelOptionsView);
|
|
var
|
|
ChangedValues: TdxMasterViewLevelOptionsView;
|
|
begin
|
|
if FOptionsView <> Value then
|
|
begin
|
|
Word(ChangedValues) := Word(Value) xor Word(FOptionsView);
|
|
|
|
if lovPreview in ChangedValues then
|
|
if not (lovPreview in Value) then PreviewChanged;
|
|
|
|
FOptionsView := Value;
|
|
|
|
if lovCaption in ChangedValues then
|
|
begin
|
|
WidthChanged;
|
|
LevelChanged(True);
|
|
end;
|
|
if [lovFooter, lovGroupByBox, lovNoButtonsWhenNoChildren] * ChangedValues <> [] then
|
|
LevelChanged(False);
|
|
if lovGrid in ChangedValues then
|
|
begin
|
|
FExtLineWidth := DefaultLineWidth * Byte(ShowGrid);
|
|
CalcLineWidth;
|
|
if ShowPreview then
|
|
PreviewChanged
|
|
else
|
|
LevelChanged(False);
|
|
end;
|
|
if lovGridWithPreview in ChangedValues then
|
|
if ShowPreview then
|
|
begin
|
|
CalcLineWidth;
|
|
PreviewChanged;
|
|
end;
|
|
if lovHeader in ChangedValues then
|
|
begin
|
|
CalcDefaultWidths(nil);
|
|
if not FHorizontal then WidthChanged;
|
|
LevelChanged(False);
|
|
end;
|
|
if lovPreview in ChangedValues then
|
|
begin
|
|
CalcLineWidth;
|
|
if lovPreview in FOptionsView then LevelChanged(False);
|
|
end;
|
|
if lovOccupyRestSpace in ChangedValues then
|
|
if not FControl.AutoColumnWidth then
|
|
begin
|
|
FLayout.CheckColumnsWidths(nil);
|
|
LevelChanged(False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetPreviewField(Value: TField);
|
|
begin
|
|
if FPreviewField <> Value then
|
|
begin
|
|
SetPreviewFieldInternally(Value);
|
|
PreviewChanged;
|
|
if Active then
|
|
begin
|
|
FCanUseSmartReload := False;
|
|
LevelChanged(True);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetPreviewFieldInternally(Value: TField);
|
|
begin
|
|
if FPreviewField <> Value then
|
|
begin
|
|
FPreviewField := Value;
|
|
if FPreviewField <> nil then
|
|
begin
|
|
FPreviewField.FreeNotification(Self);
|
|
FPreviewFieldName := FPreviewField.FieldName;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetPreviewFieldName(Value: string);
|
|
begin
|
|
if FPreviewFieldName <> Value then
|
|
begin
|
|
FPreviewFieldName := Value;
|
|
SetPreviewField(FindPreviewField);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetPreviewLeftIndent(Value: Integer);
|
|
begin
|
|
if Value < 0 then Value := 0;
|
|
if FPreviewLeftIndent <> Value then
|
|
begin
|
|
FPreviewLeftIndent := Value;
|
|
if ShowPreview then PreviewChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetPreviewLineCount(Value: Integer);
|
|
begin
|
|
if Value < 0 then Value := 0;
|
|
if FPreviewLineCount <> Value then
|
|
begin
|
|
FPreviewLineCount := Value;
|
|
if ShowPreview then PreviewChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetPreviewMaxLength(Value: Integer);
|
|
begin
|
|
if Value < 0 then Value := 0;
|
|
if FPreviewMaxLength <> Value then
|
|
begin
|
|
FPreviewMaxLength := Value;
|
|
PreviewChanged;
|
|
if Active then
|
|
begin
|
|
FCanUseSmartReload := False;
|
|
LevelChanged(True);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetPreviewMaxLineCount(Value: Integer);
|
|
begin
|
|
if Value < 0 then Value := 0;
|
|
if FPreviewMaxLineCount <> Value then
|
|
begin
|
|
FPreviewMaxLineCount := Value;
|
|
if ShowPreview and (FPreviewLineCount = 0) then
|
|
PreviewChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetPreviewRightIndent(Value: Integer);
|
|
begin
|
|
if Value < 0 then Value := 0;
|
|
if FPreviewRightIndent <> Value then
|
|
begin
|
|
FPreviewRightIndent := Value;
|
|
if ShowPreview then PreviewChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetPreviewStyle(Value: TdxMasterViewStyle);
|
|
begin
|
|
if FPreviewStyle <> Value then
|
|
begin
|
|
if FPreviewStyle <> nil then
|
|
FPreviewStyle.RemoveConsumeType(Self, sctPreview);
|
|
FPreviewStyle := Value;
|
|
if FPreviewStyle <> nil then
|
|
FPreviewStyle.AddConsumeType(Self, sctPreview);
|
|
PreviewStyleChanged([]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetRowSeparatorColor(Value: TColor);
|
|
begin
|
|
if FRowSeparatorColor <> Value then
|
|
begin
|
|
FRowSeparatorColor := Value;
|
|
if FRowSeparatorWidth <> 0 then LevelChanged(False);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetRowSeparatorWidth(Value: Integer);
|
|
begin
|
|
if Value < 0 then Value := 0;
|
|
if FRowSeparatorWidth <> Value then
|
|
begin
|
|
FRowSeparatorWidth := Value;
|
|
LevelChanged(False);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetViewMode(Value: TdxMasterViewViewMode);
|
|
begin
|
|
if FViewMode <> Value then
|
|
begin
|
|
FViewMode := Value;
|
|
FHorizontal := Value = vmHorizontal;
|
|
CalcRealHeights;
|
|
FLayout.ViewModeChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetVisibleColumn(Index: Integer; Value: TdxMasterViewColumn);
|
|
begin
|
|
VisibleColumns[Index].Assign(Value);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.IsDeleteConfirmCaptionTextStored: Boolean;
|
|
begin
|
|
Result := FDeleteConfirmCaptionText <> LoadStr(dxsMVDeleteConfirmCaptionText);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.IsDeleteConfirmTextStored: Boolean;
|
|
begin
|
|
Result := FDeleteConfirmText <> LoadStr(dxsMVDeleteConfirmText);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.IsMultipleDeleteConfirmTextStored: Boolean;
|
|
begin
|
|
Result := FMultipleDeleteConfirmText <> LoadStr(dxsMVMultipleDeleteConfirmText);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.ReadHeaderWidths(Reader: TReader);
|
|
var
|
|
I, Value: Integer;
|
|
begin
|
|
I := 0;
|
|
Reader.ReadListBegin;
|
|
try
|
|
while not Reader.EndOfList do
|
|
begin
|
|
Value := Reader.ReadInteger;
|
|
FLayout.Count := I + 1;
|
|
if Value <> -1 then
|
|
FLayout.HeaderWidths[I] := Value;
|
|
Inc(I);
|
|
end;
|
|
finally
|
|
Reader.ReadListEnd;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.WriteHeaderWidths(Writer: TWriter);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Writer.WriteListBegin;
|
|
try
|
|
for I := 0 to FLayout.Count - 1 do
|
|
if FLayout.HeaderWidthAssigned[I] then
|
|
Writer.WriteInteger(FLayout.HeaderWidths[I])
|
|
else
|
|
Writer.WriteInteger(-1);
|
|
finally
|
|
Writer.WriteListEnd;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.AddColumn(AColumn: TdxMasterViewColumn);
|
|
begin
|
|
AColumn.FLevel := Self;
|
|
FColumns.Add(AColumn);
|
|
if AColumn.Visible then
|
|
begin
|
|
FVisibleColumns.Add(AColumn);
|
|
if not IsLoading then
|
|
if FViewMode = vmHorizontal then
|
|
begin
|
|
AColumn.RowIndex := 0;
|
|
AColumn.ColIndex := FLayout[0].Count - 1;
|
|
end
|
|
else
|
|
begin
|
|
AColumn.ColIndex := 0;
|
|
AColumn.RowIndex := FLayout[0].Count - 1;
|
|
end;
|
|
end;
|
|
if FControl <> nil then
|
|
FControl.Items.MoveData(Self, -1, AColumn.Index);
|
|
FontsChanged;
|
|
LevelChanged(False);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.RemoveColumn(AColumn: TdxMasterViewColumn);
|
|
begin
|
|
AColumn.GroupIndex := -1;
|
|
if (FControl <> nil) and (FControl.Items <> nil) then
|
|
FControl.Items.MoveData(Self, AColumn.Index, -1);
|
|
if AColumn.Visible then
|
|
begin
|
|
FVisibleColumns.Remove(AColumn);
|
|
FLayout.RemoveColumn(AColumn);
|
|
end;
|
|
SummaryColumnsChanged(AColumn, opRemove);
|
|
FSortedColumns.Remove(AColumn);
|
|
FColumns.Remove(AColumn);
|
|
FontsChanged;
|
|
LevelChanged(False);
|
|
AColumn.FLevel := nil;
|
|
// if dxMVDesigner <> nil then dxMVDesigner.Changed(FControl, [rcColumns]);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.AddItem(Value: TdxMasterViewLevel);
|
|
begin
|
|
DestroySummaries([ntData]);
|
|
Value.FIndex := FItems.Add(Value);
|
|
Value.FParent := Self;
|
|
Value.FControl := FControl;
|
|
Value.CalcParents;
|
|
FControl.RefreshAbsoluteLevels;
|
|
Value.FontsChanged;
|
|
if Count = 1 then WidthChanged;
|
|
//FControl.FItems.ChangeExpanded(True);
|
|
if Active then
|
|
begin
|
|
FCanUseSmartReload := False;
|
|
LevelChanged(True);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.RemoveItem(Value: TdxMasterViewLevel);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
//if (LevelCount = 1) and (FItems <> nil) then FItems.ChangeExpanded(False);
|
|
Value.DeleteNodes;
|
|
DestroySummaries([ntData]);
|
|
FItems.Remove(Value);
|
|
with Value do
|
|
begin
|
|
I := Index;
|
|
FAbsoluteIndex := -1;
|
|
FIndex := -1;
|
|
FParent := nil;
|
|
end;
|
|
for I := I to Count - 1 do Dec(Items[I].FIndex);
|
|
if (FParent <> nil) or (FControl <> nil) and (FControl.Levels = Self) then
|
|
begin
|
|
FControl.RefreshAbsoluteLevels;
|
|
if Count = 0 then WidthChanged;
|
|
if Active then
|
|
begin
|
|
FCanUseSmartReload := False;
|
|
LevelChanged(True);
|
|
end;
|
|
end;
|
|
// if dxMVDesigner <> nil then dxMVDesigner.Changed(FControl, [rcLevels]);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.FindPreviewField: TField;
|
|
begin
|
|
if (FPreviewFieldName <> '') and (DataSet <> nil) then
|
|
Result := DataSet.FindField(FPreviewFieldName)
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.FontsChanged;
|
|
begin
|
|
if (FControl <> nil) and not IsDestroying then
|
|
begin
|
|
ContentStyleChanged([svFont]);
|
|
FooterStyleChanged([svFont]);
|
|
HeaderStyleChanged([svFont]);
|
|
PreviewStyleChanged([svFont]);
|
|
CaptionStyleChanged([svFont]);
|
|
GroupStyleChanged([svFont]);
|
|
GroupByBoxStyleChanged([svFont]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DeleteNodes;
|
|
|
|
procedure DeleteOne(Root: TdxMasterViewNode);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
with Root do
|
|
begin
|
|
if Level = FParent then
|
|
begin
|
|
FItems.BeginDeletion;
|
|
try
|
|
for I := Count - 1 downto 0 do
|
|
if Items[I].Level = Self then Items[I].Free;
|
|
finally
|
|
FItems.EndDeletion;
|
|
end;
|
|
end;
|
|
if Self.HasAsParent(Level) then
|
|
for I := 0 to Count - 1 do DeleteOne(Items[I]);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
with FControl do
|
|
if FItems <> nil then
|
|
begin
|
|
FAbsoluteItems.BeginDeletion;
|
|
FSelectedItems.BeginDeletion;
|
|
try
|
|
DeleteOne(FItems);
|
|
finally
|
|
FSelectedItems.EndDeletion;
|
|
FAbsoluteItems.EndDeletion;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.RefreshDetailKeyFieldsList;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FDetailKeyFields.Clear;
|
|
if DataSet <> nil then
|
|
begin
|
|
try
|
|
DataSet.GetFieldList(FDetailKeyFields, FDetailKey);
|
|
except
|
|
FDetailKeyFields.Clear;
|
|
end;
|
|
for I := 0 to DetailKeyFieldCount - 1 do
|
|
DetailKeyFields[I].FreeNotification(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.RefreshIDFieldsList;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FIDFields.Clear;
|
|
if DataSet <> nil then
|
|
begin
|
|
try
|
|
DataSet.GetFieldList(FIDFields, FID);
|
|
except
|
|
FIDFields.Clear;
|
|
end;
|
|
for I := 0 to IDFieldCount - 1 do
|
|
IDFields[I].FreeNotification(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.RefreshMasterKeyFieldsList;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FMasterKeyFields.Clear;
|
|
if FParent.DataSet <> nil then
|
|
begin
|
|
try
|
|
FParent.DataSet.GetFieldList(FMasterKeyFields, FMasterKey);
|
|
except
|
|
FMasterKeyFields.Clear;
|
|
end;
|
|
for I := 0 to MasterKeyFieldCount - 1 do
|
|
MasterKeyFields[I].FreeNotification(FParent);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.RefreshVisibleColumnsList;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FVisibleColumns.Clear;
|
|
for I := 0 to ColumnCount - 1 do
|
|
if Columns[I].Visible then FVisibleColumns.Add(Columns[I]);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SummaryColumnsChanged(AColumn: TdxMasterViewColumn;
|
|
Operation: TOperation);
|
|
begin
|
|
if Operation = opInsert then
|
|
if AColumn.SummaryIndex = -1 then
|
|
FSummaryColumns.Add(AColumn)
|
|
else
|
|
Exit
|
|
else
|
|
if AColumn.SummaryIndex = -1 then
|
|
Exit
|
|
else
|
|
FSummaryColumns.Remove(AColumn);
|
|
if ShowCaption or (GroupColumnCount <> 0) then
|
|
DestroySummaries([ntCaption, ntGroup]);
|
|
if FParent <> nil then
|
|
FParent.DestroySummaries([ntData]);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DefineProperties(Filer: TFiler);
|
|
begin
|
|
inherited;
|
|
Filer.DefineProperty('HeaderWidths', ReadHeaderWidths, WriteHeaderWidths, not FHorizontal);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.GetChildren(Proc: TGetChildProc; Root: TComponent);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to ColumnCount - 1 do
|
|
if Columns[I].Owner = Root then Proc(Columns[I]);
|
|
for I := 0 to Count - 1 do
|
|
if Items[I].Owner = Root then Proc(Items[I]);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.Loaded;
|
|
begin
|
|
inherited;
|
|
LoadingComplete;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.Notification(AComponent: TComponent; Operation: TOperation);
|
|
var
|
|
NeedLayout: Boolean;
|
|
I: Integer;
|
|
begin
|
|
inherited;
|
|
if (Operation = opRemove) and (AComponent is TdxMasterViewStyle) then
|
|
begin
|
|
if HeaderStyle = AComponent then HeaderStyle := nil;
|
|
if ContentStyle = AComponent then ContentStyle := nil;
|
|
if FooterStyle = AComponent then FooterStyle := nil;
|
|
if PreviewStyle = AComponent then PreviewStyle := nil;
|
|
if CaptionStyle = AComponent then CaptionStyle := nil;
|
|
if GroupStyle = AComponent then GroupStyle := nil;
|
|
if GroupByBoxStyle = AComponent then GroupByBoxStyle := nil;
|
|
end;
|
|
if not IsDestroying and (Operation = opRemove) then
|
|
if AComponent = DataSource then
|
|
DataSource := nil
|
|
else
|
|
if AComponent is TField then
|
|
begin
|
|
NeedLayout := False;
|
|
FControl.BeginLayout;
|
|
try
|
|
if FDetailKeyFields.Remove(AComponent) <> -1 then
|
|
NeedLayout := True;
|
|
if FIDFields.Remove(AComponent) <> -1 then
|
|
NeedLayout := True;
|
|
for I := 0 to Count - 1 do
|
|
if Items[I].FMasterKeyFields.Remove(AComponent) <> -1 then
|
|
NeedLayout := True;
|
|
if FPreviewField = AComponent then
|
|
begin
|
|
PreviewField := nil;
|
|
NeedLayout := True;
|
|
end;
|
|
for I := 0 to ColumnCount - 1 do
|
|
with Columns[I] do
|
|
begin
|
|
if Field = AComponent then
|
|
begin
|
|
Field := nil;
|
|
NeedLayout := True;
|
|
end;
|
|
if SummaryField = AComponent then
|
|
begin
|
|
SummaryField := nil;
|
|
NeedLayout := True;
|
|
end;
|
|
end;
|
|
finally
|
|
if NeedLayout and Active then
|
|
FControl.EndLayout
|
|
else
|
|
FControl.CancelLayout;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetName(const NewName: TComponentName);
|
|
var
|
|
OldName: TComponentName;
|
|
I: Integer;
|
|
Column: TdxMasterViewColumn;
|
|
ColumnName, NamePrefix: TComponentName;
|
|
begin
|
|
OldName := Name;
|
|
inherited;
|
|
{ In design mode the name of the columns should track the level name }
|
|
if FControl.IsDesigning and (Name <> OldName) then
|
|
for I := 0 to ColumnCount - 1 do
|
|
begin
|
|
Column := Columns[I];
|
|
if Column.Owner = Owner then
|
|
begin
|
|
ColumnName := Column.Name;
|
|
if Length(ColumnName) > Length(OldName) then
|
|
begin
|
|
NamePrefix := Copy(ColumnName, 1, Length(OldName));
|
|
if CompareText(OldName, NamePrefix) = 0 then
|
|
begin
|
|
System.Delete(ColumnName, 1, Length(OldName));
|
|
System.Insert(NewName, ColumnName, 1);
|
|
try
|
|
Column.Name := ColumnName;
|
|
except
|
|
on EComponentError do {Ignore rename errors };
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
if dxMVDesigner <> nil then dxMVDesigner.Changed(FControl, [rcLevels]);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SetParentComponent(AParent: TComponent);
|
|
begin
|
|
if AParent is TdxMasterView then
|
|
TdxMasterView(AParent).Levels.AddItem(Self)
|
|
else
|
|
if AParent is TdxMasterViewLevel then
|
|
TdxMasterViewLevel(AParent).AddItem(Self);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.ActiveChanged;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FControl.BeginLayout;
|
|
try
|
|
LayoutChanged;
|
|
finally
|
|
FControl.EndLayout;
|
|
end;
|
|
if FControl.FocusedNode = nil then
|
|
begin
|
|
if FControl.SyncMove then
|
|
if Active then
|
|
SyncPos
|
|
else
|
|
for I := ParentCount - 2 downto 1 do
|
|
with Parents[I] do
|
|
if Active then
|
|
SyncPos
|
|
else
|
|
Break;
|
|
with FControl do
|
|
if (FocusedNode = nil) and (AbsoluteItemCount <> 0) then
|
|
FocusNode(AbsoluteItems[0], True);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.AfterPaint;
|
|
begin
|
|
DeleteObject(FRowSeparatorBrush);
|
|
DeleteObject(FLevelSeparatorBrush);
|
|
DeleteObject(FGridLinesPen);
|
|
DeleteObject(FGridLinesBrush);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.AssignColumnWidths;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
BeginAssignWidths;
|
|
try
|
|
for I := 0 to VisibleColumnCount - 1 do
|
|
with VisibleColumns[I] do
|
|
Width := FVisibleWidth;
|
|
finally
|
|
EndAssignWidths;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.BeforePaint;
|
|
begin
|
|
FGridLinesBrush := CreateSolidBrush(ColorToRGB(FGridLinesColor));
|
|
FGridLinesPen := CreatePen(PS_SOLID, DefaultLineWidth, ColorToRGB(FGridLinesColor));
|
|
FLevelSeparatorBrush := CreateSolidBrush(ColorToRGB(FLevelSeparatorColor));
|
|
FRowSeparatorBrush := CreateSolidBrush(ColorToRGB(FRowSeparatorColor));
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.BeginLoad;
|
|
var
|
|
NeedUpdateData: Boolean;
|
|
begin
|
|
NeedUpdateData := False;
|
|
if (FLoadLockCount = 0) and (DataSet <> nil) then
|
|
begin
|
|
DataSet.DisableControls;
|
|
if DataSet.State in dsEditModes then
|
|
begin
|
|
DataSet.Cancel;
|
|
NeedUpdateData := True;
|
|
end;
|
|
FBeforeLoadBookmark := DataSet.GetBookmark;
|
|
FBeforeLoadActiveRecord := TDummyDataSet(DataSet).ActiveRecord;
|
|
FBeforeLoadBOF := DataSet.BOF;
|
|
FBeforeLoadEOF := DataSet.EOF;
|
|
end;
|
|
Inc(FLoadLockCount);
|
|
if NeedUpdateData then DataChanged;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.BeginLoading;
|
|
begin
|
|
if FLoadingLockCount = 0 then
|
|
begin
|
|
FCursorBeforeLoading := Screen.Cursor;
|
|
Screen.Cursor := crHourglass;
|
|
end;
|
|
Inc(FLoadingLockCount);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.CalcDefaultWidths(Column: TdxMasterViewColumn);
|
|
var
|
|
AChanged: Boolean;
|
|
I, PrevWidth: Integer;
|
|
|
|
procedure ProcessColumn(Column: TdxMasterViewColumn);
|
|
begin
|
|
with Column do
|
|
if not (cvWidth in AssignedValues) then
|
|
begin
|
|
PrevWidth := FWidth;
|
|
FWidth := DefaultWidth;
|
|
if FWidth <> PrevWidth then
|
|
FVisibleWidth := FWidth;
|
|
AChanged := AChanged or Visible and (FWidth <> PrevWidth);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if IsLoading or (Column <> nil) and Column.IsLoading or
|
|
Control.IsDestroying then Exit;
|
|
AChanged := False;
|
|
BeginAssignWidths;
|
|
try
|
|
if Column <> nil then ProcessColumn(Column)
|
|
else
|
|
for I := 0 to ColumnCount - 1 do
|
|
ProcessColumn(Columns[I]);
|
|
finally
|
|
if AChanged then
|
|
EndAssignWidths
|
|
else
|
|
CancelAssignWidths;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.CalcLineWidth;
|
|
begin
|
|
FLineWidth := DefaultLineWidth * Byte(HasGrid);
|
|
CalcRealHeights;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.CalcParents;
|
|
var
|
|
ALevel: TdxMasterViewLevel;
|
|
begin
|
|
if FParents <> nil then FreeMem(FParents);
|
|
FParentCount := 0;
|
|
ALevel := Self;
|
|
while ALevel <> nil do
|
|
begin
|
|
Inc(FParentCount);
|
|
ALevel := ALevel.Parent;
|
|
end;
|
|
GetMem(FParents, FParentCount * SizeOf(TdxMasterViewLevel));
|
|
FParentCount := 0;
|
|
ALevel := Self;
|
|
while ALevel <> nil do
|
|
begin
|
|
FParents[FParentCount] := ALevel;
|
|
Inc(FParentCount);
|
|
ALevel := ALevel.Parent;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.CalcRealHeights;
|
|
begin
|
|
FHeaderRealHeight := FHeaderHeight;
|
|
FContentRealHeight := FContentHeight + FLineWidth;
|
|
if not FHorizontal then
|
|
if FHeaderRealHeight > FContentRealHeight then
|
|
FContentRealHeight := FHeaderRealHeight
|
|
else
|
|
FHeaderRealHeight := FContentRealHeight;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DestroySummaries(NodeTypes: TdxMasterViewNodeTypes);
|
|
|
|
procedure CheckNode(Node: TdxMasterViewNode);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (Node.Level = Self) and (Node.NodeType in NodeTypes) then
|
|
Node.DestroySummaries;
|
|
for I := 0 to Node.Count - 1 do
|
|
CheckNode(Node[I]);
|
|
end;
|
|
|
|
begin
|
|
with FControl do
|
|
if FItems <> nil then CheckNode(FItems);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.EndLoad(RecalcInfo: Boolean);
|
|
var
|
|
AFreezeCount: Integer;
|
|
begin
|
|
if FLoadLockCount > 0 then
|
|
begin
|
|
Dec(FLoadLockCount);
|
|
if FLoadLockCount = 0 then
|
|
begin
|
|
if DataSet <> nil then
|
|
with TDummyDataSet(DataSet) do
|
|
begin
|
|
if FBeforeLoadBookmark <> nil then
|
|
begin
|
|
if BookmarkValid(FBeforeLoadBookmark) then GotoBookmark(FBeforeLoadBookmark);
|
|
FreeBookmark(FBeforeLoadBookmark);
|
|
end;
|
|
|
|
if ActiveRecord > FBeforeLoadActiveRecord then
|
|
begin
|
|
MoveBy(BufferCount - ActiveRecord - 1 +
|
|
ActiveRecord - FBeforeLoadActiveRecord);
|
|
MoveBy(FBeforeLoadActiveRecord - BufferCount + 1);
|
|
end
|
|
else
|
|
if ActiveRecord < FBeforeLoadActiveRecord then
|
|
begin
|
|
MoveBy(-ActiveRecord +
|
|
ActiveRecord - FBeforeLoadActiveRecord);
|
|
MoveBy(FBeforeLoadActiveRecord);
|
|
end;
|
|
|
|
if FBeforeLoadBOF and not BOF then Prior;
|
|
if FBeforeLoadEOF and not EOF then Next;
|
|
|
|
AFreezeCount := FControl.FreezeDataSet(Self);
|
|
try
|
|
EnableControls;
|
|
finally
|
|
if FDataLink.FreezeCount = AFreezeCount then
|
|
FControl.UnfreezeDataSet(Self);
|
|
end;
|
|
end;
|
|
if RecalcInfo then
|
|
begin
|
|
DoSorting;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.EndLoading;
|
|
begin
|
|
if FLoadingLockCount > 0 then
|
|
begin
|
|
Dec(FLoadingLockCount);
|
|
if FLoadingLockCount = 0 then
|
|
begin
|
|
LoadingComplete;
|
|
LevelChanged(True);
|
|
Screen.Cursor := FCursorBeforeLoading;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.LoadingComplete;
|
|
var
|
|
List: TList;
|
|
PrevProcessedCount, ProcessedCount, CurIndex, I: Integer;
|
|
PrevLeaveSortOrder: Boolean;
|
|
Column: TdxMasterViewColumn;
|
|
begin
|
|
BeginLayout;
|
|
List := TList.Create;
|
|
try
|
|
// grouping
|
|
CurIndex := -1;
|
|
repeat
|
|
ProcessedCount := 0;
|
|
for I := 0 to ColumnCount - 1 do
|
|
begin
|
|
Column := Columns[I];
|
|
with Column do
|
|
if FLoadedGroupIndex = CurIndex then
|
|
begin
|
|
PrevLeaveSortOrder := FLeaveSortOrder;
|
|
if GroupIndex <> FLoadedGroupIndex then
|
|
ChangeGrouping(Column, FLoadedGroupIndex);
|
|
FLeaveSortOrder := PrevLeaveSortOrder;
|
|
ProcessedCount := 1;
|
|
if CurIndex <> -1 then Break;
|
|
end;
|
|
end;
|
|
Inc(CurIndex);
|
|
until (ProcessedCount = 0) and (CurIndex <> -1);
|
|
|
|
// sorting
|
|
CurIndex := -1;
|
|
repeat
|
|
ProcessedCount := 0;
|
|
for I := 0 to ColumnCount - 1 do
|
|
begin
|
|
Column := Columns[I];
|
|
if Column.FLoadedSortIndex = CurIndex then
|
|
begin
|
|
with Column do
|
|
if SortIndex <> FLoadedSortIndex then
|
|
ChangeSorting(Column, SortOrder, FLoadedSortIndex);
|
|
ProcessedCount := 1;
|
|
if CurIndex <> -1 then Break;
|
|
end;
|
|
end;
|
|
Inc(CurIndex);
|
|
until (ProcessedCount = 0) and (CurIndex <> -1);
|
|
|
|
// layout
|
|
CalcDefaultWidths(nil);
|
|
MakeVisibleColumnsSortedList(List);
|
|
FLayout.Clear;
|
|
|
|
PrevProcessedCount := 0;
|
|
ProcessedCount := 0;
|
|
CurIndex := 0;
|
|
while ProcessedCount < List.Count do
|
|
begin
|
|
while ProcessedCount < List.Count do
|
|
begin
|
|
Column := TdxMasterViewColumn(List[ProcessedCount]);
|
|
if FHorizontal and (Column.RowIndex <> CurIndex) or
|
|
not FHorizontal and (Column.ColIndex <> CurIndex) then Break;
|
|
Inc(ProcessedCount);
|
|
end;
|
|
for I := PrevProcessedCount to ProcessedCount - 1 do
|
|
with TdxMasterViewColumn(List[I]) do
|
|
FLayout.InsertColumn(FRowIndex, FColIndex, List[I]);
|
|
PrevProcessedCount := ProcessedCount;
|
|
Inc(CurIndex);
|
|
end;
|
|
finally
|
|
List.Free;
|
|
EndLayout;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.CalcPreviewLineCount(DC: HDC; const S: string;
|
|
Width: Integer; Node: TdxMasterViewNode; var Height: Integer);
|
|
var
|
|
R: TRect;
|
|
Size: TSize;
|
|
LineCount: Integer;
|
|
begin
|
|
GetTextExtentPoint{32}(DC, 'Qq', 2, Size);
|
|
if FPreviewLineCount = 0 then
|
|
begin
|
|
R := Rect(0, 0, Width - (FPreviewLeftIndent + FPreviewRightIndent + FExtLineWidth), 0);
|
|
Windows.DrawText(DC, PChar(S), Length(S), R,
|
|
DT_CALCRECT or DT_EXPANDTABS or DT_NOCLIP or DT_NOPREFIX or DT_WORDBREAK);
|
|
|
|
LineCount := R.Bottom div Size.cy;
|
|
if (FPreviewMaxLineCount <> 0) and (LineCount > FPreviewMaxLineCount) then
|
|
LineCount := FPreviewMaxLineCount;
|
|
end
|
|
else
|
|
LineCount := FPreviewLineCount;
|
|
if Assigned(FOnGetPreviewLineCount) then
|
|
FOnGetPreviewLineCount(Self, Node, LineCount);
|
|
Height := 1 + Size.cy * LineCount + 1 + FExtLineWidth;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.CanDelete: Boolean;
|
|
begin
|
|
Result := (lodAllowDelete in FOptionsDB) and Active and DataSet.CanModify;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.CanGrouping(Column: TdxMasterViewColumn;
|
|
Index: Integer): Boolean;
|
|
begin
|
|
Result := locColumnGrouping in FOptionsCustomize;
|
|
if Assigned(FOnChangeGrouping) then
|
|
FOnChangeGrouping(Self, Column, Index, Result);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.CanHorSizing: Boolean;
|
|
begin
|
|
Result := locColumnHorSizing in FOptionsCustomize;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.CanInsert: Boolean;
|
|
begin
|
|
Result := (lodAllowInsert in FOptionsDB) and Active and DataSet.CanModify;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.CanSmartRefresh: Boolean;
|
|
begin
|
|
Result := FControl.SyncMove and (lodSmartRefresh in FOptionsDB) and
|
|
not (FDataLink.DataSet.BOF or FDataLink.DataSet.EOF);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.CanSorting(Column: TdxMasterViewColumn): Boolean;
|
|
begin
|
|
Result := locColumnSorting in FOptionsCustomize;
|
|
if Assigned(FOnColumnSorting) then FOnColumnSorting(Self, Column, Result);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.CaptionStyleChanged(Values: TdxMasterViewStyleValues);
|
|
var
|
|
Size: TSize;
|
|
begin
|
|
if (Values = []) or (svFont in Values) then
|
|
begin
|
|
CalcFontSize(CaptionFont, Size);
|
|
FCaptionHeight := Size.cy + 2 + 2; // 17 - without line
|
|
end;
|
|
if ShowCaption then LevelChanged(False);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.ChangeGrouping(Column: TdxMasterViewColumn;
|
|
AIndex: Integer);
|
|
begin
|
|
with FGroupColumns, Column do
|
|
if GroupIndex = -1 then
|
|
begin
|
|
FLeaveSortOrder := FSortOrder <> soNone;
|
|
if (locHideColumnOnGrouping in OptionsCustomize) and
|
|
(VisibleColumnCount <> 1) then
|
|
Visible := False;
|
|
if SortOrder = soNone then SortOrder := soAscending;
|
|
Insert(AIndex, Column);
|
|
end
|
|
else
|
|
if AIndex = -1 then
|
|
begin
|
|
Remove(Column);
|
|
if locShowColumnOnUngrouping in OptionsCustomize then
|
|
Visible := True;
|
|
end
|
|
else
|
|
if AIndex = Count then
|
|
Exit
|
|
else
|
|
Move(GroupIndex, AIndex);
|
|
WidthChanged;
|
|
if Active then LevelChanged(True);
|
|
with Column do
|
|
if (AIndex = -1) and not FLeaveSortOrder then SortOrder := soNone;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.ChangeSorting(Column: TdxMasterViewColumn;
|
|
ASortOrder: TdxMasterViewSortOrder; ASortIndex: Integer);
|
|
var
|
|
Resort: Boolean;
|
|
I: Integer;
|
|
begin
|
|
if ASortIndex = -2 then
|
|
if SortedColumnCount <> 0 then
|
|
begin
|
|
BeginSorting;
|
|
try
|
|
for I := SortedColumnCount - 1 downto 0 do
|
|
if SortedColumns[I] <> Column then // exceptional column
|
|
SortedColumns[I].SortOrder := soNone;
|
|
finally
|
|
EndSorting;
|
|
end;
|
|
end
|
|
else
|
|
else
|
|
if Column <> nil then
|
|
begin
|
|
if (ASortOrder = soNone) and (Column.GroupIndex <> -1) then Exit;
|
|
Column.FSortOrder := ASortOrder;
|
|
Column.ColumnChanged(False, hpOne, vpHeader);
|
|
Resort := True;
|
|
if ASortOrder = soNone then
|
|
begin
|
|
FSortedColumns.Remove(Column);
|
|
if FSortedColumns.Count = 0 then Resort := False;
|
|
end
|
|
else
|
|
if Column.SortIndex = -1 then
|
|
if ASortIndex = -1 then
|
|
FSortedColumns.Add(Column)
|
|
else
|
|
FSortedColumns.Insert(ASortIndex, Column)
|
|
else
|
|
FSortedColumns.Move(Column.SortIndex, ASortIndex);
|
|
if Column.Visible and not FHorizontal and ShowHeader and
|
|
not FLayout.HeaderWidthAssigned[Column.ColIndex] then
|
|
WidthChanged;
|
|
if Resort then DoSorting
|
|
else
|
|
if Column.Visible and ShowHeader then
|
|
if FHorizontal or FLayout.HeaderWidthAssigned[Column.ColIndex] then
|
|
Column.ColumnChanged(False, hpOne, vpHeader)
|
|
else
|
|
LevelChanged(False);
|
|
if not IsDestroying and Assigned(FOnColumnSorted) then
|
|
FOnColumnSorted(Self, Column);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.ContentStyleChanged(Values: TdxMasterViewStyleValues);
|
|
var
|
|
Size: TSize;
|
|
H, I: Integer;
|
|
begin
|
|
if (Values = []) or (svFont in Values) then
|
|
begin
|
|
if VisibleColumnCount = 0 then
|
|
begin
|
|
CalcFontSize(ContentFont, Size);
|
|
H := Size.cy;
|
|
end
|
|
else
|
|
begin
|
|
H := 0;
|
|
for I := 0 to VisibleColumnCount - 1 do
|
|
begin
|
|
CalcFontSize(VisibleColumns[I].ContentFont, Size);
|
|
if Size.cy > H then H := Size.cy;
|
|
end;
|
|
end;
|
|
FContentHeight := H + 2 + 2; // 17 - without line
|
|
CalcRealHeights;
|
|
CalcDefaultWidths(nil);
|
|
end;
|
|
LevelChanged(False);
|
|
if (svColor in Values) and not PreviewColorAssigned or
|
|
(svFont in Values) and not PreviewFontAssigned then
|
|
PreviewStyleChanged(Values);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DataChanged;
|
|
var
|
|
AKeyValue: Variant;
|
|
ParentNode, Node: TdxMasterViewNode;
|
|
begin
|
|
if FDataChanging then Exit;
|
|
FDataChanging := True;
|
|
try
|
|
if FDataLink.DataSet.State = dsSetKey then Exit;
|
|
|
|
if FDataLink.DataSet.State = dsBrowse then
|
|
if CanSmartRefresh then
|
|
begin
|
|
if FIsInsertMode or (FEditingNode <> nil) then
|
|
begin
|
|
UncheckTriedToExpand;
|
|
if FIsInsertMode then
|
|
begin
|
|
FIsInsertMode := False;
|
|
AKeyValue := GetCurDetailKeyValue;
|
|
if not VarIsEmpty(AKeyValue) or IsTop then
|
|
begin
|
|
if IsTop then
|
|
ParentNode := FControl.FItems
|
|
else
|
|
ParentNode := FControl.NodeFromKeyValue(FParent, Index, AKeyValue);
|
|
if ParentNode <> nil then
|
|
begin
|
|
ParentNode := GetParentNode(ParentNode, nil, nil, nil, nil, True);
|
|
if ParentNode <> nil then
|
|
begin
|
|
Node := ParentNode.Add(Self, -1, ntData, GetCurIDValue, GetCurKeyValue);
|
|
Node.UpdateData(True, False, False);
|
|
ParentNode.CheckChildNodes(Self, True);
|
|
Node.MakeVisible;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
if FEditingNode <> nil then
|
|
with FEditingNode do
|
|
begin
|
|
UpdateData(True, False, True);
|
|
CheckParentNodes;
|
|
MakeVisible;
|
|
FEditingNode := nil;
|
|
end;
|
|
end;
|
|
SyncPos;
|
|
end
|
|
else
|
|
begin
|
|
FIsInsertMode := False;
|
|
FEditingNode := nil;
|
|
UncheckTriedToExpand;
|
|
//FCanUseSmartReload := False;
|
|
LevelChanged(True);
|
|
end;
|
|
|
|
if FDataLink.DataSet.State = dsInsert then FIsInsertMode := True;
|
|
finally
|
|
FDataChanging := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DoAfterCollapse(Node: TdxMasterViewNode);
|
|
begin
|
|
if Assigned(FOnCollapsed) then FOnCollapsed(Self, Node);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DoAfterExpand(Node: TdxMasterViewNode);
|
|
begin
|
|
if Assigned(FOnExpanded) then FOnExpanded(Self, Node);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.DoBeforeCollapse(Node: TdxMasterViewNode): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnCollapsing) then FOnCollapsing(Self, Node, Result);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.DoBeforeExpand(Node: TdxMasterViewNode): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnExpanding) then FOnExpanding(Self, Node, Result);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DoGetContentStyle(Node: TdxMasterViewNode;
|
|
Column: TdxMasterViewColumn; var NewStyle: TdxMasterViewStyle);
|
|
begin
|
|
if Assigned(FOnGetContentStyle) then FOnGetContentStyle(Self, Node, Column, NewStyle);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DoGetFooterCellText(Node: TdxMasterViewNode;
|
|
Column: TdxMasterViewColumn; var Text: string);
|
|
begin
|
|
if Assigned(FOnGetFooterCellText) then
|
|
FOnGetFooterCellText(Self, Node, Column, Text);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DoHideColumn(Column: TdxMasterViewColumn);
|
|
begin
|
|
if Assigned(FOnHideColumn) then FOnHideColumn(Self, Column);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DoNodeDeleted(Node: TdxMasterViewNode);
|
|
begin
|
|
if Node = FEditingNode then FEditingNode := nil;
|
|
if Assigned(FOnDeleteNode) then FOnDeleteNode(Self, Node);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DoShowColumn(Column: TdxMasterViewColumn);
|
|
begin
|
|
if Assigned(FOnShowColumn) then FOnShowColumn(Self, Column);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DoSorting;
|
|
var
|
|
PrevCursor: TCursor;
|
|
begin
|
|
if (SortedColumnCount = 0) or
|
|
(FSortingLockCount <> 0) or (FLoadLockCount <> 0) or
|
|
IsDestroying then Exit;
|
|
with FControl do
|
|
begin
|
|
PrevCursor := Screen.Cursor;
|
|
if ShowHourGlassCursor then Screen.Cursor := crHourGlass;
|
|
BeginUpdate;
|
|
try
|
|
Items.DoSorting(Self);
|
|
finally
|
|
EndUpdate;
|
|
ShowFocusedNode;
|
|
if ShowHourGlassCursor then Screen.Cursor := PrevCursor;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DrawIndent(DC: HDC; const ARect: TRect; Node: TdxMasterViewNode);
|
|
var
|
|
R: TRect;
|
|
NextLevelIndex, I, RelativeLevelIndex: Integer;
|
|
IsLowerIndent: Boolean;
|
|
ABrush: HBRUSH;
|
|
|
|
function GetYoungerParentNodeIndex(AParentIndex: Integer): Integer;
|
|
begin
|
|
for Result := AParentIndex - 1 downto 0 do
|
|
if Node.ParentNodes[Result].NodeType = ntData then Exit;
|
|
Result := 0;
|
|
end;
|
|
|
|
begin
|
|
R := ARect;
|
|
Dec(R.Left, FControl.LeftPos);
|
|
|
|
if Node.AbsoluteIndex = Control.AbsoluteItemCount - 1 then
|
|
NextLevelIndex := -1
|
|
else
|
|
with FControl.AbsoluteItems[Node.AbsoluteIndex + 1], ViewInfo do
|
|
if AbsoluteIndex = FControl.TopIndex + FControl.FLastPartVisibleItemCount then
|
|
NextLevelIndex := GetLevelIndex
|
|
else
|
|
NextLevelIndex := LevelIndex;
|
|
|
|
for I := Node.ViewInfo.LevelIndex downto 1 do
|
|
with Node.ViewInfo, Node.ParentNodes[I], R do
|
|
begin
|
|
Right := Left + LevelIndent;
|
|
if (Level = Self) and (Node.ViewInfo.GroupByBoxSize <> 0) and
|
|
(NodeType in [ntData, ntGroup]) and
|
|
(ParentNode.NodeType in [ntData, ntCaption]) then
|
|
Inc(Top, Node.ViewInfo.GroupByBoxSize);
|
|
if AbsoluteIndex < FControl.TopIndex then
|
|
IsLowerIndent := NextLevelIndex <= GetLevelIndex
|
|
else
|
|
IsLowerIndent := NextLevelIndex <= ViewInfo.LevelIndex;
|
|
|
|
with Level do
|
|
begin
|
|
GetContentParams(ParentNodes[0], nil, @ABrush, nil, nil, nil, False);
|
|
case NodeType of
|
|
ntData:
|
|
begin
|
|
RelativeLevelIndex := Node.Level.IndexOfParent(Level);
|
|
if Node.HasFooter(RelativeLevelIndex) then
|
|
Dec(Bottom, RowCount * FooterHeight);
|
|
if IsLowerIndent then
|
|
begin
|
|
if (RowSeparatorWidth <> 0) and
|
|
Node.HasRowSeparator(GetYoungerParentNodeIndex(I)) then
|
|
begin
|
|
FillRect(DC,
|
|
Rect(Left, Bottom - RowSeparatorWidth,
|
|
Right + ExtLineWidth + LevelSeparatorWidth, Bottom),
|
|
RowSeparatorBrush);
|
|
Dec(Bottom, RowSeparatorWidth);
|
|
end;
|
|
FillRect(DC, Rect(Left, Bottom - ExtLineWidth, Right, Bottom), GridLinesBrush);
|
|
Dec(Bottom, ExtLineWidth);
|
|
FillRect(DC, R, ABrush);
|
|
Inc(Bottom, ExtLineWidth);
|
|
end
|
|
else
|
|
FillRect(DC, R, ABrush);
|
|
if ExtLineWidth <> 0 then
|
|
begin
|
|
FillRect(DC, Rect(Right, Top, Right + ExtLineWidth, Bottom), GridLinesBrush);
|
|
Inc(Right, ExtLineWidth);
|
|
end;
|
|
if LevelSeparatorWidth <> 0 then
|
|
begin
|
|
FillRect(DC,
|
|
Rect(Right, Top, Right + LevelSeparatorWidth, Bottom),
|
|
LevelSeparatorBrush);
|
|
Inc(Right, LevelSeparatorWidth);
|
|
if Node.HasLevelSeparator(GetYoungerParentNodeIndex(I)) then
|
|
Dec(Bottom, LevelSeparatorWidth);
|
|
end;
|
|
Left := Right;
|
|
end;
|
|
ntCaption, ntGroup:
|
|
begin
|
|
if IsLowerIndent then
|
|
begin
|
|
FillRect(DC, Rect(Left, Bottom - ExtLineWidth, Right, Bottom), GridLinesBrush);
|
|
Dec(Bottom, ExtLineWidth);
|
|
FillRect(DC, R, ABrush);
|
|
Inc(Bottom, ExtLineWidth);
|
|
end
|
|
else
|
|
FillRect(DC, R, ABrush);
|
|
FillRect(DC, Rect(Right, Top, Right + ExtLineWidth, Bottom), GridLinesBrush);
|
|
Left := Right + ExtLineWidth;
|
|
Right := Left + LevelIndent;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DrawGroupByBox(DC: HDC; const ARect: TRect; Node: TdxMasterViewNode);
|
|
var
|
|
ATextColor, ABkColor: TColor;
|
|
AFont: TFont;
|
|
R, R1: TRect;
|
|
RestRgn, ClipRgn, Rgn: HRGN;
|
|
ClipRgnExists: Boolean;
|
|
PrevFont: HFONT;
|
|
Size: TSize;
|
|
I, X, Y: Integer;
|
|
ABrush, LineBrush: HBRUSH;
|
|
|
|
procedure ExcludeRect(const R: TRect);
|
|
begin
|
|
Rgn := CreateRectRgnIndirect(R);
|
|
CombineRgn(RestRgn, RestRgn, Rgn, RGN_DIFF);
|
|
DeleteObject(Rgn);
|
|
end;
|
|
|
|
begin
|
|
GetGroupByBoxParams(Node, @ABrush, @ATextColor, @ABkColor, @AFont);
|
|
R := ARect;
|
|
RestRgn := CreateRectRgnIndirect(R);
|
|
try
|
|
ClipRgn := CreateRectRgn(0, 0, 0, 0);
|
|
ClipRgnExists := GetClipRgn(DC, ClipRgn) = 1;
|
|
with R do
|
|
IntersectClipRect(DC, Left, Top, Right, Bottom);
|
|
try
|
|
if GroupColumnCount = 0 then
|
|
begin
|
|
SetTextColor(DC, ColorToRGB(ATextColor));
|
|
SetBkColor(DC, ColorToRGB(ABkColor));
|
|
PrevFont := SelectObject(DC, AFont.Handle);
|
|
GetTextExtentPoint{32}(DC, PChar(dxMVGroupByBoxText),
|
|
Length(dxMVGroupByBoxText), Size);
|
|
with R do
|
|
begin
|
|
Inc(Left, GroupByBoxLeftOffset);
|
|
if Left + Size.cx < Right then
|
|
Right := Left + Size.cx;
|
|
Top := (Top + Bottom - Size.cy) div 2;
|
|
Bottom := Top + Size.cy;
|
|
end;
|
|
DrawText(DC, PChar(dxMVGroupByBoxText), Length(dxMVGroupByBoxText),
|
|
R, DT_SINGLELINE);
|
|
SelectObject(DC, PrevFont);
|
|
ExcludeRect(R);
|
|
end
|
|
else
|
|
begin
|
|
LineBrush := CreateSolidBrush(ColorToRGB(GroupByBoxLineColor));
|
|
try
|
|
for I := 0 to GroupColumnCount - 1 do
|
|
with GroupColumns[I] do
|
|
begin
|
|
R := GetGroupByBoxBounds(Node);
|
|
ExcludeRect(R);
|
|
if I < GroupColumnCount - 1 then
|
|
with R do
|
|
begin
|
|
Y := (HeaderRealHeight div 2 + GroupByBoxVerOffset) div 2;
|
|
X := Right - 2 * Y;//(Left + Right) div 2;
|
|
Y := Bottom + Y;
|
|
R1 := Rect(X, Bottom, X + 1, Y);
|
|
FillRect(DC, R1, LineBrush);
|
|
ExcludeRect(R1);
|
|
R1 := Rect(X + 1, Y - 1, Right + GroupByBoxHorOffset, Y);
|
|
FillRect(DC, R1, LineBrush);
|
|
ExcludeRect(R1);
|
|
end;
|
|
if RectVisible(DC, R) then
|
|
begin
|
|
DrawEdge(DC, R, BDR_RAISEDINNER, BF_RECT);
|
|
R1 := R;
|
|
InflateRect(R, -1, -1);
|
|
DrawHeader(DC, R, Node);
|
|
if Pressed then DrawDowned(DC, R1);
|
|
end;
|
|
end;
|
|
finally
|
|
DeleteObject(LineBrush);
|
|
end;
|
|
end;
|
|
finally
|
|
SelectClipRgn(DC, Byte(ClipRgnExists) * ClipRgn);
|
|
DeleteObject(ClipRgn);
|
|
end;
|
|
finally
|
|
FillRgn(DC, RestRgn, ABrush);
|
|
DeleteObject(RestRgn);
|
|
|
|
R := ARect;
|
|
with R do
|
|
begin
|
|
Left := Right;
|
|
Right := FControl.ClientWidth;
|
|
end;
|
|
FillRect(DC, R, FControl.Brush.Handle);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DrawHeader(DC: HDC; const ARect: TRect; Node: TdxMasterViewNode);
|
|
var
|
|
ABrush: HBRUSH;
|
|
R, R1, R2: TRect;
|
|
RestRgn, Rgn: HRGN;
|
|
I: Integer;
|
|
Column: TdxMasterViewColumn;
|
|
|
|
procedure ExcludeRect(const R: TRect);
|
|
begin
|
|
Rgn := CreateRectRgnIndirect(R);
|
|
CombineRgn(RestRgn, RestRgn, Rgn, RGN_DIFF);
|
|
DeleteObject(Rgn);
|
|
end;
|
|
|
|
begin
|
|
GetHeaderParams(Node, nil, nil, @ABrush, nil, nil, nil);
|
|
R := ARect;
|
|
RestRgn := 0;
|
|
if FHorizontal then
|
|
if RowCount > 1 then
|
|
RestRgn := CreateRectRgnIndirect(ARect)
|
|
else
|
|
else
|
|
if (Node.ViewInfo.PreviewSize = 0) and (LineWidth <> 0) then
|
|
Dec(R.Bottom, LineWidth);
|
|
try
|
|
for I := 0 to VisibleColumnCount - 1 do
|
|
begin
|
|
Column := VisibleColumns[I];
|
|
with Column, R1 do
|
|
begin
|
|
R1 := GetHeaderBounds(Node);
|
|
if RestRgn <> 0 then ExcludeRect(R1)
|
|
else
|
|
if not FHorizontal and FLayout.IsColumnLast(Column) then
|
|
FillRect(DC, Rect(Left, Bottom, Right, R.Bottom), ABrush);
|
|
if (Left = Right) or not RectVisible(DC, R1) then Continue;
|
|
// draw column's border
|
|
DrawEdge(DC, R1, BDR_RAISEDINNER, BF_RECT);
|
|
// draw column's content
|
|
R2 := R1;
|
|
InflateRect(R2, -1, -1);
|
|
DrawHeader(DC, R2, Node);
|
|
if Pressed then DrawDowned(DC, R1);
|
|
end;
|
|
end;
|
|
finally
|
|
// fill in rest space
|
|
if RestRgn <> 0 then
|
|
begin
|
|
FillRgn(DC, RestRgn, ABrush);
|
|
DeleteObject(RestRgn);
|
|
end;
|
|
// draw rest space
|
|
if FHorizontal then
|
|
begin
|
|
with R do
|
|
begin
|
|
Left := Right;
|
|
Right := FControl.ClientWidth;
|
|
end;
|
|
FillRect(DC, R, FControl.Brush.Handle);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DrawContent(DC: HDC; const ARect: TRect; Node: TdxMasterViewNode);
|
|
type
|
|
PPointArray = ^TPointArray;
|
|
TPointArray = array[0..MaxInt div SizeOf(TPoint) - 1] of TPoint;
|
|
PDWORDArray = ^TDWORDArray;
|
|
TDWORDArray = array[0..MaxInt div SizeOf(DWORD) - 1] of DWORD;
|
|
var
|
|
R, R1, R2: TRect;
|
|
RestRgn, Rgn: HRGN;
|
|
AShowGrid, AHasExpandButton, IsMultiRows, HasLeftBorder, HasTopBorder: Boolean;
|
|
S: string;
|
|
I, J, K, L: Integer;
|
|
AFont: TFont;
|
|
P, RectsP: PPointArray;
|
|
C, RectsC: PDWORDArray;
|
|
Column: TdxMasterViewColumn;
|
|
ABrush: HBRUSH;
|
|
ATextColor, ABkColor: TColor;
|
|
ADC: HDC;
|
|
PrevFont: HFONT;
|
|
|
|
procedure DrawFocus(const R: TRect);
|
|
begin
|
|
R1 := R;
|
|
if AShowGrid or ShowPreview then
|
|
begin
|
|
if Node.Horizontal or AShowGrid or (I = FLayout.Count - 1) then
|
|
Dec(R1.Right, ExtLineWidth);
|
|
if Node.Horizontal or AShowGrid then
|
|
Dec(R1.Bottom, ExtLineWidth);
|
|
end;
|
|
if FControl.HasFocus then
|
|
begin
|
|
with R1 do
|
|
if Odd(Left) = Odd(Top) then
|
|
begin
|
|
SetTextColor(DC, $FFFFFF);
|
|
SetBkColor(DC, 0);
|
|
end
|
|
else
|
|
begin
|
|
SetTextColor(DC, 0);
|
|
SetBkColor(DC, $FFFFFF);
|
|
end;
|
|
DrawFocusRect(DC, R1);
|
|
end
|
|
else
|
|
if not (movHideFocusRect in FControl.OptionsView) then
|
|
if FControl.InactiveFocusColor = clNone then
|
|
with R1 do
|
|
begin
|
|
BitBlt(DC, Left, Top, Right - Left, 1, 0, 0, 0, DSTINVERT);
|
|
BitBlt(DC, Left, Bottom - 1, Right - Left, 1, 0, 0, 0, DSTINVERT);
|
|
BitBlt(DC, Left, Top + 1, 1, Bottom - Top - 2, 0, 0, 0, DSTINVERT);
|
|
BitBlt(DC, Right - 1, Top + 1, 1, Bottom - Top - 2, 0, 0, 0, DSTINVERT);
|
|
end
|
|
else
|
|
FrameRect(DC, R1, FControl.InactiveFocusBrush);
|
|
end;
|
|
|
|
begin
|
|
R := ARect;
|
|
AShowGrid := HasGrid;
|
|
AHasExpandButton := Node.HasExpandButton;
|
|
Inc(R.Left, Byte(AHasExpandButton) * LevelIndent);
|
|
IsMultiRows := False;
|
|
case Node.NodeType of
|
|
ntData:
|
|
begin
|
|
IsMultiRows := FHorizontal and (RowCount > 1);
|
|
R.Bottom := R.Top +
|
|
VisibleRowCount * ContentRealHeight + Node.ViewInfo.PreviewSize;
|
|
if (Node.ViewInfo.PreviewSize <> 0) or (LineWidth = 0) then
|
|
Inc(R.Bottom, ExtLineWidth);
|
|
end;
|
|
ntCaption:
|
|
R.Bottom := R.Top + CaptionHeight + ExtLineWidth;
|
|
ntGroup:
|
|
R.Bottom := R.Top + GroupHeight + ExtLineWidth;
|
|
end;
|
|
R1 := R;
|
|
|
|
// draw expand button
|
|
if AHasExpandButton then
|
|
with R, Node do
|
|
begin
|
|
GetContentParams(Node, nil, @ABrush, nil, nil, nil, False);
|
|
R2 := Rect(Left - LevelIndent, Top, Left, Bottom - ExtLineWidth);
|
|
if Node.ShowExpandButton then
|
|
DrawExpandButton(DC, R2, ABrush, Expanded, CanExpand)
|
|
else
|
|
FillRect(DC, R2, ABrush);
|
|
if ShowGrid then
|
|
begin
|
|
if not Node.Expanded then ABrush := GridLinesBrush;
|
|
FillRect(DC, Rect(Left - LevelIndent, Bottom - ExtLineWidth, Left, Bottom), ABrush);
|
|
end;
|
|
end;
|
|
|
|
// draw last(bottom and right) grid lines
|
|
with R1 do
|
|
if Left < Right then
|
|
begin
|
|
FillRect(DC, Rect(Left, Bottom - ExtLineWidth, Right, Bottom), GridLinesBrush);
|
|
Dec(Bottom, ExtLineWidth);
|
|
FillRect(DC, Rect(Right - ExtLineWidth, Top, Right, Bottom), GridLinesBrush);
|
|
Dec(Right, ExtLineWidth);
|
|
end;
|
|
Dec(R1.Bottom, Node.ViewInfo.PreviewSize);
|
|
|
|
if Node.NodeType in [ntCaption, ntGroup] then
|
|
begin
|
|
GetContentParams(Node, nil, @ABrush, @ATextColor, @ABkColor, @AFont, True);
|
|
if Node.NodeType = ntCaption then
|
|
S := FCaption
|
|
else
|
|
with GroupColumns[Node.GroupIndex] do
|
|
S := Caption + ' : ' + GetGroupDisplayText(Node);
|
|
FControl.DrawText(DC, R1, AFont, ABrush, ATextColor, ABkColor, taLeftJustify,
|
|
S, True, True, True, False);
|
|
end
|
|
else
|
|
begin
|
|
R2 := R1;
|
|
GetMem(P, 2 * 4 * VisibleColumnCount * SizeOf(TPoint));
|
|
GetMem(C, 4 * VisibleColumnCount * SizeOf(DWORD));
|
|
if IsMultiRows then
|
|
begin
|
|
GetMem(RectsP, 4 * VisibleColumnCount * SizeOf(TPoint));
|
|
GetMem(RectsC, VisibleColumnCount * SizeOf(DWORD));
|
|
end
|
|
else
|
|
begin
|
|
RectsP := nil;
|
|
RectsC := nil;
|
|
end;
|
|
J := 0;
|
|
GetContentParams(Node, nil, @ABrush, nil, nil, nil, True);
|
|
try
|
|
// draw data in cells
|
|
for I := 0 to VisibleColumnCount - 1 do
|
|
begin
|
|
Column := VisibleColumns[I];
|
|
with Column, R1 do
|
|
begin
|
|
R1 := GetContentBounds(Node);
|
|
Inc(Left, AddInWidth);
|
|
if Left = Right then Continue;
|
|
if not FHorizontal then
|
|
begin
|
|
K := FLayout.ContentWidths[ColIndex];
|
|
L := Left + K;
|
|
if (ColIndex = FLayout.Count - 1) and (RowIndex = 0) and (L < R2.Right) then
|
|
FillRect(DC, Rect(L, Top, R2.Right, R2.Bottom), ABrush);
|
|
if L = R.Right then L := R2.Right;
|
|
if Right < L then
|
|
FillRect(DC,
|
|
Rect(Right, Top, L, Bottom - Byte(Bottom = R.Bottom) * LineWidth),
|
|
ABrush);
|
|
if FLayout.IsColumnLast(Column) and (Bottom < R2.Bottom) then
|
|
FillRect(DC, Rect(Left, Bottom, L, R2.Bottom), ABrush);
|
|
end;
|
|
HasLeftBorder := Left <> R.Left;
|
|
HasTopBorder := Top <> R.Top;
|
|
if AShowGrid then
|
|
begin
|
|
if HasLeftBorder then Dec(Left, LineWidth);
|
|
if HasTopBorder then Dec(Top, LineWidth);
|
|
end
|
|
else
|
|
if Right = R.Right then Dec(Right, ExtLineWidth);
|
|
if IsMultiRows then
|
|
begin
|
|
K := 4 * I;
|
|
RectsP[K] := TopLeft;
|
|
with RectsP[K + 1] do
|
|
begin
|
|
X := Right;
|
|
Y := Top;
|
|
end;
|
|
RectsP[K + 2] := BottomRight;
|
|
with RectsP[K + 3] do
|
|
begin
|
|
X := Left;
|
|
Y := Bottom;
|
|
end;
|
|
RectsC[I] := 4;
|
|
end;
|
|
if not RectVisible(DC, R1) then Continue;
|
|
// calc cell's border
|
|
if AShowGrid then
|
|
begin
|
|
if HasLeftBorder then
|
|
begin
|
|
with P[J] do
|
|
begin
|
|
X := Left;
|
|
Y := Top;
|
|
end;
|
|
with P[J + 1] do
|
|
begin
|
|
X := Left;
|
|
Y := Bottom;
|
|
end;
|
|
Inc(J, 2);
|
|
Inc(Left, LineWidth);
|
|
end;
|
|
if HasTopBorder then
|
|
begin
|
|
with P[J] do
|
|
begin
|
|
X := Left;
|
|
Y := Top;
|
|
end;
|
|
with P[J + 1] do
|
|
begin
|
|
X := Right;
|
|
Y := Top;
|
|
end;
|
|
Inc(J, 2);
|
|
Inc(Top, LineWidth);
|
|
end;
|
|
with P[J] do
|
|
begin
|
|
X := Left;
|
|
Y := Bottom - LineWidth;
|
|
end;
|
|
with P[J + 1] do
|
|
begin
|
|
X := Right;
|
|
Y := P[J].Y;
|
|
end;
|
|
Inc(J, 2);
|
|
Dec(Bottom, LineWidth);
|
|
with P[J] do
|
|
begin
|
|
X := Right - LineWidth;
|
|
Y := Top;
|
|
end;
|
|
with P[J + 1] do
|
|
begin
|
|
X := P[J].X;
|
|
Y := Bottom;
|
|
end;
|
|
Inc(J, 2);
|
|
Dec(Right, LineWidth);
|
|
end;
|
|
// draw cell's content
|
|
DrawContent(DC, R1, Node);
|
|
end;
|
|
end;
|
|
// draw grid
|
|
J := J div 2;
|
|
if J <> 0 then
|
|
begin
|
|
for I := 0 to J - 1 do C[I] := 2;
|
|
FGridLinesPen := SelectObject(DC, FGridLinesPen);
|
|
PolyPolyLine(DC, P^, C^, J);
|
|
FGridLinesPen := SelectObject(DC, FGridLinesPen);
|
|
end;
|
|
// fill in rest space
|
|
if IsMultiRows then
|
|
begin
|
|
RestRgn := CreateRectRgnIndirect(R2);
|
|
Rgn := CreatePolyPolygonRgn(RectsP^, RectsC^, VisibleColumnCount, WINDING);
|
|
CombineRgn(RestRgn, RestRgn, Rgn, RGN_DIFF);
|
|
DeleteObject(Rgn);
|
|
FillRgn(DC, RestRgn, ABrush);
|
|
DeleteObject(RestRgn);
|
|
end;
|
|
finally
|
|
if IsMultiRows then
|
|
begin
|
|
FreeMem(RectsC, VisibleColumnCount * SizeOf(DWORD));
|
|
FreeMem(RectsP, 4 * VisibleColumnCount * SizeOf(TPoint));
|
|
end;
|
|
FreeMem(C, 4 * VisibleColumnCount * SizeOf(DWORD));
|
|
FreeMem(P, 2 * 4 * VisibleColumnCount * SizeOf(TPoint));
|
|
end;
|
|
end;
|
|
|
|
// draw preview
|
|
if Node.ViewInfo.PreviewSize <> 0 then
|
|
begin
|
|
R1 := R2;
|
|
R1.Top := R1.Bottom;
|
|
R1.Bottom := R1.Top + Node.ViewInfo.PreviewSize;
|
|
if RectVisible(DC, R1) then
|
|
with R1 do
|
|
begin
|
|
R2 := R1;
|
|
GetPreviewParams(Node, @ABrush, @ATextColor, nil, @AFont);
|
|
if movUseBitmapToDrawPreview in FControl.OptionsView then
|
|
with R1 do
|
|
begin
|
|
OffsetRect(R1, -Left, -Top);
|
|
with FControl do
|
|
begin
|
|
PrepareBitmap(Right, Bottom);
|
|
ADC := FBitmap.Canvas.Handle;
|
|
end;
|
|
end
|
|
else
|
|
ADC := DC;
|
|
begin
|
|
with R1 do
|
|
begin
|
|
FillRect(ADC, R1, ABrush);
|
|
Inc(Left, FPreviewLeftIndent);
|
|
Dec(Right, FPreviewRightIndent);
|
|
Inc(Top);
|
|
Dec(Bottom);
|
|
end;
|
|
SetTextColor(ADC, ColorToRGB(ATextColor));
|
|
SetBkMode(ADC, TRANSPARENT);
|
|
PrevFont := SelectObject(ADC, AFont.Handle);
|
|
Windows.DrawText(ADC, PChar(Node.PreviewText), Length(Node.PreviewText), R1,
|
|
DT_EXPANDTABS or DT_NOPREFIX or DT_WORDBREAK);
|
|
SelectObject(ADC, PrevFont);
|
|
SetBkMode(ADC, OPAQUE);
|
|
end;
|
|
if movUseBitmapToDrawPreview in FControl.OptionsView then
|
|
with R2 do
|
|
BitBlt(DC, Left, Top, Right - Left, Bottom - Top, ADC, 0, 0, SRCCOPY);
|
|
end;
|
|
end;
|
|
|
|
// draw focus rect
|
|
if Node.Focused then
|
|
if {true}Node.Horizontal or not ShowHeader then
|
|
DrawFocus(R)
|
|
else
|
|
begin
|
|
R2 := R;
|
|
for I := 0 to FLayout.Count - 1 do
|
|
with FLayout, R2 do
|
|
begin
|
|
Inc(Left, HeaderWidths[I]);
|
|
Right := Left + ContentWidths[I];
|
|
Bottom := Top + Items[I].Count * ContentRealHeight;
|
|
DrawFocus(R2);
|
|
Left := Right;
|
|
end;
|
|
end;
|
|
|
|
// draw separator of level or row
|
|
if Node.NodeType = ntData then
|
|
if Node.Expanded then
|
|
if LevelSeparatorWidth <> 0 then
|
|
with R do
|
|
begin
|
|
GetContentParams(Node, nil, @ABrush, nil, nil, nil, False);
|
|
FillRect(DC,
|
|
Rect(Left - LevelIndent, Bottom, Left, Bottom + LevelSeparatorWidth),
|
|
ABrush);
|
|
FillRect(DC,
|
|
Rect(Left, Bottom, Left + ExtLineWidth, Bottom + LevelSeparatorWidth),
|
|
GridLinesBrush);
|
|
FillRect(DC,
|
|
Rect(Left + ExtLineWidth, Bottom, FControl.ClientWidth, Bottom + LevelSeparatorWidth),
|
|
LevelSeparatorBrush);
|
|
end
|
|
else
|
|
else
|
|
if RowSeparatorWidth <> 0 then
|
|
with R do
|
|
begin
|
|
FillRect(DC,
|
|
Rect(ARect.Left, Bottom, Right, Bottom + RowSeparatorWidth),
|
|
RowSeparatorBrush);
|
|
FillRect(DC,
|
|
Rect(Right, Bottom, FControl.ClientWidth, Bottom + RowSeparatorWidth),
|
|
FControl.Brush.Handle);
|
|
end;
|
|
|
|
// draw rest space
|
|
with R do
|
|
begin
|
|
Left := Right;
|
|
Right := FControl.ClientWidth;
|
|
end;
|
|
FillRect(DC, R, FControl.Brush.Handle);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DrawFooter(DC: HDC; const ARect: TRect; Node: TdxMasterViewNode);
|
|
var
|
|
ABrush: HBRUSH;
|
|
R, R1, R2: TRect;
|
|
RestRgn, Rgn: HRGN;
|
|
I, J, K: Integer;
|
|
|
|
procedure ExcludeRect(const R: TRect);
|
|
begin
|
|
Rgn := CreateRectRgnIndirect(R);
|
|
CombineRgn(RestRgn, RestRgn, Rgn, RGN_DIFF);
|
|
DeleteObject(Rgn);
|
|
end;
|
|
|
|
begin
|
|
R := ARect;
|
|
for I := 0 to Node.ViewInfo.EndLevelCount - 1 do
|
|
with Parents[I] do
|
|
begin
|
|
if Node.HasFooter(I) then
|
|
begin
|
|
GetFooterParams(Node, nil, @ABrush, nil, nil, nil);
|
|
R2 := Node.SubFooterBounds[I];
|
|
Inc(R.Top, R2.Bottom - R2.Top);
|
|
DrawEdge(DC, R2, BDR_RAISEDINNER, BF_RECT);
|
|
InflateRect(R2, -1, -1);
|
|
RestRgn := CreateRectRgnIndirect(R2);
|
|
try
|
|
for J := 0 to VisibleColumnCount - 1 do
|
|
with VisibleColumns[J], R1 do
|
|
begin
|
|
R1 := GetFooterBounds(Node);
|
|
InflateRect(R1, -1, -1);
|
|
ExcludeRect(R1);
|
|
if (Left >= Right) or not RectVisible(DC, R1) then Continue;
|
|
if SummaryType = stNone then
|
|
FillRect(DC, R1, ABrush)
|
|
else
|
|
begin
|
|
FrameRect(DC, R1, ABrush);
|
|
InflateRect(R1, -1, -1);
|
|
DrawEdge(DC, R1, BDR_SUNKENOUTER, BF_RECT);
|
|
InflateRect(R1, -1, -1);
|
|
// draw summary's content
|
|
DrawFooter(DC, R1, Node);
|
|
end;
|
|
end;
|
|
finally
|
|
// fill in rest space
|
|
FillRgn(DC, RestRgn, ABrush);
|
|
DeleteObject(RestRgn);
|
|
// draw rest space
|
|
InflateRect(R2, 1, 1);
|
|
with R2 do
|
|
begin
|
|
Left := Right;
|
|
Right := FControl.ClientWidth;
|
|
FillRect(DC, R2, {Content}FControl.Brush.Handle);
|
|
end;
|
|
end;
|
|
end;
|
|
if Parent.Parent <> nil then
|
|
begin
|
|
J := R.Left;
|
|
if (I <> 0) or (Node.NodeType = ntData) then
|
|
Dec(J, (Byte(ShowCaption) + GroupColumnCount) * (LevelIndent + ExtLineWidth))
|
|
else
|
|
if Node.NodeType = ntGroup then
|
|
Dec(J, (Byte(ShowCaption) + Node.GroupIndex) * (LevelIndent + ExtLineWidth));
|
|
with Parent, R do
|
|
begin
|
|
if (LevelSeparatorWidth <> 0) and Node.HasLevelSeparator(I) then
|
|
begin
|
|
FillRect(DC,
|
|
Rect(J, Top, FControl.ClientWidth, Top + LevelSeparatorWidth),
|
|
LevelSeparatorBrush);
|
|
Inc(Top, LevelSeparatorWidth);
|
|
end;
|
|
if (RowSeparatorWidth <> 0) and Node.HasRowSeparator(I) then
|
|
begin
|
|
K := Indent + VisibleWidth - FControl.LeftPos{?!};
|
|
FillRect(DC,
|
|
Rect(J, Top, K, Top + RowSeparatorWidth), RowSeparatorBrush);
|
|
FillRect(DC,
|
|
Rect(K, Top, FControl.ClientWidth, Top + RowSeparatorWidth),
|
|
FControl.Brush.Handle);
|
|
Inc(Top, RowSeparatorWidth);
|
|
end;
|
|
Left := J - (LevelIndent + ExtLineWidth + LevelSeparatorWidth);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.EditingChanged;
|
|
begin
|
|
if (FDataLink.DataSet.State = dsEdit) {and CanSmartRefresh }then
|
|
FEditingNode := FControl.NodeFromID(Self, GetCurIDValue);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.FooterStyleChanged(Values: TdxMasterViewStyleValues);
|
|
var
|
|
Size: TSize;
|
|
H, I: Integer;
|
|
begin
|
|
if (Values = []) or (svFont in Values) then
|
|
begin
|
|
if VisibleColumnCount = 0 then
|
|
begin
|
|
CalcFontSize(FooterFont, Size);
|
|
H := Size.cy;
|
|
end
|
|
else
|
|
begin
|
|
H := 0;
|
|
for I := 0 to VisibleColumnCount - 1 do
|
|
begin
|
|
CalcFontSize(VisibleColumns[I].FooterFont, Size);
|
|
if Size.cy > H then H := Size.cy;
|
|
end;
|
|
end;
|
|
FFooterHeight := H + 2 + 2 * 3; // 21
|
|
end;
|
|
LevelChanged(False);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetCurDetailKeyValue: Variant;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
I := FDetailKeyFields.Count;
|
|
case I of
|
|
0: Result := Unassigned;
|
|
1: Result := TField(FDetailKeyFields[0]).Value;
|
|
else
|
|
Result := VarArrayCreate([0, I - 1], varVariant);
|
|
for I := 0 to I - 1 do
|
|
Result[I] := TField(FDetailKeyFields[I]).Value;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetCurIDValue: Variant;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
I := FIDFields.Count;
|
|
case I of
|
|
0: Result := Unassigned;
|
|
1: Result := TField(FIDFields[0]).Value;
|
|
else
|
|
Result := VarArrayCreate([0, I - 1], varVariant);
|
|
for I := 0 to I - 1 do
|
|
Result[I] := TField(FIDFields[I]).Value;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetCurKeyValue: Variant;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
I := FItems.Count;
|
|
if I = 0 then Result := Unassigned
|
|
else
|
|
begin
|
|
Result := VarArrayCreate([0, I - 1], varVariant);
|
|
for I := 0 to I - 1 do
|
|
Result[I] := TdxMasterViewLevel(FItems[I]).GetCurMasterKeyValue;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetCurMasterKeyValue: Variant;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
I := FMasterKeyFields.Count;
|
|
case I of
|
|
0: Result := Unassigned;
|
|
1: Result := TField(FMasterKeyFields[0]).Value;
|
|
else
|
|
Result := VarArrayCreate([0, I - 1], varVariant);
|
|
for I := 0 to I - 1 do
|
|
Result[I] := TField(FMasterKeyFields[I]).Value;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetCurPreviewText(Node: TdxMasterViewNode): string;
|
|
begin
|
|
if PreviewField = nil then Result := ''
|
|
else
|
|
begin
|
|
Result := PreviewField.AsString;
|
|
if (FPreviewMaxLength <> 0) and (Length(Result) > FPreviewMaxLength) then
|
|
Result := Copy(Result, 1, FPreviewMaxLength);
|
|
end;
|
|
if Assigned(FOnGetPreviewText) then FOnGetPreviewText(Self, Node, Result);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetParentNode(Root, Node: TdxMasterViewNode;
|
|
FirstIndex, AvailIndex: PInteger; RestItems: TList;
|
|
CheckRoot: Boolean): TdxMasterViewNode;
|
|
var
|
|
I, L, R, C, CResult, APos: Integer;
|
|
|
|
function CompareGroupValues(const Node: TdxMasterViewNode): Integer;
|
|
begin
|
|
GPNCurValue := Node.GroupValue;
|
|
GPNCurValueIsNull := VarIsNull(GPNCurValue);
|
|
if GPNFindingValueIsNull or GPNCurValueIsNull then
|
|
if GPNFindingValueIsNull and GPNCurValueIsNull then
|
|
Result := 0
|
|
else
|
|
if GPNFindingValueIsNull then
|
|
Result := 1
|
|
else
|
|
Result := -1
|
|
else
|
|
if VarType(GPNFindingValue) <> VarType(GPNCurValue) then
|
|
begin
|
|
Result := -1;
|
|
Exit;
|
|
end
|
|
else
|
|
begin
|
|
if GPNCanUseCaseInsensitiveGrouping then
|
|
GPNCurValue := VarAnsiUpperCase(GPNCurValue);
|
|
if GPNCanUseAnsiCompareStrOnGrouping then
|
|
begin
|
|
GPNS2 := GPNCurValue;
|
|
Result := CompareString(LOCALE_USER_DEFAULT, 0,
|
|
PChar(GPNS1), Length(GPNS1), PChar(GPNS2), Length(GPNS2)) - 2;
|
|
end
|
|
else
|
|
if GPNCurValue < GPNFindingValue then
|
|
Result := -1
|
|
else
|
|
if GPNCurValue = GPNFindingValue then
|
|
Result := 0
|
|
else
|
|
Result := 1;
|
|
end;
|
|
if GPNReverseOrder then Result := -Result;
|
|
end;
|
|
|
|
function NodeFromGroupValue(const Root: TdxMasterViewNode;
|
|
var AParentNode: TdxMasterViewNode): Integer;
|
|
begin
|
|
Result := 0;
|
|
if I = 0 then
|
|
begin
|
|
if FirstIndex = nil then
|
|
begin
|
|
AParentNode := Root.FirstInLevel[Self];
|
|
if AParentNode = nil then
|
|
begin
|
|
Result := Root.GetAvailIndex(Index);
|
|
Exit;
|
|
end;
|
|
L := AParentNode.Index;
|
|
end
|
|
else
|
|
L := FirstIndex^;
|
|
AParentNode := nil;
|
|
if AvailIndex = nil then
|
|
R := L + Root.CountInLevel[Self] - 1
|
|
else
|
|
R := AvailIndex^ - 1;
|
|
if L > R then
|
|
begin
|
|
Result := R + 1;
|
|
Exit;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
AParentNode := nil;
|
|
R := Root.FItems.Count - 1;
|
|
if R = -1 then Exit;
|
|
L := 0;
|
|
end;
|
|
|
|
while L <= R do
|
|
begin
|
|
C := (L + R) div 2;
|
|
CResult := CompareGroupValues(Root.FItems[C]);
|
|
case CResult of
|
|
0: begin
|
|
Result := C;
|
|
AParentNode := Root.FItems[C];
|
|
Exit;
|
|
end;
|
|
-1: L := C + 1;
|
|
1: R := C - 1;
|
|
end;
|
|
end;
|
|
Result := C;
|
|
if CResult = -1 then Inc(Result);
|
|
end;
|
|
|
|
procedure RemoveNodeFromRestItems(const Node: TdxMasterViewNode);
|
|
begin
|
|
R := RestItems.Count - 1;
|
|
if R = -1 then Exit;
|
|
L := 0;
|
|
while L <= R do
|
|
begin
|
|
C := (L + R) div 2;
|
|
CResult := Integer(Node) - Integer(RestItems.List^[C]);
|
|
if CResult = 0 then
|
|
begin
|
|
RestItems.Delete(C);
|
|
Break;
|
|
end
|
|
else
|
|
if CResult < 0 then
|
|
R := C - 1
|
|
else
|
|
L := C + 1;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if CheckRoot then
|
|
begin
|
|
if (Root = nil) or not Root.Expanded and SmartLoad then
|
|
begin
|
|
Result := nil;
|
|
Exit;
|
|
end
|
|
else
|
|
Result := Root;
|
|
if (Result.NodeType = ntData) and ShowCaption then
|
|
begin
|
|
Result := Result.FirstInLevel[Self];
|
|
if not Result.Expanded and SmartLoad then
|
|
begin
|
|
Result := nil;
|
|
Exit;
|
|
end
|
|
end;
|
|
end
|
|
else
|
|
Result := Root;
|
|
|
|
for I := 0 to FGroupColumns.Count - 1 do
|
|
begin
|
|
GPNCanUseAnsiCompareStrOnGrouping := False;
|
|
GPNCanUseCaseInsensitiveGrouping := False;
|
|
with TdxMasterViewColumn(FGroupColumns[I]) do
|
|
if {(Node = nil)!!! and} (Field = nil) then
|
|
begin
|
|
GPNGroupValue := Null;
|
|
GPNDisplayText := '';
|
|
GPNFindingValue := Null;
|
|
end
|
|
else
|
|
begin
|
|
if Node = nil then
|
|
begin
|
|
GPNGroupValue := Field.Value;
|
|
GPNDisplayText := Field.DisplayText;
|
|
end
|
|
else
|
|
begin
|
|
GPNGroupValue := Node.Values[Index];
|
|
GPNDisplayText := Node.Strings[Index];
|
|
end;
|
|
GPNFindingValue := GPNGroupValue;
|
|
if not VarIsNull(GPNFindingValue) and
|
|
(VarType(GPNFindingValue) = varString) then
|
|
begin
|
|
GPNCanUseAnsiCompareStrOnGrouping :=
|
|
mobAnsiCompareStrOnGrouping in FControl.OptionsBehavior;
|
|
GPNCanUseCaseInsensitiveGrouping :=
|
|
mobCaseInsensitiveGrouping in FControl.OptionsBehavior;
|
|
if GPNCanUseCaseInsensitiveGrouping then
|
|
GPNFindingValue := VarAnsiUpperCase(GPNFindingValue);
|
|
if GPNCanUseAnsiCompareStrOnGrouping then
|
|
GPNS1 := GPNFindingValue;
|
|
end;
|
|
end;
|
|
GPNFindingValueIsNull := VarIsNull(GPNFindingValue);
|
|
GPNReverseOrder :=
|
|
TdxMasterViewColumn(FGroupColumns[Result.GroupIndex + 1]).SortOrder = soDescending;
|
|
APos := NodeFromGroupValue(Result, GPNParentNode);
|
|
if GPNParentNode = nil then
|
|
begin
|
|
if (I = 0) and (AvailIndex <> nil) then
|
|
Inc(AvailIndex^);
|
|
with Result do
|
|
GPNParentNode := Add(Self, APos, ntGroup, GPNDisplayText, GPNGroupValue);
|
|
end
|
|
else
|
|
if RestItems <> nil then RemoveNodeFromRestItems(GPNParentNode);
|
|
Result := GPNParentNode;
|
|
end;
|
|
Result.CheckSummaries;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.GroupByBoxStyleChanged(Values: TdxMasterViewStyleValues);
|
|
var
|
|
Size: TSize;
|
|
begin
|
|
if (Values = []) or (svFont in Values) then
|
|
begin
|
|
CalcFontSize(GroupByBoxFont, Size);
|
|
FGroupByBoxTextHeight := Size.cy + 2 + 2 * 2; // 19
|
|
end;
|
|
if ShowGroupByBox then LevelChanged(False);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.GroupStyleChanged(Values: TdxMasterViewStyleValues);
|
|
var
|
|
Size: TSize;
|
|
begin
|
|
if (Values = []) or (svFont in Values) then
|
|
begin
|
|
CalcFontSize(GroupFont, Size);
|
|
FGroupHeight := Size.cy + 2 + 2; // 17 - without line
|
|
end;
|
|
if GroupColumnCount <> 0 then LevelChanged(False);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.HasExpandButton: Boolean;
|
|
begin
|
|
Result := HasChildren and (VisibleColumnCount <> 0);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.HasGrid: Boolean;
|
|
begin
|
|
Result := ShowGrid and (not ShowPreview or ShowGridWithPreview);
|
|
end;
|
|
{
|
|
function TdxMasterViewLevel.HasAsChild(Level: TdxMasterViewLevel): Boolean;
|
|
var
|
|
I: Integer;
|
|
ALevel: TdxMasterViewLevel;
|
|
begin
|
|
Result := False;
|
|
for I := AbsoluteIndex to FControl.AbsoluteLevelCount - 1 do
|
|
begin
|
|
ALevel := FControl.AbsoluteLevels[I];
|
|
if ALevel.Parent = Parent then Break;
|
|
if Level = ALevel then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
}
|
|
function TdxMasterViewLevel.HasAsParent(Level: TdxMasterViewLevel): Boolean;
|
|
var
|
|
ALevel: TdxMasterViewLevel;
|
|
begin
|
|
ALevel := Self;
|
|
while (ALevel <> nil) and (ALevel <> Level) do
|
|
ALevel := ALevel.Parent;
|
|
Result := ALevel <> nil;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.HeaderStyleChanged(Values: TdxMasterViewStyleValues);
|
|
var
|
|
Size: TSize;
|
|
H, I: Integer;
|
|
begin
|
|
if (Values = []) or (svFont in Values) then
|
|
begin
|
|
if VisibleColumnCount = 0 then
|
|
begin
|
|
CalcFontSize(HeaderFont, Size);
|
|
H := Size.cy;
|
|
end
|
|
else
|
|
begin
|
|
H := 0;
|
|
for I := 0 to VisibleColumnCount - 1 do
|
|
begin
|
|
CalcFontSize(VisibleColumns[I].HeaderFont, Size);
|
|
if Size.cy > H then H := Size.cy;
|
|
end;
|
|
end;
|
|
FHeaderHeight := H + 2 + 2 * 2; // 19
|
|
CalcRealHeights;
|
|
if ShowHeader then CalcDefaultWidths(nil);
|
|
end;
|
|
if ShowHeader then LevelChanged(False);
|
|
if GroupColumnCount <> 0 then
|
|
GroupByBoxStyleChanged(Values);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.IndexOfParent(Level: TdxMasterViewLevel): Integer;
|
|
begin
|
|
for Result := 0 to FParentCount - 1 do
|
|
if FParents[Result] = Level then Exit;
|
|
Result := -1;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.LayoutChanged;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
RefreshDetailKeyFieldsList;
|
|
RefreshIDFieldsList;
|
|
for I := 0 to Count - 1 do
|
|
Items[I].RefreshMasterKeyFieldsList;
|
|
SetPreviewFieldInternally(FindPreviewField);
|
|
|
|
for I := 0 to ColumnCount - 1 do
|
|
with Columns[I] do
|
|
begin
|
|
SetFieldInternally(FindField);
|
|
if cvSummaryFieldName in AssignedValues then
|
|
SetSummaryFieldInternally(FindSummaryField);
|
|
end;
|
|
|
|
CalcDefaultWidths(nil);
|
|
WidthChangedEx;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.LevelChanged(HardRefresh: Boolean);
|
|
var
|
|
PrevCursor: TCursor;
|
|
begin
|
|
if IsDestroying then Exit;
|
|
if FControl <> nil then
|
|
begin
|
|
if FControl.IsLoading then Exit;
|
|
if HardRefresh then
|
|
begin
|
|
if (FDataChangingLockCount <> 0) or (FControl.FLayoutLockCount <> 0) or
|
|
IsLoading or FControl.IsDestroying then Exit;
|
|
FControl.DoBeforeUpdateData(Self);
|
|
try
|
|
if FParent = nil then
|
|
if FControl.FItems <> nil then
|
|
with FControl do
|
|
begin
|
|
FItems.UpdateData(False, True, False);
|
|
CanUseSmartReload := True;
|
|
end
|
|
else
|
|
else
|
|
begin
|
|
PrevCursor := Screen.Cursor;
|
|
if FControl.ShowHourGlassCursor then Screen.Cursor := crHourGlass;
|
|
FControl.BeginTopNodeChange;
|
|
try
|
|
FControl.BeginUpdate;
|
|
try
|
|
BeginLoad;
|
|
try
|
|
FControl.FItems.UpdateDataForLevel(Self);
|
|
finally
|
|
EndLoad(True);
|
|
end;
|
|
finally
|
|
try
|
|
if not FControl.SyncMove then SyncPos;
|
|
finally
|
|
FControl.EndUpdate;
|
|
if FControl.SyncMove then SyncPos;
|
|
if FControl.ShowHourGlassCursor then Screen.Cursor := PrevCursor;
|
|
FCanUseSmartReload := True;
|
|
end;
|
|
end;
|
|
finally
|
|
FControl.EndTopNodeChange;
|
|
end;
|
|
end;
|
|
finally
|
|
FControl.DoAfterUpdateData(Self);
|
|
end;
|
|
end
|
|
else
|
|
FControl.Invalidate;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.LoadDataOnExpand: Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := True;
|
|
for I := 0 to Count - 1 do
|
|
if Items[I].SmartLoad then Exit;
|
|
Result := False;
|
|
end;
|
|
|
|
function MakeVisibleColumnsSortedListCompareHor(Column1, Column2: TdxMasterViewColumn): Integer;
|
|
begin
|
|
if Column1.FRowIndex < Column2.FRowIndex then
|
|
Result := -1
|
|
else
|
|
if Column1.FRowIndex > Column2.FRowIndex then
|
|
Result := 1
|
|
else
|
|
if Column1.FColIndex < Column2.FColIndex then
|
|
Result := -1
|
|
else
|
|
if Column1.FColIndex > Column2.FColIndex then
|
|
Result := 1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function MakeVisibleColumnsSortedListCompareVer(Column1, Column2: TdxMasterViewColumn): Integer;
|
|
begin
|
|
if Column1.FColIndex < Column2.FColIndex then
|
|
Result := -1
|
|
else
|
|
if Column1.FColIndex > Column2.FColIndex then
|
|
Result := 1
|
|
else
|
|
if Column1.FRowIndex < Column2.FRowIndex then
|
|
Result := -1
|
|
else
|
|
if Column1.FRowIndex > Column2.FRowIndex then
|
|
Result := 1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.MakeVisibleColumnsSortedList(List: TList);
|
|
begin
|
|
List.Count := VisibleColumnCount;
|
|
Move(FVisibleColumns.List^, List.List^, List.Count * SizeOf(Pointer));
|
|
if FHorizontal then
|
|
List.Sort(@MakeVisibleColumnsSortedListCompareHor)
|
|
else
|
|
List.Sort(@MakeVisibleColumnsSortedListCompareVer);
|
|
end;
|
|
{
|
|
function TdxMasterViewLevel.ParentIndex(Level: TdxMasterViewLevel): Integer;
|
|
var
|
|
ALevel: TdxMasterViewLevel;
|
|
begin
|
|
Result := 0;
|
|
ALevel := Self;
|
|
while (ALevel <> nil) and (ALevel <> Level) do
|
|
begin
|
|
Inc(Result);
|
|
ALevel := ALevel.Parent;
|
|
end;
|
|
if ALevel = nil then Result := -1;
|
|
end;
|
|
}
|
|
procedure TdxMasterViewLevel.PreviewChanged;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (FControl = nil) or not ShowPreview then Exit;
|
|
with FControl do
|
|
for I := 0 to AbsoluteItemCount - 1 do
|
|
AbsoluteItems[I].FViewInfo.PreviewSize := 0;
|
|
if not FControl.FPainting then LevelChanged(False);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.PreviewStyleChanged(Values: TdxMasterViewStyleValues);
|
|
begin
|
|
if (Values = []) or (svFont in Values) then
|
|
PreviewChanged
|
|
else
|
|
if ShowPreview then LevelChanged(False);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.RecordChanged(Field: TField);
|
|
begin
|
|
{ if not FControl.SyncMove or (FDataLink.DataSet.State = dsSetKey) then Exit;
|
|
if FInsertedNode <> nil then
|
|
with FInsertedNode do
|
|
begin
|
|
UpdateData(True, False, False);
|
|
Invalidate(nil, vpContent);
|
|
end;
|
|
if FEditingNode <> nil then
|
|
with FEditingNode do
|
|
begin
|
|
UpdateData(True, False, False);
|
|
Invalidate(nil, vpContent);
|
|
end;}
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.RemoveFreeSpace;
|
|
begin
|
|
FLayout.RemoveFreeSpace;
|
|
end;
|
|
|
|
type
|
|
PColumnPlace = ^TColumnPlace;
|
|
TColumnPlace = record
|
|
Column: TdxMasterViewColumn;
|
|
RowIndex, ColIndex, RowCount: Integer;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.RestoreVisibleColumnsPlaces(var List: TList);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FLayout.BeginUpdate;
|
|
try
|
|
for I := 0 to List.Count - 1 do
|
|
with PColumnPlace(List[I])^ do
|
|
begin
|
|
Column.RowIndex := RowIndex;
|
|
Column.ColIndex := ColIndex;
|
|
Column.RowCount := RowCount;
|
|
end;
|
|
finally
|
|
FLayout.EndUpdate;
|
|
FreeVisibleColumnsPlaces(List);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SaveVisibleColumnsPlaces(var List: TList);
|
|
var
|
|
I: Integer;
|
|
ColumnPlace: PColumnPlace;
|
|
begin
|
|
List := TList.Create;
|
|
MakeVisibleColumnsSortedList(List);
|
|
for I := 0 to List.Count - 1 do
|
|
begin
|
|
New(ColumnPlace);
|
|
ColumnPlace^.Column := List[I];
|
|
List[I] := ColumnPlace;
|
|
with ColumnPlace^ do
|
|
begin
|
|
RowIndex := Column.RowIndex;
|
|
ColIndex := Column.ColIndex;
|
|
RowCount := Column.RowCount;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.FreeVisibleColumnsPlaces(var List: TList);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to List.Count - 1 do
|
|
Dispose(PColumnPlace(List[I]));
|
|
List.Free;
|
|
List := nil;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.SyncPos;
|
|
var
|
|
I, AFreezeCount: Integer;
|
|
Value: Variant;
|
|
Node: TdxMasterViewNode;
|
|
Level: TdxMasterViewLevel;
|
|
{
|
|
ft,lt:integer;}
|
|
begin
|
|
if not FControl.SyncMove then
|
|
begin
|
|
if FControl.FocusedNode <> nil then
|
|
with FControl do
|
|
begin
|
|
FocusedNode.MakeVisible;
|
|
ShowFocusedNode;
|
|
end;
|
|
Exit;
|
|
end;
|
|
|
|
// ft:=gettickcount;
|
|
|
|
for I := 0 to ParentCount - 3 do
|
|
with Parents[I] do
|
|
if Active then
|
|
if DataSet = Parent.DataSet then
|
|
Continue
|
|
else
|
|
//if Parent.DataSet.Active then
|
|
begin
|
|
Value := GetCurDetailKeyValue;
|
|
if not VarAreEqual(GetCurMasterKeyValue, Value) then
|
|
begin
|
|
AFreezeCount := FControl.FreezeDataSet(Parent);
|
|
try
|
|
Parent.DataSet.Locate(MasterKey, Value, []);
|
|
finally
|
|
if Parent.DataLink.FreezeCount = AFreezeCount then
|
|
FControl.UnfreezeDataSet(Parent);
|
|
end;
|
|
end;
|
|
end
|
|
{else
|
|
Break}
|
|
else
|
|
Break;
|
|
|
|
Node := FControl.FItems;
|
|
for I := ParentCount - 2 downto 0 do
|
|
begin
|
|
Level := Parents[I];
|
|
Node := Node.NodeFromID(Level, Level.GetCurIDValue);
|
|
if Node = nil then
|
|
Break
|
|
else
|
|
begin
|
|
Node.MakeVisible;
|
|
if I = 0 then
|
|
with FControl do
|
|
begin
|
|
Freeze;
|
|
try
|
|
FocusNode(Node, True);
|
|
finally
|
|
Unfreeze;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// lt:=gettickcount;
|
|
// application.mainform.caption:=inttostr(lt-ft);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.UncheckTriedToExpand;
|
|
|
|
procedure ProcessOneNode(Node: TdxMasterViewNode);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
with Node do
|
|
if (NodeType = ntData) and (Level = Self) then
|
|
FTriedToExpand := False
|
|
else
|
|
begin
|
|
if ContainsDataInChildren(Self) then
|
|
FTriedToExpand := False;
|
|
if Self.HasAsParent(Level) then
|
|
for I := 0 to Count - 1 do
|
|
ProcessOneNode(Items[I]);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
ProcessOneNode(FControl.Items);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.WidthChanged;
|
|
var
|
|
AWidth: Integer;
|
|
begin
|
|
if (FAssignWidthsLockCount = 0) and not IsLoading and not IsDestroying then
|
|
begin
|
|
AWidth := VisibleWidth;
|
|
FLayout.CalcNeighbours;
|
|
if not FHorizontal then FLayout.CalcColWidths;
|
|
FControl.CalcScrollableWidth(Self);
|
|
FLayout.CheckColumnsWidths(nil);
|
|
if VisibleWidth <> AWidth then
|
|
begin
|
|
PreviewChanged;
|
|
if Assigned(FOnWidthChanged) then FOnWidthChanged(Self);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.WidthChangedEx;
|
|
begin
|
|
WidthChanged;
|
|
LevelChanged(False);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.Assign(Source: TPersistent);
|
|
var
|
|
ALevel: TdxMasterViewLevel;
|
|
I: Integer;
|
|
begin
|
|
if Source is TdxMasterViewLevel then
|
|
begin
|
|
ALevel := TdxMasterViewLevel(Source);
|
|
|
|
BeginLoading;
|
|
try
|
|
DestroyColumns;
|
|
|
|
Caption := ALevel.Caption;
|
|
CaptionStyle := ALevel.CaptionStyle;
|
|
ContentStyle := ALevel.ContentStyle;
|
|
DataSource := ALevel.DataSource;
|
|
DeleteConfirmCaptionText := ALevel.DeleteConfirmCaptionText;
|
|
DeleteConfirmText := ALevel.DeleteConfirmText;
|
|
DetailKey := ALevel.DetailKey;
|
|
FooterStyle := ALevel.FooterStyle;
|
|
GridLinesColor := ALevel.GridLinesColor;
|
|
GroupByBoxStyle := ALevel.GroupByBoxStyle;
|
|
GroupStyle := ALevel.GroupStyle;
|
|
HeaderStyle := ALevel.HeaderStyle;
|
|
ID := ALevel.ID;
|
|
LevelSeparatorColor := ALevel.LevelSeparatorColor;
|
|
LevelSeparatorWidth := ALevel.LevelSeparatorWidth;
|
|
MasterKey := ALevel.MasterKey;
|
|
MultipleDeleteConfirmText := ALevel.MultipleDeleteConfirmText;
|
|
OptionsBehavior := ALevel.OptionsBehavior;
|
|
OptionsCustomize := ALevel.OptionsCustomize;
|
|
OptionsDB := ALevel.OptionsDB;
|
|
OptionsHeader := ALevel.OptionsHeader;
|
|
OptionsView := ALevel.OptionsView;
|
|
PreviewFieldName := ALevel.PreviewFieldName;
|
|
PreviewLeftIndent := ALevel.PreviewLeftIndent;
|
|
PreviewLineCount := ALevel.PreviewLineCount;
|
|
PreviewMaxLength := ALevel.PreviewMaxLength;
|
|
PreviewMaxLineCount := ALevel.PreviewMaxLineCount;
|
|
PreviewRightIndent := ALevel.PreviewRightIndent;
|
|
PreviewStyle := ALevel.PreviewStyle;
|
|
RowSeparatorColor := ALevel.RowSeparatorColor;
|
|
RowSeparatorWidth := ALevel.RowSeparatorWidth;
|
|
ViewMode := ALevel.ViewMode;
|
|
if not FHorizontal then
|
|
begin
|
|
FLayout.Count := ALevel.Layout.Count;
|
|
for I := 0 to ALevel.Layout.Count - 1 do
|
|
if ALevel.Layout.HeaderWidthAssigned[I] then
|
|
FLayout.HeaderWidths[I] := ALevel.Layout.HeaderWidths[I];
|
|
end;
|
|
|
|
for I := 0 to ALevel.ColumnCount - 1 do
|
|
CreateColumn(TdxMasterViewColumnClass(ALevel.Columns[I].ClassType)).Assign(ALevel.Columns[I]);
|
|
finally
|
|
EndLoading;
|
|
end;
|
|
end
|
|
else
|
|
inherited;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.GetParentComponent: TComponent;
|
|
begin
|
|
if IsTop then
|
|
Result := FControl
|
|
else
|
|
Result := FParent;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.HasParent: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.Add: TdxMasterViewLevel;
|
|
begin
|
|
if ParentCount = 1 + 16 then Result := nil // due to <Node>.ViewInfo.EndLevelData
|
|
else
|
|
begin
|
|
Result := TdxMasterViewLevel.Create(FControl.Owner);
|
|
AddItem(Result);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.BeginAssignWidths;
|
|
begin
|
|
Inc(FAssignWidthsLockCount);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.BeginDataChanging;
|
|
begin
|
|
Inc(FDataChangingLockCount);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.BeginLayout;
|
|
begin
|
|
BeginAssignWidths;
|
|
FLayout.BeginUpdate;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.BeginSorting;
|
|
begin
|
|
Inc(FSortingLockCount);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.CancelAssignWidths;
|
|
begin
|
|
if FAssignWidthsLockCount > 0 then
|
|
begin
|
|
Dec(FAssignWidthsLockCount);
|
|
{if FAssignWidthsLockCount = 0 then
|
|
FLayout.CheckColumnsWidths;}
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.CancelDataChanging;
|
|
begin
|
|
if FDataChangingLockCount > 0 then
|
|
begin
|
|
Dec(FDataChangingLockCount);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.CancelLayout;
|
|
begin
|
|
FLayout.CancelUpdate;
|
|
CancelAssignWidths;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.CancelSorting;
|
|
begin
|
|
if FSortingLockCount > 0 then
|
|
begin
|
|
Dec(FSortingLockCount);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.Clear;
|
|
begin
|
|
if Count = 0 then Exit;
|
|
if (FControl <> nil) and (FParent <> nil) then FControl.BeginLayout;
|
|
try
|
|
while Count <> 0 do Items[0].Free;
|
|
finally
|
|
if (FControl <> nil) and (FParent <> nil) then FControl.EndLayout;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.ClearSorting(ExceptionalColumn: TdxMasterViewColumn);
|
|
begin
|
|
ChangeSorting(ExceptionalColumn, soNone, -2);
|
|
end;
|
|
|
|
function TdxMasterViewLevel.ColumnByFieldName(const AFieldName: string): TdxMasterViewColumn;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to ColumnCount - 1 do
|
|
begin
|
|
Result := Columns[I];
|
|
if AnsiCompareText(Result.FieldName, AFieldName) = 0 then Exit;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.ColumnByName(const AName: string): TdxMasterViewColumn;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to ColumnCount - 1 do
|
|
begin
|
|
Result := Columns[I];
|
|
if CompareText(Result.Name, AName) = 0 then Exit;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.CreateAllColumns;
|
|
var
|
|
PrevCursor: TCursor;
|
|
I: Integer;
|
|
|
|
function GetValidName(const S: string): string;
|
|
const
|
|
ValidChars = ['A'..'Z', 'a'..'z', '_', '0'..'9'];
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := '';
|
|
for I := 1 to Length(S) do
|
|
if S[I] in ValidChars then Result := Result + S[I];
|
|
end;
|
|
|
|
begin
|
|
if DataSet = nil then Exit;
|
|
PrevCursor := Screen.Cursor;
|
|
if FControl.ShowHourGlassCursor then Screen.Cursor := crHourglass;
|
|
try
|
|
FControl.BeginLayout;
|
|
try
|
|
BeginLayout;
|
|
try
|
|
with DataSet do
|
|
for I := 0 to FieldCount - 1 do
|
|
with CreateColumn(TdxMasterViewColumn) do
|
|
begin
|
|
FieldName := Fields[I].FieldName;
|
|
Visible := Fields[I].Visible;
|
|
try
|
|
Name := Self.Name + GetValidName(FieldName);
|
|
except
|
|
on EComponentError do
|
|
if FControl.IsDesigning then
|
|
Name := dxMVDesigner.UniqueName(FControl, Self.Name + 'Column');
|
|
end;
|
|
end;
|
|
finally
|
|
EndLayout;
|
|
end;
|
|
finally
|
|
FControl.EndLayout;
|
|
end;
|
|
finally
|
|
Screen.Cursor := PrevCursor;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewLevel.CreateColumn(AColumnClass: TdxMasterViewColumnClass): TdxMasterViewColumn;
|
|
begin
|
|
Result := AColumnClass.Create(Owner);
|
|
AddColumn(Result);
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.DestroyColumns;
|
|
var
|
|
LockControlLayout, LockSorting: Boolean;
|
|
begin
|
|
if ColumnCount = 0 then Exit;
|
|
LockControlLayout := GroupColumnCount <> 0;
|
|
LockSorting := SortedColumnCount <> 0;
|
|
if LockControlLayout then FControl.BeginLayout;
|
|
try
|
|
if LockSorting then BeginSorting;
|
|
try
|
|
BeginLayout;
|
|
try
|
|
while ColumnCount <> 0 do Columns[0].Free;
|
|
finally
|
|
EndLayout;
|
|
end;
|
|
finally
|
|
if LockSorting then EndSorting;
|
|
end;
|
|
finally
|
|
if LockControlLayout then FControl.EndLayout;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.EndAssignWidths;
|
|
begin
|
|
if FAssignWidthsLockCount > 0 then
|
|
begin
|
|
Dec(FAssignWidthsLockCount);
|
|
if FAssignWidthsLockCount = 0 then WidthChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.EndDataChanging;
|
|
begin
|
|
if FDataChangingLockCount > 0 then
|
|
begin
|
|
Dec(FDataChangingLockCount);
|
|
if FDataChangingLockCount = 0 then LevelChanged(True);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.EndLayout;
|
|
begin
|
|
FLayout.EndUpdate;
|
|
EndAssignWidths;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.EndSorting;
|
|
begin
|
|
if FSortingLockCount > 0 then
|
|
begin
|
|
Dec(FSortingLockCount);
|
|
if FSortingLockCount = 0 then DoSorting;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.GetContentParams(Node: TdxMasterViewNode;
|
|
Column: TdxMasterViewColumn; ABrush: PBRUSH; ATextColor, ABkColor: PColor;
|
|
AFont: PFont; CheckSelected: Boolean);
|
|
var
|
|
NewStyle: TdxMasterViewStyle;
|
|
IsOdd: Boolean;
|
|
begin
|
|
NewStyle := nil;
|
|
case Node.NodeType of
|
|
ntData:
|
|
begin
|
|
DoGetContentStyle(Node, Column, NewStyle);
|
|
if Column <> nil then
|
|
with Column do
|
|
if Assigned(FOnGetContentStyle) then FOnGetContentStyle(Column, Node, NewStyle);
|
|
end;
|
|
ntCaption:
|
|
if Assigned(FOnGetCaptionStyle) then FOnGetCaptionStyle(Self, Node, nil, NewStyle);
|
|
ntGroup:
|
|
if Assigned(FOnGetGroupStyle) then FOnGetGroupStyle(Self, Node, nil, NewStyle);
|
|
end;
|
|
|
|
if not CheckSelected or
|
|
not FControl.GetSelectionParams(Node, ABrush, ATextColor, ABkColor) then
|
|
begin
|
|
IsOdd := Odd(Node.Index) and (Node.NodeType = ntData);
|
|
|
|
if ABrush <> nil then
|
|
if (NewStyle <> nil) and IsOdd and (svAnotherColor in NewStyle.AssignedValues) then
|
|
ABrush^ := NewStyle.AnotherBrush
|
|
else
|
|
if (NewStyle <> nil) and (svColor in NewStyle.AssignedValues) then
|
|
ABrush^ := NewStyle.Brush
|
|
else
|
|
case Node.NodeType of
|
|
ntData:
|
|
if Column = nil then
|
|
if IsOdd then
|
|
begin
|
|
ABrush^ := ContentAnotherBrush;
|
|
if ABrush^ = 0 then ABrush^ := ContentBrush;
|
|
end
|
|
else
|
|
ABrush^ := ContentBrush
|
|
else
|
|
if IsOdd then
|
|
begin
|
|
ABrush^ := Column.ContentAnotherBrush;
|
|
if ABrush^ = 0 then ABrush^ := Column.ContentBrush;
|
|
end
|
|
else
|
|
ABrush^ := Column.ContentBrush;
|
|
ntCaption:
|
|
ABrush^ := CaptionBrush;
|
|
ntGroup:
|
|
ABrush^ := GroupBrush;
|
|
end;
|
|
if ATextColor <> nil then
|
|
if (NewStyle <> nil) and (svFont in NewStyle.AssignedValues) then
|
|
ATextColor^ := NewStyle.Font.Color
|
|
else
|
|
case Node.NodeType of
|
|
ntData:
|
|
ATextColor^ := Column.ContentFont.Color;
|
|
ntCaption:
|
|
ATextColor^ := CaptionFont.Color;
|
|
ntGroup:
|
|
ATextColor^ := GroupFont.Color;
|
|
end;
|
|
if ABkColor <> nil then
|
|
if (NewStyle <> nil) and IsOdd and (svAnotherColor in NewStyle.AssignedValues) then
|
|
ABkColor^ := NewStyle.AnotherColor
|
|
else
|
|
if (NewStyle <> nil) and (svColor in NewStyle.AssignedValues) then
|
|
ABkColor^ := NewStyle.Color
|
|
else
|
|
case Node.NodeType of
|
|
ntData:
|
|
if IsOdd then
|
|
begin
|
|
ABkColor^ := Column.ContentAnotherColor;
|
|
if ABkColor^ = clNone then ABkColor^ := Column.ContentColor;
|
|
end
|
|
else
|
|
ABkColor^ := Column.ContentColor;
|
|
ntCaption:
|
|
ABkColor^ := CaptionColor;
|
|
ntGroup:
|
|
ABkColor^ := GroupColor;
|
|
end;
|
|
end;
|
|
if AFont <> nil then
|
|
if (NewStyle <> nil) and (svFont in NewStyle.AssignedValues) then
|
|
AFont^ := NewStyle.Font
|
|
else
|
|
case Node.NodeType of
|
|
ntData:
|
|
AFont^ := Column.ContentFont;
|
|
ntCaption:
|
|
AFont^ := CaptionFont;
|
|
ntGroup:
|
|
AFont^ := GroupFont;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.GetFooterParams(Node: TdxMasterViewNode;
|
|
Column: TdxMasterViewColumn; ABrush: PBRUSH; ATextColor, ABkColor: PColor;
|
|
AFont: PFont);
|
|
var
|
|
NewStyle: TdxMasterViewStyle;
|
|
begin
|
|
NewStyle := nil;
|
|
if Assigned(FOnGetFooterStyle) then FOnGetFooterStyle(Self, Node, Column, NewStyle);
|
|
if Column <> nil then
|
|
with Column do
|
|
if Assigned(FOnGetFooterStyle) then FOnGetFooterStyle(Column, Node, NewStyle);
|
|
|
|
if ABrush <> nil then
|
|
if (NewStyle <> nil) and (svColor in NewStyle.AssignedValues) then
|
|
ABrush^ := NewStyle.Brush
|
|
else
|
|
if Column = nil then
|
|
ABrush^ := FooterBrush
|
|
else
|
|
ABrush^ := Column.FooterBrush;
|
|
if ATextColor <> nil then
|
|
if (NewStyle <> nil) and (svFont in NewStyle.AssignedValues) then
|
|
ATextColor^ := NewStyle.Font.Color
|
|
else
|
|
ATextColor^ := Column.FooterFont.Color;
|
|
if ABkColor <> nil then
|
|
if (NewStyle <> nil) and (svColor in NewStyle.AssignedValues) then
|
|
ABkColor^ := NewStyle.Color
|
|
else
|
|
ABkColor^ := Column.FooterColor;
|
|
if AFont <> nil then
|
|
if (NewStyle <> nil) and (svFont in NewStyle.AssignedValues) then
|
|
AFont^ := NewStyle.Font
|
|
else
|
|
AFont^ := Column.FooterFont;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.GetGroupByBoxParams(Node: TdxMasterViewNode;
|
|
ABrush: PBRUSH; ATextColor, ABkColor: PColor; AFont: PFont);
|
|
var
|
|
NewStyle: TdxMasterViewStyle;
|
|
begin
|
|
NewStyle := nil;
|
|
if Assigned(FOnGetGroupByBoxStyle) then FOnGetGroupByBoxStyle(Self, Node, nil, NewStyle);
|
|
|
|
if ABrush <> nil then
|
|
if (NewStyle <> nil) and (svColor in NewStyle.AssignedValues) then
|
|
ABrush^ := NewStyle.Brush
|
|
else
|
|
ABrush^ := GroupByBoxBrush;
|
|
if ATextColor <> nil then
|
|
if (NewStyle <> nil) and (svFont in NewStyle.AssignedValues) then
|
|
ATextColor^ := NewStyle.Font.Color
|
|
else
|
|
ATextColor^ := GroupByBoxFontColor;
|
|
if ABkColor <> nil then
|
|
if (NewStyle <> nil) and (svColor in NewStyle.AssignedValues) then
|
|
ABkColor^ := NewStyle.Color
|
|
else
|
|
ABkColor^ := GroupByBoxColor;
|
|
if AFont <> nil then
|
|
if (NewStyle <> nil) and (svFont in NewStyle.AssignedValues) then
|
|
AFont^ := NewStyle.Font
|
|
else
|
|
AFont^ := GroupByBoxFont;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.GetHeaderParams(Node: TdxMasterViewNode;
|
|
Column: TdxMasterViewColumn; ABrush, ARestSpaceBrush: PBRUSH;
|
|
ATextColor, ABkColor: PColor; AFont: PFont);
|
|
var
|
|
NewStyle: TdxMasterViewStyle;
|
|
begin
|
|
NewStyle := nil;
|
|
if Assigned(FOnGetHeaderStyle) then FOnGetHeaderStyle(Self, Node, Column, NewStyle);
|
|
if Column <> nil then
|
|
with Column do
|
|
if Assigned(FOnGetHeaderStyle) then FOnGetHeaderStyle(Column, Node, NewStyle);
|
|
|
|
if ABrush <> nil then
|
|
if (NewStyle <> nil) and (svColor in NewStyle.AssignedValues) then
|
|
ABrush^ := NewStyle.Brush
|
|
else
|
|
ABrush^ := Column.HeaderBrush;
|
|
if ARestSpaceBrush <> nil then
|
|
if (NewStyle <> nil) and (svAnotherColor in NewStyle.AssignedValues) then
|
|
ARestSpaceBrush^ := NewStyle.AnotherBrush
|
|
else
|
|
ARestSpaceBrush^ := HeaderRestSpaceBrush;
|
|
if ATextColor <> nil then
|
|
if (NewStyle <> nil) and (svFont in NewStyle.AssignedValues) then
|
|
ATextColor^ := NewStyle.Font.Color
|
|
else
|
|
ATextColor^ := Column.HeaderFont.Color;
|
|
if ABkColor <> nil then
|
|
if (NewStyle <> nil) and (svColor in NewStyle.AssignedValues) then
|
|
ABkColor^ := NewStyle.Color
|
|
else
|
|
ABkColor^ := Column.HeaderColor;
|
|
if AFont <> nil then
|
|
if (NewStyle <> nil) and (svFont in NewStyle.AssignedValues) then
|
|
AFont^ := NewStyle.Font
|
|
else
|
|
AFont^ := Column.HeaderFont;
|
|
end;
|
|
|
|
procedure TdxMasterViewLevel.GetPreviewParams(Node: TdxMasterViewNode;
|
|
ABrush: PBRUSH; ATextColor, ABkColor: PColor; AFont: PFont);
|
|
var
|
|
NewStyle: TdxMasterViewStyle;
|
|
IsOdd: Boolean;
|
|
begin
|
|
NewStyle := nil;
|
|
DoGetContentStyle(Node, nil, NewStyle);
|
|
if Assigned(FOnGetPreviewStyle) then FOnGetPreviewStyle(Self, Node, nil, NewStyle);
|
|
|
|
if not FControl.GetSelectionParams(Node, ABrush, ATextColor, ABkColor) then
|
|
begin
|
|
IsOdd := Odd(Node.Index) and (Node.NodeType = ntData);
|
|
if ABrush <> nil then
|
|
if (NewStyle <> nil) and IsOdd and (svAnotherColor in NewStyle.AssignedValues) then
|
|
ABrush^ := NewStyle.AnotherBrush
|
|
else
|
|
if (NewStyle <> nil) and (svColor in NewStyle.AssignedValues) then
|
|
ABrush^ := NewStyle.Brush
|
|
else
|
|
if IsOdd then
|
|
begin
|
|
ABrush^ := PreviewAnotherBrush;
|
|
if ABrush^ = 0 then ABrush^ := PreviewBrush;
|
|
end
|
|
else
|
|
ABrush^ := PreviewBrush;
|
|
if ATextColor <> nil then
|
|
if (NewStyle <> nil) and (svFont in NewStyle.AssignedValues) then
|
|
ATextColor^ := NewStyle.Font.Color
|
|
else
|
|
ATextColor^ := PreviewFontColor;
|
|
if ABkColor <> nil then
|
|
if (NewStyle <> nil) and IsOdd and (svAnotherColor in NewStyle.AssignedValues) then
|
|
ABkColor^ := NewStyle.AnotherColor
|
|
else
|
|
if (NewStyle <> nil) and (svColor in NewStyle.AssignedValues) then
|
|
ABkColor^ := NewStyle.Color
|
|
else
|
|
if IsOdd then
|
|
begin
|
|
ABkColor^ := PreviewAnotherColor;
|
|
if ABkColor^ = clNone then ABkColor^ := PreviewColor;
|
|
end
|
|
else
|
|
ABkColor^ := PreviewColor;
|
|
end;
|
|
if AFont <> nil then
|
|
if (NewStyle <> nil) and (svFont in NewStyle.AssignedValues) then
|
|
AFont^ := NewStyle.Font
|
|
else
|
|
AFont^ := PreviewFont;
|
|
end;
|
|
|
|
{ TdxMasterViewList }
|
|
|
|
constructor TdxMasterViewList.Create(AOwner: TdxMasterViewNode;
|
|
AMode: TdxMasterViewListMode);
|
|
begin
|
|
FOwner := AOwner;
|
|
FMode := AMode;
|
|
end;
|
|
|
|
destructor TdxMasterViewList.Destroy;
|
|
begin
|
|
Clear;
|
|
inherited;
|
|
end;
|
|
|
|
function TdxMasterViewList.Get(Index: Integer): TdxMasterViewNode;
|
|
begin
|
|
if (Index < 0) or (Index >= FCount) then
|
|
Error(SListIndexError, Index);
|
|
Result := FList^[Index];
|
|
end;
|
|
|
|
procedure TdxMasterViewList.Put(Index: Integer; Item: TdxMasterViewNode);
|
|
begin
|
|
if (Index < 0) or (Index >= FCount) then
|
|
Error(SListIndexError, Index);
|
|
FList^[Index] := Item;
|
|
end;
|
|
|
|
procedure TdxMasterViewList.SetCapacity(NewCapacity: Integer);
|
|
begin
|
|
if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
|
|
Error(SListCapacityError, NewCapacity);
|
|
if NewCapacity <> FCapacity then
|
|
begin
|
|
ReallocMem(FList, NewCapacity * SizeOf(Pointer));
|
|
FCapacity := NewCapacity;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewList.SetCount(NewCount: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (NewCount < 0) or (NewCount > MaxListSize) then
|
|
Error(SListCountError, NewCount);
|
|
if NewCount > FCapacity then SetCapacity(NewCount);
|
|
if NewCount > FCount then
|
|
FillChar(FList^[FCount], (NewCount - FCount) * SizeOf(Pointer), 0)
|
|
else
|
|
for I := FCount - 1 downto NewCount do Delete(I);
|
|
FCount := NewCount;
|
|
end;
|
|
|
|
procedure TdxMasterViewList.Grow;
|
|
var
|
|
Delta: Integer;
|
|
begin
|
|
if FCapacity > 64 then
|
|
Delta := FCapacity div 4
|
|
else
|
|
if FCapacity > 8 then
|
|
Delta := 16
|
|
else
|
|
Delta := 4;
|
|
SetCapacity(FCapacity + Delta);
|
|
end;
|
|
|
|
function TdxMasterViewList.Add(Item: TdxMasterViewNode): Integer;
|
|
begin
|
|
Result := FCount;
|
|
if Result = FCapacity then Grow;
|
|
FList^[Result] := Item;
|
|
case FMode of
|
|
lmItems:
|
|
Item.FIndex := Result;
|
|
lmAbsoluteItems:
|
|
Item.FAbsoluteIndex := Result;
|
|
lmSelectedItems:
|
|
Item.FSelectedIndex := Result;
|
|
end;
|
|
Inc(FCount);
|
|
end;
|
|
|
|
procedure TdxMasterViewList.BeginDeletion;
|
|
begin
|
|
if FMode = lmSelectedItems then
|
|
FOwner.Control.BeginSelection;
|
|
if FDeletionLockCount = 0 then
|
|
FNewCount := FCount;
|
|
Inc(FDeletionLockCount);
|
|
end;
|
|
|
|
procedure TdxMasterViewList.BeginInsertion;
|
|
begin
|
|
if FInsertionLockCount = 0 then
|
|
FPrevCount := FCount;
|
|
Inc(FInsertionLockCount);
|
|
end;
|
|
|
|
procedure TdxMasterViewList.Clear;
|
|
begin
|
|
SetCount(0);
|
|
SetCapacity(0);
|
|
end;
|
|
|
|
procedure TdxMasterViewList.CopyTo(List: TList);
|
|
begin
|
|
List.Count := FCount;
|
|
System.Move(FList^, List.List^, FCount * SizeOf(Pointer));
|
|
end;
|
|
|
|
procedure TdxMasterViewList.Delete(Index: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (Index < 0) or (Index >= FCount) then
|
|
Error(SListIndexError, Index);
|
|
if FList^[Index] = nil then Exit;
|
|
case FMode of
|
|
lmItems:
|
|
FList^[Index].FIndex := -1;
|
|
lmAbsoluteItems:
|
|
FList^[Index].FAbsoluteIndex := -1;
|
|
lmSelectedItems:
|
|
FList^[Index].FSelectedIndex := -1;
|
|
end;
|
|
FList^[Index] := nil;
|
|
if FDeletionLockCount = 0 then
|
|
begin
|
|
Dec(FCount);
|
|
if Index < FCount then
|
|
begin
|
|
System.Move(FList^[Index + 1], FList^[Index],
|
|
(FCount - Index) * SizeOf(Pointer));
|
|
for I := Index to FCount - 1 do
|
|
case FMode of
|
|
lmItems:
|
|
Dec(FList^[I].FIndex);
|
|
lmAbsoluteItems:
|
|
Dec(FList^[I].FAbsoluteIndex);
|
|
lmSelectedItems:
|
|
Dec(FList^[I].FSelectedIndex);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
Dec(FNewCount);
|
|
end;
|
|
|
|
procedure TdxMasterViewList.EndDeletion;
|
|
var
|
|
I, J: Integer;
|
|
NewList: PdxMasterViewNodeList;
|
|
begin
|
|
if FDeletionLockCount <> 0 then
|
|
begin
|
|
Dec(FDeletionLockCount);
|
|
if (FDeletionLockCount = 0) and (FCount <> FNewCount) then
|
|
begin
|
|
if FNewCount = 0 then NewList := nil
|
|
else
|
|
begin
|
|
GetMem(NewList, FNewCount * SizeOf(Pointer));
|
|
J := 0;
|
|
for I := 0 to FCount - 1 do
|
|
if FList^[I] <> nil then
|
|
begin
|
|
NewList^[J] := FList^[I];
|
|
case FMode of
|
|
lmItems:
|
|
NewList^[J].FIndex := J;
|
|
lmAbsoluteItems:
|
|
NewList^[J].FAbsoluteIndex := J;
|
|
lmSelectedItems:
|
|
NewList^[J].FSelectedIndex := J;
|
|
end;
|
|
Inc(J);
|
|
end;
|
|
end;
|
|
if FList <> nil then FreeMem(FList);
|
|
FCapacity := FNewCount;
|
|
FCount := FNewCount;
|
|
FList := NewList;
|
|
if (FCount = 0) and (FMode = lmItems) then FOwner.CheckExpanded;
|
|
end;
|
|
end;
|
|
if FMode = lmSelectedItems then
|
|
FOwner.Control.EndSelection;
|
|
end;
|
|
|
|
procedure TdxMasterViewList.EndInsertion;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if FInsertionLockCount <> 0 then
|
|
begin
|
|
Dec(FInsertionLockCount);
|
|
if (FInsertionLockCount = 0) and (FCount <> FPrevCount) then
|
|
for I := 0 to FCount - 1 do
|
|
case FMode of
|
|
lmItems:
|
|
FList^[I].FIndex := I;
|
|
lmAbsoluteItems:
|
|
FList^[I].FAbsoluteIndex := I;
|
|
lmSelectedItems:
|
|
FList^[I].FSelectedIndex := I;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
class procedure TdxMasterViewList.Error(const Msg: string; Data: Integer);
|
|
|
|
function ReturnAddr: Pointer;
|
|
asm
|
|
MOV EAX,[EBP+4]
|
|
end;
|
|
|
|
begin
|
|
raise EListError.CreateFmt(Msg, [Data]) at ReturnAddr;
|
|
end;
|
|
|
|
function TdxMasterViewList.First: TdxMasterViewNode;
|
|
begin
|
|
Result := Get(0);
|
|
end;
|
|
|
|
function TdxMasterViewList.IndexOf(Item: TdxMasterViewNode): Integer;
|
|
begin
|
|
case FMode of
|
|
lmItems: Result := Item.FIndex;
|
|
lmAbsoluteItems: Result := Item.FAbsoluteIndex;
|
|
lmSelectedItems: Result := Item.FSelectedIndex;
|
|
else
|
|
Result := -1;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewList.Insert(Index: Integer; Item: TdxMasterViewNode);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (Index < 0) or (Index > FCount) then
|
|
Error(SListIndexError, Index);
|
|
if FCount = FCapacity then Grow;
|
|
if Index < FCount then
|
|
begin
|
|
if FInsertionLockCount = 0 then
|
|
for I := Index to FCount - 1 do
|
|
case FMode of
|
|
lmItems:
|
|
Inc(FList^[I].FIndex);
|
|
lmAbsoluteItems:
|
|
Inc(FList^[I].FAbsoluteIndex);
|
|
lmSelectedItems:
|
|
Inc(FList^[I].FSelectedIndex);
|
|
end;
|
|
System.Move(FList^[Index], FList^[Index + 1],
|
|
(FCount - Index) * SizeOf(Pointer));
|
|
end;
|
|
FList^[Index] := Item;
|
|
case FMode of
|
|
lmItems: Item.FIndex := Index;
|
|
lmAbsoluteItems: Item.FAbsoluteIndex := Index;
|
|
lmSelectedItems: Item.FSelectedIndex := Index;
|
|
end;
|
|
Inc(FCount);
|
|
end;
|
|
|
|
function TdxMasterViewList.Last: TdxMasterViewNode;
|
|
begin
|
|
Result := Get(FCount - 1);
|
|
end;
|
|
|
|
procedure TdxMasterViewList.Move(CurIndex, NewIndex: Integer);
|
|
var
|
|
Item: Pointer;
|
|
begin
|
|
if CurIndex <> NewIndex then
|
|
begin
|
|
if (NewIndex < 0) or (NewIndex >= FCount) then
|
|
Error(SListIndexError, NewIndex);
|
|
Item := Get(CurIndex);
|
|
Delete(CurIndex);
|
|
Insert(NewIndex, Item);
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewList.Remove(Item: TdxMasterViewNode): Integer;
|
|
begin
|
|
Result := IndexOf(Item);
|
|
if Result <> -1 then Delete(Result);
|
|
end;
|
|
|
|
procedure QuickSort(SortList: PdxMasterViewNodeList; L, R: Integer;
|
|
SCompare: TdxMasterViewListSortCompare);
|
|
var
|
|
I, J: Integer;
|
|
P, T: Pointer;
|
|
begin
|
|
repeat
|
|
I := L;
|
|
J := R;
|
|
P := SortList^[(L + R) shr 1];
|
|
repeat
|
|
while SCompare(SortList^[I], P) < 0 do
|
|
Inc(I);
|
|
while SCompare(SortList^[J], P) > 0 do
|
|
Dec(J);
|
|
if I <= J then
|
|
begin
|
|
T := SortList^[I];
|
|
SortList^[I] := SortList^[J];
|
|
SortList^[J] := T;
|
|
Inc(I);
|
|
Dec(J);
|
|
end;
|
|
until I > J;
|
|
if L < J then
|
|
QuickSort(SortList, L, J, SCompare);
|
|
L := I;
|
|
until I >= R;
|
|
end;
|
|
|
|
procedure TdxMasterViewList.Sort(Compare: TdxMasterViewListSortCompare;
|
|
TopBound, BottomBound: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (FList <> nil) and (FCount > 0) then
|
|
begin
|
|
QuickSort(FList, TopBound, BottomBound, Compare);
|
|
for I := TopBound to BottomBound do
|
|
with FList^[I] do
|
|
case FMode of
|
|
lmItems: FIndex := I;
|
|
lmAbsoluteItems: FAbsoluteIndex := I;
|
|
lmSelectedItems: FSelectedIndex := I;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TdxMasterViewNode }
|
|
|
|
constructor TdxMasterViewNode.Create(AControl: TdxMasterView; ALevel: TdxMasterViewLevel;
|
|
AParentNode: TdxMasterViewNode; AIndex: Integer; ANodeType: TdxMasterViewNodeType;
|
|
const AID, AKeyValue: Variant);
|
|
var
|
|
I: Integer;
|
|
PValue: PVariant;
|
|
begin
|
|
inherited Create;
|
|
FControl := AControl;
|
|
FLevel := ALevel;
|
|
FNodeType := ANodeType;
|
|
FID := AID;
|
|
FKeyValue := AKeyValue;
|
|
FAbsoluteIndex := -1;
|
|
FGroupIndex := -1;
|
|
FIndex := -1;
|
|
FItems := TdxMasterViewList.Create(Self, lmItems);
|
|
FSelectedIndex := -1;
|
|
if FNodeType = ntData then
|
|
begin
|
|
FValues := TStringList.Create;
|
|
if FLevel <> nil then
|
|
begin
|
|
FValues.Capacity := FLevel.ColumnCount;
|
|
for I := 0 to FValues.Capacity - 1 do
|
|
begin
|
|
New(PValue);
|
|
FValues.AddObject('', TObject(PValue));
|
|
end;
|
|
end;
|
|
end;
|
|
if AParentNode <> nil then AParentNode.AddItem(AIndex, Self);
|
|
end;
|
|
|
|
destructor TdxMasterViewNode.Destroy;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FLevel.DoNodeDeleted(Self);
|
|
Clear;
|
|
if FParentNode <> nil then
|
|
with FParentNode do
|
|
begin
|
|
Invalidate(nil, vpAllAndBelow);
|
|
RemoveItem(Self);
|
|
end;
|
|
FControl.DoNodeDeleted(Self);
|
|
DestroySummaries;
|
|
if FNodeType = ntData then
|
|
begin
|
|
for I := 0 to FValues.Count - 1 do
|
|
Dispose(PVariant(FValues.Objects[I]));
|
|
FValues.Free;
|
|
end;
|
|
FItems.Free;
|
|
inherited;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetBounds: TRect;
|
|
begin
|
|
Result := FViewInfo.Bounds;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetContentBounds: TRect;
|
|
begin
|
|
with FViewInfo, Result do
|
|
begin
|
|
Result := Bounds;
|
|
if Top <> Bottom then
|
|
begin
|
|
Inc(Top, GroupByBoxSize);
|
|
if (HeaderSize <> 0) and FLevel.Horizontal then
|
|
Inc(Top, HeaderSize);
|
|
Dec(Bottom, FooterSize);
|
|
if Top > Bottom then Top := Bottom;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetContentBoundsWithoutPreview: TRect;
|
|
begin
|
|
with Result do
|
|
begin
|
|
Result := ContentBounds;
|
|
if IsRectEmpty(Result) then Exit;
|
|
with FLevel do
|
|
Bottom := Top + VisibleRowCount * ContentRealHeight;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetCount: Integer;
|
|
begin
|
|
Result := FItems.Count;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetCountInLevel(ALevel: TdxMasterViewLevel): Integer;
|
|
var
|
|
Node: TdxMasterViewNode;
|
|
I: Integer;
|
|
begin
|
|
if (FNodeType = ntData) and (FLevel.Count = 1) and (ALevel = FLevel[0]) or
|
|
(FNodeType in [ntCaption, ntGroup]) and (ALevel = FLevel) then
|
|
Result := Count
|
|
else
|
|
begin
|
|
Result := 0;
|
|
Node := FirstInLevel[ALevel];
|
|
if Node <> nil then
|
|
begin
|
|
Result := Node.Index;
|
|
for I := Result to Count - 1 do
|
|
if Items[I].Level <> ALevel then
|
|
begin
|
|
Result := I - Result;
|
|
Exit;
|
|
end;
|
|
Result := Count - Result;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetFirst: TdxMasterViewNode;
|
|
begin
|
|
if Count = 0 then Result := nil
|
|
else Result := Items[0];
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetFirstInLevel(ALevel: TdxMasterViewLevel): TdxMasterViewNode;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (FNodeType = ntData) and (FLevel.Count = 1) and (ALevel = FLevel[0]) or
|
|
(FNodeType in [ntCaption, ntGroup]) and (ALevel = FLevel) then
|
|
Result := First
|
|
else
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
Result := Items[I];
|
|
if Result.Level = ALevel then Exit;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetFocused: Boolean;
|
|
begin
|
|
Result := FControl.FocusedNode = Self;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetFooterBounds: TRect;
|
|
begin
|
|
with FViewInfo do
|
|
if FooterSize = 0 then SetRectEmpty(Result)
|
|
else
|
|
begin
|
|
Result := Bounds;
|
|
Result.Top := Result.Bottom - FooterSize;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetFullBounds: TRect;
|
|
begin
|
|
Result := FViewInfo.Bounds;
|
|
with Result do
|
|
begin
|
|
Left := 0;
|
|
Right := FControl.ClientWidth;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetFullContentBounds: TRect;
|
|
begin
|
|
Result := GetContentBounds;
|
|
with Result do
|
|
if Top <> Bottom then
|
|
begin
|
|
Left := 0;
|
|
Right := FControl.ClientWidth;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetFullFooterBounds: TRect;
|
|
begin
|
|
Result := GetFooterBounds;
|
|
with Result do
|
|
if Top <> Bottom then
|
|
begin
|
|
Left := 0;
|
|
Right := FControl.ClientWidth;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetFullGroupByBoxBounds: TRect;
|
|
begin
|
|
Result := GetGroupByBoxBounds;
|
|
with Result do
|
|
if Top <> Bottom then
|
|
begin
|
|
//Left := 0;
|
|
Right := FControl.ClientWidth;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetFullHeaderBounds: TRect;
|
|
begin
|
|
Result := GetHeaderBounds;
|
|
with Result do
|
|
if Top <> Bottom then
|
|
begin
|
|
Left := 0;
|
|
Right := FControl.ClientWidth;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetGroupByBoxBounds: TRect;
|
|
begin
|
|
with FViewInfo do
|
|
if GroupByBoxSize = 0 then SetRectEmpty(Result)
|
|
else
|
|
begin
|
|
Result := Bounds;
|
|
if FNodeType = ntData then
|
|
Dec(Result.Left,
|
|
FLevel.GroupColumnCount * (LevelIndent + FLevel.ExtLineWidth))
|
|
else
|
|
Dec(Result.Left,
|
|
GroupIndex * (LevelIndent + FLevel.ExtLineWidth));
|
|
Result.Bottom := Result.Top + GroupByBoxSize;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetGroupByBoxColumnBounds(Index: Integer): TRect;
|
|
var
|
|
I: Integer;
|
|
R: TRect;
|
|
begin
|
|
if Index = -1 then Index := 0;
|
|
Result := GroupByBoxBounds;
|
|
R := Result;
|
|
with Result do
|
|
begin
|
|
Inc(Left, GroupByBoxLeftOffset);
|
|
Inc(Top, GroupByBoxTopOffset);
|
|
for I := 0 to Index do
|
|
begin
|
|
Right := Left + GroupByBoxColumnWidth;//FLevel.GroupColumns[I].GetHeaderBestFitWidth(DC, True) + 40;
|
|
Bottom := Top + FLevel.HeaderRealHeight;
|
|
if I = Index then Break;
|
|
Left := Right + GroupByBoxHorOffset;
|
|
Inc(Top, FLevel.HeaderRealHeight div 2 + GroupByBoxVerOffset);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetGroupIndex: Integer;
|
|
var
|
|
Node: TdxMasterViewNode;
|
|
begin
|
|
Result := -1;
|
|
Node := Self;
|
|
while Node.NodeType = ntGroup do
|
|
begin
|
|
Inc(Result);
|
|
Node := Node.ParentNode;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetHasChildren: Boolean;
|
|
begin
|
|
Result := Count <> 0;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetHeaderBounds: TRect;
|
|
begin
|
|
with FViewInfo do
|
|
if HeaderSize = 0 then SetRectEmpty(Result)
|
|
else
|
|
begin
|
|
Result := Bounds;
|
|
Inc(Result.Top, GroupByBoxSize);
|
|
Result.Bottom := Result.Top + HeaderSize;
|
|
if Result.Bottom > Bounds.Bottom - FooterSize then
|
|
Result.Bottom := Bounds.Bottom - FooterSize;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetHeaderColBounds(Index: Integer): TRect;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if FViewInfo.HeaderSize = 0 then SetRectEmpty(Result)
|
|
else
|
|
with Result do
|
|
begin
|
|
Result := HeaderBounds;
|
|
if FLevel.HasExpandButton then Inc(Left, LevelIndent);
|
|
Right := Left;
|
|
for I := 0 to Index do
|
|
begin
|
|
if I <> 0 then
|
|
Inc(Right, FLevel.Layout.ContentWidths[I - 1]);
|
|
Left := Right;
|
|
Inc(Right, FLevel.Layout.HeaderWidths[I]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetHeaderRowBounds(Index: Integer): TRect;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if FViewInfo.HeaderSize = 0 then Exit;
|
|
Result := HeaderBounds;
|
|
Result.Bottom := Result.Top + FLevel.HeaderRealHeight;
|
|
for I := 0 to Index - 1 do
|
|
OffsetRect(Result, 0, FLevel.HeaderRealHeight);
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetHorizontal: Boolean;
|
|
begin
|
|
Result := FLevel.Horizontal or (FNodeType <> ntData);
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetIsEditing: Boolean;
|
|
begin
|
|
Result := FLevel.FEditingNode = Self;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetIsFirst: Boolean;
|
|
begin
|
|
Result := Index = 0;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetIsFirstInLevel: Boolean;
|
|
begin
|
|
Result := (Index = 0) or (FParentNode.FItems.List^[Index - 1].Level <> FLevel);
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetIsLast: Boolean;
|
|
begin
|
|
Result := Index = FParentNode.FItems.Count - 1;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetIsLastInLevel: Boolean;
|
|
begin
|
|
Result := IsLast or (FParentNode.FItems.List^[Index + 1].Level <> FLevel);
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetItem(Index: Integer): TdxMasterViewNode;
|
|
begin
|
|
Result := FItems[Index];
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetLast: TdxMasterViewNode;
|
|
begin
|
|
if Count = 0 then Result := nil
|
|
else Result := Items[Count - 1];
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetLastInLevel(ALevel: TdxMasterViewLevel): TdxMasterViewNode;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := Count - 1 downto 0 do
|
|
begin
|
|
Result := Items[I];
|
|
if Result.Level = ALevel then Exit;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetLeftSpaceBounds: TRect;
|
|
begin
|
|
Result := Bounds;
|
|
with Result do
|
|
begin
|
|
Right := Left;
|
|
Left := 0;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetNodeWithSummaryData(ALevel: TdxMasterViewLevel): TdxMasterViewNode;
|
|
begin
|
|
Result := GetParentNode(ALevel, False).ParentNode;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetParentNodes(Index: Integer): TdxMasterViewNode;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := Self;
|
|
for I := 0 to Index - 1 do
|
|
begin
|
|
Result := Result.ParentNode;
|
|
if Result = nil then Break;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetParentNodeWithData: TdxMasterViewNode;
|
|
begin
|
|
Result := FParentNode;
|
|
while Result.NodeType <> ntData do
|
|
Result := Result.ParentNode;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetPreviewBounds: TRect;
|
|
begin
|
|
if FViewInfo.PreviewSize = 0 then SetRectEmpty(Result)
|
|
else
|
|
with Result do
|
|
begin
|
|
Result := ContentBounds;
|
|
if HasExpandButton then Inc(Left, LevelIndent);
|
|
with FLevel do
|
|
Inc(Top, VisibleRowCount * ContentRealHeight);
|
|
Bottom := Top + FViewInfo.PreviewSize;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetRightSpaceBounds: TRect;
|
|
begin
|
|
Result := Bounds;
|
|
with Result do
|
|
if Top <> Bottom then
|
|
begin
|
|
Left := Right;
|
|
Right := FControl.ClientWidth;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetSelected: Boolean;
|
|
begin
|
|
Result :=
|
|
not FControl.MultiSelect and Focused or
|
|
FControl.MultiSelect and ((SelectedIndex <> -1) or InSelectedPeriod);
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetString(Index: Integer): string;
|
|
begin
|
|
Result := FValues[Index];
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetSubFooterBounds(AParentIndex: Integer): TRect;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (FViewInfo.FooterSize = 0) or not HasFooter(AParentIndex) then
|
|
SetRectEmpty(Result)
|
|
else
|
|
begin
|
|
Result := GetFooterBounds;
|
|
Result.Bottom := Result.Top;
|
|
for I := 0 to FLevel.ParentCount - 2 do
|
|
with Result do
|
|
begin
|
|
with FLevel.Parents[I] do
|
|
begin
|
|
if Self.HasFooter(I) then Inc(Bottom, RowCount * FooterHeight);
|
|
if I = AParentIndex then Break;
|
|
if (I <> 0) or (FNodeType = ntData) then
|
|
Dec(Left, (Byte(ShowCaption) + GroupColumnCount) * (LevelIndent + ExtLineWidth))
|
|
else
|
|
if FNodeType = ntGroup then
|
|
Dec(Left, (Byte(ShowCaption) + GroupIndex) * (LevelIndent + ExtLineWidth));
|
|
end;
|
|
with FLevel.Parents[I + 1] do
|
|
begin
|
|
Dec(Left, LevelIndent + ExtLineWidth + LevelSeparatorWidth);
|
|
Right := Left + VisibleWidth;
|
|
if (LevelSeparatorWidth <> 0) and HasLevelSeparator(I) then
|
|
Inc(Bottom, LevelSeparatorWidth);
|
|
if (RowSeparatorWidth <> 0) and HasRowSeparator(I) then
|
|
Inc(Bottom, RowSeparatorWidth);
|
|
Top := Bottom;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetValue(Index: Integer): Variant;
|
|
begin
|
|
Result := PVariant(FValues.Objects[Index])^;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetValueCount: Integer;
|
|
begin
|
|
if FValues <> nil then
|
|
Result := FValues.Count
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetVisible: Boolean;
|
|
begin
|
|
Result :=
|
|
(0 <= AbsoluteIndex) and
|
|
(AbsoluteIndex < FControl.TopIndex + FControl.FLastPartVisibleItemCount);
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.SetExpanded(Value: Boolean);
|
|
begin
|
|
if FExpanded <> Value then
|
|
if Value then
|
|
Expand(False)
|
|
else
|
|
Collapse(False);
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.SetFocused(Value: Boolean);
|
|
begin
|
|
Control.FocusedIndex := AbsoluteIndex;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.SetSelected(Value: Boolean);
|
|
begin
|
|
if FControl.MultiSelect and (Selected <> Value) and
|
|
(not Value or FControl.DoSelectNode(Self)) or
|
|
not FControl.MultiSelect and not Value and (SelectedIndex <> -1) then
|
|
begin
|
|
if Value then
|
|
FControl.AddSelectedItem(Self)
|
|
else
|
|
FControl.RemoveSelectedItem(Self);
|
|
NodeChanged(False);
|
|
FControl.DoSelectionChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.AddItem(AIndex: Integer; Value: TdxMasterViewNode);
|
|
begin
|
|
if AIndex = -1 then AIndex := GetAvailIndex(Value.Level.Index);
|
|
FItems.Insert(AIndex, Value);
|
|
with Value do
|
|
begin
|
|
FParentNode := Self;
|
|
FGroupIndex := GetGroupIndex;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.RemoveItem(Value: TdxMasterViewNode);
|
|
begin
|
|
FItems.Remove(Value);
|
|
CheckExpanded;
|
|
//FControl.DoNodeDeleted(Value);
|
|
with Value do
|
|
begin
|
|
FParentNode := nil;
|
|
FGroupIndex := -1;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.SetHasLevelSeparator(var EndLevelData: Integer;
|
|
ALevelParentIndex: Integer);
|
|
begin
|
|
EndLevelData := EndLevelData or (1 shl ALevelParentIndex);
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.SetHasRowSeparator(var EndLevelData: Integer;
|
|
ALevelParentIndex: Integer);
|
|
begin
|
|
EndLevelData := EndLevelData or (1 shl (ALevelParentIndex + 16));
|
|
end;
|
|
|
|
function TdxMasterViewNode.Add(ALevel: TdxMasterViewLevel; AIndex: Integer;
|
|
ANodeType: TdxMasterViewNodeType; const AID, AKeyValue: Variant): TdxMasterViewNode;
|
|
begin
|
|
Result := TdxMasterViewNode.Create(FControl, ALevel, Self, AIndex, ANodeType, AID, AKeyValue);
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.AddToList(ALevel: TdxMasterViewLevel;
|
|
OtherNodesList, GroupNodesList: TList; ProcessRoot: Boolean);
|
|
var
|
|
I: Integer;
|
|
Node: TdxMasterViewNode;
|
|
begin
|
|
if ProcessRoot then
|
|
if FNodeType <> ntGroup then
|
|
begin
|
|
OtherNodesList.Add(Self);
|
|
Exit;
|
|
end
|
|
else
|
|
GroupNodesList.Add(Self);
|
|
Node := FirstInLevel[ALevel];
|
|
if Node = nil then Exit;
|
|
I := Node.Index;
|
|
for I := I to I + CountInLevel[ALevel] - 1 do
|
|
Items[I].AddToList(ALevel, OtherNodesList, GroupNodesList, True);
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.AddVisibleToList(List: TdxMasterViewList);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if FParentNode <> nil then
|
|
begin
|
|
List.Add(Self);
|
|
FLevel.FVisible := True; // := FNodeType = ntData ?
|
|
end;
|
|
if Expanded then
|
|
for I := 0 to Count - 1 do Items[I].AddVisibleToList(List);
|
|
end;
|
|
|
|
function TdxMasterViewNode.CanDelete: Boolean;
|
|
begin
|
|
Result := (FNodeType = ntData) and FLevel.CanDelete;
|
|
end;
|
|
|
|
function TdxMasterViewNode.CanExpand: Boolean;
|
|
begin
|
|
Result := HasChildren;
|
|
if not Result then
|
|
case FNodeType of
|
|
ntData:
|
|
Result := FLevel.LoadDataOnExpand;
|
|
ntCaption:
|
|
Result := FLevel.SmartLoad;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.ChangeExpanded(Value: Boolean);
|
|
begin
|
|
if FExpanded <> Value then
|
|
begin
|
|
FExpanded := Value;
|
|
if Value then FTriedToExpand := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.CheckChildNodes(ALevel: TdxMasterViewLevel;
|
|
NeedCheckParentNodes: Boolean);
|
|
begin
|
|
if (FNodeType = ntGroup) and (Count = 0) then
|
|
CheckParentNodes
|
|
else
|
|
if FirstInLevel[ALevel] <> nil then
|
|
FirstInLevel[ALevel].UpdateData(False, False, True);
|
|
if NeedCheckParentNodes and (FNodeType = ntGroup) then
|
|
ParentNodes[GroupIndex + 1].CheckChildNodes(FLevel, False);
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.CheckExpanded;
|
|
begin
|
|
if (FParentNode <> nil) and not HasChildren then ChangeExpanded(False);
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.CheckParentNodes;
|
|
var
|
|
DetailKeyValue: Variant;
|
|
BaseNode, AParentNode: TdxMasterViewNode;
|
|
ALevel: TdxMasterViewLevel;
|
|
begin
|
|
case FNodeType of
|
|
ntData:
|
|
begin
|
|
if not FControl.SyncMove then Exit;
|
|
// find base data node
|
|
if FLevel.IsTop then
|
|
BaseNode := FControl.FItems
|
|
else
|
|
begin
|
|
DetailKeyValue := FLevel.GetCurDetailKeyValue;
|
|
if VarAreEqual(ParentNodeWithData.KeyValue[FLevel.Index], DetailKeyValue) then
|
|
BaseNode := ParentNodeWithData
|
|
else
|
|
BaseNode := FControl.NodeFromKeyValue(FLevel.Parent, FLevel.Index, DetailKeyValue);
|
|
end;
|
|
// find parentnode
|
|
AParentNode := FLevel.GetParentNode(BaseNode, nil, nil, nil, nil, True);
|
|
if AParentNode = nil then
|
|
begin
|
|
AParentNode := FParentNode;
|
|
ALevel := FLevel;
|
|
Free;
|
|
AParentNode.CheckChildNodes(ALevel, False);
|
|
end
|
|
else
|
|
if FParentNode <> AParentNode then
|
|
begin
|
|
with FParentNode do
|
|
begin
|
|
RemoveItem(Self);
|
|
CheckChildNodes(Self.Level, False);
|
|
end;
|
|
with AParentNode do
|
|
begin
|
|
AddItem(-1, Self);
|
|
CheckChildNodes(Self.Level, True);
|
|
end;
|
|
end;
|
|
end;
|
|
ntGroup:
|
|
if Count = 0 then
|
|
begin
|
|
AParentNode := Self;
|
|
repeat
|
|
BaseNode := AParentNode;
|
|
AParentNode := AParentNode.ParentNode;
|
|
BaseNode.Free;
|
|
until (AParentNode.NodeType <> ntGroup) or (AParentNode.Count <> 0);
|
|
AParentNode.Invalidate(nil, vpAllAndBelow);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.Clear;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FControl.BeginSelection;
|
|
try
|
|
for I := Count - 1 downto 0 do Items[I].Free;
|
|
finally
|
|
FControl.EndSelection;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.ClearValues;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if FNodeType = ntData then
|
|
begin
|
|
FID := Unassigned;
|
|
FKeyValue := Unassigned;
|
|
for I := 0 to Level.ColumnCount - 1 do
|
|
begin
|
|
FValues[I] := '';
|
|
PVariant(FValues.Objects[I])^ := Unassigned;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.ContainsDataInChildren(ALevel: TdxMasterViewLevel): Boolean;
|
|
begin
|
|
Result :=
|
|
(FNodeType = ntData) and (FLevel = ALevel.Parent) and not ALevel.ShowCaption or
|
|
(FNodeType in [ntCaption, ntGroup]) and (FLevel = ALevel);
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.DoSmartLoadChanged(ALevel: TdxMasterViewLevel);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if not ALevel.SmartLoad then
|
|
if HasDataInChildren(ALevel) and
|
|
not FExpanded and (CountInLevel[ALevel] = 0) then
|
|
UpdateData(False, True, False)
|
|
else
|
|
if ALevel.HasAsParent(FLevel) then
|
|
for I := 0 to Count - 1 do
|
|
Items[I].DoSmartLoadChanged(ALevel);
|
|
end;
|
|
|
|
function CompareItems(Item1, Item2: TdxMasterViewNode): Integer;
|
|
var
|
|
I: Integer;
|
|
S: string; // to avoid the bug with optimization
|
|
begin
|
|
S := '';
|
|
with Item1.ParentNode, FControl do
|
|
for I := 0 to FSortingColumnCount - 1 do
|
|
if FSortingData^[I] <> nil then
|
|
begin
|
|
SortV1 := FSortingData^[I]^[Item1.Index];
|
|
SortV2 := FSortingData^[I]^[Item2.Index];
|
|
//if VarIsArray(SortV1^) or VarIsArray(SortV2^) then Continue; //20..30 ms
|
|
try
|
|
if SortV1^ <> SortV2^ then
|
|
begin
|
|
if VarIsNull(SortV1^) then
|
|
Result := -1
|
|
else
|
|
if VarIsNull(SortV2^) then
|
|
Result := 1
|
|
else
|
|
if (mobAnsiCompareStrOnSorting in OptionsBehavior) and
|
|
(VarType(SortV1^) = varString) then
|
|
begin
|
|
SortS1 := SortV1^;
|
|
SortS2 := SortV2^;
|
|
Result :=
|
|
CompareString(LOCALE_USER_DEFAULT, 0,
|
|
PChar(SortS1), Length(SortS1), PChar(SortS2), Length(SortS2)) - 2;
|
|
end
|
|
else
|
|
if SortV1^ < SortV2^ then
|
|
Result := -1
|
|
else
|
|
Result := 1;
|
|
if FSortingDesc^[I] then Result := -Result;
|
|
Exit;
|
|
end;
|
|
except
|
|
on EVariantError do ; // 10..20 ms
|
|
end;
|
|
end;
|
|
Result := Item1.Index - Item2.Index;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.DoSorting(ALevel: TdxMasterViewLevel);
|
|
var
|
|
I, J, CI, TopBound, BottomBound, AGroupIndex: Integer;
|
|
UseUpperCase: PBoolArray;
|
|
IsDataNodes: Boolean;
|
|
// ft,lt:integer;
|
|
begin
|
|
if ContainsDataInChildren(ALevel) then
|
|
begin
|
|
if FItems.Count = 0 then Exit;
|
|
|
|
//ft:=gettickcount;
|
|
|
|
AGroupIndex := GroupIndex;
|
|
IsDataNodes :=
|
|
(FNodeType in [ntData, ntCaption]) and (ALevel.GroupColumnCount = 0) or
|
|
(FNodeType = ntGroup) and (AGroupIndex = ALevel.GroupColumnCount - 1);
|
|
with FControl, Self do
|
|
begin
|
|
TopBound := -1;
|
|
BottomBound := -2;
|
|
FSortingColumnCount := ALevel.SortedColumnCount;
|
|
GetMem(UseUpperCase, FSortingColumnCount * SizeOf(Boolean));
|
|
GetMem(FSortingDesc, FSortingColumnCount * SizeOf(Boolean));
|
|
GetMem(FSortingData, FSortingColumnCount * SizeOf(PdxMVSortingValues));
|
|
try
|
|
for I := 0 to FSortingColumnCount - 1 do
|
|
if IsDataNodes or
|
|
(ALevel.SortedColumns[I] = ALevel.GroupColumns[AGroupIndex + 1]) then
|
|
begin
|
|
with ALevel.SortedColumns[I] do
|
|
begin
|
|
CI := Index;
|
|
FSortingDesc^[I] := SortOrder = soDescending;
|
|
end;
|
|
GetMem(FSortingData^[I], FItems.Count * SizeOf(PVariant));
|
|
|
|
TopBound := -1;
|
|
BottomBound := FItems.Count - 1;
|
|
for J := 0 to BottomBound do
|
|
if FItems[J].Level = ALevel then
|
|
begin
|
|
if TopBound = -1 then
|
|
begin
|
|
TopBound := J;
|
|
UseUpperCase[I] :=
|
|
(mobCaseInsensitiveSorting in OptionsBehavior) and
|
|
(IsDataNodes and (VarType(PVariant(FItems[J].FValues.Objects[CI])^) = varString) or
|
|
not IsDataNodes and (VarType(FItems[J].GroupValue) = varString));
|
|
end;
|
|
if UseUpperCase[I] then
|
|
begin
|
|
New(FSortingData^[I]^[J]);
|
|
if IsDataNodes then
|
|
FSortingData^[I]^[J]^ := VarAnsiUpperCase(PVariant(FItems[J].FValues.Objects[CI])^)
|
|
else
|
|
FSortingData^[I]^[J]^ := VarAnsiUpperCase(FItems[J].GroupValue);
|
|
end
|
|
else
|
|
if IsDataNodes then
|
|
FSortingData^[I]^[J] := PVariant(FItems[J].FValues.Objects[CI])
|
|
else
|
|
FSortingData^[I]^[J] := @FItems[J].GroupValue;
|
|
end
|
|
else
|
|
if TopBound <> -1 then
|
|
begin
|
|
BottomBound := J - 1;
|
|
Break;
|
|
end;
|
|
end
|
|
else
|
|
FSortingData^[I] := nil;
|
|
if TopBound <> -1 then
|
|
FItems.Sort(CompareItems, TopBound, BottomBound);
|
|
finally
|
|
for I := 0 to FSortingColumnCount - 1 do
|
|
if FSortingData^[I] <> nil then
|
|
begin
|
|
if (TopBound <> -1) and UseUpperCase[I] then
|
|
for J := TopBound to BottomBound do Dispose(FSortingData^[I]^[J]);
|
|
FreeMem(FSortingData^[I], FItems.Count * SizeOf(PVariant));
|
|
end;
|
|
FreeMem(FSortingData, FSortingColumnCount * SizeOf(PdxMVSortingValues));
|
|
FreeMem(FSortingDesc, FSortingColumnCount * SizeOf(Boolean));
|
|
FreeMem(UseUpperCase, FSortingColumnCount * SizeOf(Boolean));
|
|
end;
|
|
end;
|
|
//lt:=gettickcount;
|
|
//application.messagebox(pchar(inttostr(lt-ft)), '', 0);
|
|
|
|
if IsDataNodes then Exit;
|
|
end;
|
|
|
|
if ALevel.HasAsParent(FLevel) then
|
|
for I := 0 to Count - 1 do
|
|
Items[I].DoSorting(ALevel);
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.Draw(DC: HDC);
|
|
begin
|
|
if RectVisible(DC, LeftSpaceBounds) then
|
|
FLevel.DrawIndent(DC, LeftSpaceBounds, Self);
|
|
if (FViewInfo.FooterSize <> 0) and RectVisible(DC, FullFooterBounds) then
|
|
begin
|
|
FLevel.DrawFooter(DC, FooterBounds, Self);
|
|
if vioClipped in FViewInfo.Options then
|
|
with FullFooterBounds do
|
|
ExcludeClipRect(DC, Left, Top, Right, Bottom);
|
|
end;
|
|
if (FViewInfo.GroupByBoxSize <> 0) and RectVisible(DC, FullGroupByBoxBounds) then
|
|
FLevel.DrawGroupByBox(DC, GroupByBoxBounds, Self);
|
|
if (FViewInfo.HeaderSize <> 0) and RectVisible(DC, FullHeaderBounds) then
|
|
FLevel.DrawHeader(DC, HeaderBounds, Self);
|
|
if RectVisible(DC, FullContentBounds) then
|
|
FLevel.DrawContent(DC, ContentBounds, Self);
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetAvailIndex(AChildLevelIndex: Integer): Integer;
|
|
begin
|
|
Result := Count;
|
|
if Result <> 0 then
|
|
for Result := 0 to Result - 1 do
|
|
if Items[Result].Level.Index > AChildLevelIndex then Break;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetLastSubChild: TdxMasterViewNode;
|
|
begin
|
|
if Count = 0 then Result := nil
|
|
else
|
|
begin
|
|
Result := Items[Count - 1];
|
|
while Result.Expanded do Result := Result[Result.Count - 1];
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetLevelIndex: Integer;
|
|
var
|
|
Node: TdxMasterViewNode;
|
|
begin
|
|
Result := -2;
|
|
Node := Self;
|
|
repeat
|
|
Inc(Result);
|
|
Node := Node.ParentNode;
|
|
until Node = nil;
|
|
end;
|
|
|
|
function TdxMasterViewNode.HasDataInChildren(ALevel: TdxMasterViewLevel): Boolean;
|
|
begin
|
|
Result :=
|
|
(FNodeType = ntData) and (FLevel = ALevel.Parent) or
|
|
(FNodeType = ntCaption) and (FLevel = ALevel);
|
|
end;
|
|
|
|
function TdxMasterViewNode.InSelectedPeriod: Boolean;
|
|
begin
|
|
Result :=
|
|
(mvsSelectPeriod in FControl.State) and FControl.DoSelectNode(Self) and
|
|
IsBetween(Self, FControl.FSelectionAnchor, FControl.FLastSelectedNode);
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.Invalidate(Column: TdxMasterViewColumn;
|
|
VPart: TdxMasterViewVPart);
|
|
var
|
|
R: TRect;
|
|
begin
|
|
if FControl.HandleAllocated and (FControl.FUpdateLockCount = 0) then
|
|
begin //!!!!
|
|
if (FControl.TopIndex <= AbsoluteIndex) and
|
|
(AbsoluteIndex < FControl.TopIndex + FControl.FLastPartVisibleItemCount) then
|
|
case VPart of
|
|
vpGroupByBox:
|
|
if HasGroupByBox(R.Left) then
|
|
if Column = nil then
|
|
R := GroupByBoxBounds
|
|
else
|
|
R := Column.GetGroupByBoxBounds(Self)
|
|
else
|
|
Exit;
|
|
vpHeader:
|
|
if HasHeader(FControl.TopIndex, R.Left) then
|
|
if Column = nil then
|
|
R := FullHeaderBounds
|
|
else
|
|
R := Column.GetHeaderBounds(Self)
|
|
else
|
|
Exit;
|
|
vpContent:
|
|
if (Column = nil) or
|
|
(FNodeType = ntGroup) and (Column = FLevel.GroupColumns[FGroupIndex]) then
|
|
R := FullContentBounds
|
|
else
|
|
R := Column.GetContentBounds(Self);
|
|
vpFooter:
|
|
if Column = nil then
|
|
R := FullFooterBounds
|
|
else
|
|
R := Column.GetFooterBounds(Self);
|
|
vpAll, vpAllAndBelow:
|
|
if Column = nil then
|
|
begin
|
|
R := FullBounds;
|
|
if VPart = vpAllAndBelow then
|
|
R.Bottom := FControl.ClientHeight;
|
|
end
|
|
else
|
|
begin
|
|
Invalidate(Column, vpGroupByBox);
|
|
Invalidate(Column, vpHeader);
|
|
Invalidate(Column, vpContent);
|
|
Invalidate(Column, vpFooter);
|
|
Exit;
|
|
end;
|
|
end
|
|
else
|
|
if VPart = vpAllAndBelow then
|
|
R := FControl.ClientRect
|
|
else
|
|
Exit;
|
|
InvalidateRect(FControl.Handle, @R, False);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.MoveData(ALevel: TdxMasterViewLevel; FromIndex, ToIndex: Integer);
|
|
var
|
|
PValue: PVariant;
|
|
I: Integer;
|
|
begin
|
|
if (FNodeType = ntData) and (FLevel = ALevel) then
|
|
if FromIndex = -1 then
|
|
begin
|
|
New(PValue);
|
|
FValues.InsertObject(ToIndex, '', TObject(PValue));
|
|
end
|
|
else
|
|
if ToIndex = -1 then
|
|
begin
|
|
Dispose(PVariant(FValues.Objects[FromIndex]));
|
|
FValues.Delete(FromIndex);
|
|
end
|
|
else FValues.Move(FromIndex, ToIndex)
|
|
else
|
|
if ALevel.HasAsParent(FLevel) then
|
|
for I := 0 to Count - 1 do
|
|
Items[I].MoveData(ALevel, FromIndex, ToIndex);
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.NodeChanged(HardRefresh: Boolean);
|
|
begin
|
|
if Control <> nil then
|
|
if HardRefresh then
|
|
else
|
|
Invalidate(nil, vpContent);
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.Sync;
|
|
var
|
|
Node: TdxMasterViewNode;
|
|
AFreezeCount: Integer;
|
|
begin
|
|
if FNodeType = ntData then
|
|
begin
|
|
Node := Self;
|
|
repeat
|
|
if Node.NodeType = ntData then
|
|
with Node.Level do
|
|
if not VarAreEqual(GetCurIDValue, Node.ID) then
|
|
begin
|
|
if DataSet.State in dsEditModes then DataSet.Post;
|
|
AFreezeCount := FControl.FreezeDataSet(Node.Level);
|
|
try
|
|
DataSet.Locate(ID, Node.ID, []);
|
|
finally
|
|
if DataLink.FreezeCount = AFreezeCount then
|
|
FControl.UnfreezeDataSet(Node.Level);
|
|
end;
|
|
end;
|
|
Node := Node.ParentNode;
|
|
until Node.ParentNode = nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.SyncPos;
|
|
begin
|
|
if not FControl.Frozen and FControl.SyncMove then Sync;
|
|
end;
|
|
|
|
function CompareItemsByID(Node1, Node2: Pointer): Integer;
|
|
begin
|
|
Result := -VarCompare(TdxMasterViewNode(Node1).ID, TdxMasterViewNode(Node2).ID);
|
|
end;
|
|
|
|
function CompareGroupItemsByPtr(Node1, Node2: Pointer): Integer;
|
|
begin
|
|
Result := Integer(Node1) - Integer(Node2);
|
|
end;
|
|
|
|
function CompareGroupItemsByGroupIndex(Node1, Node2: Pointer): Integer;
|
|
begin
|
|
if TdxMasterViewNode(Node1).GroupIndex < TdxMasterViewNode(Node2).GroupIndex then
|
|
Result := -1
|
|
else
|
|
if TdxMasterViewNode(Node1).GroupIndex = TdxMasterViewNode(Node2).GroupIndex then
|
|
Result := 0
|
|
else
|
|
Result := 1;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.UpdateData(UpdateSelf, UpdateChildren, UpdateOther: Boolean);
|
|
const
|
|
NoneUpdate = 0;
|
|
SoftUpdate = 1;
|
|
HardUpdate = 2;
|
|
var
|
|
PrevCursor: TCursor;
|
|
AID, AKeyValue: Variant;
|
|
S: string;
|
|
LockSelection: Boolean;
|
|
I: Integer;
|
|
LevelUpdateState: PIntArray;
|
|
|
|
procedure CancelLevel(ALevel: TdxMasterViewLevel; ProcessRoot: Boolean);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if ProcessRoot or (ALevel <> FLevel) then
|
|
with ALevel do
|
|
if (DataSet <> nil) and (DataSet.State in dsEditModes) then
|
|
DataSet.Cancel;
|
|
for I := 0 to ALevel.Count - 1 do
|
|
CancelLevel(ALevel[I], True);
|
|
end;
|
|
|
|
procedure UpdateNode(const Node: TdxMasterViewNode);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
with Node, Level do
|
|
begin
|
|
Node.FID := AID;
|
|
Node.FKeyValue := AKeyValue;
|
|
Node.FPreviewText := GetCurPreviewText(Node);
|
|
|
|
for I := 0 to FColumns.Count - 1 do
|
|
with TdxMasterViewColumn(FColumns[I]) do
|
|
if Field <> nil then
|
|
with Field do
|
|
begin
|
|
S := DisplayText;
|
|
FValues[I] := S;
|
|
if (DataType <> ftString) or (S = '') or
|
|
Assigned(OnGetText) or (EditMask <> ''){!} then
|
|
PVariant(FValues.Objects[I])^ := Value
|
|
else
|
|
PVariant(FValues.Objects[I])^ := S;
|
|
end
|
|
else
|
|
begin
|
|
FValues[I] := '';
|
|
PVariant(FValues.Objects[I])^ := Null;//Unassigned;
|
|
end;
|
|
|
|
if Node <> Self then CalcSummaries(True);
|
|
end;
|
|
end;
|
|
|
|
procedure UpdateLevels(AItems: TdxMasterViewNode);
|
|
var
|
|
RestItems, RestGroupItems: TList;
|
|
I, FirstIndex, AvailIndex, APos, L, R, C, CResult: Integer;
|
|
ALevel: TdxMasterViewLevel;
|
|
LastLevelToLoad, AExpanded, UseLock, ALoadAll, AFound, UnassignedID, Accept: Boolean;
|
|
KeyValue: Variant;
|
|
Node, AParentNode: TdxMasterViewNode;
|
|
|
|
procedure BeginDeletion(const UseItems: Boolean);
|
|
begin
|
|
with FControl do
|
|
begin
|
|
FAbsoluteItems.BeginDeletion;
|
|
FSelectedItems.BeginDeletion;
|
|
end;
|
|
if UseItems then AItems.FItems.BeginDeletion;
|
|
end;
|
|
|
|
procedure EndDeletion(const UseItems: Boolean);
|
|
begin
|
|
if UseItems then AItems.FItems.EndDeletion;
|
|
with FControl do
|
|
begin
|
|
FSelectedItems.EndDeletion;
|
|
FAbsoluteItems.EndDeletion;
|
|
end;
|
|
end;
|
|
|
|
function NodeFromID(const AID: Variant): TdxMasterViewNode;
|
|
begin
|
|
with RestItems do
|
|
begin
|
|
APos := -1;
|
|
Result := nil;
|
|
R := Count - 1;
|
|
if R = -1 then Exit;
|
|
L := 0;
|
|
UnassignedID := VarIsEmpty(AID);
|
|
while L <= R do
|
|
begin
|
|
C := (L + R) div 2;
|
|
with TdxMasterViewNode(List^[C]) do
|
|
if UnassignedID and VarIsEmpty(ID) then
|
|
CResult := 0
|
|
else
|
|
try
|
|
CResult := -VarCompare(AID, ID);
|
|
except
|
|
Exit;
|
|
end;
|
|
case CResult of
|
|
0: begin
|
|
APos := C;
|
|
Result := List^[C];
|
|
Exit;
|
|
end;
|
|
-1: R := C - 1;
|
|
1: L := C + 1;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure UpdateOneLevel;
|
|
var
|
|
I, J: Integer;
|
|
|
|
function GetNewIndex: Integer;
|
|
begin
|
|
if AParentNode.NodeType = ntGroup then
|
|
Result := AParentNode.Count
|
|
else
|
|
begin
|
|
Result := AvailIndex;
|
|
Inc(AvailIndex);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
AExpanded := AItems.Expanded;
|
|
AItems.AddToList(ALevel, RestItems, RestGroupItems, False);
|
|
|
|
UseLock := (AItems.NodeType = ntData) and not ALevel.IsLast or
|
|
(RestGroupItems.Count >= RestItems.Count);
|
|
if (not ALevel.ShowCaption or (AItems.NodeType = ntCaption)) and
|
|
(RestItems.Count <> 0) then
|
|
begin
|
|
J := ALevel.GroupColumnCount;
|
|
AParentNode := TdxMasterViewNode(RestItems[0]).ParentNode;
|
|
if (J = 0) and (AParentNode <> AItems) or
|
|
(J <> 0) and (AParentNode = AItems) then
|
|
begin
|
|
if UseLock then AItems.FItems.BeginDeletion;
|
|
try
|
|
for I := RestItems.Count - 1 downto 0 do
|
|
begin
|
|
Node := TdxMasterViewNode(RestItems[I]);
|
|
Node.ParentNode.RemoveItem(Node);
|
|
end;
|
|
finally
|
|
if UseLock then AItems.FItems.EndDeletion;
|
|
end;
|
|
end;
|
|
if not ALevel.SmartReload then
|
|
RestItems.Sort(CompareItemsByID);
|
|
I := RestGroupItems.Count;
|
|
if (J = 0) and (I <> 0) then
|
|
begin
|
|
if not LockSelection then
|
|
begin
|
|
LockSelection := True;
|
|
FControl.BeginSelection;
|
|
end;
|
|
if UseLock then BeginDeletion(True);
|
|
try
|
|
for I := I - 1 downto 0 do
|
|
TdxMasterViewNode(RestGroupItems[I]).Free;
|
|
RestGroupItems.Clear;
|
|
finally
|
|
if UseLock then EndDeletion(True);
|
|
end;
|
|
end;
|
|
end;
|
|
AvailIndex := AItems.GetAvailIndex(ALevel.Index);
|
|
Node := AItems.FirstInLevel[ALevel];
|
|
if Node = nil then
|
|
FirstIndex := AvailIndex
|
|
else
|
|
FirstIndex := Node.Index;
|
|
RestGroupItems.Sort(CompareGroupItemsByPtr);
|
|
|
|
if UseLock then AItems.FItems.BeginInsertion;
|
|
try
|
|
if not AExpanded and ALevel.SmartLoad then Exit;
|
|
|
|
with ALevel do
|
|
begin
|
|
if ShowCaption and (AItems.NodeType <> ntCaption) then
|
|
begin
|
|
Node := NodeFromID(Unassigned);
|
|
if Node = nil then
|
|
begin
|
|
Node := AItems.Add(ALevel, AvailIndex, ntCaption, Unassigned, Unassigned);
|
|
Inc(AvailIndex);
|
|
end
|
|
else
|
|
RestItems.Delete(APos);
|
|
UpdateLevels(Node);
|
|
Exit;
|
|
end;
|
|
|
|
if not Active then Exit;
|
|
|
|
if SmartReload and (RestItems.Count <> 0) and
|
|
(TdxMasterViewNode(RestItems[0]).NodeType <> ntCaption) then
|
|
begin
|
|
if LevelUpdateState[AbsoluteIndex] = NoneUpdate then
|
|
LevelUpdateState[AbsoluteIndex] := SoftUpdate;
|
|
for I := 0 to RestItems.Count - 1 do
|
|
begin
|
|
Node := TdxMasterViewNode(RestItems[I]);
|
|
AParentNode :=
|
|
GetParentNode(AItems, Node, @FirstIndex, @AvailIndex, RestGroupItems, False);
|
|
if Node.ParentNode <> AParentNode then
|
|
begin
|
|
if Node.ParentNode <> nil then
|
|
for J := RestItems.Count - 1 downto 0 do
|
|
begin
|
|
Node := TdxMasterViewNode(RestItems[J]);
|
|
Node.ParentNode.RemoveItem(Node);
|
|
end;
|
|
AParentNode.AddItem(GetNewIndex, Node);
|
|
end;
|
|
Node.CalcSummaries(False);
|
|
UpdateLevels(Node);
|
|
end;
|
|
RestItems.Clear;
|
|
Exit;
|
|
end;
|
|
|
|
if LevelUpdateState[AbsoluteIndex] <> HardUpdate then
|
|
begin
|
|
BeginLoad;
|
|
LevelUpdateState[AbsoluteIndex] := HardUpdate;
|
|
end;
|
|
ALoadAll := DontFilterRecords;
|
|
if not ALoadAll then
|
|
if AItems.NodeType = ntData then
|
|
KeyValue := AItems.KeyValue[Index]
|
|
else
|
|
KeyValue := AItems.ParentNode.KeyValue[Index];
|
|
with DataSet do
|
|
begin
|
|
if ALoadAll then
|
|
begin
|
|
First;
|
|
AFound := not EOF;
|
|
end
|
|
else
|
|
try
|
|
AFound := Locate(DetailKey, KeyValue, []);
|
|
except
|
|
AFound := False;
|
|
end;
|
|
|
|
while AFound do
|
|
begin
|
|
AID := GetCurIDValue;
|
|
AKeyValue := GetCurKeyValue;
|
|
|
|
Accept := True;
|
|
if Assigned(FOnFilterRecord) then
|
|
FOnFilterRecord(ALevel, AID, KeyValue, Accept);
|
|
|
|
if Accept then
|
|
begin
|
|
AParentNode :=
|
|
GetParentNode(AItems, nil{!!!}, @FirstIndex, @AvailIndex, RestGroupItems, False);
|
|
Node := NodeFromID(AID);
|
|
if Node = nil then
|
|
Node := AParentNode.Add(ALevel, GetNewIndex, ntData, AID, AKeyValue)
|
|
else
|
|
begin
|
|
RestItems.Delete(APos);
|
|
if Node.ParentNode <> AParentNode then
|
|
begin
|
|
if Node.ParentNode <> nil then
|
|
Node.ParentNode.RemoveItem(Node);
|
|
AParentNode.AddItem(GetNewIndex, Node);
|
|
end;
|
|
end;
|
|
UpdateNode(Node);
|
|
UpdateLevels(Node);
|
|
end;
|
|
|
|
Next;
|
|
AFound := not EOF;
|
|
if AFound and not ALoadAll then
|
|
AFound := VarAreEqual(GetCurDetailKeyValue, KeyValue);
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
if UseLock then AItems.FItems.EndInsertion;
|
|
|
|
RestGroupItems.Sort(CompareGroupItemsByGroupIndex);
|
|
if (RestItems.Count <> 0) or (RestGroupItems.Count <> 0) then
|
|
begin
|
|
if not LockSelection then
|
|
begin
|
|
LockSelection := True;
|
|
FControl.BeginSelection;
|
|
end;
|
|
AFound :=
|
|
//(AItems.NodeType = ntData) and
|
|
((RestItems.Count <> 0) and
|
|
(TdxMasterViewNode(RestItems[0]).ParentNode = AItems) or
|
|
(RestGroupItems.Count <> 0) and
|
|
(TdxMasterViewNode(RestGroupItems[0]).ParentNode = AItems));
|
|
BeginDeletion(AFound);
|
|
try
|
|
for I := 0 to RestItems.Count - 1 do
|
|
TdxMasterViewNode(RestItems[I]).Free;
|
|
RestItems.Clear;
|
|
for I := RestGroupItems.Count - 1 downto 0 do
|
|
TdxMasterViewNode(RestGroupItems[I]).Free;
|
|
RestGroupItems.Clear;
|
|
finally
|
|
EndDeletion(AFound);
|
|
end;
|
|
end;
|
|
|
|
if LastLevelToLoad then
|
|
with AItems do
|
|
begin
|
|
FExpanded := AExpanded;
|
|
CheckExpanded;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if (AItems.NodeType = ntData) and not AItems.Level.HasChildren then Exit;
|
|
RestItems := TList.Create;
|
|
RestItems.Capacity := 10;
|
|
RestGroupItems := TList.Create;
|
|
RestGroupItems.Capacity := 10;
|
|
try
|
|
if AItems.NodeType = ntData then
|
|
for I := 0 to AItems.Level.Count - 1 do
|
|
begin
|
|
ALevel := AItems.Level[I];
|
|
LastLevelToLoad := ALevel.IsLast;
|
|
UpdateOneLevel;
|
|
end
|
|
else
|
|
begin
|
|
ALevel := AItems.Level;
|
|
LastLevelToLoad := True;
|
|
UpdateOneLevel;
|
|
end;
|
|
finally
|
|
RestGroupItems.Free;
|
|
RestItems.Free;
|
|
AItems.FinalizeSummaries(nil);
|
|
end;
|
|
end;
|
|
|
|
//var
|
|
// ft,lt:integer;
|
|
|
|
begin
|
|
if (FControl.FLayoutLockCount <> 0) or
|
|
([csLoading, csDestroying] * FControl.ComponentState <> []) then Exit;
|
|
|
|
// ft:=gettickcount;
|
|
|
|
if UpdateChildren then
|
|
CancelLevel(FLevel, FNodeType <> ntData);
|
|
|
|
with FControl do
|
|
begin
|
|
if FUpdatingData then Exit;
|
|
FUpdatingData := True;
|
|
end;
|
|
try
|
|
PrevCursor := Screen.Cursor;
|
|
if FControl.ShowHourGlassCursor then Screen.Cursor := crHourGlass;
|
|
FControl.BeginUpdate;
|
|
try
|
|
if (FParentNode <> nil) and UpdateSelf then
|
|
begin
|
|
if FLevel.Active then
|
|
with FLevel do
|
|
begin
|
|
AID := GetCurIDValue;
|
|
AKeyValue := GetCurKeyValue;
|
|
UpdateNode(Self);
|
|
end
|
|
else
|
|
ClearValues;
|
|
if not UpdateChildren then
|
|
begin
|
|
FControl.FDontInvalidate := True;
|
|
Invalidate(nil, vpContent);
|
|
end;
|
|
end;
|
|
if UpdateChildren then
|
|
if (FNodeType = ntData) and FLevel.HasChildren or
|
|
(FNodeType = ntCaption) then
|
|
begin
|
|
FControl.BeginTopNodeChange;
|
|
try
|
|
I := FControl.AbsoluteLevelCount * SizeOf(Integer);
|
|
GetMem(LevelUpdateState, I);
|
|
FillChar(LevelUpdateState^, I, 0);
|
|
try
|
|
UpdateLevels(Self);
|
|
finally
|
|
for I := 0 to FControl.AbsoluteLevelCount - 1 do
|
|
with FControl.AbsoluteLevels[I] do
|
|
case LevelUpdateState[AbsoluteIndex] of
|
|
SoftUpdate: DoSorting;
|
|
HardUpdate: EndLoad(True);
|
|
end;
|
|
FreeMem(LevelUpdateState);
|
|
if LockSelection then FControl.EndSelection;
|
|
end;
|
|
finally
|
|
FControl.EndTopNodeChange;
|
|
end;
|
|
end
|
|
else
|
|
Clear;
|
|
if (FLevel.Parent <> nil) and UpdateOther then
|
|
with FParentNode do
|
|
begin
|
|
DoSorting(Self.FLevel);
|
|
if HasSummariesData then
|
|
begin
|
|
InitializeSummaries(Self.FLevel);
|
|
try
|
|
I := FirstInLevel[Self.Level].Index;
|
|
for I := I to I + CountInLevel[Self.Level] - 1 do
|
|
Items[I].CalcSummaries(False);
|
|
finally
|
|
FinalizeSummaries(Self.FLevel);
|
|
end;
|
|
end;
|
|
if FControl.FDontInvalidate then
|
|
Invalidate(nil, vpAllAndBelow);
|
|
end;
|
|
finally
|
|
FControl.EndUpdate;
|
|
if FControl.ShowHourGlassCursor then Screen.Cursor := PrevCursor;
|
|
end;
|
|
finally
|
|
FControl.FUpdatingData := False;
|
|
end;
|
|
|
|
// lt:=gettickcount;
|
|
// application.mainform.caption:=inttostr(lt-ft);
|
|
// application.messagebox(pchar(inttostr(lt-ft)),'TdxMasterViewNode.UpdateData',0);
|
|
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.UpdateDataForLevel(ALevel: TdxMasterViewLevel);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (FNodeType = ntData) and (FLevel = ALevel.Parent) then
|
|
UpdateData(False, True, False)
|
|
else
|
|
if ALevel.HasAsParent(FLevel) then
|
|
begin
|
|
I := 0;
|
|
while I < Count do
|
|
with Items[I] do
|
|
begin
|
|
UpdateDataForLevel(ALevel);
|
|
I := Index + 1;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.CreateSummaries;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (FNodeType = ntData) and FLevel.HasChildren or (FNodeType <> ntData) then
|
|
begin
|
|
if FNodeType = ntData then
|
|
I := FLevel.Count
|
|
else
|
|
I := 1;
|
|
GetMem(FSummaries, I * SizeOf(PdxMVSummaryValues));
|
|
if FNodeType = ntData then
|
|
for I := 0 to I - 1 do
|
|
with FLevel[I] do
|
|
if FSummaryColumns.Count <> 0 then
|
|
GetMem(FSummaries[I], FSummaryColumns.Count * SizeOf(Extended))
|
|
else
|
|
FSummaries[I] := nil
|
|
else
|
|
if FLevel.FSummaryColumns.Count <> 0 then
|
|
GetMem(FSummaries[0], FLevel.FSummaryColumns.Count * SizeOf(Extended))
|
|
else
|
|
FSummaries[0] := nil
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.DestroySummaries;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if FSummaries <> nil then
|
|
begin
|
|
if FNodeType = ntData then
|
|
for I := 0 to FLevel.Count - 1 do
|
|
if FSummaries[I] <> nil then FreeMem(FSummaries[I])
|
|
else
|
|
else
|
|
if FSummaries[0] <> nil then FreeMem(FSummaries[0]);
|
|
FreeMem(FSummaries);
|
|
FSummaries := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.CheckSummaries;
|
|
begin
|
|
if FSummaries = nil then CreateSummaries;
|
|
InitializeSummaries(nil);
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.InitializeSummaries(ALevel: TdxMasterViewLevel);
|
|
var
|
|
AIndex: Integer;
|
|
Column: TdxMasterViewColumn;
|
|
|
|
procedure InitializeOne(ALevel: TdxMasterViewLevel);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
with ALevel do
|
|
for I := 0 to FSummaryColumns.Count - 1 do
|
|
begin
|
|
Column := TdxMasterViewColumn(FSummaryColumns[I]);
|
|
case Column.SummaryType of
|
|
stMin: FSummaries[AIndex][I] := MaxExtended;
|
|
stMax: FSummaries[AIndex][I] := MinExtended;
|
|
else
|
|
FSummaries[AIndex][I] := 0;
|
|
end;
|
|
Column.DoBeforeCalcSummary(Self, DataSet, FSummaries[AIndex][I]);
|
|
end
|
|
end;
|
|
|
|
begin
|
|
if FSummariesInitialized then Exit;
|
|
if ALevel = nil then
|
|
if FNodeType = ntData then
|
|
for AIndex := 0 to FLevel.Count - 1 do
|
|
InitializeOne(FLevel[AIndex])
|
|
else
|
|
begin
|
|
AIndex := 0;
|
|
InitializeOne(FLevel);
|
|
end
|
|
else
|
|
begin
|
|
if FNodeType = ntData then
|
|
AIndex := ALevel.Index
|
|
else
|
|
AIndex := 0;
|
|
InitializeOne(ALevel);
|
|
end;
|
|
FSummariesInitialized := True;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.CalcSummaries(UseRealData: Boolean);
|
|
const
|
|
NumberVarTypes =
|
|
[varSmallint, varInteger, varSingle, varDouble, varCurrency, varDate, varByte];
|
|
var
|
|
AIndex, I: Integer;
|
|
SummaryValue: Extended;
|
|
SummaryVariant: Variant;
|
|
Column: TdxMasterViewColumn;
|
|
begin
|
|
if FNodeType = ntData then
|
|
begin
|
|
if FParentNode.NodeType = ntData then
|
|
AIndex := FLevel.Index
|
|
else
|
|
AIndex := 0;
|
|
with FLevel do
|
|
for I := 0 to FSummaryColumns.Count - 1 do
|
|
with TdxMasterViewColumn(FSummaryColumns[I]) do
|
|
begin
|
|
if (SummaryField = nil) or (SummaryType = stCount) then
|
|
SummaryValue := 0
|
|
else
|
|
begin
|
|
if UseRealData then
|
|
SummaryVariant := SummaryField.Value
|
|
else
|
|
begin
|
|
Column := ColumnByFieldName(SummaryFieldName);
|
|
if Column = nil then
|
|
SummaryVariant := Null
|
|
else
|
|
SummaryVariant := Values[Column.Index];
|
|
end;
|
|
if VarType(SummaryVariant) in NumberVarTypes then
|
|
SummaryValue := SummaryVariant
|
|
else
|
|
SummaryValue := 0;
|
|
end;
|
|
DoCalcSummary(Self, DataSet, SummaryValue);
|
|
with FParentNode do
|
|
case SummaryType of
|
|
stSum, stAverage:
|
|
FSummaries[AIndex][I] := FSummaries[AIndex][I] + SummaryValue;
|
|
stMin:
|
|
if SummaryValue < FSummaries[AIndex][I] then
|
|
FSummaries[AIndex][I] := SummaryValue;
|
|
stMax:
|
|
if SummaryValue > FSummaries[AIndex][I] then
|
|
FSummaries[AIndex][I] := SummaryValue;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.FinalizeSummaries(ALevel: TdxMasterViewLevel);
|
|
var
|
|
AIndex, C: Integer;
|
|
Column: TdxMasterViewColumn;
|
|
|
|
procedure FinalizeOne(ALevel: TdxMasterViewLevel);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
with ALevel do
|
|
for I := 0 to FSummaryColumns.Count - 1 do
|
|
begin
|
|
Column := TdxMasterViewColumn(FSummaryColumns[I]);
|
|
case Column.SummaryType of
|
|
stCount:
|
|
FSummaries[AIndex][I] := CountInLevel[ALevel];
|
|
stAverage:
|
|
begin
|
|
C := CountInLevel[ALevel];
|
|
if C = 0 then
|
|
FSummaries[AIndex][I] := 0
|
|
else
|
|
FSummaries[AIndex][I] := FSummaries[AIndex][I] / C;
|
|
end;
|
|
end;
|
|
Column.DoAfterCalcSummary(Self, DataSet, FSummaries[AIndex][I]);
|
|
end
|
|
end;
|
|
|
|
begin
|
|
if ALevel = nil then
|
|
for AIndex := 0 to Count - 1 do
|
|
Items[AIndex].FinalizeSummaries(nil);
|
|
if not FSummariesInitialized then Exit;
|
|
if ALevel = nil then
|
|
if FNodeType = ntData then
|
|
for AIndex := 0 to FLevel.Count - 1 do
|
|
FinalizeOne(FLevel[AIndex])
|
|
else
|
|
begin
|
|
AIndex := 0;
|
|
FinalizeOne(FLevel);
|
|
end
|
|
else
|
|
begin
|
|
if FNodeType = ntData then
|
|
AIndex := ALevel.Index
|
|
else
|
|
AIndex := 0;
|
|
FinalizeOne(ALevel);
|
|
end;
|
|
FSummariesInitialized := False;
|
|
end;
|
|
|
|
function TdxMasterViewNode.BeginLevel(var Size: Integer): Boolean;
|
|
begin
|
|
Result := Expanded;
|
|
if Result and (FNodeType = ntData) then
|
|
Size := Level.LevelSeparatorWidth
|
|
else
|
|
Size := 0;
|
|
end;
|
|
|
|
function TdxMasterViewNode.EndLevel(var Size, EndLevelCount, EndLevelData: Integer): Boolean;
|
|
var
|
|
ANode: TdxMasterViewNode;
|
|
AlreadyInc: Boolean;
|
|
I: Integer;
|
|
begin
|
|
Size := 0;
|
|
EndLevelCount := 0;
|
|
EndLevelData := 0;
|
|
Result := not Expanded and IsLastInLevel;
|
|
if Result then
|
|
begin
|
|
AlreadyInc := False;
|
|
I := 0;
|
|
ANode := Self;
|
|
repeat
|
|
with ANode do
|
|
begin
|
|
if not IsLastInLevel then Break;
|
|
with Level do
|
|
begin
|
|
if (NodeType = ntData) and ShowFooter then
|
|
Inc(Size, RowCount * FooterHeight);
|
|
if ParentNode.Level <> Level then
|
|
begin
|
|
if Parent.Parent <> nil then
|
|
begin
|
|
Inc(Size, Parent.LevelSeparatorWidth);
|
|
SetHasLevelSeparator(EndLevelData, I);
|
|
if ANode.IsLast then
|
|
begin
|
|
Inc(Size, Parent.RowSeparatorWidth);
|
|
SetHasRowSeparator(EndLevelData, I);
|
|
end;
|
|
end;
|
|
if AlreadyInc then AlreadyInc := False
|
|
else Inc(EndLevelCount);
|
|
end
|
|
else
|
|
if NodeType = ntData then
|
|
begin
|
|
Inc(EndLevelCount);
|
|
AlreadyInc := True;
|
|
end;
|
|
end;
|
|
if not IsLast then Break;
|
|
if ParentNode.Level <> Level then Inc(I);
|
|
ANode := ParentNode;
|
|
end;
|
|
until ANode.ParentNode = nil;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.HasExpandButton: Boolean;
|
|
begin
|
|
Result := (FNodeType <> ntData) or FLevel.HasExpandButton;
|
|
end;
|
|
|
|
function TdxMasterViewNode.HasFooter(AParentIndex: Integer): Boolean;
|
|
begin
|
|
Result := (FViewInfo.FooterSize <> 0) and
|
|
((AParentIndex <> 0) or (FNodeType = ntData));
|
|
if Result and (AParentIndex <> -1) then
|
|
with FLevel.Parents[AParentIndex] do
|
|
Result := ShowFooter and (AParentIndex < FViewInfo.EndLevelCount);
|
|
end;
|
|
|
|
function TdxMasterViewNode.HasGroupByBox(var Size: Integer): Boolean;
|
|
begin
|
|
with FLevel do
|
|
begin
|
|
Result := ShowGroupByBox and (Self = FFirstVisibleNode);
|
|
if Result then
|
|
Size := GroupByBoxHeight
|
|
else
|
|
Size := 0;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.HasHeader(ATopIndex: Integer; var Size: Integer): Boolean;
|
|
begin
|
|
Result :=
|
|
(FNodeType = ntData) and FLevel.ShowHeader and
|
|
(not FLevel.Horizontal or
|
|
((lohForFirstNode in FLevel.OptionsHeader) and IsFirstInLevel or
|
|
(lohAfterExpandedNode in FLevel.OptionsHeader) and
|
|
(Index <> 0) and FParentNode.FItems.List^[Index - 1].Expanded or
|
|
(lohForFirstVisibleNode in FLevel.OptionsHeader) and
|
|
(Self = FLevel.FFirstVisibleNodeWithData)));
|
|
if Result then
|
|
with FLevel do
|
|
Size := VisibleRowCount * HeaderRealHeight
|
|
else
|
|
Size := 0;
|
|
end;
|
|
|
|
function TdxMasterViewNode.HasLevelSeparator(ALevelParentIndex: Integer): Boolean;
|
|
begin
|
|
Result := FViewInfo.EndLevelData and (1 shl ALevelParentIndex) <> 0;
|
|
end;
|
|
|
|
function TdxMasterViewNode.HasPreview: Boolean;
|
|
begin
|
|
with Level do
|
|
Result := ShowPreview and ((FPreviewText <> '') or (PreviewLineCount <> 0));
|
|
end;
|
|
|
|
function TdxMasterViewNode.HasRowSeparator(ALevelParentIndex: Integer): Boolean;
|
|
begin
|
|
Result := FViewInfo.EndLevelData and (1 shl (ALevelParentIndex + 16)) <> 0;
|
|
end;
|
|
|
|
function TdxMasterViewNode.HasSummariesData: Boolean;
|
|
begin
|
|
Result := FSummaries <> nil;
|
|
end;
|
|
|
|
function TdxMasterViewNode.CalcViewInfo(const ATopIndex: Integer; const R: TRect;
|
|
const AIndent, AWidth: Integer; var AFooterSize: Integer; const StoreInfo: Boolean): Integer;
|
|
var
|
|
I, J: Integer;
|
|
begin
|
|
with FViewInfo do
|
|
begin
|
|
with FLevel do
|
|
begin
|
|
case FNodeType of
|
|
ntData:
|
|
begin
|
|
if PreviewSize = 0 then
|
|
if HasPreview then
|
|
CalcPreviewLineCount(FPreviewDC, FPreviewText,
|
|
AWidth - Byte(HasExpandButton) * LevelIndent, Self, I)
|
|
else
|
|
I := 0
|
|
else
|
|
I := PreviewSize;
|
|
Result := VisibleRowCount * ContentRealHeight + I;
|
|
if (I <> 0) or (LineWidth = 0) then Inc(Result, ExtLineWidth);
|
|
end;
|
|
ntCaption:
|
|
begin
|
|
I := 0;
|
|
Result := CaptionHeight + ExtLineWidth;
|
|
end;
|
|
ntGroup:
|
|
begin
|
|
I := 0;
|
|
Result := GroupHeight + ExtLineWidth;
|
|
end;
|
|
else
|
|
Result := 0;
|
|
end;
|
|
if StoreInfo then PreviewSize := I;
|
|
if not FExpanded and (FNodeType = ntData) then
|
|
Inc(Result, RowSeparatorWidth);
|
|
if HasGroupByBox(I) then Inc(Result, I);
|
|
if StoreInfo then GroupByBoxSize := I;
|
|
if HasHeader(ATopIndex, I) and Horizontal then Inc(Result, I);
|
|
if StoreInfo then HeaderSize := I;
|
|
end;
|
|
if BeginLevel(I) then
|
|
begin
|
|
Inc(Result, I);
|
|
AFooterSize := 0;
|
|
if StoreInfo then
|
|
begin
|
|
FooterSize := 0;
|
|
EndLevelCount := 0;
|
|
EndLevelData := 0;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if EndLevel(AFooterSize, I, J) then Inc(Result, AFooterSize);
|
|
if StoreInfo then
|
|
begin
|
|
FooterSize := AFooterSize;
|
|
EndLevelCount := I;
|
|
EndLevelData := J;
|
|
end;
|
|
end;
|
|
if StoreInfo then
|
|
begin
|
|
with Bounds do
|
|
begin
|
|
Left := AIndent;
|
|
Right := Left + AWidth;
|
|
case FNodeType of
|
|
ntCaption:
|
|
with FLevel do
|
|
Dec(Left, (1 + GroupColumnCount) * (LevelIndent + ExtLineWidth));
|
|
ntGroup:
|
|
with FLevel do
|
|
Dec(Left, (GroupColumnCount - GroupIndex) * (LevelIndent + ExtLineWidth));
|
|
end;
|
|
Top := R.Top;
|
|
Bottom := Top + Result;
|
|
end;
|
|
// Indent := AIndent; //:= Bounds.Left !!!
|
|
Options := [];
|
|
LevelIndex := GetLevelIndex;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.ClearViewInfo;
|
|
begin
|
|
SetRectEmpty(FViewInfo.Bounds);
|
|
end;
|
|
|
|
function TdxMasterViewNode.ContentColIndexFromX(X: Integer): Integer;
|
|
begin
|
|
Result := FLevel.Layout.ColFromX(X);
|
|
end;
|
|
|
|
function TdxMasterViewNode.ContentRowIndexFromY(Y: Integer): Integer;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
R := FullContentBounds;
|
|
if (FNodeType = ntData) and (R.Top <= Y) and (Y < R.Bottom) then
|
|
begin
|
|
Result := (Y - R.Top) div FLevel.ContentRealHeight;
|
|
if Result >= FLevel.RowCount then Result := -1;
|
|
end
|
|
else
|
|
Result := -1;
|
|
end;
|
|
|
|
function TdxMasterViewNode.FooterColIndexFromX(AParentIndex: Integer; X: Integer): Integer;
|
|
begin
|
|
Result := FLevel.Parents[AParentIndex].Layout.ColFromX(X);
|
|
end;
|
|
|
|
function TdxMasterViewNode.FooterRowIndexFromY(AParentIndex: Integer; Y: Integer): Integer;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
R := SubFooterBounds[AParentIndex];
|
|
if (R.Top <= Y) and (Y < R.Bottom) then
|
|
with FLevel.Parents[AParentIndex] do
|
|
begin
|
|
Result := (Y - R.Top) div FooterHeight;
|
|
if Result > RowCount - 1 then Result := -1;
|
|
end
|
|
else
|
|
Result := -1;
|
|
end;
|
|
|
|
function TdxMasterViewNode.HeaderColIndexFromX(X: Integer): Integer;
|
|
begin
|
|
Result := FLevel.Layout.ColFromX(X);
|
|
end;
|
|
|
|
function TdxMasterViewNode.HeaderRowIndexFromY(Y: Integer): Integer;
|
|
begin
|
|
Result := InternalHeaderRowIndexFromY(Y);
|
|
if Result >= FLevel.VisibleRowCount then Result := -1;
|
|
end;
|
|
|
|
function TdxMasterViewNode.InternalHeaderRowIndexFromY(Y: Integer): Integer;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
R := FullHeaderBounds;
|
|
if R.Top = R.Bottom then Result := -1
|
|
else
|
|
begin
|
|
Result := (Y - R.Top) div FLevel.HeaderRealHeight;
|
|
if Result < -1 then Result := -1;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.ShowExpandButton: Boolean;
|
|
begin
|
|
Result :=
|
|
HasChildren or
|
|
not (lovNoButtonsWhenNoChildren in FLevel.OptionsView) or
|
|
(not FTriedToExpand and CanExpand);
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.Collapse(Recurse: Boolean);
|
|
var
|
|
CanAnimate: Boolean;
|
|
Delta, AnimationAreaHeight, PrevBaseValue, BaseValue, I, PrevTopIndex,
|
|
PrevTopNodeContentRectTop, AVisibleItemCount, APartVisibleItemCount: Integer;
|
|
BaseNode: TdxMasterViewNode;
|
|
PrevCursor: TCursor;
|
|
R: TRect;
|
|
DC: HDC;
|
|
|
|
function GetBaseValue: Integer;
|
|
begin
|
|
if BaseNode = nil then
|
|
if FExpanded then
|
|
with GetLastSubChild do
|
|
if Visible then
|
|
Result := ContentBounds.Bottom
|
|
else
|
|
Result := 0
|
|
else
|
|
Result := ContentBounds.Bottom
|
|
else
|
|
with BaseNode do
|
|
if Visible then
|
|
Result := ContentBounds.Top
|
|
else
|
|
Result := 0;
|
|
if (Result = 0) or (Result > AnimationAreaHeight) then
|
|
Result := AnimationAreaHeight;
|
|
end;
|
|
|
|
procedure PrepareAnimation1;
|
|
begin
|
|
CanAnimate :=
|
|
FControl.Animation and (FParentNode <> nil) and FExpanded and
|
|
FControl.HandleAllocated and (FControl.FUpdateLockCount = 0);
|
|
if CanAnimate then
|
|
begin
|
|
ProcessPaintMessages(FControl.Handle);
|
|
if IsLast then
|
|
begin
|
|
with GetLastSubChild do
|
|
if Visible then
|
|
Delta := ContentBounds.Bottom
|
|
else
|
|
Delta := 0;
|
|
BaseNode := FParentNode;
|
|
while (BaseNode.ParentNode <> nil) and BaseNode.IsLast do
|
|
BaseNode := BaseNode.ParentNode;
|
|
if BaseNode.ParentNode = nil then
|
|
BaseNode := nil
|
|
else
|
|
BaseNode := BaseNode.ParentNode[BaseNode.Index + 1];
|
|
end
|
|
else
|
|
begin
|
|
with FParentNode[Index + 1] do
|
|
if Visible then
|
|
Delta := ContentBounds.Top
|
|
else
|
|
Delta := 0;
|
|
BaseNode := FParentNode[Index + 1];
|
|
end;
|
|
AnimationAreaHeight := FControl.GetAnimatableHeight;
|
|
if Delta = 0 then Delta := AnimationAreaHeight;
|
|
PrevBaseValue := GetBaseValue;
|
|
end;
|
|
end;
|
|
|
|
procedure PrepareAnimation2;
|
|
begin
|
|
if CanAnimate then
|
|
begin
|
|
PrevTopIndex := FControl.TopIndex;
|
|
PrevTopNodeContentRectTop := FControl.TopNode.ContentBounds.Top;
|
|
R := FullBounds;
|
|
end;
|
|
end;
|
|
|
|
procedure DoAnimation;
|
|
var
|
|
AnimationStep, AnimationIncreaseStep: Integer;
|
|
UpdateR: TRect;
|
|
begin
|
|
if CanAnimate then
|
|
begin
|
|
AnimationStep := AnimationOriginalStep;
|
|
FControl.CalcViewInfo(FControl.TopIndex, -1, AVisibleItemCount, APartVisibleItemCount, True);
|
|
|
|
if FControl.TopIndex = PrevTopIndex then
|
|
begin
|
|
BaseValue := GetBaseValue;
|
|
Dec(Delta, R.Bottom);
|
|
R.Top := R.Bottom + AnimationStep;
|
|
R.Bottom := AnimationAreaHeight;
|
|
AnimationIncreaseStep :=
|
|
(R.Bottom - R.Top + Delta) div AnimationIncreaseStepDivisor1;
|
|
|
|
FControl.BeginAnimation;
|
|
DC := GetDC(FControl.Handle);
|
|
try
|
|
while (Delta > AnimationStep) and (R.Top < R.Bottom) do
|
|
begin
|
|
ScrollWindowEx(FControl.Handle, 0, -AnimationStep, @R, nil, 0, @UpdateR, 0);
|
|
//FillRect(DC, UpdateR, FControl.Brush.Handle);
|
|
|
|
Dec(Delta, AnimationStep);
|
|
Inc(R.Top, AnimationIncreaseStep);
|
|
Dec(R.Bottom, AnimationStep);
|
|
Inc(AnimationStep, AnimationIncreaseStep);
|
|
end;
|
|
finally
|
|
ReleaseDC(FControl.Handle, DC);
|
|
FControl.EndAnimation;
|
|
end;
|
|
|
|
Invalidate(nil, vpAllAndBelow);
|
|
end
|
|
else
|
|
begin
|
|
Delta := ContentBounds.Bottom - R.Bottom;
|
|
R.Top := PrevTopNodeContentRectTop;
|
|
AnimationIncreaseStep :=
|
|
(R.Bottom - R.Top) div AnimationIncreaseStepDivisor2;
|
|
|
|
FControl.BeginAnimation;
|
|
DC := GetDC(FControl.Handle);
|
|
try
|
|
while Delta > AnimationStep do
|
|
begin
|
|
ScrollWindowEx(FControl.Handle, 0, AnimationStep, @R, nil, 0, @UpdateR, 0);
|
|
//FillRect(DC, UpdateR, FControl.Brush.Handle);
|
|
|
|
Dec(Delta, AnimationStep);
|
|
Inc(R.Top, AnimationStep);
|
|
Inc(R.Bottom, AnimationStep);
|
|
Inc(AnimationStep, AnimationIncreaseStep);
|
|
end;
|
|
finally
|
|
ReleaseDC(FControl.Handle, DC);
|
|
FControl.EndAnimation;
|
|
end;
|
|
|
|
FControl.Invalidate;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if not FExpanded or not FLevel.DoBeforeCollapse(Self) then Exit;
|
|
PrepareAnimation1;
|
|
PrevCursor := Screen.Cursor;
|
|
if FControl.ShowHourGlassCursor then Screen.Cursor := crHourGlass;
|
|
FControl.BeginUpdate;
|
|
try
|
|
if FParentNode <> nil then ChangeExpanded(False);
|
|
if Recurse then
|
|
for I := 0 to Count - 1 do Items[I].Collapse(True);
|
|
finally
|
|
try
|
|
PrepareAnimation2;
|
|
finally
|
|
FControl.EndUpdate;
|
|
if FControl.ShowHourGlassCursor then Screen.Cursor := PrevCursor;
|
|
DoAnimation;
|
|
FLevel.DoAfterCollapse(Self);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.Delete;
|
|
var
|
|
NewNode: TdxMasterViewNode;
|
|
LevelUsed: PBoolArray;
|
|
I: Integer;
|
|
Control: TdxMasterView;
|
|
|
|
function DeleteSelf: TdxMasterViewNode;
|
|
var
|
|
PrevNode: TdxMasterViewNode;
|
|
begin
|
|
Result := FParentNode;
|
|
Free;
|
|
while (Result.NodeType = ntGroup) and (Result.Count = 0) do
|
|
begin
|
|
PrevNode := Result;
|
|
Result := Result.ParentNode;
|
|
PrevNode.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure DeleteOne(ALevel: TdxMasterViewLevel; const AID, AKeyValue: Variant);
|
|
var
|
|
Node: TdxMasterViewNode;
|
|
I: Integer;
|
|
AFound: Boolean;
|
|
begin
|
|
if not LevelUsed[ALevel.AbsoluteIndex] then
|
|
begin
|
|
LevelUsed[ALevel.AbsoluteIndex] := True;
|
|
ALevel.BeginLoad;
|
|
end;
|
|
Node := Control.NodeFromID(ALevel, AID);
|
|
try
|
|
if Node <> nil then Node.Sync;
|
|
if ALevel.HasChildren then
|
|
for I := 0 to ALevel.Count - 1 do
|
|
with ALevel[I] do
|
|
if CanDelete then
|
|
with DataSet do
|
|
begin
|
|
AFound := Locate(DetailKey, AKeyValue[I], []);
|
|
while AFound do
|
|
begin
|
|
DeleteOne(ALevel[I], GetCurIDValue, GetCurKeyValue);
|
|
AFound := not EOF and VarAreEqual(GetCurDetailKeyValue, AKeyValue[I]);
|
|
end;
|
|
end;
|
|
ALevel.DataSet.Delete;
|
|
except
|
|
if Node <> nil then Node.UpdateData(False, False, True);
|
|
raise;
|
|
end;
|
|
if Node <> nil then
|
|
if Node = Self then
|
|
begin
|
|
ALevel := FLevel;
|
|
Node := DeleteSelf;
|
|
if Node.CountInLevel[ALevel] <> 0 then
|
|
Node.FirstInLevel[ALevel].UpdateData(False, False, True);
|
|
end
|
|
else
|
|
Node.Free;
|
|
end;
|
|
|
|
begin
|
|
if not CanDelete or
|
|
(lodDeleteOnlyChildless in FLevel.OptionsDB) and
|
|
FLevel.HasChildren and FindChildren then Exit;
|
|
|
|
if AbsoluteIndex = -1 then NewNode := nil
|
|
else
|
|
if IsLast then
|
|
if IsFirst then
|
|
if FParentNode.ParentNode = nil then NewNode := nil
|
|
else
|
|
begin
|
|
NewNode := FParentNode;
|
|
while (NewNode.NodeType = ntGroup) and (NewNode.Count = 1) do
|
|
begin
|
|
if NewNode.ParentNode.Count <> 1 then
|
|
begin
|
|
if NewNode.IsLast then
|
|
NewNode := NewNode.ParentNode[NewNode.Index - 1]
|
|
else
|
|
NewNode := NewNode.ParentNode[NewNode.Index + 1];
|
|
Break;
|
|
end;
|
|
NewNode := NewNode.ParentNode;
|
|
end;
|
|
end
|
|
else
|
|
NewNode := FParentNode[Index - 1]
|
|
else
|
|
NewNode := FParentNode[Index + 1];
|
|
|
|
I := FControl.AbsoluteLevelCount * SizeOf(Boolean);
|
|
GetMem(LevelUsed, I);
|
|
FillChar(LevelUsed^, I, 0);
|
|
try
|
|
Control := FControl;
|
|
Control.BeginSelection;
|
|
try
|
|
Control.BeginUpdate;
|
|
try
|
|
DeleteOne(FLevel, FID, FKeyValue);
|
|
finally
|
|
try
|
|
for I := 0 to Control.AbsoluteLevelCount - 1 do
|
|
if LevelUsed[I] then Control.AbsoluteLevels[I].EndLoad(True);
|
|
finally
|
|
Control.EndUpdate;
|
|
end;
|
|
end;
|
|
finally
|
|
Control.EndSelection;
|
|
end;
|
|
finally
|
|
FreeMem(LevelUsed);
|
|
end;
|
|
if NewNode <> nil then
|
|
with NewNode do
|
|
Control.FocusedIndex := AbsoluteIndex;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.Expand(Recurse: Boolean);
|
|
var
|
|
CanAnimate, PrevExpanded: Boolean;
|
|
PrevCursor: TCursor;
|
|
AnimationAreaHeight, I, AVisibleItemCount, APartVisibleItemCount, Delta: Integer;
|
|
R: TRect;
|
|
|
|
procedure PrepareAnimation;
|
|
begin
|
|
CanAnimate :=
|
|
FControl.Animation and (FParentNode <> nil) and not FExpanded and
|
|
FControl.HandleAllocated and (FControl.FUpdateLockCount = 0);
|
|
if CanAnimate then
|
|
begin
|
|
ProcessPaintMessages(FControl.Handle);
|
|
AnimationAreaHeight := FControl.GetAnimatableHeight;
|
|
R := FullContentBounds;
|
|
end;
|
|
end;
|
|
|
|
procedure DoAnimation;
|
|
var
|
|
AnimationStep, AnimationIncreaseStep: Integer;
|
|
DC: HDC;
|
|
UpdateR: TRect;
|
|
begin
|
|
if CanAnimate and FExpanded then
|
|
begin
|
|
AnimationStep := AnimationOriginalStep;
|
|
FControl.CalcViewInfo(FControl.TopIndex, -1, AVisibleItemCount, APartVisibleItemCount, True);
|
|
|
|
R.Top := R.Bottom - (FLevel.ExtLineWidth + FLevel.RowSeparatorWidth);
|
|
R.Bottom := AnimationAreaHeight - AnimationStep;
|
|
if IsLast then
|
|
with GetLastSubChild do
|
|
if Visible then
|
|
Delta := ContentBounds.Bottom
|
|
else
|
|
Delta := 0
|
|
else
|
|
with FParentNode[Index + 1] do
|
|
if Visible then
|
|
Delta := ContentBounds.Top
|
|
else
|
|
Delta := 0;
|
|
if Delta = 0 then Delta := AnimationAreaHeight;
|
|
Dec(Delta, R.Top);
|
|
AnimationIncreaseStep :=
|
|
(R.Bottom - R.Top + Delta) div AnimationIncreaseStepDivisor3;
|
|
|
|
FControl.BeginAnimation;
|
|
DC := GetDC(FControl.Handle);
|
|
try
|
|
while (Delta > AnimationStep) and (R.Top < R.Bottom) do
|
|
begin
|
|
ScrollWindowEx(FControl.Handle, 0, AnimationStep, @R, nil, 0, @UpdateR, 0);
|
|
//FillRect(DC, UpdateR, FControl.Brush.Handle);
|
|
|
|
Dec(Delta, AnimationStep);
|
|
Inc(R.Top, AnimationStep);
|
|
Dec(R.Bottom, AnimationIncreaseStep);
|
|
Inc(AnimationStep, AnimationIncreaseStep);
|
|
end;
|
|
finally
|
|
ReleaseDC(FControl.Handle, DC);
|
|
FControl.EndAnimation;
|
|
end;
|
|
|
|
Invalidate(nil, vpAllAndBelow);
|
|
end;
|
|
end;
|
|
|
|
procedure LockLevels(ALock: Boolean);
|
|
var
|
|
I: Integer;
|
|
RootLevel: TdxMasterViewLevel;
|
|
AllowDoAction: Boolean;
|
|
|
|
procedure LockOne(ALevel: TdxMasterViewLevel);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if ALevel <> RootLevel then
|
|
with ALevel do
|
|
if SmartLoad or AllowDoAction then
|
|
begin
|
|
if ALock then BeginLoad
|
|
else EndLoad(True);
|
|
AllowDoAction := True;
|
|
end;
|
|
for I := 0 to ALevel.Count - 1 do LockOne(ALevel[I]);
|
|
end;
|
|
|
|
begin
|
|
for I := 0 to FLevel.Count - 1 do
|
|
begin
|
|
RootLevel := FLevel[I];
|
|
AllowDoAction := RootLevel.SmartLoad;
|
|
LockOne(RootLevel);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if not CanExpand or IsEditing or
|
|
not Expanded and not FLevel.DoBeforeExpand(Self) then Exit;
|
|
PrepareAnimation;
|
|
PrevExpanded := Expanded;
|
|
PrevCursor := Screen.Cursor;
|
|
if FControl.ShowHourGlassCursor then Screen.Cursor := crHourGlass;
|
|
FControl.BeginUpdate;
|
|
try
|
|
ChangeExpanded(True);
|
|
if FNodeType = ntCaption then
|
|
if FLevel.SmartLoad and (Count = 0) then
|
|
UpdateData(False, True, False)
|
|
else
|
|
else
|
|
if FNodeType = ntData then
|
|
for I := 0 to FLevel.Count - 1 do
|
|
if FLevel[I].SmartLoad and (CountInLevel[FLevel[I]] = 0) then
|
|
begin
|
|
UpdateData(False, True, False);
|
|
Break;
|
|
end;
|
|
CheckExpanded;
|
|
if Recurse then
|
|
begin
|
|
LockLevels(True);
|
|
try
|
|
for I := 0 to Count - 1 do Items[I].Expand(True);
|
|
finally
|
|
LockLevels(False);
|
|
end;
|
|
end;
|
|
finally
|
|
FControl.EndUpdate;
|
|
if FControl.ShowHourGlassCursor then Screen.Cursor := PrevCursor;
|
|
DoAnimation;
|
|
if Expanded <> PrevExpanded then FLevel.DoAfterExpand(Self);
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.FindChildren: Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := HasChildren;
|
|
if Result then Exit;
|
|
case FNodeType of
|
|
ntData:
|
|
for I := 0 to FLevel.Count - 1 do
|
|
with FLevel[I] do
|
|
if SmartLoad and Active then
|
|
begin
|
|
BeginLoad;
|
|
try
|
|
Result := DataSet.Locate(DetailKey, FKeyValue[I], []);
|
|
if Result then Break;
|
|
finally
|
|
EndLoad(False);
|
|
end;
|
|
end;
|
|
ntCaption:
|
|
with FLevel do
|
|
if SmartLoad and Active then
|
|
if ParentCount = 2 then
|
|
with DataSet do
|
|
Result := not (BOF and EOF)
|
|
else
|
|
begin
|
|
BeginLoad;
|
|
try
|
|
Result := DataSet.Locate(DetailKey, FParentNode.KeyValue[Index], []);
|
|
finally
|
|
EndLoad(False);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.GetParentNode(ALevel: TdxMasterViewLevel;
|
|
OnlyDataNodes: Boolean): TdxMasterViewNode;
|
|
begin
|
|
Result := Self;
|
|
while (Result <> nil) and (Result.Level <> ALevel) do
|
|
Result := Result.ParentNode;
|
|
if Result <> nil then
|
|
if OnlyDataNodes then
|
|
begin
|
|
while (Result.NodeType <> ntData) and
|
|
(Result.ParentNode <> nil) and (Result.ParentNode.Level = ALevel) do
|
|
Result := Result.ParentNode;
|
|
if Result.NodeType <> ntData then Result := nil;
|
|
end;
|
|
{ if Result <> nil then
|
|
if OnlyDataNodes then
|
|
if Result.NodeType <> ntData then Result := nil
|
|
else
|
|
else
|
|
while (Result.ParentNode <> nil) and (Result.ParentNode.Level = ALevel) do
|
|
Result := Result.ParentNode;}
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.MakeVisible;
|
|
var
|
|
Node: TdxMasterViewNode;
|
|
begin
|
|
Node := FParentNode;
|
|
while Node <> nil do
|
|
begin
|
|
Node.Expanded := True;
|
|
Node := Node.ParentNode;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterViewNode.LoadChildren(Recurse: Boolean);
|
|
var
|
|
PrevExpanded: Boolean;
|
|
I: Integer;
|
|
begin
|
|
FControl.BeginUpdate;
|
|
try
|
|
PrevExpanded := Expanded;
|
|
try
|
|
Expanded := True;
|
|
if Recurse then
|
|
for I := 0 to Count - 1 do
|
|
Items[I].LoadChildren(Recurse);
|
|
finally
|
|
Expanded := PrevExpanded;
|
|
end;
|
|
finally
|
|
FControl.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterViewNode.NodeFromID(ALevel: TdxMasterViewLevel;
|
|
const AID: Variant): TdxMasterViewNode;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
Result := Items[I];
|
|
if Result.Level = ALevel then
|
|
if Result.NodeType = ntData then
|
|
if VarAreEqual(Result.ID, AID) then Exit
|
|
else
|
|
else
|
|
if (Result.NodeType = ntCaption) and VarIsEmpty(AID) then Exit
|
|
else
|
|
begin
|
|
Result := Result.NodeFromID(ALevel, AID);
|
|
if Result <> nil then Exit;
|
|
end;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TdxMasterViewNode.NodeFromKeyValue(ALevel: TdxMasterViewLevel;
|
|
AChildIndex: Integer; const AKeyValue: Variant): TdxMasterViewNode;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
Result := Items[I];
|
|
if Result.Level = ALevel then
|
|
if Result.NodeType = ntData then
|
|
if VarAreEqual(Result.KeyValue[AChildIndex], AKeyValue) then Exit
|
|
else
|
|
else
|
|
begin
|
|
Result := Result.NodeFromKeyValue(ALevel, AChildIndex, AKeyValue);
|
|
if Result <> nil then Exit;
|
|
end;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
{ TdxMasterView }
|
|
|
|
constructor TdxMasterView.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
ControlStyle := ControlStyle - [csCaptureMouse];
|
|
ParentColor := False;
|
|
TabStop := True;
|
|
Width := 230;
|
|
Height := 170;
|
|
FAbsoluteItems := TdxMasterViewList.Create(nil, lmAbsoluteItems);
|
|
FAbsoluteLevels := TList.Create;
|
|
FArrowsColor := clLime;
|
|
FBitmap := TBitmap.Create;
|
|
FCustomizationFormPos := Point(-1, -1);
|
|
FCustomizationFormRowCount := dxMVCustomizationFormRowCount;
|
|
FLevels := TdxMasterViewLevel.Create(nil);
|
|
FLevels.FControl := Self;
|
|
FItems := TdxMasterViewNode.Create(Self, FLevels, nil, -1, ntData, Unassigned, Unassigned);
|
|
FItems.ChangeExpanded(True);
|
|
FOptionsBehavior :=
|
|
[mobUseIndent];
|
|
FOptionsDB :=
|
|
[modSyncMove];
|
|
FOptionsView :=
|
|
[movAnimation, movHideFocusRect, movKeepColumnWidths,
|
|
movTransparentDragAndDrop, movUseBitmapToDrawPreview];
|
|
FSelectedItems := TdxMasterViewList.Create(FItems, lmSelectedItems);
|
|
FStyles := TList.Create;
|
|
end;
|
|
|
|
destructor TdxMasterView.Destroy;
|
|
begin
|
|
try
|
|
if not IsDesigning then
|
|
begin
|
|
if mobStoreInIniFile in FOptionsBehavior then
|
|
SaveToRegIniFile(FIniFileName, riIniFile);
|
|
if mobStoreInRegistry in FOptionsBehavior then
|
|
SaveToRegIniFile(FRegistryPath, riRegistry);
|
|
end;
|
|
finally
|
|
if dxMVDesigner <> nil then dxMVDesigner.Hide(Self);
|
|
HighlightStyle := nil;
|
|
InactiveStyle := nil;
|
|
DestroyStyles;
|
|
FStyles.Free;
|
|
FItems.Free;
|
|
FItems := nil;
|
|
FLevels.Free;
|
|
FLevels := nil;
|
|
FSelectedItems.Free;
|
|
FBitmap.Free;
|
|
FAbsoluteLevels.Free;
|
|
FAbsoluteItems.Free;
|
|
inherited;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterView.GetAbsoluteItemCount: Integer;
|
|
begin
|
|
Result := FAbsoluteItems.Count;
|
|
end;
|
|
|
|
function TdxMasterView.GetAbsoluteItem(Index: Integer): TdxMasterViewNode;
|
|
begin
|
|
Result := FAbsoluteItems[Index];
|
|
end;
|
|
|
|
function TdxMasterView.GetAbsoluteLevelCount: Integer;
|
|
begin
|
|
Result := FAbsoluteLevels.Count;
|
|
end;
|
|
|
|
function TdxMasterView.GetAbsoluteLevel(Index: Integer): TdxMasterViewLevel;
|
|
begin
|
|
Result := FAbsoluteLevels[Index];
|
|
end;
|
|
|
|
function TdxMasterView.GetAnimation: Boolean;
|
|
begin
|
|
Result := movAnimation in FOptionsView;
|
|
end;
|
|
|
|
function TdxMasterView.GetAutoColumnWidth: Boolean;
|
|
begin
|
|
Result := movAutoColumnWidth in FOptionsView;
|
|
end;
|
|
|
|
function TdxMasterView.GetCustomizationFormLevel: TdxMasterViewLevel;
|
|
begin
|
|
if FCustomizing then
|
|
Result := TdxMVCustomizationForm(FCustomizationForm).ActiveLevel
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TdxMasterView.GetFocusedIndex: Integer;
|
|
begin
|
|
if FFocusedNode = nil then Result := -1
|
|
else Result := FFocusedNode.AbsoluteIndex;
|
|
end;
|
|
|
|
function TdxMasterView.GetHasFocus: Boolean;
|
|
begin
|
|
Result := Focused;
|
|
end;
|
|
|
|
function TdxMasterView.GetHighlightBrush: HBRUSH;
|
|
begin
|
|
if (HighlightStyle <> nil) and (svColor in HighlightStyle.AssignedValues) then
|
|
Result := HighlightStyle.Brush
|
|
else
|
|
Result := GetSysColorBrush(COLOR_HIGHLIGHT);
|
|
end;
|
|
|
|
function TdxMasterView.GetHighlightColor: TColor;
|
|
begin
|
|
if (HighlightStyle <> nil) and (svColor in HighlightStyle.AssignedValues) then
|
|
Result := HighlightStyle.Color
|
|
else
|
|
Result := clHighlight;
|
|
end;
|
|
|
|
function TdxMasterView.GetHighlightFontColor: TColor;
|
|
begin
|
|
if (HighlightStyle <> nil) and (svFont in HighlightStyle.AssignedValues) then
|
|
Result := HighlightStyle.Font.Color
|
|
else
|
|
Result := clHighlightText;
|
|
end;
|
|
|
|
function TdxMasterView.GetInactiveBrush: HBRUSH;
|
|
begin
|
|
if (InactiveStyle <> nil) and (svColor in InactiveStyle.AssignedValues) then
|
|
Result := InactiveStyle.Brush
|
|
else
|
|
Result := GetSysColorBrush(COLOR_BTNFACE);
|
|
end;
|
|
|
|
function TdxMasterView.GetInactiveColor: TColor;
|
|
begin
|
|
if (InactiveStyle <> nil) and (svColor in InactiveStyle.AssignedValues) then
|
|
Result := InactiveStyle.Color
|
|
else
|
|
Result := clBtnFace;
|
|
end;
|
|
|
|
function TdxMasterView.GetInactiveFocusBrush: HBRUSH;
|
|
begin
|
|
if (InactiveStyle <> nil) and (svAnotherColor in InactiveStyle.AssignedValues) then
|
|
Result := InactiveStyle.AnotherBrush
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TdxMasterView.GetInactiveFocusColor: TColor;
|
|
begin
|
|
if (InactiveStyle <> nil) and (svAnotherColor in InactiveStyle.AssignedValues) then
|
|
Result := InactiveStyle.AnotherColor
|
|
else
|
|
Result := clNone;
|
|
end;
|
|
|
|
function TdxMasterView.GetInactiveFontColor: TColor;
|
|
begin
|
|
if (InactiveStyle <> nil) and (svFont in InactiveStyle.AssignedValues) then
|
|
Result := InactiveStyle.Font.Color
|
|
else
|
|
Result := clBtnText;
|
|
end;
|
|
|
|
function TdxMasterView.GetIsDesigning: Boolean;
|
|
begin
|
|
Result := csDesigning in ComponentState;
|
|
end;
|
|
|
|
function TdxMasterView.GetIsDestroying: Boolean;
|
|
begin
|
|
Result := csDestroying in ComponentState;
|
|
end;
|
|
|
|
function TdxMasterView.GetIsLoading: Boolean;
|
|
begin
|
|
Result := csLoading in ComponentState;
|
|
end;
|
|
|
|
function TdxMasterView.GetMultiSelect: Boolean;
|
|
begin
|
|
Result := mobMultiSelect in FOptionsBehavior;
|
|
end;
|
|
|
|
function TdxMasterView.GetPartVisibleItemCount: Integer;
|
|
var
|
|
AVisibleItemCount: Integer;
|
|
begin
|
|
CalcViewInfo(TopIndex, -1, AVisibleItemCount, Result, True{False});
|
|
end;
|
|
{
|
|
function TdxMasterView.GetScrollableWidth: Integer;
|
|
var
|
|
I, Size: Integer;
|
|
begin
|
|
Result := 0;
|
|
for I := 0 to LevelCount - 1 do
|
|
with Levels[I] do
|
|
if Visible then
|
|
begin
|
|
Size := Indent + VisibleWidth;
|
|
if Size > Result then Result := Size;
|
|
end;
|
|
end;
|
|
}
|
|
function TdxMasterView.GetSelectedItem(Index: Integer): TdxMasterViewNode;
|
|
begin
|
|
if MultiSelect then
|
|
Result := FSelectedItems[Index]
|
|
else
|
|
Result := FFocusedNode;
|
|
end;
|
|
|
|
function TdxMasterView.GetSelectedItemCount: Integer;
|
|
begin
|
|
if MultiSelect then
|
|
Result := FSelectedItems.Count
|
|
else
|
|
Result := Byte(FFocusedNode <> nil);
|
|
end;
|
|
|
|
function TdxMasterView.GetShowHourGlassCursor: Boolean;
|
|
begin
|
|
Result := mobShowHourGlassCursor in FOptionsBehavior;
|
|
end;
|
|
|
|
function TdxMasterView.GetStyle(Index: Integer): TdxMasterViewStyle;
|
|
begin
|
|
Result := TdxMasterViewStyle(FStyles[Index]);
|
|
end;
|
|
|
|
function TdxMasterView.GetStyleCount: Integer;
|
|
begin
|
|
Result := FStyles.Count;
|
|
end;
|
|
|
|
function TdxMasterView.GetSyncMove: Boolean;
|
|
begin
|
|
Result := modSyncMove in FOptionsDB;
|
|
end;
|
|
|
|
function TdxMasterView.GetTopIndex: Integer;
|
|
begin
|
|
if FTopNode = nil then
|
|
Result := -1
|
|
else
|
|
Result := FTopNode.AbsoluteIndex;
|
|
end;
|
|
|
|
function TdxMasterView.GetTransparentDragAndDrop: Boolean;
|
|
begin
|
|
Result := movTransparentDragAndDrop in FOptionsView;
|
|
end;
|
|
|
|
function TdxMasterView.GetUseIndent: Boolean;
|
|
begin
|
|
Result := mobUseIndent in FOptionsBehavior;
|
|
end;
|
|
|
|
function TdxMasterView.GetVisibleItemCount: Integer;
|
|
var
|
|
APartVisibleItemCount: Integer;
|
|
begin
|
|
CalcViewInfo(TopIndex, -1, Result, APartVisibleItemCount, True{False});
|
|
end;
|
|
|
|
function TdxMasterView.GetWidthForColumns: Integer;
|
|
begin
|
|
Result := ScrollableWidth;
|
|
end;
|
|
|
|
procedure TdxMasterView.SetCanUseSmartReload(Value: Boolean);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if not Value or (FLayoutLockCount = 0) then
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
if not Value or (AbsoluteLevels[I].FDataChangingLockCount = 0) then
|
|
AbsoluteLevels[I].CanUseSmartReload := Value;
|
|
end;
|
|
|
|
procedure TdxMasterView.SetCustomizationFormLevel(Value: TdxMasterViewLevel);
|
|
begin
|
|
if FCustomizing then
|
|
TdxMVCustomizationForm(FCustomizationForm).ActiveLevel := Value;
|
|
end;
|
|
|
|
procedure TdxMasterView.SetCustomizationFormRowCount(Value: Integer);
|
|
begin
|
|
if Value < 2 then Value := 2;
|
|
FCustomizationFormRowCount := Value;
|
|
end;
|
|
|
|
procedure TdxMasterView.SetCustomizing(Value: Boolean);
|
|
begin
|
|
if (FCustomizing <> Value) and
|
|
(HandleAllocated and IsWindowVisible(Handle) and (FLevels.Count <> 0) or not Value) then
|
|
begin
|
|
FCustomizing := Value;
|
|
if FCustomizing then
|
|
FCustomizationForm := TdxMVCustomizationForm.Create(Self)
|
|
else
|
|
begin
|
|
with FCustomizationForm do
|
|
if not (csDestroying in ComponentState) then Free;
|
|
FCustomizationForm := nil;
|
|
end;
|
|
if Assigned(FOnCustomizing) then FOnCustomizing(Self, Value);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.SetFocusedIndex(Value: Integer);
|
|
begin
|
|
if Value < 0 then Value := 0;
|
|
if Value >= AbsoluteItemCount then Value := AbsoluteItemCount - 1;
|
|
if FocusedIndex <> Value then
|
|
ChangeFocusedIndex(Value);
|
|
end;
|
|
|
|
procedure TdxMasterView.SetFocusedNode(Value: TdxMasterViewNode);
|
|
var
|
|
PrevFocusedNode: TdxMasterViewNode;
|
|
begin
|
|
if FFocusedNode <> Value then
|
|
begin
|
|
PrevFocusedNode := FFocusedNode;
|
|
FFocusedNode := Value;
|
|
if not IsDestroying and Assigned(FOnFocusNode) then
|
|
FOnFocusNode(Self, PrevFocusedNode, FFocusedNode);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.SetHighlightStyle(Value: TdxMasterViewStyle);
|
|
begin
|
|
if FHighlightStyle <> Value then
|
|
begin
|
|
if FHighlightStyle <> nil then
|
|
FHighlightStyle.RemoveConsumeType(Self, sctHighlight);
|
|
FHighlightStyle := Value;
|
|
if FHighlightStyle <> nil then
|
|
FHighlightStyle.AddConsumeType(Self, sctHighlight);
|
|
HighlightStyleChanged([]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.SetInactiveStyle(Value: TdxMasterViewStyle);
|
|
begin
|
|
if FInactiveStyle <> Value then
|
|
begin
|
|
if FInactiveStyle <> nil then
|
|
FInactiveStyle.RemoveConsumeType(Self, sctInactive);
|
|
FInactiveStyle := Value;
|
|
if FInactiveStyle <> nil then
|
|
FInactiveStyle.AddConsumeType(Self, sctInactive);
|
|
InactiveStyleChanged([]);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.SetLeftPos(Value: Integer);
|
|
begin
|
|
Value := CheckLeftPos(Value);
|
|
if FLeftPos <> Value then
|
|
begin
|
|
if HandleAllocated then
|
|
ScrollWindowEx(Handle, FLeftPos - Value, 0, nil, nil, 0, nil, SW_INVALIDATE);
|
|
FLeftPos := Value;
|
|
if HandleAllocated then UpdateWindow(Handle);
|
|
if Assigned(FOnLeftPosChanged) then FOnLeftPosChanged(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.SetOptionsBehavior(Value: TdxMasterViewOptionsBehavior);
|
|
var
|
|
ChangedValues: TdxMasterViewOptionsBehavior;
|
|
begin
|
|
if FOptionsBehavior <> Value then
|
|
begin
|
|
Word(ChangedValues) := Word(Value) xor Word(FOptionsBehavior);
|
|
|
|
if mobMultiSelect in ChangedValues then
|
|
if not (mobMultiSelect in Value) then ClearSelectedItems;
|
|
|
|
FOptionsBehavior := Value;
|
|
|
|
if [mobAnsiCompareStrOnGrouping, mobCaseInsensitiveGrouping] * ChangedValues <> [] then
|
|
begin
|
|
CanUseSmartReload := False;
|
|
UpdateData;
|
|
end;
|
|
if [mobAnsiCompareStrOnSorting, mobCaseInsensitiveSorting] * ChangedValues <> [] then
|
|
DoSorting;
|
|
if mobMultiSelect in ChangedValues then
|
|
if FocusedNode <> nil then FocusedNode.NodeChanged(False);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.SetOptionsDB(Value: TdxMasterViewOptionsDB);
|
|
var
|
|
ChangedValues: TdxMasterViewOptionsDB;
|
|
begin
|
|
if FOptionsDB <> Value then
|
|
begin
|
|
Byte(ChangedValues) := Byte(Value) xor Byte(FOptionsDB);
|
|
|
|
FOptionsDB := Value;
|
|
|
|
if modSyncMove in ChangedValues then
|
|
if SyncMove and (FFocusedNode <> nil) then FFocusedNode.SyncPos;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.SetOptionsView(Value: TdxMasterViewOptionsView);
|
|
var
|
|
ChangedValues: TdxMasterViewOptionsView;
|
|
begin
|
|
if FOptionsView <> Value then
|
|
begin
|
|
Word(ChangedValues) := Word(Value) xor Word(FOptionsView);
|
|
|
|
FOptionsView := Value;
|
|
|
|
if movAutoColumnWidth in ChangedValues then
|
|
if not AutoColumnWidth and (movKeepColumnWidths in FOptionsView) then
|
|
AssignColumnWidths
|
|
else
|
|
begin
|
|
WidthChanged;
|
|
Invalidate;
|
|
end;
|
|
if movDrawEndEllipsis in ChangedValues then
|
|
Invalidate;
|
|
if [movHideFocusRect, movHideSelection] * ChangedValues <> [] then
|
|
InvalidateSelection;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.SetScrollBars(Value: TdxMVScrollBars);
|
|
begin
|
|
if FScrollBars <> Value then
|
|
begin
|
|
FScrollBars := Value;
|
|
RecreateWnd;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.SetTopIndex(Value: Integer);
|
|
begin
|
|
Value := CheckTopIndex(Value);
|
|
if TopIndex <> Value then
|
|
if Value = -1 then
|
|
TopNode := nil
|
|
else
|
|
TopNode := AbsoluteItems[Value];
|
|
end;
|
|
|
|
procedure TdxMasterView.SetTopNode(Value: TdxMasterViewNode);
|
|
begin
|
|
if FTopNode <> Value then
|
|
begin
|
|
FTopNode := Value;
|
|
if not IsDestroying then DoTopNodeChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.AddStyle(AStyle: TdxMasterViewStyle);
|
|
begin
|
|
FStyles.Add(AStyle);
|
|
AStyle.FControl := Self;
|
|
end;
|
|
|
|
procedure TdxMasterView.RemoveStyle(AStyle: TdxMasterViewStyle);
|
|
begin
|
|
FStyles.Remove(AStyle);
|
|
AStyle.FControl := nil;
|
|
end;
|
|
|
|
procedure TdxMasterView.AddSelectedItem(ANode: TdxMasterViewNode);
|
|
begin
|
|
FSelectedItems.Add(ANode);
|
|
end;
|
|
|
|
procedure TdxMasterView.RemoveSelectedItem(ANode: TdxMasterViewNode);
|
|
begin
|
|
FSelectedItems.Remove(ANode);
|
|
end;
|
|
|
|
procedure TdxMasterView.ClearSelectedItems;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if not MultiSelect then Exit;
|
|
BeginSelection;
|
|
try
|
|
for I := SelectedItemCount - 1 downto 0 do
|
|
SelectedItems[I].Selected := False;
|
|
finally
|
|
EndSelection;
|
|
end;
|
|
end;
|
|
|
|
procedure ScrollTimerProc(Wnd: HWND; Msg: UINT; idEvent: UINT; Time: DWORD); stdcall;
|
|
begin
|
|
with TdxMasterView(FindControl(Wnd)) do
|
|
begin
|
|
case TdxMasterViewDirection(idEvent - ScrollLeftTimerId + 1) of
|
|
dirLeft:
|
|
Scroll(dirLeft);
|
|
dirUp:
|
|
begin
|
|
FocusedIndex := FocusedIndex - 1;
|
|
SelectPeriod(FocusedNode);
|
|
end;
|
|
dirRight:
|
|
Scroll(dirRight);
|
|
dirDown:
|
|
begin
|
|
FocusedIndex := FocusedIndex + 1;
|
|
SelectPeriod(FocusedNode);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.CreateScrollTimer(Direction: TdxMasterViewDirection);
|
|
begin
|
|
if FScrollTimer <> 0 then
|
|
if TdxMasterViewDirection(FScrollTimer - ScrollLeftTimerId + 1) <> Direction then
|
|
DestroyScrollTimer
|
|
else
|
|
Exit;
|
|
FScrollTimer := SetTimer(Handle, ScrollLeftTimerId + Ord(Direction) - 1,
|
|
ScrollTimeStep div (1 + Byte(Direction in [dirLeft, dirRight])), @ScrollTimerProc);
|
|
end;
|
|
|
|
procedure TdxMasterView.DestroyScrollTimer;
|
|
begin
|
|
if FScrollTimer <> 0 then
|
|
begin
|
|
KillTimer(Handle, FScrollTimer);
|
|
FScrollTimer := 0;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.WMCaptureChanged(var Message: TMessage);
|
|
begin
|
|
DestroyScrollTimer;
|
|
if mvsSelectPeriod in FState then SelectPeriod(FSelectionAnchor);
|
|
FSelectionAnchor := nil;
|
|
FState := FState - [mvsCtrlClick, mvsIndentClick, mvsAnchorSelected, mvsSelectPeriod];
|
|
inherited;
|
|
end;
|
|
|
|
procedure TdxMasterView.WMDestroy(var Message: TMessage);
|
|
begin
|
|
Customizing := False;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TdxMasterView.WMEraseBkgnd(var Message: TWMEraseBkgnd);
|
|
begin
|
|
Message.Result := 1;
|
|
{
|
|
fillrect(Message.DC, ClientRect, createsolidbrush(clred));
|
|
Message.Result := 0;
|
|
}
|
|
end;
|
|
|
|
procedure TdxMasterView.WMGetDlgCode(var Message: TWMGetDlgCode);
|
|
begin
|
|
Message.Result := DLGC_WANTARROWS or DLGC_WANTALLKEYS;
|
|
end;
|
|
|
|
procedure TdxMasterView.WMHScroll(var Message: TWMHScroll);
|
|
var
|
|
ScrollInfo: TScrollInfo;
|
|
begin
|
|
inherited;
|
|
case Message.ScrollCode of
|
|
SB_LINEUP:
|
|
Scroll(dirLeft);
|
|
SB_LINEDOWN:
|
|
Scroll(dirRight);
|
|
SB_PAGEUP:
|
|
LeftPos := LeftPos - ClientWidth;
|
|
SB_PAGEDOWN:
|
|
LeftPos := LeftPos + ClientWidth;
|
|
SB_THUMBTRACK:
|
|
begin
|
|
with ScrollInfo do
|
|
begin
|
|
cbSize := SizeOf(ScrollInfo);
|
|
fMask := SIF_TRACKPOS;
|
|
end;
|
|
GetScrollInfo(Handle, SB_HORZ, ScrollInfo);
|
|
LeftPos := ScrollInfo.nTrackPos;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.WMKillFocus(var Message: TWMKillFocus);
|
|
begin
|
|
inherited;
|
|
InvalidateSelection;
|
|
end;
|
|
|
|
procedure TdxMasterView.WMMouseActivate(var Message: TWMMouseActivate);
|
|
begin
|
|
inherited;
|
|
if not IsDesigning and Enabled then SetFocus;
|
|
end;
|
|
|
|
procedure TdxMasterView.WMMouseWheel(var Message: TMessage);
|
|
begin
|
|
inherited;
|
|
if SmallInt(HiWord(Message.wParam)) > 0 then
|
|
Scroll(dirUp)
|
|
else
|
|
Scroll(dirDown);
|
|
end;
|
|
|
|
procedure TdxMasterView.WMNCCalcSize(var Message: TWMNCCalcSize);
|
|
begin
|
|
inherited;
|
|
InflateRect(Message.CalcSize_Params^.rgrc[0], -1, -1);
|
|
end;
|
|
|
|
procedure TdxMasterView.WMNCHitTest(var Message: TWMNCHitTest);
|
|
begin
|
|
DefaultHandler(Message);
|
|
FLastMousePos := SmallPointToPoint(Message.Pos);
|
|
Windows.ScreenToClient(Handle, FLastMousePos);
|
|
end;
|
|
|
|
procedure TdxMasterView.WMNCPaint(var Message: TWMNCPaint);
|
|
var
|
|
R: TRect;
|
|
DC: HDC;
|
|
begin
|
|
inherited;
|
|
GetWindowRect(Handle, R);
|
|
OffsetRect(R, -R.Left, -R.Top);
|
|
|
|
DC := GetWindowDC(Handle);
|
|
|
|
DrawEdge(DC, R, BDR_SUNKENOUTER, BF_RECT);
|
|
|
|
if GetWindowLong(Handle, GWL_STYLE) and (WS_HSCROLL or WS_VSCROLL) =
|
|
WS_HSCROLL or WS_VSCROLL then
|
|
with R do
|
|
begin
|
|
Dec(Right);
|
|
Dec(Bottom);
|
|
Left := Right - GetSystemMetrics(SM_CXVSCROLL);
|
|
Top := Bottom - GetSystemMetrics(SM_CYHSCROLL);
|
|
FillRect(DC, R, COLOR_BTNFACE + 1);
|
|
end;
|
|
|
|
ReleaseDC(Handle, DC);
|
|
end;
|
|
|
|
procedure TdxMasterView.WMSetCursor(var Message: TWMSetCursor);
|
|
var
|
|
HitTestCode: TdxMasterViewHitTestCode;
|
|
Node: TdxMasterViewNode;
|
|
Column: TdxMasterViewColumn;
|
|
RowIndex, ColIndex: Integer;
|
|
ACursor: TCursor;
|
|
begin
|
|
HitTestCode := GetHitTestInfo(FLastMousePos, Node, Column, RowIndex, ColIndex);
|
|
if (HitTestCode = htIndent) and not IsDesigning then
|
|
ACursor := crdxMasterViewMirror
|
|
else
|
|
case HitTestCode of
|
|
htHeaderRightEdge, htContentRightEdge:
|
|
ACursor := crdxMasterViewHorSize;
|
|
htHeaderTopEdge, htHeaderBottomEdge:
|
|
ACursor := crdxMasterViewVerSize;
|
|
else
|
|
inherited;
|
|
Exit;
|
|
end;
|
|
SetCursor(Screen.Cursors[ACursor]);
|
|
end;
|
|
|
|
procedure TdxMasterView.WMSetFocus(var Message: TWMSetFocus);
|
|
begin
|
|
InvalidateSelection;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TdxMasterView.WMSize(var Message: TWMSize);
|
|
begin
|
|
inherited;
|
|
if AutoColumnWidth then CalcScrollableWidth(nil);
|
|
end;
|
|
|
|
procedure TdxMasterView.WMVScroll(var Message: TWMVScroll);
|
|
var
|
|
ScrollInfo: TScrollInfo;
|
|
begin
|
|
case Message.ScrollCode of
|
|
SB_LINEUP:
|
|
Scroll(dirUp);
|
|
SB_LINEDOWN:
|
|
Scroll(dirDown);
|
|
SB_PAGEUP:
|
|
ShowPrevPage(TopIndex, False);
|
|
SB_PAGEDOWN:
|
|
ShowNextPage(TopIndex + VisibleItemCount - 1, False);
|
|
SB_THUMBTRACK:
|
|
begin
|
|
with ScrollInfo do
|
|
begin
|
|
cbSize := SizeOf(ScrollInfo);
|
|
fMask := SIF_TRACKPOS;
|
|
end;
|
|
GetScrollInfo(Handle, SB_VERT, ScrollInfo);
|
|
TopIndex := ScrollInfo.nTrackPos;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.WMWindowPosChanged(var Message: TWMWindowPosChanged);
|
|
begin
|
|
inherited;
|
|
if Message.WindowPos^.flags and SWP_HIDEWINDOW <> 0 then
|
|
Customizing := False;
|
|
end;
|
|
|
|
procedure TdxMasterView.CMDesignHitTest(var Message: TCMDesignHitTest);
|
|
var
|
|
HitTestCode: TdxMasterViewHitTestCode;
|
|
Node: TdxMasterViewNode;
|
|
Column: TdxMasterViewColumn;
|
|
RowIndex, ColIndex: Integer;
|
|
begin
|
|
HitTestCode := GetHitTestInfo(SmallPointToPoint(Message.Pos), Node, Column,
|
|
RowIndex, ColIndex);
|
|
Message.Result := Byte(
|
|
(Message.Keys and MK_LBUTTON <> 0) and
|
|
(HitTestCode in
|
|
HeaderHitTests + [htExpandButton, htContentLeftEdge, htContentRightEdge]) or
|
|
(Message.Keys and MK_MBUTTON <> 0));
|
|
end;
|
|
|
|
procedure TdxMasterView.CMFontChanged(var Message: TMessage);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
inherited;
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
AbsoluteLevels[I].FontsChanged;
|
|
end;
|
|
|
|
procedure TdxMasterView.CMSysColorChange(var Message: TMessage);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
inherited;
|
|
for I := 0 to StyleCount - 1 do
|
|
Styles[I].SysColorChanged;
|
|
end;
|
|
|
|
procedure TdxMasterView.CreateParams(var Params: TCreateParams);
|
|
begin
|
|
inherited;
|
|
with Params do
|
|
begin
|
|
if FScrollBars <> sbNone then
|
|
Style := Style or WS_HSCROLL or WS_VSCROLL;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.CreateWnd;
|
|
begin
|
|
inherited;
|
|
SendMessage(Handle, CM_FONTCHANGED, 0, 0);
|
|
end;
|
|
|
|
procedure TdxMasterView.GetChildren(Proc: TGetChildProc; Root: TComponent);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to StyleCount - 1 do
|
|
if Styles[I].Owner = Root then Proc(Styles[I]);
|
|
for I := 0 to FLevels.Count - 1 do
|
|
if FLevels[I].Owner = Root then Proc(FLevels[I]);
|
|
end;
|
|
|
|
procedure TdxMasterView.KeyDown(var Key: Word; Shift: TShiftState);
|
|
var
|
|
PrevFocusedNode, Node: TdxMasterViewNode;
|
|
Level: TdxMasterViewLevel;
|
|
I: Integer;
|
|
begin
|
|
inherited;
|
|
PrevFocusedNode := FocusedNode;
|
|
case Key of
|
|
VK_ESCAPE:
|
|
if GetCapture = Handle then ReleaseCapture;
|
|
VK_UP:
|
|
begin
|
|
Node :=
|
|
GetPrevNode(FFocusedNode, (ssAlt in Shift) and (FFocusedNode <> nil));
|
|
if Node <> nil then Node.Focused := True;
|
|
end;
|
|
VK_DOWN:
|
|
begin
|
|
Node :=
|
|
GetNextNode(FFocusedNode, (ssAlt in Shift) and (FFocusedNode <> nil));
|
|
if Node <> nil then Node.Focused := True;
|
|
end;
|
|
VK_HOME:
|
|
begin
|
|
if (ssAlt in Shift) and (FFocusedNode <> nil) then
|
|
Node := FFocusedNode.ParentNode.FirstInLevel[FFocusedNode.Level]
|
|
else
|
|
Node := nil;
|
|
Node := GetNextNode(Node, Node <> nil);
|
|
if Node <> nil then Node.Focused := True;
|
|
end;
|
|
VK_END:
|
|
begin
|
|
if (ssAlt in Shift) and (FFocusedNode <> nil) then
|
|
Node := FFocusedNode.ParentNode.LastInLevel[FFocusedNode.Level]
|
|
else
|
|
Node := nil;
|
|
Node := GetPrevNode(Node, Node <> nil);
|
|
if Node <> nil then Node.Focused := True;
|
|
end;
|
|
VK_PRIOR:
|
|
begin
|
|
if (ssAlt in Shift) and (FFocusedNode <> nil) then
|
|
Level := FFocusedNode.Level
|
|
else
|
|
Level := nil;
|
|
Node := GetFirstNodeFromVisible(Level);
|
|
I := TopIndex;
|
|
if (Node <> nil) and (Node.AbsoluteIndex > I) then
|
|
I := Node.AbsoluteIndex;
|
|
if (TopIndex > 0) and
|
|
((FocusedIndex <= I) or
|
|
(FocusedIndex > TopIndex + VisibleItemCount - 1)) then
|
|
ShowPrevPage(FocusedIndex, Level <> nil);
|
|
Node := GetFirstNodeFromVisible(Level);
|
|
if Node <> nil then Node.Focused := True;
|
|
end;
|
|
VK_NEXT:
|
|
begin
|
|
if (ssAlt in Shift) and (FFocusedNode <> nil) then
|
|
Level := FFocusedNode.Level
|
|
else
|
|
Level := nil;
|
|
Node := GetLastNodeFromVisible(Level);
|
|
I := TopIndex + VisibleItemCount - 1;
|
|
if (Node <> nil) and (Node.AbsoluteIndex < I) then
|
|
I := Node.AbsoluteIndex;
|
|
if (FocusedIndex < TopIndex) or (FocusedIndex >= I) then
|
|
ShowNextPage(FocusedIndex, Level <> nil);
|
|
Node := GetLastNodeFromVisible(Level);
|
|
if Node <> nil then Node.Focused := True;
|
|
end;
|
|
VK_ADD, VK_RIGHT:
|
|
if (FocusedNode <> nil) and not FocusedNode.Expanded and FocusedNode.CanExpand then
|
|
FocusedNode.Expanded := True
|
|
else
|
|
if Key = VK_RIGHT then Scroll(dirRight);
|
|
VK_SUBTRACT, VK_LEFT:
|
|
if (FocusedNode <> nil) and FocusedNode.Expanded then
|
|
FocusedNode.Expanded := False
|
|
else
|
|
if Key = VK_LEFT then Scroll(dirLeft);
|
|
VK_MULTIPLY:
|
|
if FocusedNode <> nil then
|
|
{ if FocusedNode.Expanded then
|
|
FocusedNode.Collapse(True)
|
|
else}
|
|
FocusedNode.Expand(True);
|
|
VK_SPACE:
|
|
if MultiSelect and (FocusedNode <> nil) then
|
|
with FocusedNode do
|
|
Selected := not Selected;
|
|
VK_INSERT:
|
|
begin
|
|
if FocusedNode = nil then
|
|
if FLevels.Count = 0 then
|
|
Level := nil
|
|
else
|
|
Level := FLevels[0]
|
|
else
|
|
Level := FocusedNode.Level; //!!!
|
|
if (Level <> nil) and Level.CanInsert then
|
|
begin
|
|
ClearSelection;
|
|
Level.DataSet.Insert;
|
|
end;
|
|
end;
|
|
VK_DELETE:
|
|
if (Shift = []) or (Shift = [ssCtrl]) then DeleteSelection;
|
|
end;
|
|
if MultiSelect and (AbsoluteItemCount <> 0) and (FocusedNode <> PrevFocusedNode) and
|
|
(Key in [VK_UP, VK_DOWN, VK_HOME, VK_END, VK_PRIOR, VK_NEXT]) then
|
|
if ssShift in Shift then
|
|
begin
|
|
if FSelectionAnchor = nil then
|
|
if PrevFocusedNode = nil then
|
|
FSelectionAnchor := AbsoluteItems[0]
|
|
else
|
|
FSelectionAnchor := PrevFocusedNode;
|
|
BeginSelection;
|
|
try
|
|
ClearSelection;
|
|
SelectItems(FSelectionAnchor.AbsoluteIndex, FocusedIndex, True);
|
|
finally
|
|
EndSelection;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
FSelectionAnchor := nil;
|
|
if not (ssCtrl in Shift) then
|
|
begin
|
|
BeginSelection;
|
|
try
|
|
ClearSelection;
|
|
if FocusedNode <> nil then FocusedNode.Selected := True;
|
|
finally
|
|
EndSelection;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.Loaded;
|
|
begin
|
|
inherited;
|
|
try
|
|
if not IsDesigning then
|
|
begin
|
|
if mobStoreInIniFile in FOptionsBehavior then
|
|
LoadFromRegIniFile(FIniFileName, riIniFile);
|
|
if mobStoreInRegistry in FOptionsBehavior then
|
|
LoadFromRegIniFile(FRegistryPath, riRegistry);
|
|
end;
|
|
finally
|
|
UpdateData;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
const
|
|
NonDragableHitTests = HeaderHitTests +
|
|
[htNone, htLeftSpace, htRightSpace, htGroupByBox, htExpandButton, htContentRightEdge, htFooter];
|
|
DragSources: array[Boolean] of TdxMasterViewDragSource = (dsHeader, dsGroupByBox);
|
|
var
|
|
HitTestCode: TdxMasterViewHitTestCode;
|
|
Node, PrevFocusedNode: TdxMasterViewNode;
|
|
Column: TdxMasterViewColumn;
|
|
PrevFocusedIndex, RowIndex, ColIndex: Integer;
|
|
NewSortOrder: TdxMasterViewSortOrder;
|
|
LockSelection, PrevSelected: Boolean;
|
|
begin
|
|
inherited;
|
|
HitTestCode := GetHitTestInfo(Point(X, Y), Node, Column, RowIndex, ColIndex);
|
|
if (Button = mbLeft) or
|
|
(Button = mbRight) and (HitTestCode in [htContent, htContentLeftEdge, htPreview]) then
|
|
begin
|
|
if Node <> nil then
|
|
begin
|
|
case HitTestCode of
|
|
htHeader:
|
|
if Column <> nil then
|
|
if not (ssDouble in Shift) then
|
|
begin
|
|
Column.Pressed := True;
|
|
case DragDetect(Handle) of
|
|
ddDrag:
|
|
try
|
|
DoColumnMoving(Node, Column, Point(X, Y), DragSources[RowIndex = -1]);
|
|
finally
|
|
Column.Pressed := False;
|
|
end;
|
|
ddNone:
|
|
with Column do
|
|
begin
|
|
Pressed := False;
|
|
if CanSorting then
|
|
begin
|
|
if ssCtrl in Shift then
|
|
NewSortOrder := soNone
|
|
else
|
|
if SortOrder in [soNone, soDescending] then
|
|
NewSortOrder := soAscending
|
|
else
|
|
NewSortOrder := soDescending;
|
|
if [ssCtrl, ssShift] * Shift = [] then
|
|
with Level do
|
|
begin
|
|
BeginSorting;
|
|
ClearSorting(Column);
|
|
end;
|
|
SortOrder := NewSortOrder;
|
|
if [ssCtrl, ssShift] * Shift = [] then
|
|
Level.EndSorting;
|
|
Modified;
|
|
end;
|
|
end;
|
|
else
|
|
Column.Pressed := False;
|
|
end;
|
|
end
|
|
else
|
|
else
|
|
if ssDouble in Shift then
|
|
Node.Level.RemoveFreeSpace;
|
|
htHeaderRightEdge:
|
|
if Column.Level.Horizontal then
|
|
if ssDouble in Shift then
|
|
Column.ApplyBestFit
|
|
else
|
|
DoColumnHorSizing(Column, True)
|
|
else
|
|
if ssDouble in Shift then
|
|
begin
|
|
Column.Level.Layout.HeaderWidthAssigned[Column.ColIndex] := False;
|
|
Modified;
|
|
end
|
|
else
|
|
DoColumnHorSizing(Column, False);
|
|
htHeaderTopEdge, htHeaderBottomEdge:
|
|
if not (ssDouble in Shift) then
|
|
DoColumnVerSizing(Node, Column, HitTestCode);
|
|
htIndent, htContent, htContentLeftEdge, htPreview, htOther:
|
|
begin
|
|
Shift := Shift - [ssLeft, ssRight];
|
|
PrevFocusedIndex := FocusedIndex;
|
|
PrevFocusedNode := FocusedNode;
|
|
if ssDouble in Shift then
|
|
begin
|
|
FocusedIndex := Node.AbsoluteIndex;
|
|
if lobDblClkExpanding in Node.Level.OptionsBehavior then
|
|
with Node do
|
|
Expanded := not Expanded;
|
|
end
|
|
else
|
|
if MultiSelect then
|
|
if (Shift = []) or (Shift = [ssCtrl]) then
|
|
begin
|
|
FocusedIndex := Node.AbsoluteIndex;
|
|
|
|
LockSelection :=
|
|
(Shift = []) and (SelectedItemCount > 0) and
|
|
(not Node.Selected or (Button <> mbRight) and (DragMode = dmManual));
|
|
if LockSelection then
|
|
begin
|
|
BeginSelection;
|
|
ClearSelection;
|
|
end;
|
|
try
|
|
FSelectionAnchor := Node;
|
|
PrevSelected := Node.Selected;
|
|
Node.Selected := True;
|
|
finally
|
|
if LockSelection then EndSelection;
|
|
end;
|
|
|
|
if Shift = [ssCtrl] then Include(FState, mvsCtrlClick);
|
|
if HitTestCode = htIndent then Include(FState, mvsIndentClick);
|
|
if (FState * [mvsCtrlClick, mvsIndentClick] <> []) and
|
|
not PrevSelected then
|
|
Include(FState, mvsAnchorSelected);
|
|
|
|
if (Button = mbLeft) and (HitTestCode <> htIndent) and
|
|
(DragMode = dmAutomatic) then
|
|
begin
|
|
if DragDetect(Handle) = ddDrag then
|
|
BeginDrag(False)
|
|
else
|
|
if (Shift = []) and (Button <> mbRight) and
|
|
PrevSelected and (SelectedItemCount > 1) then
|
|
begin
|
|
BeginSelection;
|
|
try
|
|
ClearSelection;
|
|
Node.Selected := True;
|
|
finally
|
|
EndSelection;
|
|
end;
|
|
end;
|
|
Exit;
|
|
end;
|
|
|
|
if FState * [mvsCtrlClick, mvsIndentClick] <> [] then
|
|
SetCapture(Handle);
|
|
end
|
|
else
|
|
begin
|
|
FocusedIndex := Node.AbsoluteIndex;
|
|
if Shift = [ssShift] then
|
|
begin
|
|
if FSelectionAnchor = nil then
|
|
if PrevFocusedNode = nil then
|
|
FSelectionAnchor := AbsoluteItems[0]
|
|
else
|
|
FSelectionAnchor := PrevFocusedNode;
|
|
BeginSelection;
|
|
try
|
|
ClearSelection;
|
|
SelectItems(FSelectionAnchor.AbsoluteIndex, Node.AbsoluteIndex, True);
|
|
finally
|
|
EndSelection;
|
|
end;
|
|
end
|
|
else
|
|
if Shift = [ssCtrl, ssShift] then
|
|
SelectItems(PrevFocusedIndex, Node.AbsoluteIndex, True)
|
|
else
|
|
begin
|
|
FSelectionAnchor := nil;
|
|
BeginSelection;
|
|
try
|
|
ClearSelection;
|
|
Node.Selected := True;
|
|
finally
|
|
EndSelection;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if (Shift = []) and (HitTestCode = htIndent) then
|
|
begin
|
|
Include(FState, mvsIndentClick);
|
|
SetCapture(Handle);
|
|
end;
|
|
FocusedIndex := Node.AbsoluteIndex;
|
|
if (Button = mbLeft) and (HitTestCode <> htIndent) and
|
|
(DragMode = dmAutomatic) and (DragDetect(Handle) = ddDrag) then
|
|
BeginDrag(False);
|
|
end;
|
|
end;
|
|
htExpandButton:
|
|
Node.Expanded := not Node.Expanded;
|
|
htContentRightEdge:
|
|
if not Column.Level.Horizontal then
|
|
if ssDouble in Shift then
|
|
Column.ApplyBestFit
|
|
else
|
|
DoColumnHorSizing(Column, True);
|
|
end;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
ReleaseCapture;
|
|
if Button = mbMiddle then DoScrolling;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.MouseMove(Shift: TShiftState; X, Y: Integer);
|
|
var
|
|
Node: TdxMasterViewNode;
|
|
Column: TdxMasterViewColumn;
|
|
RowIndex, ColIndex: Integer;
|
|
begin
|
|
inherited;
|
|
GetHitTestInfo(Point(X, Y), Node, Column, RowIndex, ColIndex);
|
|
|
|
if not (mvsSelectPeriod in FState) and (mvsIndentClick in FState) then
|
|
begin
|
|
Include(FState, mvsSelectPeriod);
|
|
FLastSelectedNode := FSelectionAnchor;
|
|
end;
|
|
|
|
if mvsSelectPeriod in FState then
|
|
begin
|
|
if (Node = nil) and (Y < 0) or
|
|
(Node = TopNode) and (Y < Node.ContentBounds.Top) then
|
|
CreateScrollTimer(dirUp)
|
|
else
|
|
if (Node = nil) and (Y >= ClientHeight) or
|
|
(Y >= AbsoluteItems[TopIndex + VisibleItemCount - 1].ContentBounds.Bottom) then
|
|
CreateScrollTimer(dirDown)
|
|
else
|
|
if X < 0 then
|
|
CreateScrollTimer(dirLeft)
|
|
else
|
|
if X >= ClientWidth then
|
|
CreateScrollTimer(dirRight)
|
|
else
|
|
DestroyScrollTimer;
|
|
|
|
if Node <> nil then
|
|
begin
|
|
FocusedIndex := Node.AbsoluteIndex;
|
|
SelectPeriod(Node);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
var
|
|
Node: TdxMasterViewNode;
|
|
Column: TdxMasterViewColumn;
|
|
RowIndex, ColIndex: Integer;
|
|
begin
|
|
inherited;
|
|
if (GetCapture = Handle) and not (mvsScrolling in FState) then
|
|
begin
|
|
if mvsSelectPeriod in FState then
|
|
begin
|
|
Exclude(FState, mvsSelectPeriod);
|
|
if MultiSelect then
|
|
SelectItems(FSelectionAnchor.AbsoluteIndex, FLastSelectedNode.AbsoluteIndex, True);
|
|
end
|
|
else
|
|
begin
|
|
GetHitTestInfo(Point(X, Y), Node, Column, RowIndex, ColIndex);
|
|
if (mvsCtrlClick in FState) and (Node = FSelectionAnchor) and
|
|
FSelectionAnchor.Selected and not (mvsAnchorSelected in FState) then
|
|
FSelectionAnchor.Selected := False;
|
|
end;
|
|
ReleaseCapture;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.Notification(AComponent: TComponent; Operation: TOperation);
|
|
begin
|
|
inherited;
|
|
if (Operation = opRemove) and (AComponent is TdxMasterViewStyle) then
|
|
begin
|
|
if HighlightStyle = AComponent then HighlightStyle := nil;
|
|
if InactiveStyle = AComponent then InactiveStyle := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.Paint;
|
|
var
|
|
DC: HDC;
|
|
R: TRect;
|
|
FromIndex, AVisibleItemCount, APartVisibleItemCount, I: Integer;
|
|
(*
|
|
var
|
|
ft,lt{,c}:integer;
|
|
*)
|
|
begin
|
|
if FUpdateLockCount > 0 then Exit;
|
|
|
|
//ft:=gettickcount;
|
|
//for c:=1 to 10 do
|
|
//begin
|
|
|
|
FPainting := True;
|
|
try
|
|
FromIndex := TopIndex;
|
|
SetScrollBarsInfo(AVisibleItemCount, APartVisibleItemCount);
|
|
|
|
BeforePaint;
|
|
for I := 0 to AbsoluteLevelCount - 1 do AbsoluteLevels[I].BeforePaint;
|
|
try
|
|
DC := Canvas.Handle;
|
|
R := ClientRect;
|
|
if APartVisibleItemCount <> 0 then
|
|
begin
|
|
for I := FromIndex to FromIndex + APartVisibleItemCount - 1 do
|
|
AbsoluteItems[I].Draw(DC);
|
|
R.Top := AbsoluteItems[FromIndex + APartVisibleItemCount - 1].Bounds.Bottom;
|
|
FillRect(DC, R, Brush.Handle);
|
|
end
|
|
else
|
|
FillRect(DC, R, Brush.Handle);
|
|
finally
|
|
for I := 0 to AbsoluteLevelCount - 1 do AbsoluteLevels[I].AfterPaint;
|
|
AfterPaint;
|
|
|
|
LeftPos := LeftPos; // for checking LeftPos
|
|
TopIndex := TopIndex; // for checking TopIndex
|
|
end;
|
|
finally
|
|
FPainting := False;
|
|
end;
|
|
|
|
//end;
|
|
{lt:=gettickcount;
|
|
application.mainform.caption :=inttostr(lt-ft);}
|
|
end;
|
|
|
|
procedure TdxMasterView.SetName(const NewName: TComponentName);
|
|
var
|
|
OldName: TComponentName;
|
|
|
|
procedure RenameComponents(Mode: Integer);
|
|
var
|
|
I: Integer;
|
|
Component: TComponent;
|
|
ComponentName, NamePrefix: TComponentName;
|
|
begin
|
|
if Mode = 1 then
|
|
I := StyleCount
|
|
else
|
|
I := AbsoluteLevelCount;
|
|
for I := 0 to I - 1 do
|
|
begin
|
|
if Mode = 1 then
|
|
Component := Styles[I]
|
|
else
|
|
Component := AbsoluteLevels[I];
|
|
if Component.Owner = Owner then
|
|
begin
|
|
ComponentName := Component.Name;
|
|
if Length(ComponentName) > Length(OldName) then
|
|
begin
|
|
NamePrefix := Copy(ComponentName, 1, Length(OldName));
|
|
if CompareText(OldName, NamePrefix) = 0 then
|
|
begin
|
|
System.Delete(ComponentName, 1, Length(OldName));
|
|
System.Insert(NewName, ComponentName, 1);
|
|
try
|
|
Component.Name := ComponentName;
|
|
except
|
|
on EComponentError do {Ignore rename errors };
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
OldName := Name;
|
|
inherited;
|
|
{ In design mode the name of the columns should track the level name }
|
|
if IsDesigning and (Name <> OldName) then
|
|
begin
|
|
RenameComponents(1);
|
|
RenameComponents(2);
|
|
end;
|
|
if dxMVDesigner <> nil then dxMVDesigner.Changed(Self, [rcName]);
|
|
end;
|
|
|
|
procedure TdxMasterView.WndProc(var Message: TMessage);
|
|
begin
|
|
with TWMMouse(Message) do
|
|
if (DragMode = dmAutomatic) and not IsDesigning and not Dragging and
|
|
((Msg = WM_LBUTTONDOWN) or (Msg = WM_LBUTTONDBLCLK)) then
|
|
begin
|
|
if not IsControlMouseMsg(TWMMouse(Message)) then
|
|
begin
|
|
ControlState := ControlState + [csLButtonDown];
|
|
Dispatch(Message);
|
|
end;
|
|
Exit;
|
|
end;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TdxMasterView.BeginAnimation;
|
|
begin
|
|
FAnimation := True;
|
|
ValidateRect(Handle, nil);
|
|
end;
|
|
|
|
procedure TdxMasterView.EndAnimation;
|
|
begin
|
|
FAnimation := False;
|
|
end;
|
|
|
|
procedure TdxMasterView.BeforePaint;
|
|
begin
|
|
FBtnHighlightPen := CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNHIGHLIGHT));
|
|
FBtnShadowPen := CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
|
|
end;
|
|
|
|
procedure TdxMasterView.AfterPaint;
|
|
begin
|
|
DeleteObject(FBtnShadowPen);
|
|
DeleteObject(FBtnHighlightPen);
|
|
end;
|
|
|
|
procedure TdxMasterView.BeginTopNodeChange;
|
|
begin
|
|
if FTopNodeChangeLockCount = 0 then
|
|
FPrevTopNode := FTopNode;
|
|
Inc(FTopNodeChangeLockCount);
|
|
end;
|
|
|
|
procedure TdxMasterView.EndTopNodeChange;
|
|
begin
|
|
if FTopNodeChangeLockCount > 0 then
|
|
begin
|
|
Dec(FTopNodeChangeLockCount);
|
|
if (FTopNodeChangeLockCount = 0) and (FTopNode <> FPrevTopNode) then
|
|
DoTopNodeChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.CalcScrollableWidth(CallingLevel: TdxMasterViewLevel);
|
|
var
|
|
PrevScrollableWidth, I, Size: Integer;
|
|
|
|
function IsLocked: Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := True;
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
if AbsoluteLevels[I].FAssignWidthsLockCount <> 0 then Exit;
|
|
Result := False;
|
|
end;
|
|
|
|
begin
|
|
if FCalculatingScrollableWidth or IsLocked then Exit;
|
|
FCalculatingScrollableWidth := True;
|
|
try
|
|
PrevScrollableWidth := FScrollableWidth;
|
|
FScrollableWidth := 0;
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
with AbsoluteLevels[I] do
|
|
if Visible then
|
|
begin
|
|
Size := Indent + Layout.GetVisibleWidth;
|
|
if Size > FScrollableWidth then FScrollableWidth := Size;
|
|
end;
|
|
if AutoColumnWidth and (FScrollableWidth <> PrevScrollableWidth) then
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
with AbsoluteLevels[I] do
|
|
if (AbsoluteLevels[I] <> CallingLevel) and Visible then WidthChanged;
|
|
finally
|
|
FCalculatingScrollableWidth := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.CalcViewInfo(ATopIndex: Integer; AHeight: Integer;
|
|
var AVisibleItemCount, APartVisibleItemCount: Integer; CalcNodesViewInfo: Boolean);
|
|
var
|
|
Indents, Widths: PIntArray;
|
|
I, J, FooterSize: Integer;
|
|
R: TRect;
|
|
Node: TdxMasterViewNode;
|
|
PartialVisibility: Boolean;
|
|
begin
|
|
if ATopIndex = -1 then ATopIndex := 0;
|
|
AVisibleItemCount := 0;
|
|
APartVisibleItemCount := 0;
|
|
|
|
GetMem(Indents, AbsoluteLevelCount * SizeOf(Integer));
|
|
GetMem(Widths, AbsoluteLevelCount * SizeOf(Integer));
|
|
try
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
with AbsoluteLevels[I] do
|
|
begin
|
|
FFirstVisibleNode := nil;
|
|
FFirstVisibleNodeWithData := nil;
|
|
Widths[I] := VisibleWidth;
|
|
Indents[I] := Indent - LeftPos;
|
|
FPreviewDC := GetDC(Handle);
|
|
FPreviewPrevFont := SelectObject(FPreviewDC, PreviewFont.Handle);
|
|
end;
|
|
|
|
Windows.GetClientRect(Handle, R);
|
|
if AHeight = -1 then AHeight := ClientHeight;
|
|
|
|
if CalcNodesViewInfo then
|
|
begin
|
|
FItems.FViewInfo.Bounds.Right := R.Right;
|
|
{ for I := 0 to ATopIndex - 1 do
|
|
with FAbsoluteItems.List^[I] do
|
|
begin
|
|
ClearViewInfo;
|
|
FViewInfo.Bounds.Right := R.Right;
|
|
end;}
|
|
end;
|
|
|
|
for I := ATopIndex to AbsoluteItemCount - 1 do
|
|
begin
|
|
Node := FAbsoluteItems.List^[I];
|
|
with Node, Level do
|
|
begin
|
|
if (FFirstVisibleNode = nil) and (NodeType <> ntCaption) then
|
|
FFirstVisibleNode := Node;
|
|
if (FFirstVisibleNodeWithData = nil) and (NodeType = ntData) then
|
|
FFirstVisibleNodeWithData := Node;
|
|
J := CalcViewInfo(ATopIndex, R, Indents[AbsoluteIndex], Widths[AbsoluteIndex],
|
|
FooterSize, CalcNodesViewInfo);
|
|
end;
|
|
PartialVisibility := R.Top + J > AHeight;
|
|
Inc(R.Top, J);
|
|
if R.Top >= AHeight then
|
|
begin
|
|
APartVisibleItemCount := I - ATopIndex + 1;
|
|
AVisibleItemCount := APartVisibleItemCount - Byte(PartialVisibility);
|
|
if AVisibleItemCount = 0 then AVisibleItemCount := 1;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
APartVisibleItemCount := AbsoluteItemCount - ATopIndex;
|
|
AVisibleItemCount := APartVisibleItemCount;
|
|
finally
|
|
(* if CalcNodesViewInfo then
|
|
for I := ATopIndex + APartVisibleItemCount to AbsoluteItemCount - 1 do
|
|
FAbsoluteItems.List^[I].ClearViewInfo;*)
|
|
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
with AbsoluteLevels[I] do
|
|
begin
|
|
SelectObject(FPreviewDC, FPreviewPrevFont);
|
|
ReleaseDC(Handle, FPreviewDC);
|
|
FPreviewDC := 0;
|
|
end;
|
|
FreeMem(Widths);
|
|
FreeMem(Indents);
|
|
if CalcNodesViewInfo then
|
|
begin
|
|
FLastVisibleItemCount := AVisibleItemCount;
|
|
FLastPartVisibleItemCount := APartVisibleItemCount;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.AssignColumnWidths;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to AbsoluteLevelCount - 1 do AbsoluteLevels[I].AssignColumnWidths;
|
|
end;
|
|
|
|
function TdxMasterView.GetAnimatableHeight: Integer;
|
|
begin
|
|
Result := ClientHeight;
|
|
end;
|
|
|
|
procedure TdxMasterView.SetScrollBarsInfo(
|
|
var AVisibleItemCount, APartVisibleItemCount: Integer);
|
|
var
|
|
AStyle, HorSize, VerSize: Integer;
|
|
HasHorScrollBar, HasVerScrollBar: Boolean;
|
|
ScrollInfo: TScrollInfo;
|
|
|
|
function AlwaysShowHorScrollBar: Boolean;
|
|
begin
|
|
Result := (FScrollBars = sbHorizontal) or (FScrollBars = sbBoth);
|
|
end;
|
|
|
|
function AlwaysShowVerScrollBar: Boolean;
|
|
begin
|
|
Result := (FScrollBars = sbVertical) or (FScrollBars = sbBoth);
|
|
end;
|
|
|
|
function GetHasHorScrollBar: Boolean;
|
|
begin
|
|
Result := (FScrollBars <> sbNone) and
|
|
(AlwaysShowHorScrollBar or (ScrollableWidth > HorSize));
|
|
end;
|
|
|
|
function GetHasVerScrollBar: Boolean;
|
|
begin
|
|
Result := (FScrollBars <> sbNone) and
|
|
(AlwaysShowVerScrollBar or (AbsoluteItemCount > AVisibleItemCount));
|
|
end;
|
|
|
|
begin // sbAuto, sbHorizontal, sbVertical, sbBoth, sbNone
|
|
AStyle := GetWindowLong(Handle, GWL_STYLE);
|
|
HorSize := ClientWidth;
|
|
if AStyle and WS_VSCROLL <> 0 then
|
|
Inc(HorSize, GetSystemMetrics(SM_CXVSCROLL));
|
|
VerSize := ClientHeight;
|
|
if AStyle and WS_HSCROLL <> 0 then
|
|
Inc(VerSize, GetSystemMetrics(SM_CYHSCROLL));
|
|
|
|
HasHorScrollBar := GetHasHorScrollBar;
|
|
if HasHorScrollBar then
|
|
Dec(VerSize, GetSystemMetrics(SM_CYHSCROLL));
|
|
CalcViewInfo(TopIndex, VerSize, AVisibleItemCount, APartVisibleItemCount, True);
|
|
HasVerScrollBar := GetHasVerScrollBar;
|
|
if HasVerScrollBar then
|
|
begin
|
|
Dec(HorSize, GetSystemMetrics(SM_CXVSCROLL));
|
|
if not HasHorScrollBar then
|
|
begin
|
|
HasHorScrollBar := GetHasHorScrollBar;
|
|
if HasHorScrollBar then
|
|
begin
|
|
Dec(VerSize, GetSystemMetrics(SM_CYHSCROLL));
|
|
CalcViewInfo(TopIndex, VerSize, AVisibleItemCount, APartVisibleItemCount, True);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if FScrollBars <> sbNone then
|
|
begin
|
|
with ScrollInfo do
|
|
begin
|
|
cbSize := SizeOf(ScrollInfo);
|
|
fMask := SIF_ALL;
|
|
if AlwaysShowHorScrollBar then
|
|
fMask := fMask or SIF_DISABLENOSCROLL;
|
|
nMin := 0;
|
|
nMax := ScrollableWidth - 1;
|
|
nPage := HorSize;
|
|
nPos := LeftPos;
|
|
end;
|
|
SetScrollInfo(Handle, SB_HORZ, ScrollInfo, True);
|
|
with ScrollInfo do
|
|
begin
|
|
fMask := SIF_ALL;
|
|
if AlwaysShowVerScrollBar then
|
|
fMask := fMask or SIF_DISABLENOSCROLL;
|
|
nMin := 0;
|
|
nMax := AbsoluteItemCount - 1;
|
|
nPage := AVisibleItemCount;
|
|
nPos := TopIndex;
|
|
end;
|
|
SetScrollInfo(Handle, SB_VERT, ScrollInfo, True);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.WidthChanged;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to AbsoluteLevelCount - 1 do AbsoluteLevels[I].WidthChanged;
|
|
end;
|
|
|
|
function TdxMasterView.CanScroll(Direction: TdxMasterViewDirection): Boolean;
|
|
begin
|
|
case Direction of
|
|
dirLeft:
|
|
Result := LeftPos <> 0;
|
|
dirRight:
|
|
Result := LeftPos + ClientWidth < ScrollableWidth;
|
|
dirUp:
|
|
Result := TopIndex <> 0;
|
|
dirDown:
|
|
Result := TopIndex + VisibleItemCount < AbsoluteItemCount;
|
|
else
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterView.CheckLeftPos(Value: Integer): Integer;
|
|
begin
|
|
Result := Value;
|
|
if HandleAllocated then
|
|
begin
|
|
Value := ScrollableWidth - ClientWidth;
|
|
if Result > Value then Result := Value;
|
|
end;
|
|
if Result < 0 then Result := 0;
|
|
end;
|
|
|
|
function TdxMasterView.CheckTopIndex(Value: Integer): Integer;
|
|
var
|
|
FirstCall: Boolean;
|
|
AVisibleItemCount, APartVisibleItemCount: Integer;
|
|
begin
|
|
Result := Value;
|
|
if HandleAllocated and (Result > 0) then
|
|
begin
|
|
Value := AbsoluteItemCount - 1;
|
|
FirstCall := True;
|
|
repeat
|
|
if FirstCall and FPainting then
|
|
AVisibleItemCount := FLastVisibleItemCount
|
|
else
|
|
CalcViewInfo(Result, -1, AVisibleItemCount, APartVisibleItemCount, False);
|
|
if Value > Result + AVisibleItemCount - 1 then
|
|
begin
|
|
if not FirstCall then Inc(Result);
|
|
Break;
|
|
end;
|
|
FirstCall := False;
|
|
Dec(Result);
|
|
if Result = -1 then Break;
|
|
until False;
|
|
end;
|
|
if Result < 0 then
|
|
if AbsoluteItemCount > 0 then
|
|
Result := 0
|
|
else
|
|
Result := -1;
|
|
if Result >= AbsoluteItemCount then
|
|
Result := AbsoluteItemCount - 1;
|
|
end;
|
|
|
|
procedure TdxMasterView.CheckFocusedNode;
|
|
var
|
|
NonExpandedNode, Node: TdxMasterViewNode;
|
|
begin
|
|
if FocusedNode = nil then Exit; //!!!
|
|
NonExpandedNode := nil;
|
|
Node := FocusedNode;
|
|
while Node.ParentNode <> nil do
|
|
begin
|
|
if not Node.Expanded then NonExpandedNode := Node;
|
|
Node := Node.ParentNode;
|
|
end;
|
|
if NonExpandedNode <> nil then
|
|
if CanFocusNode(NonExpandedNode) then
|
|
NonExpandedNode.Focused := True
|
|
else
|
|
FocusedNode := nil;
|
|
end;
|
|
|
|
procedure TdxMasterView.DestroyStyles;
|
|
begin
|
|
while StyleCount <> 0 do Styles[0].Free;
|
|
end;
|
|
|
|
procedure TdxMasterView.DoAfterUpdateData(Level: TdxMasterViewLevel);
|
|
begin
|
|
if Assigned(FOnAfterUpdateData) then FOnAfterUpdateData(Self, Level);
|
|
end;
|
|
|
|
procedure TdxMasterView.DoBeforeUpdateData(Level: TdxMasterViewLevel);
|
|
begin
|
|
if Assigned(FOnBeforeUpdateData) then FOnBeforeUpdateData(Self, Level);
|
|
end;
|
|
|
|
procedure TdxMasterView.DoColumnMoving(Node: TdxMasterViewNode; Column: TdxMasterViewColumn;
|
|
const InitialP: TPoint; DragSource: TdxMasterViewDragSource);
|
|
const
|
|
ArrowWidth = 11;
|
|
ArrowHeight = 9;
|
|
Cursors: array[Boolean] of Integer = (crdxMasterViewNoDrop, crdxMasterViewRemove);
|
|
type
|
|
PColors = ^TColors;
|
|
TColors = array[0..MaxInt - 1] of Byte;
|
|
var
|
|
Level: TdxMasterViewLevel;
|
|
PrevP, P, Offset: TPoint;
|
|
R: TRect;
|
|
W, H, TempBitmapW, TempBitmapH,
|
|
AColIndex, ARowIndex, ActiveRowIndex, ActiveColIndex: Integer;
|
|
DC, AlphaBlendDC, TempDC, SaveDC, BDC, SaveArrowsDC: HDC;
|
|
AlphaBlendBitmap, PrevAlphaBlendBitmap, TempBitmap, SaveB, B, SaveArrowsB: HBITMAP;
|
|
BI: TBitmapInfo;
|
|
DColors, SColors: PColors;
|
|
ArrowsBrush: HBRUSH;
|
|
Accept, Success, AForceMove, ActiveForceMove, AInsert, ActiveInsert: Boolean;
|
|
CaptureWnd: HWND;
|
|
Msg: TMsg;
|
|
HitTestCode: TdxMasterViewHitTestCode;
|
|
ActiveNode, ANode: TdxMasterViewNode;
|
|
AColumn: TdxMasterViewColumn;
|
|
|
|
procedure PrepareAlphaBlend;
|
|
begin
|
|
with BI.bmiHeader do
|
|
begin
|
|
biSize := SizeOf(BI.bmiHeader);
|
|
biWidth := W;
|
|
biHeight := -H;
|
|
biPlanes := 1;
|
|
biBitCount := 32;
|
|
biCompression := BI_RGB;
|
|
end;
|
|
|
|
AlphaBlendDC := CreateCompatibleDC(DC);
|
|
AlphaBlendBitmap := CreateCompatibleBitmap(DC, W, H);
|
|
PrevAlphaBlendBitmap := SelectObject(AlphaBlendDC, AlphaBlendBitmap);
|
|
|
|
TempBitmapW := W;
|
|
TempBitmapH := H;
|
|
TempDC := CreateCompatibleDC(DC);
|
|
TempBitmap := CreateCompatibleBitmap(DC, TempBitmapW, TempBitmapH);
|
|
TempBitmap := SelectObject(TempDC, TempBitmap);
|
|
|
|
GetMem(DColors, 4 * W * H);
|
|
GetMem(SColors, 4 * W * H);
|
|
|
|
B := SelectObject(BDC, B);
|
|
GetDIBits(DC, B, 0, H, SColors, BI, DIB_RGB_COLORS);
|
|
B := SelectObject(BDC, B);
|
|
end;
|
|
|
|
procedure UnprepareAlphaBlend;
|
|
begin
|
|
FreeMem(SColors, 4 * W * H);
|
|
FreeMem(DColors, 4 * W * H);
|
|
|
|
DeleteObject(SelectObject(TempDC, TempBitmap));
|
|
DeleteDC(TempDC);
|
|
|
|
DeleteObject(SelectObject(AlphaBlendDC, PrevAlphaBlendBitmap));
|
|
DeleteDC(AlphaBlendDC);
|
|
end;
|
|
|
|
procedure DrawDraggingColumn(P: TPoint);
|
|
var
|
|
SaveR, R, R1, R2: TRect;
|
|
CurOffset: TPoint;
|
|
Rgn, Rgn1, Rgn2: HRGN;
|
|
|
|
procedure MakeAlphaBlend;
|
|
const
|
|
AlphaConst = 127;
|
|
var
|
|
I, J, K: Integer;
|
|
begin
|
|
GetDIBits(DC, AlphaBlendBitmap, 0, H, DColors, BI, DIB_RGB_COLORS);
|
|
|
|
for I := 0 to W - 1 do
|
|
for J := 0 to H - 1 do
|
|
begin
|
|
K := (J * W + I) * 4;
|
|
Inc(DColors^[K], MulDiv(AlphaConst, SColors^[K] - DColors^[K], 255));
|
|
Inc(DColors^[K + 1], MulDiv(AlphaConst, SColors^[K + 1] - DColors^[K + 1], 255));
|
|
Inc(DColors^[K + 2], MulDiv(AlphaConst, SColors^[K + 2] - DColors^[K + 2], 255));
|
|
end;
|
|
|
|
SetDIBits(DC, AlphaBlendBitmap, 0, H, DColors, BI, DIB_RGB_COLORS);
|
|
end;
|
|
|
|
function GetTempBitmapBounds: TRect;
|
|
begin
|
|
with Result do
|
|
begin
|
|
if P.X < PrevP.X then
|
|
begin
|
|
Left := P.X;
|
|
Right := PrevP.X;
|
|
end
|
|
else
|
|
begin
|
|
Left := PrevP.X;
|
|
Right := P.X;
|
|
end;
|
|
if P.Y < PrevP.Y then
|
|
begin
|
|
Top := P.Y;
|
|
Bottom := PrevP.Y;
|
|
end
|
|
else
|
|
begin
|
|
Top := PrevP.Y;
|
|
Bottom := P.Y;
|
|
end;
|
|
Inc(Right, W);
|
|
Inc(Bottom, H);
|
|
end;
|
|
end;
|
|
|
|
procedure CheckTempBitmapSize(const R: TRect);
|
|
var
|
|
RequireRecreate: Boolean;
|
|
begin
|
|
RequireRecreate := False;
|
|
if R.Right - R.Left > TempBitmapW then
|
|
RequireRecreate := True
|
|
else
|
|
if R.Bottom - R.Top > TempBitmapH then
|
|
RequireRecreate := True;
|
|
if RequireRecreate then
|
|
begin
|
|
DeleteObject(SelectObject(TempDC, TempBitmap));
|
|
TempBitmapW := R.Right - R.Left;
|
|
TempBitmapH := R.Bottom - R.Top;
|
|
TempBitmap := CreateCompatibleBitmap(DC, TempBitmapW, TempBitmapH);
|
|
TempBitmap := SelectObject(TempDC, TempBitmap);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if P.X = MaxInt then
|
|
BitBlt(DC, PrevP.X - Offset.X, PrevP.Y - Offset.Y, W, H, SaveDC, 0, 0, SRCCOPY)
|
|
else
|
|
begin
|
|
Dec(P.X, Offset.X);
|
|
Dec(P.Y, Offset.Y);
|
|
|
|
if PrevP.X = MaxInt then
|
|
begin
|
|
BitBlt(SaveDC, 0, 0, W, H, DC, P.X, P.Y, SRCCOPY);
|
|
if TransparentDragAndDrop then
|
|
begin
|
|
BitBlt(AlphaBlendDC, 0, 0, W, H, DC, P.X, P.Y, SRCCOPY);
|
|
MakeAlphaBlend;
|
|
BitBlt(DC, P.X, P.Y, W, H, AlphaBlendDC, 0, 0, SRCCOPY);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Dec(PrevP.X, Offset.X);
|
|
Dec(PrevP.Y, Offset.Y);
|
|
if TransparentDragAndDrop then
|
|
begin
|
|
R := GetTempBitmapBounds;
|
|
CheckTempBitmapSize(R);
|
|
|
|
with R do
|
|
begin
|
|
BitBlt(TempDC, 0, 0, R.Right - R.Left, R.Bottom - R.Top, DC, Left, Top, SRCCOPY);
|
|
BitBlt(TempDC, PrevP.X - Left, PrevP.Y - Top, W, H, SaveDC, 0, 0, SRCCOPY);
|
|
BitBlt(SaveDC, 0, 0, W, H, TempDC, P.X - Left, P.Y - Top, SRCCOPY);
|
|
|
|
BitBlt(AlphaBlendDC, 0, 0, W, H, SaveDC, 0, 0, SRCCOPY);
|
|
MakeAlphaBlend;
|
|
BitBlt(TempDC, P.X - Left, P.Y - Top, W, H, AlphaBlendDC, 0, 0, SRCCOPY);
|
|
|
|
BitBlt(DC, Left, Top, Right - Left, Bottom - Top, TempDC, 0, 0, SRCCOPY);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
SaveR := Bounds(PrevP.X, PrevP.Y, W, H);
|
|
R := Bounds(P.X, P.Y, W, H);
|
|
|
|
Rgn := CreateRectRgn(0, 0, 0, 0);
|
|
Rgn1 := CreateRectRgnIndirect(SaveR);
|
|
Rgn2 := CreateRectRgnIndirect(R);
|
|
|
|
CombineRgn(Rgn, Rgn1, Rgn2, RGN_DIFF);
|
|
|
|
SelectClipRgn(DC, Rgn);
|
|
BitBlt(DC, PrevP.X, PrevP.Y, W, H, SaveDC, 0, 0, SRCCOPY);
|
|
SelectClipRgn(DC, 0);
|
|
|
|
R1 := Rect(0, 0, W, H);
|
|
R2 := R1;
|
|
CurOffset := Point(P.X - PrevP.X, P.Y - PrevP.Y);
|
|
OffsetRect(R2, -CurOffset.X, -CurOffset.Y);
|
|
|
|
with R2 do
|
|
BitBlt(SaveDC, Left, Top, Right - Left, Bottom - Top, SaveDC, 0, 0, SRCCOPY);
|
|
|
|
CombineRgn(Rgn, Rgn2, Rgn1, RGN_DIFF);
|
|
OffsetRgn(Rgn, -P.X, -P.Y);
|
|
|
|
SelectClipRgn(SaveDC, Rgn);
|
|
BitBlt(SaveDC, 0, 0, W, H, DC, P.X, P.Y, SRCCOPY);
|
|
SelectClipRgn(SaveDC, 0);
|
|
|
|
DeleteObject(Rgn2);
|
|
DeleteObject(Rgn1);
|
|
DeleteObject(Rgn);
|
|
end;
|
|
end;
|
|
|
|
if not TransparentDragAndDrop then
|
|
BitBlt(DC, P.X, P.Y, W, H, BDC, 0, 0, SRCCOPY);
|
|
|
|
Inc(P.X, Offset.X);
|
|
Inc(P.Y, Offset.Y);
|
|
end;
|
|
|
|
PrevP := P;
|
|
end;
|
|
|
|
procedure SetActivePlace(NodeValue: TdxMasterViewNode; ARowIndex, AColIndex: Integer;
|
|
AForceMove, AInsert: Boolean);
|
|
|
|
procedure CalcArrowsRects(var TopArrowRect, BottomArrowRect: TRect);
|
|
begin
|
|
if ActiveRowIndex = -1 then // GroupBy Box
|
|
begin
|
|
TopArrowRect := ActiveNode.GroupByBoxColumnBounds[ActiveColIndex -
|
|
Byte(ActiveColIndex = Level.GroupColumnCount)];
|
|
if ActiveColIndex = 0 then
|
|
Dec(TopArrowRect.Left, GroupByBoxHorOffset div 2)
|
|
else
|
|
if ActiveColIndex = Level.GroupColumnCount then
|
|
TopArrowRect.Left := TopArrowRect.Right + GroupByBoxHorOffset div 2
|
|
else
|
|
OffsetRect(TopArrowRect,
|
|
-GroupByBoxHorOffset div 2,
|
|
-(Level.HeaderRealHeight div 2 + GroupByBoxVerOffset) div 2);
|
|
with TopArrowRect do
|
|
begin
|
|
if Left < 0 then Left := 0;
|
|
if Left >= ClientWidth then Left := ClientWidth - 1;
|
|
end;
|
|
TopArrowRect.Right := TopArrowRect.Left + 1;
|
|
InflateRect(TopArrowRect, ArrowWidth div 2, ArrowHeight);
|
|
MapWindowPoints(Handle, 0, TopArrowRect, 2);
|
|
BottomArrowRect := TopArrowRect;
|
|
with TopArrowRect do
|
|
Bottom := Top + ArrowHeight;
|
|
with BottomArrowRect do
|
|
Top := Bottom - ArrowHeight;
|
|
end
|
|
else
|
|
if Level.Horizontal then
|
|
begin
|
|
TopArrowRect := ActiveNode.HeaderRowBounds[ActiveRowIndex];
|
|
if ActiveInsert then
|
|
begin
|
|
with TopArrowRect do
|
|
begin
|
|
if Left < 0 then Left := 0;
|
|
if Right > ClientWidth then Right := ClientWidth;
|
|
if ActiveRowIndex <> 0 then Dec(Top);
|
|
Bottom := Top + 1;
|
|
InflateRect(TopArrowRect, -(Right - Left) div 4, ArrowWidth div 2);
|
|
end;
|
|
MapWindowPoints(Handle, 0, TopArrowRect, 2);
|
|
BottomArrowRect := TopArrowRect;
|
|
with TopArrowRect do
|
|
Right := Left + ArrowHeight;
|
|
with BottomArrowRect do
|
|
Left := Right - ArrowHeight;
|
|
end
|
|
else
|
|
begin
|
|
with Level, TopArrowRect do
|
|
if ActiveColIndex > 0 then
|
|
Left := Layout.Columns[ActiveRowIndex, ActiveColIndex - 1].
|
|
GetHeaderBounds(ActiveNode).Right;
|
|
with TopArrowRect do
|
|
begin
|
|
if Left < 0 then Left := 0;
|
|
if Left >= ClientWidth then Left := ClientWidth - 1;
|
|
Right := Left + 1;
|
|
end;
|
|
InflateRect(TopArrowRect, ArrowWidth div 2, ArrowHeight);
|
|
MapWindowPoints(Handle, 0, TopArrowRect, 2);
|
|
BottomArrowRect := TopArrowRect;
|
|
with TopArrowRect do
|
|
Bottom := Top + ArrowHeight;
|
|
with BottomArrowRect do
|
|
Top := Bottom - ArrowHeight;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if (ActiveColIndex = Level.Layout.Count) (*or
|
|
(ActiveRowIndex = Level.Layout[ActiveColIndex].Count) and (ActiveRowIndex = 0){!?}*) then
|
|
with TopArrowRect do
|
|
begin
|
|
with Level.Layout do
|
|
begin
|
|
Left := ColOffsets[ActiveColIndex];
|
|
Right := Left + FMovingColumn.Width;
|
|
end;
|
|
Top := ActiveNode.ContentBounds.Top;
|
|
Bottom := Top + 1;
|
|
end
|
|
else
|
|
if ActiveRowIndex = Level.Layout[ActiveColIndex].Count then
|
|
begin
|
|
TopArrowRect :=
|
|
Level.Layout.Columns[ActiveRowIndex - 1, ActiveColIndex].GetHeaderBounds(ActiveNode);
|
|
with TopArrowRect do
|
|
begin
|
|
Top := Bottom;
|
|
Inc(Bottom);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TopArrowRect :=
|
|
Level.Layout.Columns[ActiveRowIndex, ActiveColIndex].GetHeaderBounds(ActiveNode);
|
|
with TopArrowRect do
|
|
Bottom := Top + 1;
|
|
end;
|
|
with TopArrowRect do
|
|
begin
|
|
if Left < 0 then Left := 0;
|
|
if Left >= ClientWidth then Left := ClientWidth - 1;
|
|
if Right < 0 then Right := 0;
|
|
if Right >= ClientWidth then Right := ClientWidth - 1;
|
|
if ActiveInsert then
|
|
begin
|
|
Right := Left + 1;
|
|
Bottom := ActiveNode.ContentBoundsWithoutPreview.Bottom;
|
|
InflateRect(TopArrowRect, ArrowWidth div 2, ArrowHeight)
|
|
end
|
|
else
|
|
InflateRect(TopArrowRect, ArrowHeight, ArrowWidth div 2);
|
|
end;
|
|
MapWindowPoints(Handle, 0, TopArrowRect, 2);
|
|
BottomArrowRect := TopArrowRect;
|
|
if ActiveInsert then
|
|
begin
|
|
with TopArrowRect do
|
|
Bottom := Top + ArrowHeight;
|
|
with BottomArrowRect do
|
|
Top := Bottom - ArrowHeight;
|
|
end
|
|
else
|
|
begin
|
|
with TopArrowRect do
|
|
Right := Left + ArrowHeight;
|
|
with BottomArrowRect do
|
|
Left := Right - ArrowHeight;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure HideArrows;
|
|
var
|
|
R1, R2: TRect;
|
|
begin
|
|
CalcArrowsRects(R1, R2);
|
|
with R1 do
|
|
BitBlt(DC, Left, Top, Right - Left, Bottom - Top, SaveArrowsDC, 0, 0, SRCCOPY);
|
|
with R2 do
|
|
BitBlt(DC, Left, Top, Right - Left, Bottom - Top, SaveArrowsDC, 0, ArrowWidth, SRCCOPY);
|
|
end;
|
|
|
|
procedure ShowArrows;
|
|
var
|
|
R1, R2: TRect;
|
|
P: array[1..7] of TPoint;
|
|
PrevPen: HPEN;
|
|
PrevBrush: HBRUSH;
|
|
begin
|
|
CalcArrowsRects(R1, R2);
|
|
with R1 do
|
|
BitBlt(SaveArrowsDC, 0, 0, Right - Left, Bottom - Top, DC, Left, Top, SRCCOPY);
|
|
with R2 do
|
|
BitBlt(SaveArrowsDC, 0, ArrowWidth, Right - Left, Bottom - Top, DC, Left, Top, SRCCOPY);
|
|
|
|
PrevPen := SelectObject(DC, GetStockObject(BLACK_PEN));
|
|
PrevBrush := SelectObject(DC, ArrowsBrush);
|
|
|
|
if (ActiveRowIndex <> -1) and // not GroupBy Box
|
|
(Level.Horizontal and ActiveInsert or
|
|
not Level.Horizontal and not ActiveInsert) then
|
|
begin
|
|
with R1 do
|
|
begin
|
|
P[1] := Point(Left, Top + 3);
|
|
P[2] := Point(Left + 3, Top + 3);
|
|
P[3] := Point(Left + 3, Top);
|
|
P[4] := Point(Right - 1, Top + 5);
|
|
P[5] := Point(Left + 3, Bottom - 1);
|
|
P[6] := Point(Left + 3, Bottom - 4);
|
|
P[7] := Point(Left, Bottom - 4);
|
|
end;
|
|
Polygon(DC, P, 7);
|
|
with R2 do
|
|
begin
|
|
P[1].X := Right - 1;
|
|
P[2].X := Right - 4;
|
|
P[3].X := Right - 4;
|
|
P[4].X := Left;
|
|
P[5].X := Right - 4;
|
|
P[6].X := Right - 4;
|
|
P[7].X := Right - 1;
|
|
end;
|
|
Polygon(DC, P, 7);
|
|
end
|
|
else
|
|
begin
|
|
with R1 do
|
|
begin
|
|
P[1] := Point(Left + 3, Top);
|
|
P[2] := Point(Right - 4, Top);
|
|
P[3] := Point(Right - 4, Top + 3);
|
|
P[4] := Point(Right - 1, Top + 3);
|
|
P[5] := Point(Left + 5, Bottom - 1);
|
|
P[6] := Point(Left, Top + 3);
|
|
P[7] := Point(Left + 3, Top + 3);
|
|
end;
|
|
Polygon(DC, P, 7);
|
|
with R2 do
|
|
begin
|
|
P[1].Y := Bottom - 1;
|
|
P[2].Y := Bottom - 1;
|
|
P[3].Y := Bottom - 4;
|
|
P[4].Y := Bottom - 4;
|
|
P[5].Y := Top;
|
|
P[6].Y := Bottom - 4;
|
|
P[7].Y := Bottom - 4;
|
|
end;
|
|
Polygon(DC, P, 7);
|
|
end;
|
|
|
|
SelectObject(DC, PrevBrush);
|
|
SelectObject(DC, PrevPen);
|
|
end;
|
|
|
|
function CanInsert: Boolean;
|
|
begin
|
|
if ActiveRowIndex = -1 then // GroupBy Box
|
|
Result :=
|
|
(FMovingColumn.GroupIndex = -1) or
|
|
(ActiveColIndex < FMovingColumn.GroupIndex) or
|
|
(FMovingColumn.GroupIndex < ActiveColIndex - 1)
|
|
else
|
|
if FMovingColumn.Visible then
|
|
if Level.Horizontal then
|
|
Result :=
|
|
(FMovingColumn.RowIndex <> ActiveRowIndex) or
|
|
ActiveForceMove or ActiveInsert or
|
|
(ActiveColIndex < FMovingColumn.ColIndex) or
|
|
(FMovingColumn.ColIndex + 1 < ActiveColIndex)
|
|
else
|
|
Result :=
|
|
ActiveInsert and
|
|
(not Level.Layout.OneOnLine(FMovingColumn) or
|
|
(ActiveColIndex < FMovingColumn.ColIndex) or
|
|
(FMovingColumn.ColIndex + 1 < ActiveColIndex)) or
|
|
not ActiveInsert and
|
|
((ActiveColIndex <> FMovingColumn.ColIndex) or
|
|
(ActiveRowIndex < FMovingColumn.RowIndex) or
|
|
(ActiveRowIndex > FMovingColumn.RowIndex + FMovingColumn.RowCount))
|
|
else
|
|
Result := True;
|
|
end;
|
|
|
|
begin
|
|
if (ActiveNode <> NodeValue) or
|
|
(ActiveRowIndex <> ARowIndex) or (ActiveColIndex <> AColIndex) or
|
|
(ActiveForceMove <> AForceMove) or (ActiveInsert <> AInsert) then
|
|
begin
|
|
if PrevP.X <> MaxInt then DrawDraggingColumn(Point(MaxInt, 0));
|
|
if (ActiveNode <> nil) and (ActiveColIndex <> -1) and CanInsert then
|
|
HideArrows;
|
|
ActiveNode := NodeValue;
|
|
ActiveRowIndex := ARowIndex;
|
|
ActiveColIndex := AColIndex;
|
|
ActiveForceMove := AForceMove;
|
|
ActiveInsert := AInsert;
|
|
if (ActiveNode <> nil) and (ActiveColIndex <> -1) and CanInsert then
|
|
ShowArrows;
|
|
if PrevP.X <> MaxInt then DrawDraggingColumn(PrevP);
|
|
end;
|
|
end;
|
|
|
|
procedure DestroyScrollTimer;
|
|
begin
|
|
if FScrollTimer <> 0 then
|
|
begin
|
|
KillTimer(Handle, FScrollTimer);
|
|
FScrollTimer := 0;
|
|
end;
|
|
end;
|
|
|
|
procedure CreateScrollTimer(Direction: TdxMasterViewDirection);
|
|
begin
|
|
if FScrollTimer <> 0 then
|
|
if TdxMasterViewDirection(FScrollTimer - ScrollLeftTimerId + 1) <> Direction then
|
|
DestroyScrollTimer
|
|
else
|
|
Exit;
|
|
FScrollTimer := SetTimer(Handle, ScrollLeftTimerId + Ord(Direction) - 1,
|
|
ScrollTimeStep div 2, nil);
|
|
end;
|
|
|
|
function CheckInsertStatus: Boolean;
|
|
var
|
|
I: Integer;
|
|
CurNode: TdxMasterViewNode;
|
|
R: TRect;
|
|
begin
|
|
Result := False;
|
|
if not Level.Horizontal then Exit;
|
|
for I := TopIndex to TopIndex + PartVisibleItemCount - 1 do
|
|
begin
|
|
CurNode := AbsoluteItems[I];
|
|
if CurNode.Level = Level then
|
|
begin
|
|
R := CurNode.HeaderBounds;
|
|
if IsRectEmpty(R) or PtInRect(R, P) then Continue;
|
|
InflateRect(R, 0, InsertZoneWidth);
|
|
if PtInRect(R, P) then
|
|
begin
|
|
Accept := True;
|
|
ANode := CurNode;
|
|
R.Bottom := R.Top + InsertZoneWidth;
|
|
if PtInRect(R, P) then
|
|
ARowIndex := 0
|
|
else
|
|
ARowIndex := Level.Layout.Count;
|
|
AColIndex := 0;
|
|
AInsert := True;
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure HideDragImages;
|
|
begin
|
|
ANode := ActiveNode;
|
|
ARowIndex := ActiveRowIndex;
|
|
AColIndex := ActiveColIndex;
|
|
AForceMove := ActiveForceMove;
|
|
AInsert := ActiveInsert;
|
|
DrawDraggingColumn(Point(MaxInt, 0));
|
|
SetActivePlace(nil, -1, -1, False, False);
|
|
end;
|
|
|
|
begin
|
|
if Column = nil then Exit;
|
|
|
|
Level := Column.Level;
|
|
|
|
if DragSource = dsCustomizingForm then
|
|
GetCursorPos(P)
|
|
else
|
|
begin
|
|
P := InitialP;
|
|
Windows.ClientToScreen(Handle, P);
|
|
end;
|
|
|
|
Accept := Column.CanMoving;
|
|
if Assigned(FOnBeforeColumnMoving) then
|
|
begin
|
|
Windows.ScreenToClient(Handle, P);
|
|
FOnBeforeColumnMoving(Self, Column, P, -1, -1, False, Accept);
|
|
Windows.ClientToScreen(Handle, P);
|
|
end;
|
|
if not Accept then Exit;
|
|
|
|
FMovingColumnNode := Node;
|
|
FMovingColumn := Column;
|
|
Include(FState, mvsColumnMoving);
|
|
|
|
if Customizing then
|
|
TdxMVCustomizationForm(FCustomizationForm).ActiveLevel := Column.Level;
|
|
|
|
if DragSource = dsCustomizingForm then
|
|
begin
|
|
with Column do
|
|
begin
|
|
W := Width;
|
|
H := GetHeaderHeight;//Level.HeaderRealHeight;
|
|
end;
|
|
Offset := Point(W div 2, H div 2);
|
|
end
|
|
else
|
|
begin
|
|
if DragSource = dsHeader then
|
|
R := Column.GetHeaderBounds(Node)
|
|
else
|
|
R := Column.GetGroupByBoxBounds(Node);
|
|
MapWindowPoints(Handle, 0, R, 2);
|
|
with Offset, R do
|
|
begin
|
|
X := P.X - Left;
|
|
Y := P.Y - Top;
|
|
W := Right - Left;
|
|
H := Bottom - Top;
|
|
end;
|
|
end;
|
|
|
|
DC := GetDC(0);
|
|
|
|
SaveDC := CreateCompatibleDC(DC);
|
|
SaveB := CreateCompatibleBitmap(DC, W, H);
|
|
SaveB := SelectObject(SaveDC, SaveB);
|
|
|
|
BDC := CreateCompatibleDC(DC);
|
|
B := CreateCompatibleBitmap(DC, W, H);
|
|
B := SelectObject(BDC, B);
|
|
|
|
SaveArrowsDC := CreateCompatibleDC(DC);
|
|
SaveArrowsB := CreateCompatibleBitmap(DC, ArrowWidth, 2 * ArrowWidth);
|
|
SaveArrowsB := SelectObject(SaveArrowsDC, SaveArrowsB);
|
|
|
|
ArrowsBrush := CreateSolidBrush(ColorToRGB(FArrowsColor));
|
|
|
|
BeforePaint;
|
|
Level.BeforePaint;
|
|
R := Rect(0, 0, W, H);
|
|
DrawEdge(BDC, R, BDR_RAISEDINNER, BF_RECT);
|
|
InflateRect(R, -1, -1);
|
|
Column.DrawHeader(BDC, R, Node);
|
|
Level.AfterPaint;
|
|
AfterPaint;
|
|
|
|
PrepareAlphaBlend;
|
|
|
|
PrevP.X := MaxInt;
|
|
DrawDraggingColumn(P);
|
|
|
|
Success := False;
|
|
ActiveNode := nil;
|
|
ActiveRowIndex := -1;
|
|
ActiveColIndex := -1;
|
|
ActiveForceMove := False;
|
|
ActiveInsert := False;
|
|
CaptureWnd := Handle;
|
|
SetCapture(CaptureWnd);
|
|
try
|
|
while GetCapture = CaptureWnd do
|
|
begin
|
|
case Integer(GetMessage(Msg, 0, 0, 0)) of
|
|
-1: Break;
|
|
0: begin
|
|
PostQuitMessage(Msg.wParam);
|
|
Break;
|
|
end;
|
|
end;
|
|
try
|
|
case Msg.message of
|
|
WM_KEYDOWN, WM_KEYUP:
|
|
if Msg.wParam = VK_ESCAPE then Break;
|
|
WM_RBUTTONDOWN, WM_MBUTTONDOWN:
|
|
Break;
|
|
WM_MOUSEMOVE:
|
|
begin
|
|
P := SmallPointToPoint(TSmallPoint(Msg.lParam));
|
|
Windows.ClientToScreen(Msg.hwnd, P);
|
|
if (P.X <> PrevP.X) or (P.Y <> PrevP.Y) then
|
|
begin
|
|
Windows.ScreenToClient(Handle, P);
|
|
HitTestCode := GetHitTestInfo(P, ANode, AColumn, ARowIndex, AColIndex);
|
|
AForceMove := False;
|
|
AInsert := False;
|
|
|
|
if PtInRect(ClientRect, P) and (HitTestCode <> htCustomizationForm) then
|
|
if CanScroll(dirLeft) and (P.X < ColumnMovingHScrollZone) then
|
|
CreateScrollTimer(dirLeft)
|
|
else
|
|
if CanScroll(dirRight) and (P.X >= ClientWidth - ColumnMovingHScrollZone) then
|
|
CreateScrollTimer(dirRight)
|
|
else
|
|
DestroyScrollTimer
|
|
else
|
|
DestroyScrollTimer;
|
|
|
|
Accept :=
|
|
(ANode <> nil) and (ANode.Level = Level) and not CheckInsertStatus and
|
|
((HitTestCode = htGroupByBox) and FMovingColumn.CanGrouping(AColIndex) or
|
|
ANode.HasHeader(TopIndex, R.Left) and
|
|
((HitTestCode in HeaderHitTests) or
|
|
(HitTestCode = htRightSpace) and (ARowIndex <> -1) or
|
|
not Level.Horizontal and (HitTestCode in LeftHitTests + ContentHitTests) and
|
|
((HitTestCode <> htExpandButton) or (ARowIndex <> -1))));
|
|
if Accept then
|
|
if HitTestCode = htGroupByBox then
|
|
//
|
|
else
|
|
if HitTestCode = htRightSpace then
|
|
if not Level.Horizontal then
|
|
AInsert := True
|
|
else
|
|
else
|
|
if not Level.Horizontal and
|
|
(HitTestCode in [htHeaderLeftEdge] + LeftHitTests + ContentHitTests) then
|
|
begin
|
|
if HitTestCode <> htHeaderLeftEdge then
|
|
Inc(AColIndex);
|
|
ARowIndex := 0;
|
|
AInsert := True;
|
|
end
|
|
else
|
|
if AColumn = nil then
|
|
if Level.Horizontal then
|
|
begin
|
|
AColIndex :=
|
|
Level.Layout.GetNearestCol(ARowIndex, P.X - ANode.HeaderBounds.Left);
|
|
AForceMove := FMovingColumn.Visible and
|
|
(ARowIndex = FMovingColumn.RowIndex) {and (AColIndex = 0)};
|
|
end
|
|
else
|
|
ARowIndex := Level.Layout[AColIndex].Count
|
|
else
|
|
begin
|
|
R := AColumn.GetHeaderBounds(ANode);
|
|
if Level.Horizontal then
|
|
AColIndex := Level.Layout[ARowIndex].IndexOf(AColumn) +
|
|
Byte(P.X >= (R.Left + R.Right) div 2)
|
|
else
|
|
ARowIndex := AColumn.RowIndex +
|
|
Byte(P.Y >= (R.Top + R.Bottom) div 2) * AColumn.RowCount;
|
|
end
|
|
else
|
|
begin
|
|
ANode := nil;
|
|
ARowIndex := -1;
|
|
AColIndex := -1;
|
|
if HitTestCode <> htCustomizationForm then
|
|
CheckInsertStatus;
|
|
end;
|
|
|
|
if Assigned(FOnColumnMoving) then
|
|
begin
|
|
FOnColumnMoving(Self, FMovingColumn, P, ARowIndex, AColIndex, AInsert, Accept);
|
|
if not Accept then
|
|
begin
|
|
ARowIndex := -1;
|
|
AColIndex := -1;
|
|
end;
|
|
end;
|
|
|
|
SetActivePlace(ANode, ARowIndex, AColIndex, AForceMove, AInsert);
|
|
if Accept or
|
|
(HitTestCode = htCustomizationForm) and (DragSource = dsCustomizingForm) then
|
|
SetCursor(Screen.Cursors[crDefault])
|
|
else
|
|
SetCursor(Screen.Cursors[Cursors[
|
|
(DragSource <> dsGroupByBox) and FMovingColumn.CanHiding or
|
|
(DragSource = dsGroupByBox) and FMovingColumn.CanGrouping(AColIndex)]]);
|
|
|
|
Windows.ClientToScreen(Handle, P);
|
|
|
|
DrawDraggingColumn(P);
|
|
end;
|
|
end;
|
|
WM_LBUTTONUP:
|
|
begin
|
|
Success := True;
|
|
Break;
|
|
end;
|
|
WM_TIMER:
|
|
if (Msg.hwnd = Handle) and
|
|
(Msg.wParam in [ScrollLeftTimerId, ScrollRightTimerId]) and
|
|
CanScroll(TdxMasterViewDirection(FScrollTimer - ScrollLeftTimerId + 1)) then
|
|
begin
|
|
HideDragImages;
|
|
if Msg.wParam = ScrollLeftTimerId then
|
|
Scroll(dirLeft)
|
|
else
|
|
Scroll(dirRight);
|
|
GetCursorPos(P);
|
|
Windows.ScreenToClient(Handle, P);
|
|
PostMessage(Handle, WM_MOUSEMOVE, 0, LPARAM(PointToSmallPoint(P)));
|
|
end;
|
|
end;
|
|
finally
|
|
TranslateMessage(Msg);
|
|
DispatchMessage(Msg);
|
|
end;
|
|
end;
|
|
finally
|
|
if GetCapture = CaptureWnd then ReleaseCapture;
|
|
DestroyScrollTimer;
|
|
HideDragImages;
|
|
|
|
UnprepareAlphaBlend;
|
|
|
|
DeleteObject(ArrowsBrush);
|
|
|
|
DeleteObject(SelectObject(SaveArrowsDC, SaveArrowsB));
|
|
DeleteDC(SaveArrowsDC);
|
|
|
|
DeleteObject(SelectObject(BDC, B));
|
|
DeleteDC(BDC);
|
|
|
|
DeleteObject(SelectObject(SaveDC, SaveB));
|
|
DeleteDC(SaveDC);
|
|
|
|
ReleaseDC(0, DC);
|
|
|
|
if Success then
|
|
begin
|
|
Accept := True;
|
|
if Assigned(FOnAfterColumnMoving) then
|
|
begin
|
|
GetCursorPos(P);
|
|
Windows.ScreenToClient(Handle, P);
|
|
FOnAfterColumnMoving(Self, FMovingColumn, P, ARowIndex, AColIndex, AInsert, Accept);
|
|
end;
|
|
|
|
if Accept then
|
|
begin
|
|
with FMovingColumn do
|
|
if ARowIndex = -1 then
|
|
if AColIndex = -1 then
|
|
if DragSource = dsGroupByBox then
|
|
if CanGrouping(-1) then
|
|
begin
|
|
GroupIndex := -1;
|
|
if not Visible and Hidden then Visible := True;
|
|
end
|
|
else
|
|
else
|
|
if CanHiding then Visible := False
|
|
else
|
|
else
|
|
if CanGrouping(AColIndex) then
|
|
begin
|
|
if (GroupIndex <> -1) and (AColIndex > GroupIndex) then
|
|
Dec(AColIndex);
|
|
if GroupIndex <> AColIndex then
|
|
begin
|
|
GroupIndex := AColIndex;
|
|
{if (DragSource = dsHeader) and
|
|
(locHideColumnOnGrouping in Level.OptionsCustomize) then
|
|
Visible := False;}
|
|
end;
|
|
end
|
|
else
|
|
else
|
|
begin
|
|
Level.BeginLayout;
|
|
try
|
|
if Level.Horizontal then
|
|
begin
|
|
Success := Visible and
|
|
(RowIndex <= ARowIndex) and (ARowIndex <= RowIndex + RowCount - 1) and
|
|
(ColIndex < AColIndex);
|
|
if AInsert and (ARowIndex = 0) then
|
|
Level.Layout.Insert(0, RowCount);
|
|
RowIndex := ARowIndex;
|
|
if (ColIndex <> AColIndex - Byte(Success)) or AForceMove then
|
|
ColIndex := AColIndex - Byte(Success);
|
|
end
|
|
else
|
|
begin
|
|
Success := Visible and
|
|
(ColIndex = AColIndex) and (RowIndex < ARowIndex);
|
|
if AInsert then Level.Layout.Insert(AColIndex, 1);
|
|
ColIndex := AColIndex;
|
|
RowIndex := ARowIndex - Byte(Success) * RowCount;
|
|
end;
|
|
if (DragSource = dsGroupByBox) and CanGrouping(-1) then
|
|
GroupIndex := -1;
|
|
Visible := True;
|
|
finally
|
|
Level.EndLayout;
|
|
end;
|
|
end;
|
|
Modified;
|
|
end;
|
|
end;
|
|
|
|
Exclude(FState, mvsColumnMoving);
|
|
FMovingColumn := nil;
|
|
FMovingColumnNode := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.DoColumnHorSizing(Column: TdxMasterViewColumn; ContentSizing: Boolean);
|
|
var
|
|
P, PrevP: TPoint;
|
|
PrevWidths, PrevHeaderWidths: PIntArray;
|
|
I, Offset, Delta, PrevLeftPos, AWidth: Integer;
|
|
Success: Boolean;
|
|
CaptureWnd: HWND;
|
|
Msg: TMsg;
|
|
begin
|
|
if Column = nil then Exit;
|
|
FSizingColumn := Column;
|
|
Include(FState, mvsColumnSizing);
|
|
|
|
with Column.Level do
|
|
begin
|
|
if ContentSizing or AutoColumnWidth then
|
|
begin
|
|
I := VisibleColumnCount;
|
|
GetMem(PrevWidths, I * SizeOf(Integer));
|
|
for I := 0 to I - 1 do
|
|
with VisibleColumns[I] do
|
|
if cvWidth in AssignedValues then
|
|
PrevWidths[I] := Width
|
|
else
|
|
PrevWidths[I] := -1;
|
|
end
|
|
else
|
|
PrevWidths := nil;
|
|
if not ContentSizing then
|
|
begin
|
|
I := Layout.Count;
|
|
GetMem(PrevHeaderWidths, I * SizeOf(Integer));
|
|
for I := 0 to I - 1 do
|
|
with Layout do
|
|
if HeaderWidthAssigned[I] then
|
|
PrevHeaderWidths[I] := HeaderWidths[I]
|
|
else
|
|
PrevHeaderWidths[I] := -1;
|
|
end
|
|
else
|
|
PrevHeaderWidths := nil;
|
|
end;
|
|
GetCursorPos(PrevP);
|
|
P := Point(Column.Offset, 0);
|
|
Windows.ClientToScreen(Handle, P);
|
|
Offset := P.X;
|
|
if not Column.Level.Horizontal and ContentSizing then
|
|
Inc(Offset, Column.Level.Layout.HeaderWidths[Column.ColIndex]);
|
|
if ContentSizing then
|
|
Delta := Column.VisibleWidth
|
|
else
|
|
Delta := Column.Level.Layout.HeaderWidths[Column.ColIndex];
|
|
Dec(Delta, PrevP.X - Offset);
|
|
PrevLeftPos := LeftPos;
|
|
|
|
Success := False;
|
|
CaptureWnd := Handle;
|
|
SetCapture(CaptureWnd);
|
|
try
|
|
while GetCapture = CaptureWnd do
|
|
begin
|
|
case Integer(GetMessage(Msg, 0, 0, 0)) of
|
|
-1: Break;
|
|
0: begin
|
|
PostQuitMessage(Msg.wParam);
|
|
Break;
|
|
end;
|
|
end;
|
|
if LeftPos <> PrevLeftPos then
|
|
begin
|
|
PrevP.X := MaxInt;
|
|
Dec(Offset, LeftPos - PrevLeftPos);
|
|
PrevLeftPos := LeftPos;
|
|
end;
|
|
try
|
|
case Msg.message of
|
|
WM_KEYDOWN, WM_KEYUP:
|
|
if Msg.wParam = VK_ESCAPE then Break;
|
|
WM_RBUTTONDOWN, WM_MBUTTONDOWN:
|
|
Break;
|
|
WM_MOUSEMOVE:
|
|
begin
|
|
P := SmallPointToPoint(TSmallPoint(Msg.lParam));
|
|
Windows.ClientToScreen(Msg.hwnd, P);
|
|
if P.X <> PrevP.X then
|
|
begin
|
|
AWidth := P.X - Offset + Delta;
|
|
if ContentSizing then
|
|
Column.VisibleWidth := AWidth
|
|
else
|
|
Column.Level.Layout.ChangeHeaderWidth(Column.ColIndex, AWidth, True);
|
|
UpdateWindow(Handle);
|
|
PrevP := P;
|
|
end;
|
|
end;
|
|
WM_LBUTTONUP:
|
|
begin
|
|
Success := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
finally
|
|
TranslateMessage(Msg);
|
|
DispatchMessage(Msg);
|
|
end;
|
|
end;
|
|
finally
|
|
if GetCapture = CaptureWnd then ReleaseCapture;
|
|
try
|
|
if Success then
|
|
Modified
|
|
else
|
|
with Column.Level do
|
|
begin
|
|
BeginAssignWidths;
|
|
try
|
|
if PrevWidths <> nil then
|
|
for I := 0 to VisibleColumnCount - 1 do
|
|
with VisibleColumns[I] do
|
|
if PrevWidths[I] = -1 then
|
|
AssignedValues := AssignedValues - [cvWidth]
|
|
else
|
|
Width := PrevWidths[I];
|
|
if PrevHeaderWidths <> nil then
|
|
for I := 0 to Layout.Count - 1 do
|
|
if PrevHeaderWidths[I] = -1 then
|
|
Layout.HeaderWidthAssigned[I] := False
|
|
else
|
|
Layout.HeaderWidths[I] := PrevHeaderWidths[I];
|
|
finally
|
|
EndAssignWidths;
|
|
end;
|
|
end;
|
|
finally
|
|
if PrevWidths <> nil then FreeMem(PrevWidths);
|
|
if PrevHeaderWidths <> nil then FreeMem(PrevHeaderWidths);
|
|
|
|
Exclude(FState, mvsColumnSizing);
|
|
FSizingColumn := nil;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.DoColumnVerSizing(Node: TdxMasterViewNode;
|
|
Column: TdxMasterViewColumn; Edge: TdxMasterViewHitTestCode);
|
|
var
|
|
Level: TdxMasterViewLevel;
|
|
ColumnsPlaces: TList;
|
|
P, PrevP: TPoint;
|
|
Delta, PrevNodeBoundsTop, ARowIndex, ARowCount, AColIndex: Integer;
|
|
Success: Boolean;
|
|
CaptureWnd: HWND;
|
|
Msg: TMsg;
|
|
ANode: TdxMasterViewNode;
|
|
AColumn: TdxMasterViewColumn;
|
|
begin
|
|
if Column = nil then Exit;
|
|
Level := Column.Level;
|
|
FSizingColumn := Column;
|
|
Include(FState, mvsColumnSizing);
|
|
|
|
Level.SaveVisibleColumnsPlaces(ColumnsPlaces);
|
|
|
|
GetCursorPos(PrevP);
|
|
Windows.ScreenToClient(Handle, PrevP);
|
|
Delta := 0;
|
|
PrevNodeBoundsTop := Node.Bounds.Top;
|
|
|
|
Success := False;
|
|
CaptureWnd := Handle;
|
|
SetCapture(CaptureWnd);
|
|
try
|
|
while GetCapture = CaptureWnd do
|
|
begin
|
|
case Integer(GetMessage(Msg, 0, 0, 0)) of
|
|
-1: Break;
|
|
0: begin
|
|
PostQuitMessage(Msg.wParam);
|
|
Break;
|
|
end;
|
|
end;
|
|
Inc(Delta, Node.Bounds.Top - PrevNodeBoundsTop);
|
|
PrevNodeBoundsTop := Node.Bounds.Top;
|
|
try
|
|
case Msg.message of
|
|
WM_KEYDOWN, WM_KEYUP:
|
|
if Msg.wParam = VK_ESCAPE then Break;
|
|
WM_RBUTTONDOWN, WM_MBUTTONDOWN:
|
|
Break;
|
|
WM_MOUSEMOVE:
|
|
begin
|
|
P := SmallPointToPoint(TSmallPoint(Msg.lParam));
|
|
MapWindowPoints(Msg.hwnd, Handle, P, 1);
|
|
if P.Y <> PrevP.Y then
|
|
begin
|
|
if Node.ViewInfo.HeaderSize = 0 then
|
|
begin
|
|
GetHitTestInfo(P, ANode, AColumn, ARowIndex, AColIndex);
|
|
if (ANode <> nil) and (ANode.Level = Level) and
|
|
(ANode.ViewInfo.HeaderSize <> 0) then
|
|
Node := ANode
|
|
else
|
|
begin
|
|
Success := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
ARowIndex := Node.InternalHeaderRowIndexFromY(P.Y + Delta);
|
|
with Column do
|
|
begin
|
|
if Edge = htHeaderTopEdge then
|
|
if ARowIndex = -1 then
|
|
begin
|
|
ARowIndex := RowIndex + RowCount - MaxRowCount;
|
|
if ARowIndex < 0 then ARowIndex := 0;
|
|
ARowCount := RowIndex + RowCount - ARowIndex;
|
|
end
|
|
else
|
|
begin
|
|
if ARowIndex < RowIndex + RowCount - MaxRowCount then
|
|
ARowIndex := RowIndex + RowCount - MaxRowCount
|
|
else
|
|
if ARowIndex > RowIndex + RowCount - MinRowCount then
|
|
ARowIndex := RowIndex + RowCount - MinRowCount;
|
|
ARowCount := RowIndex + RowCount - ARowIndex;
|
|
end
|
|
else
|
|
begin
|
|
if ARowIndex = -1 then
|
|
ARowCount := MinRowCount
|
|
else
|
|
ARowCount := ARowIndex - RowIndex + 1;
|
|
ARowIndex := RowIndex;
|
|
end;
|
|
CheckRowCount(ARowCount);
|
|
end;
|
|
|
|
if Column.RowIndex <> ARowIndex then
|
|
Level.Layout.ChangeRowAndRowCount(Column, ARowIndex, ARowCount, True)
|
|
else
|
|
Column.RowCount := ARowCount;
|
|
|
|
PrevP := P;
|
|
end;
|
|
end;
|
|
WM_LBUTTONUP:
|
|
begin
|
|
Success := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
finally
|
|
TranslateMessage(Msg);
|
|
DispatchMessage(Msg);
|
|
end;
|
|
end;
|
|
finally
|
|
if GetCapture = CaptureWnd then ReleaseCapture;
|
|
|
|
if Success then
|
|
begin
|
|
Level.FreeVisibleColumnsPlaces(ColumnsPlaces);
|
|
Modified;
|
|
end
|
|
else
|
|
Level.RestoreVisibleColumnsPlaces(ColumnsPlaces);
|
|
|
|
Exclude(FState, mvsColumnSizing);
|
|
FSizingColumn := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.DoNodeDeleted(Node: TdxMasterViewNode);
|
|
var
|
|
NewNode: TdxMasterViewNode;
|
|
begin
|
|
if FSelectionAnchor = Node then FSelectionAnchor := nil;
|
|
if FFocusedNode = Node then FocusedNode := nil;
|
|
if FTopNode = Node then
|
|
begin
|
|
NewNode := GetNextNode(Node, False);
|
|
if NewNode = nil then NewNode := GetPrevNode(Node, False);
|
|
end
|
|
else
|
|
NewNode := nil;
|
|
Node.Selected := False;
|
|
FAbsoluteItems.Remove(Node);
|
|
if FTopNode = Node then TopNode := NewNode;
|
|
end;
|
|
|
|
procedure TdxMasterView.DoScrolling;
|
|
const
|
|
ScrollTimeStep = 20;
|
|
ScrollValueStep = 5;
|
|
MaxSpeed = 12;
|
|
var
|
|
BreakOnMouseUp: Boolean;
|
|
AllowHorScrolling, AllowVerScrolling: Boolean;
|
|
P, PrevP: TPoint;
|
|
AnchorPos: TPoint;
|
|
AnchorSize: Integer;
|
|
AnchorWnd: HWND;
|
|
Direction: TdxMasterViewDirection;
|
|
Speed: Integer;
|
|
TimerHits: Integer;
|
|
Timer: UINT;
|
|
CaptureWnd: HWND;
|
|
Msg: TMsg;
|
|
|
|
function CreateScrollingAnchorWnd: HWND;
|
|
var
|
|
B: TBitmap;
|
|
W, H: Integer;
|
|
Rgn: HRGN;
|
|
DC: HDC;
|
|
|
|
function GetResourceBitmapName: string;
|
|
begin
|
|
if AllowHorScrolling and AllowVerScrolling then
|
|
Result := 'DXMASTERVIEWFULLSCROLLBITMAP'
|
|
else
|
|
if AllowHorScrolling then
|
|
Result := 'DXMASTERVIEWHORSCROLLBITMAP'
|
|
else
|
|
Result := 'DXMASTERVIEWVERSCROLLBITMAP';
|
|
end;
|
|
|
|
begin
|
|
B := TBitmap.Create;
|
|
B.LoadFromResourceName(HInstance, GetResourceBitmapName);
|
|
|
|
W := B.Width;
|
|
H := B.Height;
|
|
AnchorSize := W;
|
|
with AnchorPos do
|
|
Result := CreateWindow('STATIC', nil, WS_POPUP,
|
|
X - W div 2, Y - H div 2, W, H, Handle, 0, HInstance, nil);
|
|
Rgn := CreateEllipticRgn(0, 0, W + 1, H + 1);
|
|
SetWindowRgn(Result, Rgn, True);
|
|
SetWindowPos(Result, 0, 0, 0, 0, 0,
|
|
SWP_NOZORDER or SWP_NOMOVE or SWP_NOSIZE or SWP_SHOWWINDOW or SWP_NOACTIVATE);
|
|
|
|
DC := GetWindowDC(Result);
|
|
BitBlt(DC, 0, 0, W, H, B.Canvas.Handle, 0, 0, SRCCOPY);
|
|
Rgn := CreateEllipticRgn(0, 0, W + 1, H + 1);
|
|
FrameRgn(DC, Rgn, GetSysColorBrush(COLOR_WINDOWTEXT), 1, 1);
|
|
DeleteObject(Rgn);
|
|
ReleaseDC(Result, DC);
|
|
|
|
B.Free;
|
|
end;
|
|
|
|
procedure CalcDirectionAndSpeed(const P: TPoint);
|
|
var
|
|
DeltaX, DeltaY, SpeedValue: Integer;
|
|
|
|
function GetNeutralZone: TRect;
|
|
begin
|
|
with AnchorPos do
|
|
Result := Bounds(X - AnchorSize div 2, Y - AnchorSize div 2, AnchorSize, AnchorSize);
|
|
if not AllowHorScrolling then
|
|
begin
|
|
Result.Left := 0;
|
|
Result.Right := Screen.Width;
|
|
end;
|
|
if not AllowVerScrolling then
|
|
begin
|
|
Result.Top := 0;
|
|
Result.Bottom := Screen.Height;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if PtInRect(GetNeutralZone, P) then
|
|
begin
|
|
Direction := dirNone;
|
|
Speed := 0;
|
|
Exit;
|
|
end
|
|
else
|
|
begin
|
|
BreakOnMouseUp := True;
|
|
DeltaX := P.X - AnchorPos.X;
|
|
DeltaY := P.Y - AnchorPos.Y;
|
|
if AllowHorScrolling and (not AllowVerScrolling or (Abs(DeltaX) > Abs(DeltaY))) then
|
|
begin
|
|
if DeltaX < 0 then Direction := dirLeft
|
|
else Direction := dirRight;
|
|
SpeedValue := Abs(DeltaX);
|
|
end
|
|
else
|
|
begin
|
|
if DeltaY < 0 then Direction := dirUp
|
|
else Direction := dirDown;
|
|
SpeedValue := Abs(DeltaY);
|
|
end;
|
|
end;
|
|
Dec(SpeedValue, AnchorSize div 2);
|
|
Speed := 1 + SpeedValue div ScrollValueStep;
|
|
if Speed > MaxSpeed then Speed := MaxSpeed;
|
|
end;
|
|
|
|
procedure SetMouseCursor;
|
|
var
|
|
Cursor: TCursor;
|
|
begin
|
|
case Direction of
|
|
dirLeft:
|
|
Cursor := crdxMasterViewLeftScroll;
|
|
dirUp:
|
|
Cursor := crdxMasterViewUpScroll;
|
|
dirRight:
|
|
Cursor := crdxMasterViewRightScroll;
|
|
dirDown:
|
|
Cursor := crdxMasterViewDownScroll;
|
|
else
|
|
if AllowHorScrolling and AllowVerScrolling then
|
|
Cursor := crdxMasterViewFullScroll
|
|
else
|
|
if AllowHorScrolling then
|
|
Cursor := crdxMasterViewHorScroll
|
|
else
|
|
Cursor := crdxMasterViewVerScroll;
|
|
end;
|
|
SetCursor(Screen.Cursors[Cursor]);
|
|
end;
|
|
|
|
begin
|
|
Include(FState, mvsScrolling);
|
|
|
|
BreakOnMouseUp := False;
|
|
AllowHorScrolling := GetWindowLong(Handle, GWL_STYLE) and WS_HSCROLL <> 0;
|
|
AllowVerScrolling := GetWindowLong(Handle, GWL_STYLE) and WS_VSCROLL <> 0;
|
|
GetCursorPos(PrevP);
|
|
AnchorPos := PrevP;
|
|
AnchorWnd := CreateScrollingAnchorWnd;
|
|
Direction := dirNone;
|
|
SetMouseCursor;
|
|
Speed := 1;
|
|
TimerHits := 0;
|
|
Timer := SetTimer(0, 0, ScrollTimeStep, nil);
|
|
|
|
CaptureWnd := Handle;
|
|
SetCapture(CaptureWnd);
|
|
try
|
|
while GetCapture = CaptureWnd do
|
|
begin
|
|
case Integer(GetMessage(Msg, 0, 0, 0)) of
|
|
-1: Break;
|
|
0: begin
|
|
PostQuitMessage(Msg.wParam);
|
|
Break;
|
|
end;
|
|
end;
|
|
if (Msg.message = WM_PAINT) and (Msg.hwnd = AnchorWnd) then
|
|
begin
|
|
ValidateRect(AnchorWnd, nil);
|
|
Continue;
|
|
end;
|
|
if (Msg.message >= WM_MOUSEFIRST) and (Msg.message <= WM_MOUSELAST) and
|
|
(Msg.message <> WM_MOUSEMOVE) and (Msg.message <> WM_MBUTTONUP) then
|
|
Break;
|
|
try
|
|
case Msg.message of
|
|
WM_KEYDOWN, WM_KEYUP:
|
|
if Msg.wParam = VK_ESCAPE then Break;
|
|
WM_MOUSEMOVE:
|
|
begin
|
|
P := SmallPointToPoint(TSmallPoint(Msg.lParam));
|
|
Windows.ClientToScreen(Msg.hwnd, P);
|
|
if (P.X <> PrevP.X) or (P.Y <> PrevP.Y) then
|
|
begin
|
|
CalcDirectionAndSpeed(P);
|
|
SetMouseCursor;
|
|
PrevP := P;
|
|
end;
|
|
end;
|
|
WM_MBUTTONUP:
|
|
if BreakOnMouseUp then Break;
|
|
WM_TIMER:
|
|
if UINT(Msg.wParam) = Timer then
|
|
begin
|
|
Inc(TimerHits);
|
|
if TimerHits mod (MaxSpeed - Speed + 1) = 0 then Scroll(Direction);
|
|
end;
|
|
end;
|
|
finally
|
|
TranslateMessage(Msg);
|
|
DispatchMessage(Msg);
|
|
end;
|
|
end;
|
|
finally
|
|
if GetCapture = CaptureWnd then ReleaseCapture;
|
|
|
|
KillTimer(0, Timer);
|
|
DestroyWindow(AnchorWnd);
|
|
|
|
Exclude(FState, mvsScrolling);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.DoSelectionChanged;
|
|
begin
|
|
if (FSelectionLockCount <> 0) or not MultiSelect or IsDestroying then Exit;
|
|
if Assigned(FOnSelectionChanged) then FOnSelectionChanged(Self);
|
|
end;
|
|
|
|
function TdxMasterView.DoSelectNode(Node: TdxMasterViewNode): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnSelectNode) then FOnSelectNode(Self, Node, Result);
|
|
end;
|
|
|
|
procedure TdxMasterView.DoSorting;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
for I := 0 to AbsoluteLevelCount - 1 do AbsoluteLevels[I].DoSorting;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.DoTopNodeChanged;
|
|
begin
|
|
if FTopNodeChangeLockCount <> 0 then Exit;
|
|
Invalidate;
|
|
if Assigned(FOnTopNodeChanged) then FOnTopNodeChanged(Self);
|
|
end;
|
|
|
|
procedure TdxMasterView.HighlightStyleChanged(Values: TdxMasterViewStyleValues);
|
|
begin
|
|
if HasFocus then InvalidateSelection;
|
|
end;
|
|
|
|
procedure TdxMasterView.InactiveStyleChanged(Values: TdxMasterViewStyleValues);
|
|
begin
|
|
if not HasFocus then InvalidateSelection;
|
|
end;
|
|
|
|
function TdxMasterView.CanFocusNode(Node: TdxMasterViewNode): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnBeforeFocusNode) then FOnBeforeFocusNode(Self, Node, Result);
|
|
end;
|
|
|
|
procedure TdxMasterView.ChangeFocusedIndex(Value: Integer);
|
|
var
|
|
NewFocusedNode: TdxMasterViewNode;
|
|
ATopIndex, AVisibleItemCount, APartVisibleItemCount, Delta, PrevDelta: Integer;
|
|
begin
|
|
if Value < 0 then Value := 0;
|
|
if Value >= AbsoluteItemCount then Value := AbsoluteItemCount - 1;
|
|
|
|
if Value = -1 then
|
|
NewFocusedNode := nil
|
|
else
|
|
NewFocusedNode := AbsoluteItems[Value];
|
|
if not CanFocusNode(NewFocusedNode) then Exit;
|
|
//try
|
|
if NewFocusedNode <> nil then NewFocusedNode.SyncPos;
|
|
//finally
|
|
if FFocusedNode <> nil then FFocusedNode.Invalidate(nil, vpContent);
|
|
FocusedNode := NewFocusedNode;
|
|
if Value < TopIndex then TopIndex := Value
|
|
else
|
|
if Value >= TopIndex + VisibleItemCount then
|
|
begin
|
|
ATopIndex := Value - FLastVisibleItemCount + 1;
|
|
Delta := 0;
|
|
repeat
|
|
CalcViewInfo(ATopIndex, -1, AVisibleItemCount, APartVisibleItemCount, False);
|
|
PrevDelta := Delta;
|
|
if Value > ATopIndex + AVisibleItemCount - 1 then
|
|
Delta := 1
|
|
else
|
|
Delta := -1;
|
|
if (PrevDelta <> 0) and (Delta <> PrevDelta) then
|
|
begin
|
|
if Delta = 1 then Inc(ATopIndex);
|
|
Break;
|
|
end;
|
|
Inc(ATopIndex, Delta);
|
|
until False;
|
|
TopIndex := ATopIndex;
|
|
end;
|
|
if FFocusedNode <> nil then
|
|
FFocusedNode.Invalidate(nil, vpContent);
|
|
//end;
|
|
end;
|
|
|
|
function TdxMasterView.GetFirstNodeFromVisible(Level: TdxMasterViewLevel): TdxMasterViewNode;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := TopIndex to AbsoluteItemCount - 1 do
|
|
begin
|
|
Result := AbsoluteItems[I];
|
|
if ((Level = nil) or (Result.Level = Level)) and
|
|
CanFocusNode(Result) then Exit;
|
|
end;
|
|
for I := TopIndex - 1 downto 0 do
|
|
begin
|
|
Result := AbsoluteItems[I];
|
|
if ((Level = nil) or (Result.Level = Level)) and
|
|
CanFocusNode(Result) then Exit;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TdxMasterView.GetLastNodeFromVisible(Level: TdxMasterViewLevel): TdxMasterViewNode;
|
|
var
|
|
I, Margin: Integer;
|
|
begin
|
|
Result := nil;
|
|
Margin := TopIndex + VisibleItemCount - 1;
|
|
for I := TopIndex to AbsoluteItemCount - 1 do
|
|
begin
|
|
if (I > Margin) and (Result <> nil) then Exit;
|
|
if ((Level = nil) or (AbsoluteItems[I].Level = Level)) and
|
|
CanFocusNode(AbsoluteItems[I]) then
|
|
Result := AbsoluteItems[I];
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterView.GetNextNode(Value: TdxMasterViewNode; OnSameLevel: Boolean): TdxMasterViewNode;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (Value <> nil) and (Value.AbsoluteIndex = AbsoluteItemCount - 1) or
|
|
(Value = nil) and OnSameLevel then
|
|
Result := nil
|
|
else
|
|
if OnSameLevel then
|
|
begin
|
|
for I := Value.AbsoluteIndex + 1 to AbsoluteItemCount - 1 do
|
|
begin
|
|
Result := AbsoluteItems[I];
|
|
if (Result.Level = Value.Level) and CanFocusNode(Result) then Exit;
|
|
end;
|
|
Result := nil;
|
|
end
|
|
else
|
|
begin
|
|
if Value = nil then
|
|
I := 0
|
|
else
|
|
I := Value.AbsoluteIndex + 1;
|
|
for I := I to AbsoluteItemCount - 1 do
|
|
begin
|
|
Result := AbsoluteItems[I];
|
|
if (Result <> nil) and CanFocusNode(Result) then Exit;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterView.GetPrevNode(Value: TdxMasterViewNode; OnSameLevel: Boolean): TdxMasterViewNode;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (Value <> nil) and (Value.AbsoluteIndex = 0) or
|
|
(Value = nil) and OnSameLevel then
|
|
Result := nil
|
|
else
|
|
if OnSameLevel then
|
|
begin
|
|
for I := Value.AbsoluteIndex - 1 downto 0 do
|
|
begin
|
|
Result := AbsoluteItems[I];
|
|
if (Result.Level = Value.Level) and CanFocusNode(Result) then Exit;
|
|
end;
|
|
Result := nil;
|
|
end
|
|
else
|
|
begin
|
|
if Value = nil then
|
|
I := AbsoluteItemCount - 1
|
|
else
|
|
I := Value.AbsoluteIndex - 1;
|
|
for I := I downto 0 do
|
|
begin
|
|
Result := AbsoluteItems[I];
|
|
if (Result <> nil) and CanFocusNode(Result) then Exit;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.ShowPrevPage(CurTopIndex: Integer; OnSameLevel: Boolean);
|
|
var
|
|
ATopIndex, LastVisibleIndex, AVisibleItemCount, APartVisibleItemCount: Integer;
|
|
NodeVisible, PrevNodeVisible: Boolean;
|
|
FirstVisibleNode, PrevFirstVisibleNode: TdxMasterViewNode;
|
|
|
|
function IsNodeVisible: Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
PrevFirstVisibleNode := FirstVisibleNode;
|
|
Result := True;
|
|
for I := ATopIndex to ATopIndex + AVisibleItemCount - 1 do
|
|
begin
|
|
FirstVisibleNode := AbsoluteItems[I];
|
|
if FirstVisibleNode.Level = FFocusedNode.Level then Exit;
|
|
end;
|
|
FirstVisibleNode := nil;
|
|
Result := False;
|
|
end;
|
|
|
|
begin
|
|
if CurTopIndex = 0 then Exit;
|
|
if OnSameLevel then
|
|
begin
|
|
ATopIndex := TopIndex;
|
|
AVisibleItemCount := VisibleItemCount;
|
|
PrevNodeVisible := IsNodeVisible;
|
|
if PrevNodeVisible then LastVisibleIndex := TopIndex
|
|
else
|
|
begin
|
|
LastVisibleIndex := FocusedIndex;
|
|
FirstVisibleNode := FFocusedNode;
|
|
end;
|
|
ATopIndex := CurTopIndex - 1;
|
|
repeat
|
|
CalcViewInfo(ATopIndex, -1, AVisibleItemCount, APartVisibleItemCount, False);
|
|
NodeVisible := IsNodeVisible;
|
|
if NodeVisible then
|
|
begin
|
|
if FirstVisibleNode <> PrevFirstVisibleNode then
|
|
LastVisibleIndex := ATopIndex;
|
|
if (ATopIndex + AVisibleItemCount - 1 <= FocusedIndex) and
|
|
(LastVisibleIndex <> TopIndex) then
|
|
begin
|
|
if (ATopIndex + AVisibleItemCount - 1 < FocusedIndex) and PrevNodeVisible then
|
|
Inc(ATopIndex);
|
|
Break;
|
|
end;
|
|
end;
|
|
PrevNodeVisible := NodeVisible;
|
|
Dec(ATopIndex);
|
|
if ATopIndex = -1 then
|
|
begin
|
|
ATopIndex := LastVisibleIndex;
|
|
Break;
|
|
end;
|
|
until False;
|
|
end
|
|
else
|
|
begin
|
|
ATopIndex := CurTopIndex - 1;
|
|
repeat
|
|
if ATopIndex = 0 then Break;
|
|
CalcViewInfo(ATopIndex, -1, AVisibleItemCount, APartVisibleItemCount, False);
|
|
if ATopIndex + AVisibleItemCount - 1 <= CurTopIndex then
|
|
begin
|
|
if ATopIndex + AVisibleItemCount - 1 < CurTopIndex then Inc(ATopIndex);
|
|
Break;
|
|
end;
|
|
Dec(ATopIndex);
|
|
until False;
|
|
if ATopIndex = CurTopIndex then Dec(ATopIndex);
|
|
end;
|
|
TopIndex := ATopIndex;
|
|
end;
|
|
|
|
procedure TdxMasterView.ShowNextPage(CurBottomIndex: Integer; OnSameLevel: Boolean);
|
|
var
|
|
ATopIndex, AVisibleItemCount, APartVisibleItemCount: Integer;
|
|
LastVisibleNode, PrevLastVisibleNode: TdxMasterViewNode;
|
|
|
|
function IsNodeVisible: Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
PrevLastVisibleNode := LastVisibleNode;
|
|
Result := True;
|
|
for I := ATopIndex + AVisibleItemCount - 1 downto ATopIndex do
|
|
begin
|
|
LastVisibleNode := AbsoluteItems[I];
|
|
if LastVisibleNode.Level = FFocusedNode.Level then Exit;
|
|
end;
|
|
LastVisibleNode := nil;
|
|
Result := False;
|
|
end;
|
|
|
|
begin
|
|
if OnSameLevel then
|
|
begin
|
|
ATopIndex := TopIndex;
|
|
AVisibleItemCount := VisibleItemCount;
|
|
if not IsNodeVisible then LastVisibleNode := FFocusedNode;
|
|
ATopIndex := CurBottomIndex;
|
|
repeat
|
|
CalcViewInfo(ATopIndex, -1, AVisibleItemCount, APartVisibleItemCount, False);
|
|
if IsNodeVisible and (LastVisibleNode <> PrevLastVisibleNode) then Break;
|
|
Inc(ATopIndex);
|
|
if ATopIndex = AbsoluteItemCount then Exit;
|
|
until False;
|
|
end
|
|
else
|
|
begin
|
|
ATopIndex := CurBottomIndex;
|
|
if ATopIndex = TopIndex then Inc(ATopIndex);
|
|
end;
|
|
TopIndex := ATopIndex;
|
|
end;
|
|
|
|
procedure TdxMasterView.Scroll(Direction: TdxMasterViewDirection);
|
|
begin
|
|
case Direction of
|
|
dirLeft:
|
|
LeftPos := LeftPos - HScrollDelta;
|
|
dirRight:
|
|
LeftPos := LeftPos + HScrollDelta;
|
|
dirUp:
|
|
TopIndex := TopIndex - 1;
|
|
dirDown:
|
|
TopIndex := TopIndex + 1;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.RefreshAbsoluteItems;
|
|
var
|
|
I: Integer;
|
|
PrevVisibles: PBoolArray;
|
|
NeedCalcScrollableWidth: Boolean;
|
|
begin
|
|
if FUpdateLockCount = 0 then
|
|
begin
|
|
GetMem(PrevVisibles, AbsoluteLevelCount * SizeOf(Boolean));
|
|
try
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
with AbsoluteLevels[I] do
|
|
begin
|
|
PrevVisibles[I] := Visible;
|
|
FVisible := False;
|
|
end;
|
|
FAbsoluteItems.Clear;
|
|
if FItems <> nil then FItems.AddVisibleToList(FAbsoluteItems);
|
|
if AutoColumnWidth then
|
|
begin
|
|
NeedCalcScrollableWidth := False;
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
with AbsoluteLevels[I] do
|
|
if Visible and not PrevVisibles[I] then
|
|
WidthChanged
|
|
else
|
|
if not Visible and PrevVisibles[I] then
|
|
NeedCalcScrollableWidth := True;
|
|
if NeedCalcScrollableWidth then
|
|
CalcScrollableWidth(nil);
|
|
end
|
|
else
|
|
CalcScrollableWidth(nil);
|
|
finally
|
|
FreeMem(PrevVisibles, AbsoluteLevelCount * SizeOf(Boolean));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.RefreshAbsoluteLevels;
|
|
|
|
procedure AddLevel(Level: TdxMasterViewLevel);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if Level <> FLevels then
|
|
Level.FAbsoluteIndex := FAbsoluteLevels.Add(Level);
|
|
for I := 0 to Level.Count - 1 do AddLevel(Level[I]);
|
|
end;
|
|
|
|
begin
|
|
FAbsoluteLevels.Clear;
|
|
AddLevel(FLevels);
|
|
end;
|
|
|
|
procedure TdxMasterView.SelectPeriod(ToNode: TdxMasterViewNode);
|
|
var
|
|
M1, M2, I: Integer;
|
|
begin
|
|
if MultiSelect and (FLastSelectedNode <> ToNode) then
|
|
begin
|
|
M1 := FLastSelectedNode.AbsoluteIndex;
|
|
M2 := ToNode.AbsoluteIndex;
|
|
if M1 > M2 then
|
|
begin
|
|
I := M1;
|
|
M1 := M2;
|
|
M2 := I;
|
|
end;
|
|
FLastSelectedNode := ToNode;
|
|
for I := M1 to M2 do AbsoluteItems[I].Invalidate(nil, vpContent);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.InvalidateSelection;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to SelectedItemCount - 1 do
|
|
SelectedItems[I].Invalidate(nil, vpContent);
|
|
if (FFocusedNode <> nil) and not FFocusedNode.Selected then
|
|
FFocusedNode.Invalidate(nil, vpContent);
|
|
end;
|
|
|
|
procedure TdxMasterView.Modified;
|
|
begin
|
|
if not (csLoading in ComponentState) and
|
|
(GetParentForm(Self) <> nil) and (GetParentForm(Self).Designer <> nil) then
|
|
GetParentForm(Self).Designer.Modified;
|
|
end;
|
|
|
|
procedure TdxMasterView.Freeze;
|
|
begin
|
|
FFrozen := True;
|
|
end;
|
|
|
|
function TdxMasterView.FreezeDataSet(ALevel: TdxMasterViewLevel): Integer;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := 0;
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
with AbsoluteLevels[I] do
|
|
if DataSet = ALevel.DataSet then
|
|
Result := DataLink.Freeze;
|
|
end;
|
|
|
|
procedure TdxMasterView.Unfreeze;
|
|
begin
|
|
FFrozen := False;
|
|
end;
|
|
|
|
procedure TdxMasterView.UnfreezeDataSet(ALevel: TdxMasterViewLevel);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
with AbsoluteLevels[I] do
|
|
if DataSet = ALevel.DataSet then
|
|
DataLink.Unfreeze;
|
|
end;
|
|
|
|
procedure TdxMasterView.Invalidate;
|
|
begin
|
|
if HandleAllocated then InvalidateRect(Handle, nil, False);
|
|
end;
|
|
|
|
procedure TdxMasterView.DrawText(const DrawDC: HDC; var ARect: TRect;
|
|
const Font: TFont; const Brush: HBRUSH; const TextColor, BkColor: TColor;
|
|
const Alignment: TAlignment; const Text: string;
|
|
const FillBackground, MakeRightSpace, AllowUseBitmap, MultiLine: Boolean);
|
|
const
|
|
Alignments: array[TAlignment] of Integer = (DT_LEFT, DT_RIGHT, DT_CENTER);
|
|
EndEllipsis: array[Boolean] of Integer = (0, DT_END_ELLIPSIS);
|
|
MultiLines: array[Boolean] of Integer = (DT_SINGLELINE or DT_VCENTER, DT_WORDBREAK);
|
|
Opaques: array[Boolean] of Integer = (0, ETO_OPAQUE);
|
|
var
|
|
R: TRect;
|
|
CanUseBitmap: Boolean;
|
|
DC: HDC;
|
|
PrevFont: HFONT;
|
|
Size: TSize;
|
|
X, Y: Integer;
|
|
begin
|
|
R := ARect;
|
|
CanUseBitmap := (movUseBitmap in FOptionsView) and AllowUseBitmap;
|
|
if CanUseBitmap then
|
|
begin
|
|
with R do
|
|
begin
|
|
OffsetRect(R, -Left, -Top);
|
|
PrepareBitmap(Right, Bottom);
|
|
end;
|
|
DC := FBitmap.Canvas.Handle;
|
|
end
|
|
else
|
|
DC := DrawDC;
|
|
|
|
PrevFont := SelectObject(DC, Font.Handle);
|
|
SetTextColor(DC, ColorToRGB(TextColor));
|
|
GetTextExtentPoint{32}(DC, PChar(Text), Length(Text), Size);
|
|
|
|
if (movDrawEndEllipsis in FOptionsView) or MultiLine then
|
|
begin
|
|
if FillBackground then FillRect(DC, R, Brush);
|
|
Inc(R.Left, 2);
|
|
if MakeRightSpace then
|
|
Dec(R.Right, 2)
|
|
else
|
|
Dec(R.Right, SortOrderMarkZoneWidth);
|
|
if MultiLine then InflateRect(R, 0, -2);
|
|
SetBkMode(DC, TRANSPARENT);
|
|
Windows.DrawText(DC, PChar(Text), Length(Text), R,
|
|
MultiLines[MultiLine] or DT_NOPREFIX or Alignments[Alignment] or
|
|
Byte(not MultiLine and not (fsItalic in Font.Style) and
|
|
(Size.cx <= R.Right - R.Left)) * DT_NOCLIP or
|
|
EndEllipsis[not MultiLine and (movDrawEndEllipsis in FOptionsView)]);
|
|
SetBkMode(DC, OPAQUE);
|
|
end
|
|
else
|
|
begin
|
|
with R, Size do
|
|
begin
|
|
if not MakeRightSpace then
|
|
begin
|
|
Dec(Right, SortOrderMarkZoneWidth);
|
|
if FillBackground then
|
|
FillRect(DC, Rect(Right, Top, Right + SortOrderMarkZoneWidth, Bottom), Brush);
|
|
end;
|
|
case Alignment of
|
|
taLeftJustify:
|
|
X := Left + 2;
|
|
taRightJustify:
|
|
X := Right - Byte(MakeRightSpace) * 2 - cx;
|
|
else
|
|
X := (Left + Right + Byte(not MakeRightSpace) * 2 - cx) div 2;
|
|
end;
|
|
if Right - Left - (1 + Byte(MakeRightSpace)) * 2 < cx then
|
|
begin
|
|
X := Left + 2;
|
|
if MakeRightSpace then
|
|
begin
|
|
Dec(Right, 2);
|
|
if FillBackground then
|
|
FillRect(DC, Rect(Right, Top, Right + 2, Bottom), Brush);
|
|
end;
|
|
end;
|
|
Y := (Top + Bottom - cy) div 2;
|
|
end;
|
|
if FillBackground then
|
|
SetBkColor(DC, ColorToRGB(BkColor))
|
|
else
|
|
SetBkMode(DC, TRANSPARENT);
|
|
ExtTextOut(DC, X, Y, ETO_CLIPPED or Opaques[FillBackground],
|
|
@R, PChar(Text), Length(Text), nil);
|
|
if not FillBackground then SetBkMode(DC, OPAQUE);
|
|
end;
|
|
|
|
SelectObject(DC, PrevFont);
|
|
|
|
if CanUseBitmap then
|
|
with ARect do
|
|
BitBlt(DrawDC, Left, Top, Right - Left, Bottom - Top, DC, 0, 0, SRCCOPY);
|
|
end;
|
|
|
|
function TdxMasterView.GetSelectionParams(Node: TdxMasterViewNode;
|
|
ABrush: PBRUSH; ATextColor, ABkColor: PColor): Boolean;
|
|
begin
|
|
Result :=
|
|
Node.Selected and (HasFocus or not (movHideSelection in FOptionsView));
|
|
if Result then
|
|
if HasFocus then
|
|
begin
|
|
if ABrush <> nil then ABrush^ := HighlightBrush;
|
|
if ATextColor <> nil then ATextColor^ := HighlightFontColor;
|
|
if ABkColor <> nil then ABkColor^ := HighlightColor;
|
|
end
|
|
else
|
|
begin
|
|
if ABrush <> nil then ABrush^ := InactiveBrush;
|
|
if ATextColor <> nil then ATextColor^ := InactiveFontColor;
|
|
if ABkColor <> nil then ABkColor^ := InactiveColor;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.PrepareBitmap(const AWidth, AHeight: Integer);
|
|
begin
|
|
with FBitmap do
|
|
begin
|
|
if AWidth > Width then Width := AWidth;
|
|
if AHeight > Height then Height := AHeight;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.ApplyBestFit(Level: TdxMasterViewLevel; Column: TdxMasterViewColumn);
|
|
var
|
|
I, J: Integer;
|
|
begin
|
|
if Level = nil then
|
|
if Column = nil then
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
for J := 0 to AbsoluteLevels[I].VisibleColumnCount - 1 do
|
|
AbsoluteLevels[I].VisibleColumns[J].ApplyBestFit
|
|
else
|
|
Column.ApplyBestFit
|
|
else
|
|
for I := 0 to Level.VisibleColumnCount - 1 do
|
|
Level.VisibleColumns[I].ApplyBestFit;
|
|
end;
|
|
|
|
procedure TdxMasterView.BeginLayout;
|
|
begin
|
|
Inc(FLayoutLockCount);
|
|
BeginUpdate;
|
|
end;
|
|
|
|
procedure TdxMasterView.BeginSelection;
|
|
begin
|
|
Inc(FSelectionLockCount);
|
|
end;
|
|
|
|
procedure TdxMasterView.BeginUpdate;
|
|
begin
|
|
Inc(FUpdateLockCount);
|
|
end;
|
|
|
|
procedure TdxMasterView.CancelLayout;
|
|
begin
|
|
if FLayoutLockCount > 0 then
|
|
begin
|
|
Dec(FLayoutLockCount);
|
|
CancelUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.CancelUpdate;
|
|
begin
|
|
if FUpdateLockCount > 0 then Dec(FUpdateLockCount);
|
|
FDontInvalidate := False;
|
|
end;
|
|
|
|
procedure TdxMasterView.ClearSelection;
|
|
begin
|
|
ClearSelectedItems;
|
|
end;
|
|
|
|
function TdxMasterView.CreateStyle(AStyleClass: TdxMasterViewStyleClass): TdxMasterViewStyle;
|
|
begin
|
|
Result := AStyleClass.Create(Owner);
|
|
AddStyle(Result);
|
|
end;
|
|
|
|
procedure TdxMasterView.DeleteSelection;
|
|
var
|
|
PrevCursor: TCursor;
|
|
List: TList;
|
|
I, J: Integer;
|
|
S: string;
|
|
begin
|
|
if SelectedItemCount = 0 then Exit;
|
|
if SelectedItemCount = 1 then
|
|
begin
|
|
if not SelectedItems[0].CanDelete then Exit;
|
|
with SelectedItems[0].Level do
|
|
if (lodConfirmDelete in OptionsDB) and
|
|
(Application.MessageBox(
|
|
PChar(Format(DeleteConfirmText, [Caption])),
|
|
PChar(DeleteConfirmCaptionText),
|
|
MB_ICONQUESTION or MB_OKCANCEL) = ID_CANCEL) then Exit;
|
|
SelectedItems[0].Delete;
|
|
end
|
|
else
|
|
begin
|
|
BeginSelection;
|
|
List := TList.Create;
|
|
try
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
if AbsoluteLevels[I].CanDelete then
|
|
begin
|
|
List.Clear;
|
|
for J := 0 to SelectedItemCount - 1 do
|
|
with SelectedItems[J] do
|
|
if (Level.AbsoluteIndex = I) and CanDelete then
|
|
List.Add(SelectedItems[J]);
|
|
if List.Count = 0 then Continue;
|
|
|
|
with AbsoluteLevels[I] do
|
|
if lodConfirmDelete in OptionsDB then
|
|
begin
|
|
if List.Count = 1 then
|
|
S := DeleteConfirmText
|
|
else
|
|
S := MultipleDeleteConfirmText;
|
|
case Application.MessageBox(
|
|
PChar(Format(S, [Caption])),
|
|
PChar(DeleteConfirmCaptionText),
|
|
MB_ICONQUESTION or MB_YESNOCANCEL) of
|
|
ID_CANCEL: Break;
|
|
ID_NO: Continue;
|
|
end;
|
|
end;
|
|
|
|
PrevCursor := Screen.Cursor;
|
|
if ShowHourGlassCursor then Screen.Cursor := crHourGlass;
|
|
BeginUpdate;
|
|
AbsoluteLevels[I].BeginLoad;
|
|
try
|
|
for J := 0 to List.Count - 1 do
|
|
TdxMasterViewNode(List[J]).Delete;
|
|
finally
|
|
try
|
|
AbsoluteLevels[I].EndLoad(True);
|
|
finally
|
|
EndUpdate;
|
|
if ShowHourGlassCursor then Screen.Cursor := PrevCursor;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
List.Free;
|
|
EndSelection;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.EndLayout;
|
|
begin
|
|
if FLayoutLockCount > 0 then
|
|
begin
|
|
Dec(FLayoutLockCount);
|
|
try
|
|
if FLayoutLockCount = 0 then UpdateData;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.EndSelection;
|
|
begin
|
|
if FSelectionLockCount > 0 then
|
|
begin
|
|
Dec(FSelectionLockCount);
|
|
if FSelectionLockCount = 0 then
|
|
begin
|
|
DoSelectionChanged;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.EndUpdate;
|
|
begin
|
|
if FUpdateLockCount > 0 then
|
|
begin
|
|
Dec(FUpdateLockCount);
|
|
if FUpdateLockCount = 0 then
|
|
begin
|
|
RefreshAbsoluteItems;
|
|
TopIndex := CheckTopIndex(TopIndex);
|
|
CheckFocusedNode;
|
|
if not FDontInvalidate then Invalidate;
|
|
end;
|
|
end;
|
|
FDontInvalidate := False;
|
|
end;
|
|
|
|
procedure TdxMasterView.FocusNode(Node: TdxMasterViewNode; ChangeSelection: Boolean);
|
|
begin
|
|
ChangeSelection := ChangeSelection and MultiSelect and
|
|
((FocusedNode = nil) or
|
|
(SelectedItemCount = 1) and FocusedNode.Selected);
|
|
if Node = nil then
|
|
FocusedIndex := -1
|
|
else
|
|
FocusedIndex := Node.AbsoluteIndex;
|
|
if ChangeSelection and (FFocusedNode <> nil) and (FFocusedNode = Node) then
|
|
begin
|
|
BeginSelection;
|
|
try
|
|
ClearSelection;
|
|
FFocusedNode.Selected := True;
|
|
finally
|
|
EndSelection;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.FullCollapse;
|
|
begin
|
|
Items.Collapse(True);
|
|
end;
|
|
|
|
procedure TdxMasterView.FullExpand;
|
|
{var
|
|
ft,lt:integer;}
|
|
begin
|
|
// ft:=gettickcount;
|
|
Items.Expand(True);
|
|
// lt:=gettickcount;
|
|
// application.messagebox(pchar(inttostr(lt-ft)),'',0);
|
|
end;
|
|
|
|
function TdxMasterView.GetHitTestInfo(const P: TPoint; var Node: TdxMasterViewNode;
|
|
var Column: TdxMasterViewColumn; var RowIndex, ColIndex: Integer): TdxMasterViewHitTestCode;
|
|
var
|
|
FromIndex, AVisibleItemCount, APartVisibleItemCount, I, J, K: Integer;
|
|
R, R1, R2: TRect;
|
|
List: TList;
|
|
|
|
function ProcessHeader(const R: TRect; var HitTestCode: TdxMasterViewHitTestCode): Boolean;
|
|
var
|
|
K, J: Integer;
|
|
R1: TRect;
|
|
AColumn: TdxMasterViewColumn;
|
|
begin
|
|
Result := PtInRect(R, P);
|
|
if Result then
|
|
begin
|
|
RowIndex := Node.HeaderRowIndexFromY(P.Y);
|
|
ColIndex := Node.HeaderColIndexFromX(P.X);
|
|
HitTestCode := htHeader;
|
|
with Node.Level do
|
|
for K := 0 to VisibleColumnCount - 1 do
|
|
begin
|
|
Column := VisibleColumns[K];
|
|
R1 := Column.GetHeaderBounds(Node);
|
|
if PtInRect(R1, P) then
|
|
begin
|
|
if P.X < R1.Left + ColumnSizingZoneWidth then
|
|
begin
|
|
if Horizontal then
|
|
begin
|
|
List := TList.Create;
|
|
try
|
|
if Layout.HasLeftNeighbours(Column, List, True) then
|
|
for J := 0 to List.Count - 1 do
|
|
with TdxMasterViewColumn(List[J]) do
|
|
if CanHorSizing then
|
|
with GetHeaderBounds(Node) do
|
|
if (Top <= P.Y) and (P.Y < Bottom) then
|
|
begin
|
|
Column := List[J];
|
|
HitTestCode := htHeaderRightEdge;
|
|
Exit;
|
|
end;
|
|
finally
|
|
List.Free;
|
|
end;
|
|
end
|
|
else
|
|
if (Column.ColIndex > 0) and
|
|
(RowIndex < Layout[Column.ColIndex - 1].Count) then
|
|
begin
|
|
AColumn := Layout.Columns[RowIndex, Column.ColIndex - 1];
|
|
if AColumn.CanHorSizing and AColumn.IsWidthLinked then
|
|
begin
|
|
Column := AColumn;
|
|
Dec(ColIndex);
|
|
HitTestCode := htContentRightEdge;
|
|
Exit;
|
|
end;
|
|
end;
|
|
HitTestCode := htHeaderLeftEdge;
|
|
Exit;
|
|
end
|
|
else
|
|
if (P.X >= R1.Right - ColumnSizingZoneWidth) and
|
|
(Column.Level.Horizontal and Column.CanHorSizing and
|
|
(not AutoColumnWidth or not Column.Level.Layout.OneOnLine(Column)) or
|
|
not Column.Level.Horizontal and Column.Level.CanHorSizing) then
|
|
begin
|
|
HitTestCode := htHeaderRightEdge;
|
|
Exit;
|
|
end;
|
|
|
|
if P.Y < R1.Top + ColumnSizingZoneWidth then
|
|
if FHorizontal then
|
|
if Column.CanVerSizing and
|
|
((Column.RowIndex <> 0) or (Column.RowCount <> Column.MinRowCount)) then
|
|
HitTestCode := htHeaderTopEdge
|
|
else
|
|
Exit
|
|
else
|
|
if Column.RowIndex = 0 then
|
|
Exit
|
|
else
|
|
begin
|
|
AColumn := Layout.Columns[Column.RowIndex - 1, Column.ColIndex];
|
|
if AColumn.CanVerSizing then
|
|
begin
|
|
Column := AColumn;
|
|
HitTestCode := htHeaderBottomEdge;
|
|
end;
|
|
end
|
|
else
|
|
if (P.Y >= R1.Bottom - ColumnSizingZoneWidth) and
|
|
Column.CanVerSizing then
|
|
HitTestCode := htHeaderBottomEdge;
|
|
Exit;
|
|
end;
|
|
end;
|
|
Column := nil;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Column := nil;
|
|
RowIndex := -1;
|
|
ColIndex := -1;
|
|
|
|
if Customizing and TdxMVCustomizationForm(FCustomizationForm).MouseInBounds(P) then
|
|
begin
|
|
Node := nil;
|
|
Result := htCustomizationForm;
|
|
Exit;
|
|
end;
|
|
|
|
if PtInRect(ClientRect, P) then
|
|
begin
|
|
FromIndex := TopIndex;
|
|
if FromIndex <> -1 then
|
|
begin
|
|
CalcViewInfo(TopIndex, -1, AVisibleItemCount, APartVisibleItemCount, True);
|
|
for I := FromIndex to FromIndex + APartVisibleItemCount - 1 do
|
|
begin
|
|
Node := AbsoluteItems[I];
|
|
R := Node.FullBounds;
|
|
if PtInRect(R, P) then
|
|
begin
|
|
// work with footer
|
|
if Node.ViewInfo.FooterSize <> 0 then
|
|
for J := 0 to Node.ViewInfo.EndLevelCount - 1 do
|
|
begin
|
|
R1 := Node.SubFooterBounds[J];
|
|
if PtInRect(R1, P) then
|
|
begin
|
|
RowIndex := Node.FooterRowIndexFromY(J, P.Y);
|
|
ColIndex := Node.FooterColIndexFromX(J, P.X);
|
|
Result := htFooter;
|
|
with Node.Level.Parents[J] do
|
|
for K := 0 to VisibleColumnCount - 1 do
|
|
begin
|
|
Column := VisibleColumns[K];
|
|
R1 := Column.GetFooterBounds(Node);
|
|
if PtInRect(R1, P) then Exit;
|
|
end;
|
|
Column := nil;
|
|
Exit;
|
|
end
|
|
else
|
|
begin
|
|
R2 := R1;
|
|
R2.Right := R1.Left;
|
|
R2.Left := R.Left;
|
|
if PtInRect(R2, P) then
|
|
begin
|
|
Result := htLeftSpace;
|
|
Exit;
|
|
end
|
|
else
|
|
begin
|
|
R1.Left := R1.Right;
|
|
R1.Right := R.Right;
|
|
if PtInRect(R1, P) then
|
|
begin
|
|
Result := htRightSpace;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
// work with groupby box
|
|
R1 := Node.GroupByBoxBounds;
|
|
if PtInRect(R1, P) then
|
|
begin
|
|
Result := htGroupByBox;
|
|
if mvsColumnMoving in FState then
|
|
begin
|
|
for J := 0 to Node.Level.GroupColumnCount - 1 do
|
|
begin
|
|
Column := Node.Level.GroupColumns[J];
|
|
with Column.GetGroupByBoxBounds(Node) do
|
|
R1.Right := (Left + Right) div 2;
|
|
if PtInRect(R1, P) then
|
|
begin
|
|
ColIndex := J;
|
|
Exit;
|
|
end;
|
|
R1.Left := R1.Right;
|
|
end;
|
|
ColIndex := Node.Level.GroupColumnCount;
|
|
end
|
|
else
|
|
for J := 0 to Node.Level.GroupColumnCount - 1 do
|
|
begin
|
|
Column := Node.Level.GroupColumns[J];
|
|
R1 := Column.GetGroupByBoxBounds(Node);
|
|
if PtInRect(R1, P) then
|
|
begin
|
|
Result := htHeader;
|
|
Exit;
|
|
end;
|
|
end;
|
|
Column := nil;
|
|
Exit;
|
|
end;
|
|
// work with left space
|
|
R1 := Node.LeftSpaceBounds;
|
|
if PtInRect(R1, P) then
|
|
begin
|
|
if UseIndent and not PtInRect(Node.FullHeaderBounds, P) then
|
|
Result := htIndent
|
|
else
|
|
Result := htLeftSpace;
|
|
Exit;
|
|
end;
|
|
// work with right space
|
|
R1 := Node.RightSpaceBounds;
|
|
if PtInRect(R1, P) then
|
|
begin
|
|
RowIndex := Node.HeaderRowIndexFromY(P.Y);
|
|
if Node.Level.Horizontal then
|
|
if RowIndex <> -1 then
|
|
if Node.Level.RowCount = 0 then
|
|
ColIndex := 0
|
|
else
|
|
ColIndex := Node.Level.Layout[RowIndex].Count
|
|
else
|
|
else
|
|
ColIndex := Node.Level.Layout.Count;
|
|
Result := htRightSpace;
|
|
Exit;
|
|
end;
|
|
// work with header
|
|
if Node.Level.Horizontal then
|
|
if ProcessHeader(Node.HeaderBounds, Result) then Exit
|
|
else
|
|
else
|
|
for J := 0 to Node.Level.Layout.Count - 1 do
|
|
if ProcessHeader(Node.HeaderColBounds[J], Result) then Exit;
|
|
// work with content
|
|
R1 := Node.ContentBounds;
|
|
R2 := R1;
|
|
if UseIndent then
|
|
begin
|
|
R2.Right := R2.Left + ExpandButtonIndent;
|
|
if PtInRect(R2, P) then
|
|
begin
|
|
Result := htIndent;
|
|
Exit;
|
|
end;
|
|
end;
|
|
if Node.HasExpandButton and Node.ShowExpandButton then
|
|
begin
|
|
R2.Right := R2.Left + LevelIndent;
|
|
if PtInRect(R2, P) then
|
|
begin
|
|
RowIndex := Node.ContentRowIndexFromY(P.Y);
|
|
Result := htExpandButton;
|
|
Exit;
|
|
end;
|
|
R1.Left := R2.Right;
|
|
end;
|
|
// R2 := R1;
|
|
if Node.ViewInfo.PreviewSize <> 0 then
|
|
begin
|
|
R2 := Node.PreviewBounds;
|
|
if PtInRect(R2, P) then
|
|
begin
|
|
Result := htPreview;
|
|
Exit;
|
|
end;
|
|
end;
|
|
RowIndex := Node.ContentRowIndexFromY(P.Y);
|
|
ColIndex := Node.ContentColIndexFromX(P.X);
|
|
if PtInRect(R1, P) and (RowIndex <> -1) then
|
|
Result := htContent
|
|
else
|
|
Result := htOther;
|
|
if RowIndex <> -1 then
|
|
with Node.Level do
|
|
for J := 0 to VisibleColumnCount - 1 do
|
|
begin
|
|
Column := VisibleColumns[J];
|
|
R1 := Column.GetContentBounds(Node);
|
|
if PtInRect(R1, P) then
|
|
begin
|
|
if not Horizontal then
|
|
if P.X < R1.Left + ColumnSizingZoneWidth then
|
|
if ShowHeader then
|
|
if Column.Level.CanHorSizing then
|
|
Result := htHeaderRightEdge
|
|
else
|
|
else
|
|
Result := htContentLeftEdge
|
|
else
|
|
if (P.X >= R1.Right - ColumnSizingZoneWidth) and
|
|
Column.CanHorSizing and Column.IsWidthLinked and
|
|
(not AutoColumnWidth or (Column.Level.Layout.Count <> 1)) then
|
|
Result := htContentRightEdge;
|
|
Exit;
|
|
end;
|
|
end;
|
|
Column := nil;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Node := nil;
|
|
Result := htNone;
|
|
end;
|
|
|
|
procedure TdxMasterView.LoadFromRegIniFile(const AFileName: string;
|
|
AMode: TdxMasterViewRegIniFileMode);
|
|
var
|
|
ARegIniFile: TdxMVRegIniFile;
|
|
Section: string;
|
|
I: Integer;
|
|
|
|
procedure LoadLevel(ALevel: TdxMasterViewLevel);
|
|
var
|
|
LevelSection, ColumnSection: string;
|
|
I, W: Integer;
|
|
|
|
procedure ReadOptionView(const AName: string; AValue: TdxMasterViewLevelOptionView);
|
|
begin
|
|
with ALevel do
|
|
if ARegIniFile.ReadBool(LevelSection, AName, AValue in OptionsView) then
|
|
OptionsView := OptionsView + [AValue]
|
|
else
|
|
OptionsView := OptionsView - [AValue];
|
|
end;
|
|
|
|
procedure ReadHeaderOption(const AName: string; AValue: TdxMasterViewLevelOptionHeader);
|
|
begin
|
|
with ALevel do
|
|
if ARegIniFile.ReadBool(LevelSection, AName, AValue in OptionsHeader) then
|
|
OptionsHeader := OptionsHeader + [AValue]
|
|
else
|
|
OptionsHeader := OptionsHeader - [AValue];
|
|
end;
|
|
|
|
procedure LoadColumn(AColumn: TdxMasterViewColumn);
|
|
begin
|
|
ColumnSection := LevelSection + '\' + AColumn.Name;
|
|
with ARegIniFile, AColumn do
|
|
if SectionExists(ColumnSection) then
|
|
begin
|
|
GroupIndex := ReadInteger(ColumnSection, 'GroupIndex', GroupIndex);
|
|
RowIndex := ReadInteger(ColumnSection, 'RowIndex', RowIndex);
|
|
ColIndex := ReadInteger(ColumnSection, 'ColIndex', ColIndex);
|
|
RowCount := ReadInteger(ColumnSection, 'RowCount', RowCount);
|
|
SortIndex := ReadInteger(ColumnSection, 'SortIndex', SortIndex);
|
|
SortOrder := TdxMasterViewSortOrder(
|
|
ReadInteger(ColumnSection, 'SortOrder', Integer(SortOrder)));
|
|
FLeaveSortOrder := ReadBool(ColumnSection, 'LeaveSortOrder', FLeaveSortOrder);
|
|
Visible := ReadBool(ColumnSection, 'Visible', Visible);
|
|
if ValueExists(ColumnSection, 'Width') then
|
|
Width := ReadInteger(ColumnSection, 'Width', Width);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if Section = '' then
|
|
LevelSection := ALevel.Name
|
|
else
|
|
LevelSection := Section + '\' + ALevel.Name;
|
|
with ARegIniFile, ALevel do
|
|
if SectionExists(LevelSection) then
|
|
begin
|
|
ReadOptionView('ShowCaption', lovCaption);
|
|
ReadOptionView('ShowFooter', lovFooter);
|
|
ReadOptionView('ShowGrid', lovGrid);
|
|
ReadOptionView('ShowGridWithPreview', lovGridWithPreview);
|
|
ReadOptionView('ShowGroupByBox', lovGroupByBox);
|
|
ReadOptionView('ShowHeader', lovHeader);
|
|
ReadOptionView('ShowPreview', lovPreview);
|
|
ReadOptionView('OccupyRestSpace', lovOccupyRestSpace);
|
|
|
|
ReadHeaderOption('shForFirstNode', lohForFirstNode);
|
|
ReadHeaderOption('shForFirstVisibleNode', lohForFirstVisibleNode);
|
|
ReadHeaderOption('shAfterExpandedNode', lohAfterExpandedNode);
|
|
|
|
ViewMode := TdxMasterViewViewMode(
|
|
ReadInteger(LevelSection, 'ViewMode', Integer(ViewMode)));
|
|
if not FHorizontal then
|
|
begin
|
|
I := 0;
|
|
repeat
|
|
W := ReadInteger(LevelSection, 'HeaderWidth' + IntToStr(I), -2);
|
|
if W = -2 then Break;
|
|
FLayout.Count := I + 1;
|
|
if W <> -1 then
|
|
FLayout.HeaderWidths[I] := W;
|
|
Inc(I);
|
|
until False;
|
|
end;
|
|
|
|
for I := 0 to ColumnCount - 1 do
|
|
LoadColumn(Columns[I]);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if AFileName = '' then Exit;
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
AbsoluteLevels[I].BeginLoading;
|
|
try
|
|
ARegIniFile := TdxMVRegIniFile.Create(AFileName, AMode);
|
|
with ARegIniFile do
|
|
try
|
|
case AMode of
|
|
riIniFile:
|
|
Section := Name;
|
|
riRegistry:
|
|
Section := '';
|
|
end;
|
|
if not SectionExists(Section) then Exit;
|
|
|
|
if ReadBool(Section, 'Animation', movAnimation in OptionsView) then
|
|
OptionsView := OptionsView + [movAnimation]
|
|
else
|
|
OptionsView := OptionsView - [movAnimation];
|
|
if ReadBool(Section, 'AutoColumnWidth', movAutoColumnWidth in OptionsView) then
|
|
OptionsView := OptionsView + [movAutoColumnWidth]
|
|
else
|
|
OptionsView := OptionsView - [movAutoColumnWidth];
|
|
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
LoadLevel(AbsoluteLevels[I]);
|
|
finally
|
|
Free;
|
|
end;
|
|
finally
|
|
for I := AbsoluteLevelCount - 1 downto 0 do
|
|
AbsoluteLevels[I].EndLoading;
|
|
ShowFocusedNode;
|
|
end;
|
|
end;
|
|
|
|
function TdxMasterView.NodeFromID(ALevel: TdxMasterViewLevel;
|
|
const AID: Variant): TdxMasterViewNode;
|
|
|
|
procedure FindNode(Root: TdxMasterViewNode);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
with Root do
|
|
if (NodeType = ntData) and (Level = ALevel.Parent) {or
|
|
(NodeType = ntCaption) and (Level = ALevel)} then
|
|
Result := NodeFromID(ALevel, AID)
|
|
else
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
FindNode(Items[I]);
|
|
if Result <> nil then Break;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Result := nil;
|
|
if VarIsEmpty(AID) then Exit;
|
|
FindNode(FItems);
|
|
end;
|
|
|
|
function TdxMasterView.NodeFromKeyValue(ALevel: TdxMasterViewLevel;
|
|
AChildIndex: Integer; const AKeyValue: Variant): TdxMasterViewNode;
|
|
|
|
procedure FindNode(Root: TdxMasterViewNode);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
with Root do
|
|
if (NodeType = ntData) and (Level = ALevel.Parent) {or
|
|
(NodeType = ntCaption) and (Level = ALevel)} then
|
|
Result := NodeFromKeyValue(ALevel, AChildIndex, AKeyValue)
|
|
else
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
FindNode(Items[I]);
|
|
if Result <> nil then Break;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Result := nil;
|
|
if VarIsEmpty(AKeyValue) or (ALevel[AChildIndex].MasterKeyFieldCount = 0) then Exit;
|
|
FindNode(FItems);
|
|
end;
|
|
|
|
procedure TdxMasterView.SaveToRegIniFile(const AFileName: string;
|
|
AMode: TdxMasterViewRegIniFileMode);
|
|
var
|
|
ARegIniFile: TdxMVRegIniFile;
|
|
Section: string;
|
|
I: Integer;
|
|
|
|
procedure SaveLevel(ALevel: TdxMasterViewLevel);
|
|
var
|
|
I, W: Integer;
|
|
LevelSection, ColumnSection: string;
|
|
|
|
procedure SaveColumn(AColumn: TdxMasterViewColumn);
|
|
begin
|
|
ColumnSection := LevelSection + '\' + AColumn.Name;
|
|
with ARegIniFile, AColumn do
|
|
begin
|
|
WriteInteger(ColumnSection, 'GroupIndex', GroupIndex);
|
|
WriteInteger(ColumnSection, 'RowIndex', RowIndex);
|
|
WriteInteger(ColumnSection, 'ColIndex', ColIndex);
|
|
WriteInteger(ColumnSection, 'RowCount', RowCount);
|
|
WriteInteger(ColumnSection, 'SortIndex', SortIndex);
|
|
WriteInteger(ColumnSection, 'SortOrder', Integer(SortOrder));
|
|
WriteBool(ColumnSection, 'LeaveSortOrder', FLeaveSortOrder);
|
|
WriteBool(ColumnSection, 'Visible', Visible);
|
|
if cvWidth in AssignedValues then
|
|
WriteInteger(ColumnSection, 'Width', Width);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if Section = '' then
|
|
LevelSection := ALevel.Name
|
|
else
|
|
LevelSection := Section + '\' + ALevel.Name;
|
|
with ARegIniFile, ALevel do
|
|
begin
|
|
WriteBool(LevelSection, 'ShowCaption', ShowCaption);
|
|
WriteBool(LevelSection, 'ShowFooter', ShowFooter);
|
|
WriteBool(LevelSection, 'ShowGrid', ShowGrid);
|
|
WriteBool(LevelSection, 'ShowGridWithPreview', ShowGridWithPreview);
|
|
WriteBool(LevelSection, 'ShowGroupByBox', ShowGroupByBox);
|
|
WriteBool(LevelSection, 'ShowHeader', ShowHeader);
|
|
WriteBool(LevelSection, 'ShowPreview', ShowPreview);
|
|
WriteBool(LevelSection, 'OccupyRestSpace', OccupyRestSpace);
|
|
|
|
WriteBool(LevelSection, 'shForFirstNode', lohForFirstNode in OptionsHeader);
|
|
WriteBool(LevelSection, 'shForFirstVisibleNode', lohForFirstVisibleNode in OptionsHeader);
|
|
WriteBool(LevelSection, 'shAfterExpandedNode', lohAfterExpandedNode in OptionsHeader);
|
|
|
|
WriteInteger(LevelSection, 'ViewMode', Ord(ViewMode));
|
|
if not FHorizontal then
|
|
for I := 0 to FLayout.Count - 1 do
|
|
begin
|
|
if FLayout.HeaderWidthAssigned[I] then
|
|
W := FLayout.HeaderWidths[I]
|
|
else
|
|
W := -1;
|
|
WriteInteger(LevelSection, 'HeaderWidth' + IntToStr(I), W);
|
|
end;
|
|
|
|
for I := 0 to ColumnCount - 1 do
|
|
SaveColumn(Columns[I]);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if AFileName = '' then Exit;
|
|
ARegIniFile := TdxMVRegIniFile.Create(AFileName, AMode);
|
|
with ARegIniFile do
|
|
try
|
|
case AMode of
|
|
riIniFile:
|
|
Section := Name;
|
|
riRegistry:
|
|
Section := '';
|
|
end;
|
|
|
|
WriteBool(Section, 'Animation', movAnimation in FOptionsView);
|
|
WriteBool(Section, 'AutoColumnWidth', movAutoColumnWidth in FOptionsView);
|
|
|
|
for I := 0 to AbsoluteLevelCount - 1 do
|
|
SaveLevel(AbsoluteLevels[I]);
|
|
finally
|
|
Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.SelectItems(FromIndex, ToIndex: Integer; Select: Boolean);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if FromIndex < 0 then FromIndex := 0;
|
|
if FromIndex >= AbsoluteItemCount then FromIndex := AbsoluteItemCount - 1;
|
|
if ToIndex < 0 then ToIndex := 0;
|
|
if ToIndex >= AbsoluteItemCount then ToIndex := AbsoluteItemCount - 1;
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
I := FromIndex;
|
|
FromIndex := ToIndex;
|
|
ToIndex := I;
|
|
end;
|
|
BeginSelection;
|
|
try
|
|
for I := FromIndex to ToIndex do
|
|
AbsoluteItems[I].Selected := Select;
|
|
finally
|
|
EndSelection;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.ShowFocusedNode;
|
|
begin
|
|
if (FocusedNode = nil) or (FUpdateLockCount <> 0) then Exit;
|
|
CheckFocusedNode;
|
|
if (FocusedIndex < TopIndex) or (FocusedIndex > TopIndex + VisibleItemCount - 1) then
|
|
begin
|
|
Freeze;
|
|
try
|
|
ChangeFocusedIndex(FocusedIndex);
|
|
finally
|
|
Unfreeze;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMasterView.UpdateData;
|
|
begin
|
|
if FLevels <> nil then FLevels.LevelChanged(True);
|
|
end;
|
|
|
|
initialization
|
|
Screen.Cursors[crdxMasterViewMirror] := LoadCursor(HInstance, 'DXMASTERVIEWMIRRORCURSOR');
|
|
Screen.Cursors[crdxMasterViewFullScroll] := LoadCursor(HInstance, 'DXMASTERVIEWFULLSCROLLCURSOR');
|
|
Screen.Cursors[crdxMasterViewHorScroll] := LoadCursor(HInstance, 'DXMASTERVIEWHORSCROLLCURSOR');
|
|
Screen.Cursors[crdxMasterViewVerScroll] := LoadCursor(HInstance, 'DXMASTERVIEWVERSCROLLCURSOR');
|
|
Screen.Cursors[crdxMasterViewUpScroll] := LoadCursor(HInstance, 'DXMASTERVIEWUPSCROLLCURSOR');
|
|
Screen.Cursors[crdxMasterViewRightScroll] := LoadCursor(HInstance, 'DXMASTERVIEWRIGHTSCROLLCURSOR');
|
|
Screen.Cursors[crdxMasterViewDownScroll] := LoadCursor(HInstance, 'DXMASTERVIEWDOWNSCROLLCURSOR');
|
|
Screen.Cursors[crdxMasterViewLeftScroll] := LoadCursor(HInstance, 'DXMASTERVIEWLEFTSCROLLCURSOR');
|
|
Screen.Cursors[crdxMasterViewHorSize] := LoadCursor(HInstance, 'DXMASTERVIEWHORSIZECURSOR');
|
|
Screen.Cursors[crdxMasterViewVerSize] := LoadCursor(HInstance, 'DXMASTERVIEWVERSIZECURSOR');
|
|
Screen.Cursors[crdxMasterViewRemove] := LoadCursor(HInstance, 'DXMASTERVIEWREMOVECURSOR');
|
|
Screen.Cursors[crdxMasterViewNoDrop] := LoadCursor(HInstance, 'DXMASTERVIEWNODROPCURSOR');
|
|
|
|
RegisterClasses([TdxMasterViewStyle, TdxMasterViewLevel]);
|
|
|
|
RegColumnList := TList.Create;
|
|
|
|
dxMasterViewRegisterColumn(TdxMasterViewColumn);
|
|
|
|
dxMVGroupByBoxText := LoadStr(dxsMVGroupByBoxText);
|
|
|
|
WndProcHandlers := TList.Create;
|
|
|
|
finalization
|
|
WndProcHandlers.Free;
|
|
|
|
dxMasterViewUnregisterColumn(TdxMasterViewColumn);
|
|
|
|
with RegColumnList do
|
|
begin
|
|
while Count > 0 do
|
|
begin
|
|
Dispose(PRegColumnRecord(Last));
|
|
Remove(Last);
|
|
end;
|
|
Free;
|
|
end;
|
|
|
|
end.
|