git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.DevExpressVCL@24 05c56307-c608-d34a-929d-697000501d7a
1454 lines
43 KiB
ObjectPascal
1454 lines
43 KiB
ObjectPascal
|
|
{********************************************************************}
|
|
{ }
|
|
{ Developer Express Visual Component Library }
|
|
{ ExpressQuantumTreeList }
|
|
{ }
|
|
{ Copyright (c) 1998-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 EXPRESSQUANTUMTREELIST 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 cxTLData;
|
|
|
|
{$I cxVer.inc}
|
|
|
|
interface
|
|
uses
|
|
Classes, SysUtils,
|
|
Windows, Messages,
|
|
{$IFDEF DELPHI6} Variants, {$ENDIF} cxVariants, cxControls, cxClasses,
|
|
cxData, cxCustomData, cxInplaceContainer, cxTL, cxTLIntf, cxTLStrs;
|
|
|
|
type
|
|
TcxCustomDataTreeList = class;
|
|
TcxTreeListDataNode = class;
|
|
|
|
{ TcxTreeListCustomDataSource }
|
|
|
|
TcxTreeListCustomDataSource = class(TcxCustomDataSource)
|
|
protected
|
|
procedure DeleteNode(AParentHandle: TcxDataRecordHandle);
|
|
procedure DeleteChildItems(AParentHandle: TcxDataRecordHandle); virtual;
|
|
function GetChildCount(AParentHandle: TcxDataRecordHandle): Integer; virtual;
|
|
function GetChildRecordHandle(AParentHandle: TcxDataRecordHandle;
|
|
AChildIndex: Integer): TcxDataRecordHandle; virtual;
|
|
function GetHandleFromNode(ANode: TcxTreeListDataNode): TcxDataRecordHandle;
|
|
function GetKeyValue(ARecordHandle: TcxDataRecordHandle): Variant; virtual;
|
|
function GetParentKeyValue(ARecordHandle: TcxDataRecordHandle): Variant; virtual;
|
|
function GetRootRecordHandle: TcxDataRecordHandle; virtual;
|
|
procedure NodeMoveTo(ARecordHandle, AttachRecordHandle: TcxDataRecordHandle;
|
|
AttachMode: TcxTreeListNodeAttachMode; IsCopy: Boolean); virtual;
|
|
end;
|
|
|
|
{ TcxVirtualTreeListDataController }
|
|
|
|
TcxVirtualTreeListDataController = class(TcxControlDataController)
|
|
private
|
|
function GetCustomDataSource: TcxTreeListCustomDataSource;
|
|
function GetRecordHandle(var ARecordHandle: TcxDataRecordHandle): Boolean;
|
|
function GetTreeList: TcxCustomDataTreeList;
|
|
procedure SetCustomDataSource(Value: TcxTreeListCustomDataSource);
|
|
protected
|
|
function GetKeyValue(ARecordIndex: Integer): Variant;
|
|
function GetParentKeyValue(ARecordIndex: Integer): Variant;
|
|
function IsSmartLoad: Boolean; override;
|
|
procedure NodesMoveTo(AttachNode: TcxTreeListDataNode;
|
|
AttachMode: TcxTreeListNodeAttachMode; ANodes: TList; IsCopy: Boolean);
|
|
public
|
|
property TreeList: TcxCustomDataTreeList read GetTreeList;
|
|
property CustomDataSource: TcxTreeListCustomDataSource read GetCustomDataSource write SetCustomDataSource;
|
|
end;
|
|
|
|
{ TcxTreeListDataNode }
|
|
|
|
TcxTreeListDataNode = class(TcxTreeListNode)
|
|
private
|
|
FKeyValue: Variant;
|
|
FParentValue: Variant;
|
|
protected
|
|
function AddDataControllerRecord: Integer; override;
|
|
property RecordIndex;
|
|
public
|
|
function AddChild: TcxTreeListNode; override;
|
|
function AddChildFirst: TcxTreeListNode; override;
|
|
function InsertChild(ABeforeNode: TcxTreeListNode): TcxTreeListNode; override;
|
|
property KeyValue: Variant read FKeyValue write FKeyValue;
|
|
property ParentValue: Variant read FParentValue write FParentValue;
|
|
end;
|
|
|
|
{ TcxDataTreeListStructureLoader }
|
|
|
|
TcxDataTreeListStructureLoader = class
|
|
private
|
|
function GetDataController: TcxCustomDataController;
|
|
function GetLoadedNode(Index: Integer): TcxTreeListDataNode;
|
|
function GetRoot: TcxTreeListNode;
|
|
procedure SetLoadedNode(Index: Integer; Value: TcxTreeListDataNode);
|
|
protected
|
|
InSmartLoadMode: Boolean;
|
|
IsLoading: Boolean;
|
|
IsLoadLoadingData: Boolean;
|
|
LoadingNode: TcxTreeListDataNode;
|
|
LoadedList: TList;
|
|
ExpandedKeysList: TList;
|
|
TreeList: TcxCustomDataTreeList;
|
|
IsRefresh: Boolean;
|
|
// nodes handling procedures
|
|
function Add: TcxTreeListDataNode;
|
|
function AddChild(AParent: TcxTreeListNode): TcxTreeListDataNode;
|
|
function AddNodeToList(ANode: TcxTreeListDataNode; ARecordIndex: Integer = -1): TcxTreeListDataNode; virtual;
|
|
procedure AfterSmartLoad; virtual;
|
|
procedure AssignNodeImages(ANode: TcxTreeListDataNode);
|
|
procedure BeforeSmartLoad; virtual;
|
|
function GetKeyValue(ARecordIndex: Integer): Variant; virtual;
|
|
function GetNodeImageIndex(ARecordIndex: Integer): Integer; virtual;
|
|
function GetNodeStateImage(ARecordIndex: Integer): Integer; virtual;
|
|
function GetParentKeyValue(ARecordIndex: Integer): Variant; virtual;
|
|
procedure InternalMove(ANode, ADestNode: TcxTreeListNode; AMode: TcxTreeListNodeAttachMode);
|
|
function IsSmartLoad: Boolean;
|
|
// loading procedures
|
|
procedure CheckHasChildren(ANode: TcxTreeListDataNode); virtual;
|
|
procedure DoneLoading; virtual;
|
|
procedure InitLoading; virtual;
|
|
procedure InitLoadedNode(ANode: TcxTreeListDataNode); virtual;
|
|
function IsKeyExpanded(const AKeyValue: Variant; var ANode: TcxTreeListDataNode): Boolean;
|
|
function IsNodeExpanded(const AKeyValue: Variant): Boolean;
|
|
function FindParentNode(const AParentKeyValue: Variant; var Index: Integer): Boolean;
|
|
procedure LoadChildItems(AParentNode: TcxTreeListDataNode); virtual; abstract;
|
|
procedure LoadTreeList; virtual;
|
|
procedure LoadTreeListInLoadAllRecordsMode; virtual;
|
|
procedure LoadTreeListInSmartLoadMode; virtual; abstract;
|
|
function LoadValues(const AParentValue, AKeyValue: Variant): TcxTreeListDataNode; overload;
|
|
function LoadValues(AParentNode: TcxTreeListDataNode; const AParentValue, AKeyValue: Variant): TcxTreeListDataNode; overload;
|
|
property DataController: TcxCustomDataController read GetDataController;
|
|
property Loaded[Index: Integer]: TcxTreeListDataNode read GetLoadedNode write SetLoadedNode;
|
|
property Root: TcxTreeListNode read GetRoot;
|
|
public
|
|
constructor Create(AOwner: TcxCustomDataTreeList);
|
|
procedure DoLoadTreeList(ALoadingNode: TcxTreeListDataNode);
|
|
end;
|
|
|
|
TcxDataTreeListStructureLoaderClass = class of TcxDataTreeListStructureLoader;
|
|
|
|
{ TcxVirtualTreeListLoader }
|
|
|
|
TcxVirtualTreeListLoader = class(TcxDataTreeListStructureLoader)
|
|
private
|
|
function GetDataController: TcxVirtualTreeListDataController;
|
|
function GetDataSource: TcxTreeListCustomDataSource;
|
|
protected
|
|
procedure CheckHasChildren(ANode: TcxTreeListDataNode); override;
|
|
function GetKeyValue(ARecordIndex: Integer): Variant; override;
|
|
function GetParentKeyValue(ARecordIndex: Integer): Variant; override;
|
|
procedure LoadChildItems(AParentNode: TcxTreeListDataNode); override;
|
|
procedure LoadTreeListInSmartLoadMode; override;
|
|
property DataController: TcxVirtualTreeListDataController read GetDataController;
|
|
property DataSource: TcxTreeListCustomDataSource read GetDataSource;
|
|
end;
|
|
|
|
{ TcxVirtualTreeListOptionsData }
|
|
|
|
TcxVirtualTreeListOptionsData = class(TcxTreeListOptionsData)
|
|
protected
|
|
procedure SetSmartLoad(Index: Integer; Value: Boolean); virtual;
|
|
published
|
|
property SmartLoad: Boolean index 3 read GetState write SetSmartLoad default False;
|
|
end;
|
|
|
|
{ TcxCustomDataTreeList }
|
|
|
|
TcxCustomDataTreeList = class(TcxCustomTreeListControl)
|
|
private
|
|
FIsDataChanging: Boolean;
|
|
function GetOptionsData: TcxVirtualTreeListOptionsData;
|
|
procedure SetOptionsData(Value: TcxVirtualTreeListOptionsData);
|
|
protected
|
|
DragKeyValue: Variant;
|
|
Loader: TcxDataTreeListStructureLoader;
|
|
function CreateNode: TcxTreeListNode; override;
|
|
procedure CreateSubClasses; override;
|
|
procedure DataChanged; override;
|
|
function DoCanNodeExpand(ANode: TcxTreeListNode): Boolean; override;
|
|
procedure DoClear; override;
|
|
procedure DoClearDataSource; virtual;
|
|
procedure DoDataChanged; virtual;
|
|
procedure DestroySubClasses; override;
|
|
procedure DestroyNodes; virtual;
|
|
function GetOptionsDataClass: TcxControlOptionsDataClass; override;
|
|
function GetNodeByRecordIndex(AIndex: Integer): TcxTreeListDataNode;
|
|
function IsDataChangedBusy: Boolean; virtual;
|
|
function IsSmartLoad: Boolean; override;
|
|
procedure RestoreSorting; override;
|
|
function SkipFocusedRecordChanged: Boolean; override;
|
|
function SkipCancelOperation: Boolean; override;
|
|
// IcxTreeListDesignTimeOperations implementation
|
|
function SupportsBandColumnEditor: Boolean; override;
|
|
// nodes handling procedure
|
|
function InsertNode(IsAppend: Boolean): Boolean; override;
|
|
// loading structure procedures
|
|
function GetLoaderClass: TcxDataTreeListStructureLoaderClass; virtual;
|
|
function IsDataSettingsValid: Boolean; virtual; // for DB IsKeyFieldEmpty
|
|
procedure LoadTreeList(ALoadingNode: TcxTreeListDataNode); virtual;
|
|
procedure RecreateLoader;
|
|
function UseRowIndexForNewRecord: Boolean; override;
|
|
// dragdrop
|
|
procedure SaveDragPos; override;
|
|
procedure RestoreDragPos; override;
|
|
|
|
property IsDataChanging: Boolean read FIsDataChanging write FIsDataChanging;
|
|
property OptionsData: TcxVirtualTreeListOptionsData read GetOptionsData write SetOptionsData;
|
|
public
|
|
procedure FullRefresh; override;
|
|
function FindNodeByKeyValue(const AKeyValue: Variant;
|
|
AColumn: TcxTreeListColumn; AStartNode: TcxTreeListNode = nil;
|
|
AExpandedOnly: Boolean = False; AForward: Boolean = True): TcxTreeListNode;
|
|
end;
|
|
|
|
{ TcxCustomVirtualTreeList }
|
|
|
|
TcxCustomVirtualTreeList = class(TcxCustomDataTreeList)
|
|
private
|
|
function GetDataController: TcxVirtualTreeListDataController;
|
|
function GetDataSource: TcxTreeListCustomDataSource;
|
|
procedure SetDataSource(Value: TcxTreeListCustomDataSource);
|
|
protected
|
|
procedure AddToDelitionList(ANode: TcxTreeListNode); override;
|
|
procedure DoDeleteRecords; override;
|
|
procedure DoMoveTo(AttachNode: TcxTreeListNode;
|
|
AttachMode: TcxTreeListNodeAttachMode; ANodes: TList; IsCopy: Boolean); override;
|
|
function GetDataControllerClass: TcxCustomDataControllerClass; override;
|
|
function GetLoaderClass: TcxDataTreeListStructureLoaderClass; override;
|
|
function IsCancelOperation: Boolean; override;
|
|
function IsDataSettingsValid: Boolean; override;
|
|
property DataController: TcxVirtualTreeListDataController read GetDataController;
|
|
public
|
|
function HandleFromNode(ANode: TcxTreeListNode): TcxDataRecordHandle; virtual;
|
|
function NodeFromHandle(ARecordHandle: TcxDataRecordHandle): TcxTreeListNode; virtual;
|
|
property CustomDataSource: TcxTreeListCustomDataSource read GetDataSource write SetDataSource;
|
|
end;
|
|
|
|
{ TcxVirtualTreeList }
|
|
|
|
TcxVirtualTreeList = class(TcxCustomVirtualTreeList)
|
|
public
|
|
property ColumnCount;
|
|
property Columns;
|
|
property Customizing;
|
|
property DataController;
|
|
property FocusedColumn;
|
|
property FocusedNode;
|
|
property HitTest;
|
|
property IsEditing;
|
|
property LevelIndentWidth;
|
|
property Nodes;
|
|
property SelectionCount;
|
|
property Selections;
|
|
property Sorted;
|
|
property SortedColumnCount;
|
|
property SortedColumns;
|
|
property TopVisibleIndex;
|
|
property TopVisibleNode;
|
|
property VisibleBandCount;
|
|
property VisibleBands;
|
|
property VisibleColumnCount;
|
|
property VisibleColumns;
|
|
property VisibleCount;
|
|
published
|
|
property Align;
|
|
property Anchors;
|
|
property Bands;
|
|
property BorderStyle;
|
|
property BufferedPaint;
|
|
property Constraints;
|
|
property Cursor;
|
|
property DefaultLayout;
|
|
property DefaultRowHeight;
|
|
property DragCursor;
|
|
property DragKind;
|
|
property DragMode;
|
|
property Enabled;
|
|
property Font;
|
|
{$IFDEF DELPHI6}
|
|
property HelpContext;
|
|
property HelpKeyword;
|
|
property HelpType;
|
|
{$ENDIF}
|
|
property Hint;
|
|
property Images;
|
|
property LookAndFeel;
|
|
property OptionsBehavior;
|
|
property OptionsCustomizing;
|
|
property OptionsData;
|
|
property OptionsSelection;
|
|
property OptionsView;
|
|
property ParentColor;
|
|
property ParentFont;
|
|
property PopupMenu;
|
|
property Preview;
|
|
property StateImages;
|
|
property Styles;
|
|
property StylesEvents;
|
|
property TabOrder;
|
|
property TabStop;
|
|
property Visible;
|
|
// TreeList events
|
|
property OnAfterSorting;
|
|
property OnAfterSummary;
|
|
property OnBandHeaderClick;
|
|
property OnBandSizeChanged;
|
|
property OnCanResize;
|
|
property OnCanSelectNode;
|
|
property OnChange;
|
|
property OnClick;
|
|
property OnCollapsed;
|
|
property OnCollapsing;
|
|
property OnColumnHeaderClick;
|
|
property OnColumnSizeChanged;
|
|
property OnCompare;
|
|
property OnConstrainedResize;
|
|
property OnSorting;
|
|
{$IFDEF DELPHI5}
|
|
property OnContextPopup;
|
|
{$ENDIF}
|
|
property OnCustomDrawBackground;
|
|
property OnCustomDrawBandHeader;
|
|
property OnCustomDrawCell;
|
|
property OnCustomDrawCellsGroup;
|
|
property OnCustomDrawFooter;
|
|
property OnCustomDrawFooterCell;
|
|
property OnCustomDrawHeader;
|
|
property OnCustomDrawHeaderCell;
|
|
property OnCustomDrawIndentCell;
|
|
property OnCustomDrawIndicatorCell;
|
|
property OnCustomDrawPreview;
|
|
property OnCustomizationFormVisibleChanged;
|
|
property OnDataChanged;
|
|
property OnDblClick;
|
|
property OnDeletion;
|
|
property OnDockDrop;
|
|
property OnDockOver;
|
|
property OnDragDrop;
|
|
property OnDragOver;
|
|
property OnEdited;
|
|
property OnEditing;
|
|
property OnEditValueChanged;
|
|
property OnEndDock;
|
|
property OnEndDrag;
|
|
property OnEnter;
|
|
property OnExit;
|
|
property OnExpanded;
|
|
property OnExpanding;
|
|
property OnFocusedColumnChanged;
|
|
property OnFocusedNodeChanged;
|
|
property OnGetNodeImageIndex;
|
|
property OnGetNodePreviewHeight;
|
|
property OnGetSiteInfo;
|
|
property OnHotTrackNode;
|
|
property OnInitEdit;
|
|
property OnIsGroupNode;
|
|
property OnKeyDown;
|
|
property OnKeyPress;
|
|
property OnKeyUp;
|
|
property OnLayoutChanged;
|
|
property OnMouseDown;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
property OnMouseWheel;
|
|
property OnMouseWheelDown;
|
|
property OnMouseWheelUp;
|
|
property OnMoveTo;
|
|
property OnNodeChanged;
|
|
property OnResize;
|
|
property OnSelectionChanged;
|
|
property OnStartDock;
|
|
property OnStartDrag;
|
|
property OnSummary;
|
|
property OnTopRecordIndexChanged;
|
|
property OnUnDock;
|
|
end;
|
|
|
|
const
|
|
cxNullRecordHandle: TcxDataRecordHandle = TcxDataRecordHandle(-1);
|
|
|
|
implementation
|
|
|
|
type
|
|
TcxEditContainerAccess = class(TcxCustomInplaceEditContainer);
|
|
TcxNodeAccess = class(TcxTreeListNode);
|
|
TcxNodesAccess = class(TcxTreeListNodes);
|
|
TcxDataControllerAccess = class(TcxCustomDataController);
|
|
|
|
function cxCompareDataNodesByKeyValue(Item1, Item2: Pointer): Integer;
|
|
begin
|
|
with TcxTreeListDataNode(Item1) do
|
|
begin
|
|
Result := VarCompare(KeyValue, TcxTreeListDataNode(Item2).KeyValue);
|
|
if Result = 0 then
|
|
Result := VarCompare(ParentValue, TcxTreeListDataNode(Item2).ParentValue);
|
|
end;
|
|
end;
|
|
|
|
function cxKeyValues(Item1, Item2: Pointer): Integer;
|
|
begin
|
|
Result := VarCompare(PVariant(Item1)^, PVariant(Item2)^);
|
|
end;
|
|
|
|
{ TcxTreeListCustomDataSource }
|
|
|
|
procedure TcxTreeListCustomDataSource.DeleteNode(
|
|
AParentHandle: TcxDataRecordHandle);
|
|
begin
|
|
DeleteChildItems(AParentHandle);
|
|
DeleteRecord(AParentHandle);
|
|
end;
|
|
|
|
procedure TcxTreeListCustomDataSource.DeleteChildItems(
|
|
AParentHandle: TcxDataRecordHandle);
|
|
var
|
|
I: Integer;
|
|
AItemHandle: TcxDataRecordHandle;
|
|
begin
|
|
for I := GetChildCount(AParentHandle) - 1 downto 0 do
|
|
begin
|
|
AItemHandle := GetChildRecordHandle(AParentHandle, I);
|
|
try
|
|
DeleteChildItems(AItemHandle);
|
|
finally
|
|
DeleteRecord(AItemHandle);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TcxTreeListCustomDataSource.GetChildCount(
|
|
AParentHandle: TcxDataRecordHandle): Integer;
|
|
begin
|
|
Result := 0;
|
|
end;
|
|
|
|
function TcxTreeListCustomDataSource.GetChildRecordHandle(
|
|
AParentHandle: TcxDataRecordHandle; AChildIndex: Integer): TcxDataRecordHandle;
|
|
begin
|
|
Result := cxNullRecordHandle;
|
|
end;
|
|
|
|
function TcxTreeListCustomDataSource.GetHandleFromNode(
|
|
ANode: TcxTreeListDataNode): TcxDataRecordHandle;
|
|
begin
|
|
if ANode = nil then
|
|
Result := GetRootRecordHandle
|
|
else
|
|
Result := GetRecordHandleByIndex(TcxNodeAccess(ANode).RecordIndex)
|
|
end;
|
|
|
|
function TcxTreeListCustomDataSource.GetKeyValue(ARecordHandle: TcxDataRecordHandle): Variant;
|
|
begin
|
|
Result := Null;
|
|
end;
|
|
|
|
procedure TcxTreeListCustomDataSource.NodeMoveTo(
|
|
ARecordHandle, AttachRecordHandle: TcxDataRecordHandle;
|
|
AttachMode: TcxTreeListNodeAttachMode; IsCopy: Boolean);
|
|
begin
|
|
end;
|
|
|
|
function TcxTreeListCustomDataSource.GetParentKeyValue(
|
|
ARecordHandle: TcxDataRecordHandle): Variant;
|
|
begin
|
|
Result := Null;
|
|
end;
|
|
|
|
function TcxTreeListCustomDataSource.GetRootRecordHandle: TcxDataRecordHandle;
|
|
begin
|
|
Result := cxNullRecordHandle;
|
|
end;
|
|
|
|
{ TcxVirtualTreeListDataController }
|
|
|
|
function TcxVirtualTreeListDataController.GetKeyValue(ARecordIndex: Integer): Variant;
|
|
begin
|
|
if GetRecordHandle(TcxDataRecordHandle(ARecordIndex)) then
|
|
Result := CustomDataSource.GetKeyValue(TcxDataRecordHandle(ARecordIndex))
|
|
else
|
|
Result := Null;
|
|
end;
|
|
|
|
function TcxVirtualTreeListDataController.GetParentKeyValue(ARecordIndex: Integer): Variant;
|
|
begin
|
|
if GetRecordHandle(TcxDataRecordHandle(ARecordIndex)) then
|
|
Result := CustomDataSource.GetParentKeyValue(TcxDataRecordHandle(ARecordIndex))
|
|
else
|
|
Result := Null;
|
|
end;
|
|
|
|
function TcxVirtualTreeListDataController.IsSmartLoad: Boolean;
|
|
begin
|
|
Result := TreeList.OptionsData.SmartLoad and
|
|
(CustomDataSource <> nil) and (CustomDataSource.GetRecordCount = 0);
|
|
end;
|
|
|
|
procedure TcxVirtualTreeListDataController.NodesMoveTo(AttachNode: TcxTreeListDataNode;
|
|
AttachMode: TcxTreeListNodeAttachMode; ANodes: TList; IsCopy: Boolean);
|
|
|
|
function GetRecordIndex(Index: Integer): Integer;
|
|
begin
|
|
Result := TcxTreeListDataNode(ANodes.List^[Index]).RecordIndex;
|
|
end;
|
|
|
|
var
|
|
I: Integer;
|
|
AMovedHandle, AttachHandle: TcxDataRecordHandle;
|
|
begin
|
|
if CustomDataSource <> nil then
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
CustomDataSource.CurrentProvider := Provider;
|
|
AttachHandle := CustomDataSource.GetRecordHandleByIndex(AttachNode.RecordIndex);
|
|
for I := 0 to ANodes.Count - 1 do
|
|
begin
|
|
AMovedHandle := CustomDataSource.GetRecordHandleByIndex(GetRecordIndex(I));
|
|
CustomDataSource.NodeMoveTo(AMovedHandle, AttachHandle, AttachMode, IsCopy);
|
|
end;
|
|
CustomDataSource.DataChanged;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TcxVirtualTreeListDataController.GetCustomDataSource: TcxTreeListCustomDataSource;
|
|
begin
|
|
Result := TcxTreeListCustomDataSource(inherited CustomDataSource);
|
|
end;
|
|
|
|
function TcxVirtualTreeListDataController.GetRecordHandle(
|
|
var ARecordHandle: TcxDataRecordHandle): Boolean;
|
|
begin
|
|
Result := CustomDataSource <> nil;
|
|
if Result then
|
|
begin
|
|
CustomDataSource.CurrentProvider := Provider;
|
|
ARecordHandle := CustomDataSource.GetRecordHandleByIndex(Integer(ARecordHandle));
|
|
end;
|
|
end;
|
|
|
|
function TcxVirtualTreeListDataController.GetTreeList: TcxCustomDataTreeList;
|
|
begin
|
|
Result := TcxCustomDataTreeList(GetOwner);
|
|
end;
|
|
|
|
procedure TcxVirtualTreeListDataController.SetCustomDataSource(Value: TcxTreeListCustomDataSource);
|
|
begin
|
|
inherited CustomDataSource := Value;
|
|
end;
|
|
|
|
{ TcxTreeListDataNode }
|
|
|
|
function TcxTreeListDataNode.AddChild: TcxTreeListNode;
|
|
begin
|
|
raise EcxTreeList.Create(scxOperationNotSupported);
|
|
end;
|
|
|
|
function TcxTreeListDataNode.AddChildFirst: TcxTreeListNode;
|
|
begin
|
|
raise EcxTreeList.Create(scxOperationNotSupported);
|
|
end;
|
|
|
|
function TcxTreeListDataNode.InsertChild(
|
|
ABeforeNode: TcxTreeListNode): TcxTreeListNode;
|
|
begin
|
|
raise EcxTreeList.Create(scxOperationNotSupported);
|
|
end;
|
|
|
|
function TcxTreeListDataNode.AddDataControllerRecord: Integer;
|
|
begin
|
|
Result := inherited AddDataControllerRecord;
|
|
end;
|
|
|
|
{ TcxDataTreeListStructureLoader }
|
|
|
|
constructor TcxDataTreeListStructureLoader.Create(AOwner: TcxCustomDataTreeList);
|
|
begin
|
|
TreeList := AOwner;
|
|
end;
|
|
|
|
procedure TcxDataTreeListStructureLoader.DoLoadTreeList(
|
|
ALoadingNode: TcxTreeListDataNode);
|
|
begin
|
|
if IsLoading or IsRefresh then
|
|
begin
|
|
IsRefresh := False;
|
|
Exit;
|
|
end;
|
|
DataController.BeginUpdate;
|
|
try
|
|
if (ALoadingNode = nil) and IsSmartLoad and InSmartLoadMode then
|
|
begin
|
|
InSmartLoadMode := False;
|
|
Exit;
|
|
end;
|
|
IsLoadLoadingData := not IsRefresh and IsSmartLoad and ((DataController.RecordCount <> 0) and (ALoadingNode = nil));
|
|
IsLoading := True;
|
|
LoadingNode := ALoadingNode;
|
|
InitLoading;
|
|
TcxNodesAccess(TreeList.Nodes).IsInternalCreating := True;
|
|
try
|
|
LoadTreeList;
|
|
finally
|
|
TreeList.SafeDelete := True;
|
|
DoneLoading;
|
|
end;
|
|
finally
|
|
TreeList.SafeDelete := False;
|
|
TcxNodesAccess(TreeList.Nodes).IsInternalCreating := False;
|
|
InSmartLoadMode := IsSmartLoad and not IsLoadLoadingData;
|
|
IsLoadLoadingData := False;
|
|
DataController.EndUpdate;
|
|
InSmartLoadMode := False;
|
|
IsLoading := False;
|
|
end;
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.Add: TcxTreeListDataNode;
|
|
begin
|
|
Result := TcxTreeListDataNode(TreeList.AddNode(nil, nil, nil, tlamAdd));
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.AddChild(
|
|
AParent: TcxTreeListNode): TcxTreeListDataNode;
|
|
begin
|
|
Result := TcxTreeListDataNode(TreeList.AddNode(nil, AParent, nil, tlamAddChild));
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.AddNodeToList(
|
|
ANode: TcxTreeListDataNode; ARecordIndex: Integer = -1): TcxTreeListDataNode;
|
|
begin
|
|
if ARecordIndex >= 0 then
|
|
begin
|
|
ANode.RecordIndex := ARecordIndex;
|
|
AssignNodeImages(ANode);
|
|
end;
|
|
TreeList.NodesList.Add(ANode);
|
|
Result := ANode;
|
|
end;
|
|
|
|
procedure TcxDataTreeListStructureLoader.InternalMove(
|
|
ANode, ADestNode: TcxTreeListNode; AMode: TcxTreeListNodeAttachMode);
|
|
begin
|
|
TreeList.InternalMove(ANode, ADestNode, AMode);
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.IsSmartLoad: Boolean;
|
|
begin
|
|
Result := TcxDataControllerAccess(DataController).IsSmartLoad;
|
|
end;
|
|
|
|
procedure TcxDataTreeListStructureLoader.CheckHasChildren(
|
|
ANode: TcxTreeListDataNode);
|
|
begin
|
|
end;
|
|
|
|
procedure TcxDataTreeListStructureLoader.DoneLoading;
|
|
|
|
procedure DoExpandExpandedNodes;
|
|
var
|
|
PrevCount, I: Integer;
|
|
ANode: TcxTreeListDataNode;
|
|
begin
|
|
repeat
|
|
PrevCount := ExpandedKeysList.Count;
|
|
for I := 0 to ExpandedKeysList.Count - 1 do
|
|
if IsKeyExpanded(PVariant(ExpandedKeysList.List[I])^, ANode) then
|
|
begin
|
|
if (ANode.Count = 0) then LoadChildItems(ANode);
|
|
Dispose(PVariant(ExpandedKeysList.List^[I]));
|
|
ExpandedKeysList.Delete(I);
|
|
ANode.Expanded := True;
|
|
Break;
|
|
end;
|
|
until PrevCount = ExpandedKeysList.Count;
|
|
end;
|
|
|
|
var
|
|
I: Integer;
|
|
begin
|
|
try
|
|
if (ExpandedKeysList <> nil) and (ExpandedKeysList.Count > 0) then
|
|
begin
|
|
LoadedList.Sort(cxCompareDataNodesByKeyValue);
|
|
DoExpandExpandedNodes;
|
|
end;
|
|
finally
|
|
if ExpandedKeysList <> nil then
|
|
begin
|
|
for I := 0 to ExpandedKeysList.Count - 1 do
|
|
Dispose(PVariant(ExpandedKeysList.List^[I]));
|
|
FreeAndNil(ExpandedKeysList);
|
|
end;
|
|
FreeAndNil(LoadedList);
|
|
if IsSmartLoad then AfterSmartLoad;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxDataTreeListStructureLoader.InitLoading;
|
|
var
|
|
I: Integer;
|
|
AKeyPtr: PVariant;
|
|
begin
|
|
if IsSmartLoad then
|
|
BeforeSmartLoad;
|
|
if LoadingNode = nil then
|
|
try
|
|
TreeList.ViewInfo.NodesViewInfo.Clear;
|
|
ExpandedKeysList := TList.Create;
|
|
LoadedList := TList.Create;
|
|
if DataController.RecordCount > 0 then
|
|
LoadedList.Capacity := DataController.RecordCount;
|
|
if TreeList.NodesList.Count > 0 then
|
|
begin
|
|
ExpandedKeysList.Capacity := TreeList.NodesList.Count;
|
|
for I := 0 to TreeList.NodesList.Count - 1 do
|
|
with TcxTreeListDataNode(TreeList.NodesList.List^[I]) do
|
|
begin
|
|
if Expanded then
|
|
begin
|
|
New(AKeyPtr);
|
|
AKeyPtr^ := KeyValue;
|
|
ExpandedKeysList.Add(AKeyPtr);
|
|
end;
|
|
end;
|
|
ExpandedKeysList.Sort(cxKeyValues);
|
|
end;
|
|
finally
|
|
TreeList.DestroyNodes;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxDataTreeListStructureLoader.InitLoadedNode(ANode: TcxTreeListDataNode);
|
|
begin
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.IsKeyExpanded(
|
|
const AKeyValue: Variant; var ANode: TcxTreeListDataNode): Boolean;
|
|
var
|
|
L, H, I, C: Integer;
|
|
begin
|
|
Result := False;
|
|
if (LoadedList = nil) or (LoadedList.Count = 0) then Exit;
|
|
L := 0;
|
|
H := LoadedList.Count - 1;
|
|
while L <= H do
|
|
begin
|
|
I := (L + H) shr 1;
|
|
ANode := TcxTreeListDataNode(LoadedList.List^[I]);
|
|
C := VarCompare(ANode.KeyValue, AKeyValue);
|
|
Result := C = 0;
|
|
if not Result then
|
|
begin
|
|
if C < 0 then
|
|
L := I + 1
|
|
else
|
|
H := I - 1;
|
|
end
|
|
else
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.IsNodeExpanded(
|
|
const AKeyValue: Variant): Boolean;
|
|
var
|
|
L, H, I, C: Integer;
|
|
begin
|
|
Result := False;
|
|
if (ExpandedKeysList = nil) or (ExpandedKeysList.Count = 0) then Exit;
|
|
L := 0;
|
|
H := ExpandedKeysList.Count - 1;
|
|
while (L <= H) and not Result do
|
|
begin
|
|
I := (L + H) shr 1;
|
|
C := VarCompare(PVariant(ExpandedKeysList.List^[I])^, AKeyValue);
|
|
if C = 0 then
|
|
Result := True
|
|
else
|
|
if C < 0 then
|
|
L := I + 1
|
|
else
|
|
H := I - 1;
|
|
end;
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.FindParentNode(
|
|
const AParentKeyValue: Variant; var Index: Integer): Boolean;
|
|
var
|
|
L, H, I, C: Integer;
|
|
begin
|
|
Result := False;
|
|
L := 0;
|
|
H := LoadedList.Count - 1;
|
|
while L <= H do
|
|
begin
|
|
I := (L + H) shr 1;
|
|
C := VarCompare(TcxTreeListDataNode(LoadedList.List^[I]).KeyValue, AParentKeyValue);
|
|
if C < 0 then
|
|
L := I + 1
|
|
else
|
|
begin
|
|
H := I - 1;
|
|
if C = 0 then
|
|
begin
|
|
Result := True;
|
|
L := I;
|
|
end;
|
|
end;
|
|
end;
|
|
Index := L;
|
|
end;
|
|
|
|
procedure TcxDataTreeListStructureLoader.AfterSmartLoad;
|
|
begin
|
|
if not IsLoadLoadingData then
|
|
TcxDataControllerAccess(DataController).EndSmartLoad;
|
|
end;
|
|
|
|
procedure TcxDataTreeListStructureLoader.AssignNodeImages(
|
|
ANode: TcxTreeListDataNode);
|
|
begin
|
|
with ANode do
|
|
begin
|
|
if RecordIndex >= 0 then
|
|
begin
|
|
FImageIndexes[tlitImageIndex] := GetNodeImageIndex(RecordIndex);
|
|
FImageIndexes[tlitStateIndex] := GetNodeStateImage(RecordIndex);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxDataTreeListStructureLoader.BeforeSmartLoad;
|
|
begin
|
|
if not IsLoadLoadingData then
|
|
TcxDataControllerAccess(DataController).BeginSmartLoad;
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.GetKeyValue(
|
|
ARecordIndex: Integer): Variant;
|
|
begin
|
|
Result := Null;
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.GetNodeImageIndex(
|
|
ARecordIndex: Integer): Integer;
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.GetNodeStateImage(
|
|
ARecordIndex: Integer): Integer;
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.GetParentKeyValue(
|
|
ARecordIndex: Integer): Variant;
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
procedure TcxDataTreeListStructureLoader.LoadTreeListInLoadAllRecordsMode;
|
|
var
|
|
I, Index: Integer;
|
|
ANode, APrevNode, ADestNode: TcxTreeListDataNode;
|
|
begin
|
|
with DataController do
|
|
begin
|
|
for I := 0 to RecordCount - 1 do
|
|
begin
|
|
ANode := LoadValues(GetParentKeyValue(I), GetKeyValue(I));
|
|
ANode.RecordIndex := I;
|
|
AssignNodeImages(ANode);
|
|
CheckHasChildren(ANode);
|
|
end;
|
|
ANode := TcxTreeListDataNode(TreeList.Nodes.Root.GetLastChild);
|
|
while ANode <> nil do
|
|
begin
|
|
APrevNode := TcxTreeListDataNode(ANode.GetPrevSibling);
|
|
if FindParentNode(ANode.FParentValue, Index) then
|
|
begin
|
|
ADestNode := Self.Loaded[Index];
|
|
if ANode.CanMove(ADestNode, tlamAddChild) then
|
|
TreeList.InternalMove(ANode, ADestNode, tlamAddChild);
|
|
end;
|
|
ANode := APrevNode;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxDataTreeListStructureLoader.LoadTreeList;
|
|
begin
|
|
if IsSmartLoad and ((LoadingNode <> nil) or not IsLoadLoadingData) then
|
|
LoadTreeListInSmartLoadMode
|
|
else
|
|
LoadTreeListInLoadAllRecordsMode;
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.LoadValues(
|
|
const AParentValue, AKeyValue: Variant): TcxTreeListDataNode;
|
|
|
|
function GetParent: TcxTreeListDataNode;
|
|
var
|
|
AIndex: Integer;
|
|
begin
|
|
Result := nil;
|
|
if FindParentNode(AParentValue, AIndex) then
|
|
Result := TcxTreeListDataNode(LoadedList.List^[AIndex]);
|
|
end;
|
|
|
|
begin
|
|
Result := LoadValues(GetParent, AParentValue, AKeyValue);
|
|
if Result.RecordIndex >= 0 then
|
|
AssignNodeImages(Result);
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.LoadValues(AParentNode: TcxTreeListDataNode;
|
|
const AParentValue, AKeyValue: Variant): TcxTreeListDataNode;
|
|
var
|
|
AIndex: Integer;
|
|
begin
|
|
Result := AddChild(AParentNode);
|
|
AddNodeToList(Result);
|
|
Result.FKeyValue := AKeyValue;
|
|
Result.FParentValue := AParentValue;
|
|
InitLoadedNode(Result);
|
|
if (LoadedList <> nil) and not FindParentNode(AKeyValue, AIndex) then
|
|
LoadedList.Insert(AIndex, Result);
|
|
AssignNodeImages(Result);
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.GetDataController: TcxCustomDataController;
|
|
begin
|
|
Result := TreeList.DataController;
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.GetLoadedNode(
|
|
Index: Integer): TcxTreeListDataNode;
|
|
begin
|
|
Result := TcxTreeListDataNode(LoadedList.List^[Index]);
|
|
end;
|
|
|
|
function TcxDataTreeListStructureLoader.GetRoot: TcxTreeListNode;
|
|
begin
|
|
Result := TreeList.Nodes.Root;
|
|
end;
|
|
|
|
procedure TcxDataTreeListStructureLoader.SetLoadedNode(
|
|
Index: Integer; Value: TcxTreeListDataNode);
|
|
begin
|
|
LoadedList.List^[Index] := Value;
|
|
end;
|
|
|
|
{ TcxVirtualTreeListLoader }
|
|
|
|
procedure TcxVirtualTreeListLoader.CheckHasChildren(ANode: TcxTreeListDataNode);
|
|
begin
|
|
if IsSmartLoad and (ANode.Count = 0) then
|
|
begin
|
|
with DataSource, ANode do
|
|
HasChildren := GetChildCount(GetRecordHandleByIndex(RecordIndex)) <> 0;
|
|
end;
|
|
end;
|
|
|
|
function TcxVirtualTreeListLoader.GetKeyValue(
|
|
ARecordIndex: Integer): Variant;
|
|
begin
|
|
Result := DataController.GetKeyValue(ARecordIndex);
|
|
end;
|
|
|
|
function TcxVirtualTreeListLoader.GetParentKeyValue(
|
|
ARecordIndex: Integer): Variant;
|
|
begin
|
|
Result := DataController.GetParentKeyValue(ARecordIndex);
|
|
end;
|
|
|
|
procedure TcxVirtualTreeListLoader.LoadChildItems(
|
|
AParentNode: TcxTreeListDataNode);
|
|
var
|
|
I: Integer;
|
|
AParentValue: Variant;
|
|
AParentHandle: TcxDataRecordHandle;
|
|
|
|
procedure AddNewNode(AHandle: TcxDataRecordHandle);
|
|
var
|
|
ANode: TcxTreeListDataNode;
|
|
begin
|
|
ANode := AddNodeToList(AddChild(AParentNode), DataController.LoadRecord(AHandle));
|
|
ANode.ParentValue := AParentValue;
|
|
ANode.KeyValue := DataSource.GetKeyValue(AHandle);
|
|
ANode.HasChildren := DataSource.GetChildCount(AHandle) > 0;
|
|
if IsNodeExpanded(ANode.KeyValue) then
|
|
begin
|
|
LoadChildItems(ANode);
|
|
ANode.Expanded := True;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
with DataSource do
|
|
begin
|
|
AParentHandle := GetHandleFromNode(AParentNode);
|
|
AParentValue := GetKeyValue(AParentHandle);
|
|
for I := 0 to GetChildCount(AParentHandle) - 1 do
|
|
AddNewNode(GetChildRecordHandle(AParentHandle, I));
|
|
end;
|
|
end;
|
|
|
|
procedure TcxVirtualTreeListLoader.LoadTreeListInSmartLoadMode;
|
|
begin
|
|
LoadChildItems(LoadingNode);
|
|
end;
|
|
|
|
function TcxVirtualTreeListLoader.GetDataController: TcxVirtualTreeListDataController;
|
|
begin
|
|
Result := TcxVirtualTreeListDataController(inherited DataController);
|
|
end;
|
|
|
|
function TcxVirtualTreeListLoader.GetDataSource: TcxTreeListCustomDataSource;
|
|
begin
|
|
Result := TcxCustomVirtualTreeList(TreeList).CustomDataSource;
|
|
end;
|
|
|
|
{ TcxVirtualTreeListOptionsData }
|
|
|
|
procedure TcxVirtualTreeListOptionsData.SetSmartLoad(
|
|
Index: Integer; Value: Boolean);
|
|
begin
|
|
if SmartLoad <> Value then
|
|
begin
|
|
SetState(Index, Value);
|
|
with TcxCustomDataTreeList(GetOwner) do
|
|
begin
|
|
if DataController <> nil then
|
|
TcxDataControllerAccess(DataController).RestructData;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TcxCustomDataTreeList }
|
|
|
|
function TcxCustomDataTreeList.CreateNode: TcxTreeListNode;
|
|
begin
|
|
Result := TcxTreeListDataNode.Create(Nodes);
|
|
end;
|
|
|
|
procedure TcxCustomDataTreeList.CreateSubClasses;
|
|
begin
|
|
RecreateLoader;
|
|
inherited CreateSubClasses;
|
|
end;
|
|
|
|
procedure TcxCustomDataTreeList.DataChanged;
|
|
|
|
function SkipDataChangedNotification: Boolean;
|
|
begin
|
|
Result := IsLoading or IsDestroying;
|
|
with Loader do
|
|
Result := Result or (IsLoading and InSmartLoadMode)
|
|
end;
|
|
|
|
begin
|
|
FIsDataChanging := True;
|
|
try
|
|
if not SkipDataChangedNotification then
|
|
DoDataChanged
|
|
else
|
|
Loader.InSmartLoadMode := False;
|
|
finally
|
|
FIsDataChanging := False;
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomDataTreeList.DoCanNodeExpand(
|
|
ANode: TcxTreeListNode): Boolean;
|
|
begin
|
|
Result := inherited DoCanNodeExpand(ANode);
|
|
if Result and IsSmartLoad and (ANode.Count = 0) and not Loader.IsLoading then
|
|
begin
|
|
LoadTreeList(TcxTreeListDataNode(ANode));
|
|
ANode.HasChildren := ANode.Count > 0;
|
|
Result := ANode.HasChildren;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomDataTreeList.DoClear;
|
|
begin
|
|
DoClearDataSource;
|
|
inherited DoClear;
|
|
end;
|
|
|
|
procedure TcxCustomDataTreeList.DoClearDataSource;
|
|
begin
|
|
DataController.CustomDataSource := nil;
|
|
end;
|
|
|
|
procedure TcxCustomDataTreeList.DoDataChanged;
|
|
begin
|
|
FIsDataChanging := True;
|
|
try
|
|
if not IsDataSettingsValid then
|
|
DestroyNodes
|
|
else
|
|
begin
|
|
LoadTreeList(nil);
|
|
inherited DataChanged;
|
|
end;
|
|
finally
|
|
LayoutChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomDataTreeList.DestroySubClasses;
|
|
begin
|
|
inherited DestroySubClasses;
|
|
FreeAndNil(Loader);
|
|
end;
|
|
|
|
procedure TcxCustomDataTreeList.DestroyNodes;
|
|
var
|
|
ATopIndex: Integer;
|
|
begin
|
|
SafeDelete := True;
|
|
ATopIndex := TcxNodesAccess(Nodes).TopIndex;
|
|
try
|
|
Nodes.Clear;
|
|
DeletedNodes.Clear;
|
|
finally
|
|
NodesList.Clear;
|
|
TcxNodesAccess(Nodes).TopIndex := ATopIndex;
|
|
SafeDelete := False;
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomDataTreeList.GetOptionsDataClass: TcxControlOptionsDataClass;
|
|
begin
|
|
Result := TcxVirtualTreeListOptionsData;
|
|
end;
|
|
|
|
function TcxCustomDataTreeList.GetNodeByRecordIndex(
|
|
AIndex: Integer): TcxTreeListDataNode;
|
|
begin
|
|
if cxInRange(AIndex, 0, NodesList.Count - 1) then
|
|
Result := TcxTreeListDataNode(NodesList.List[AIndex])
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TcxCustomDataTreeList.SkipFocusedRecordChanged: Boolean;
|
|
begin
|
|
Result := IsDataChangedBusy;
|
|
end;
|
|
|
|
function TcxCustomDataTreeList.SkipCancelOperation: Boolean;
|
|
begin
|
|
Result := IsDataChangedBusy;
|
|
end;
|
|
|
|
function TcxCustomDataTreeList.IsDataChangedBusy: Boolean;
|
|
begin
|
|
Result := Loader.IsLoading or FIsDataChanging;
|
|
end;
|
|
|
|
procedure TcxCustomDataTreeList.RestoreSorting;
|
|
var
|
|
C, I: Integer;
|
|
FIsExpanded: PByteArray;
|
|
ATopIndex: Integer;
|
|
const
|
|
AExpandedState = tlnsCollapsed{ or tlnsHasChildren};
|
|
begin
|
|
C := Nodes.Count;
|
|
GetMem(FIsExpanded, C);
|
|
ATopIndex := TcxNodesAccess(Nodes).TopIndex;
|
|
try
|
|
BeginUpdate;
|
|
try
|
|
for I := 0 to Nodes.Count - 1 do
|
|
FIsExpanded^[I] := Byte(Nodes.Items[I].Expanded);
|
|
DestroyNodes;
|
|
finally
|
|
try
|
|
DataChanged;
|
|
if C > Nodes.Count then
|
|
C := Nodes.Count;
|
|
// restore expanding
|
|
for I := 0 to C - 1 do
|
|
begin
|
|
with TcxNodeAccess(NodesList.List^[I]) do
|
|
begin
|
|
if Boolean(FIsExpanded^[I]) then
|
|
State := State and not AExpandedState
|
|
else
|
|
State := State or AExpandedState
|
|
end;
|
|
end;
|
|
finally
|
|
TcxNodesAccess(Nodes).TopIndex := ATopIndex;
|
|
EndUpdate;
|
|
if FocusedNode <> nil then FocusedNode.MakeVisible;
|
|
end;
|
|
end;
|
|
finally
|
|
FreeMem(FIsExpanded);
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomDataTreeList.SupportsBandColumnEditor: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
function TcxCustomDataTreeList.InsertNode(IsAppend: Boolean): Boolean;
|
|
begin
|
|
if IsAppend then
|
|
DataController.Append
|
|
else
|
|
DataController.Insert;
|
|
Result := True;
|
|
end;
|
|
|
|
function TcxCustomDataTreeList.GetLoaderClass: TcxDataTreeListStructureLoaderClass;
|
|
begin
|
|
Result := TcxDataTreeListStructureLoader;
|
|
end;
|
|
|
|
function TcxCustomDataTreeList.IsDataSettingsValid: Boolean;
|
|
begin
|
|
Result := (DataController.RecordCount > 0) or IsSmartLoad;
|
|
end;
|
|
|
|
function TcxCustomDataTreeList.IsSmartLoad: Boolean;
|
|
begin
|
|
Result := TcxDataControllerAccess(DataController).IsSmartLoad;
|
|
end;
|
|
|
|
procedure TcxCustomDataTreeList.LoadTreeList(ALoadingNode: TcxTreeListDataNode);
|
|
begin
|
|
SetGlassCursor;
|
|
try
|
|
Freeze;
|
|
try
|
|
NodesList.Pack;
|
|
if not IsDataSettingsValid then
|
|
DestroyNodes
|
|
else
|
|
Loader.DoLoadTreeList(ALoadingNode);
|
|
finally
|
|
if ALoadingNode = nil then RestoreCursor;
|
|
UnFreeze;
|
|
if not IsLocked and (FocusedNode <> nil) and (ALoadingNode = nil) then
|
|
FocusedNode.MakeVisible;
|
|
LayoutChanged;
|
|
end;
|
|
except
|
|
RestoreCursor;
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomDataTreeList.FullRefresh;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
DestroyNodes;
|
|
DataController.RecordCount := 0;
|
|
LoadTreeList(nil);
|
|
finally
|
|
Loader.IsRefresh := True;
|
|
EndUpdate;
|
|
Loader.IsRefresh := False;
|
|
DataController.UpdateItems(False);
|
|
end;
|
|
end;
|
|
|
|
function FindKeyFilter(ANode: TcxTreeListDataNode; AKey: PVariant): Boolean;
|
|
begin
|
|
Result := VarCompare(ANode.FKeyValue, AKey^) = 0;
|
|
end;
|
|
|
|
function TcxCustomDataTreeList.FindNodeByKeyValue(const AKeyValue: Variant;
|
|
AColumn: TcxTreeListColumn; AStartNode: TcxTreeListNode = nil;
|
|
AExpandedOnly: Boolean = False; AForward: Boolean = True): TcxTreeListNode;
|
|
begin
|
|
Result := Find(@AKeyValue, AStartNode, AExpandedOnly,
|
|
AForward, TcxTreeListFindFunc(@FindKeyFilter));
|
|
end;
|
|
|
|
procedure TcxCustomDataTreeList.RecreateLoader;
|
|
begin
|
|
try
|
|
FreeAndNil(Loader);
|
|
finally
|
|
Loader := GetLoaderClass.Create(Self);
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomDataTreeList.UseRowIndexForNewRecord: Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TcxCustomDataTreeList.SaveDragPos;
|
|
begin
|
|
if DragNode <> nil then
|
|
DragKeyValue := TcxTreeListDataNode(DragNode).KeyValue
|
|
else
|
|
DragKeyValue := Null;
|
|
end;
|
|
|
|
procedure TcxCustomDataTreeList.RestoreDragPos;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if not VarIsNull(DragKeyValue) then
|
|
begin
|
|
for I := 0 to NodesList.Count - 1 do
|
|
with TcxTreeListDataNode(NodesList.List^[I]) do
|
|
if VarEquals(DragKeyValue, KeyValue) then
|
|
begin
|
|
Focused := True;
|
|
MakeVisible;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomDataTreeList.GetOptionsData: TcxVirtualTreeListOptionsData;
|
|
begin
|
|
Result := TcxVirtualTreeListOptionsData(inherited OptionsData);
|
|
end;
|
|
|
|
procedure TcxCustomDataTreeList.SetOptionsData(
|
|
Value: TcxVirtualTreeListOptionsData);
|
|
begin
|
|
OptionsData.Assign(Value);
|
|
end;
|
|
|
|
{ TcxCustomVirtualTreeList }
|
|
|
|
function TcxCustomVirtualTreeList.HandleFromNode(
|
|
ANode: TcxTreeListNode): TcxDataRecordHandle;
|
|
begin
|
|
Result := CustomDataSource.GetHandleFromNode(TcxTreeListDataNode(ANode));
|
|
end;
|
|
|
|
function TcxCustomVirtualTreeList.NodeFromHandle(
|
|
ARecordHandle: TcxDataRecordHandle): TcxTreeListNode;
|
|
begin
|
|
with CustomDataSource do
|
|
Result := GetNodeByRecordIndex(GetRecordIndexByHandle(ARecordHandle));
|
|
end;
|
|
|
|
procedure TcxCustomVirtualTreeList.AddToDelitionList(ANode: TcxTreeListNode);
|
|
begin
|
|
if not IsSmartLoad or not ANode.Deleting then
|
|
DeletedNodes.Add(Pointer(TcxNodeAccess(ANode).RecordIndex));
|
|
end;
|
|
|
|
procedure TcxCustomVirtualTreeList.DoDeleteRecords;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if IsSmartLoad then
|
|
begin
|
|
DataController.BeginUpdate;
|
|
with DeletedNodes do
|
|
try
|
|
for I := 0 to DeletedNodes.Count - 1 do
|
|
List^[I] := CustomDataSource.GetRecordHandleByIndex(Integer(List^[I]));
|
|
for I := 0 to DeletedNodes.Count - 1 do
|
|
CustomDataSource.DeleteNode(List^[I]);
|
|
finally
|
|
Clear;
|
|
DataController.EndUpdate;
|
|
end;
|
|
end
|
|
else
|
|
inherited DoDeleteRecords;
|
|
end;
|
|
|
|
procedure TcxCustomVirtualTreeList.DoMoveTo(AttachNode: TcxTreeListNode;
|
|
AttachMode: TcxTreeListNodeAttachMode; ANodes: TList; IsCopy: Boolean);
|
|
begin
|
|
if IsSmartLoad and (AttachMode = tlamAddChild) and (AttachNode <> nil) then
|
|
Loader.DoLoadTreeList(TcxTreeListDataNode(AttachNode));
|
|
DataController.NodesMoveTo(
|
|
TcxTreeListDataNode(AttachNode), AttachMode, ANodes, IsCopy);
|
|
end;
|
|
|
|
function TcxCustomVirtualTreeList.GetDataControllerClass: TcxCustomDataControllerClass;
|
|
begin
|
|
Result := TcxVirtualTreeListDataController;
|
|
end;
|
|
|
|
function TcxCustomVirtualTreeList.GetLoaderClass: TcxDataTreeListStructureLoaderClass;
|
|
begin
|
|
Result := TcxVirtualTreeListLoader;
|
|
end;
|
|
|
|
function TcxCustomVirtualTreeList.IsCancelOperation: Boolean;
|
|
begin
|
|
if Loader.IsLoading then
|
|
Result := False
|
|
else
|
|
Result := inherited IsCancelOperation;
|
|
end;
|
|
|
|
function TcxCustomVirtualTreeList.IsDataSettingsValid: Boolean;
|
|
begin
|
|
with DataController do
|
|
Result := (CustomDataSource <> nil) and inherited IsDataSettingsValid;
|
|
end;
|
|
|
|
function TcxCustomVirtualTreeList.GetDataController: TcxVirtualTreeListDataController;
|
|
begin
|
|
Result := TcxVirtualTreeListDataController(inherited DataController);
|
|
end;
|
|
|
|
function TcxCustomVirtualTreeList.GetDataSource: TcxTreeListCustomDataSource;
|
|
begin
|
|
Result := DataController.CustomDataSource;
|
|
if Result <> nil then
|
|
Result.CurrentProvider := DataController.Provider;
|
|
end;
|
|
|
|
procedure TcxCustomVirtualTreeList.SetDataSource(
|
|
Value: TcxTreeListCustomDataSource);
|
|
begin
|
|
DataController.CustomDataSource := Value;
|
|
end;
|
|
|
|
end.
|