git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.DevExpressVCL@25 05c56307-c608-d34a-929d-697000501d7a
2261 lines
64 KiB
ObjectPascal
2261 lines
64 KiB
ObjectPascal
|
|
{*******************************************************************}
|
|
{ }
|
|
{ Developer Express Visual Component Library }
|
|
{ Express data-aware tree view }
|
|
{ }
|
|
{ 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 EXPRESSGRID 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 dxdbtree;
|
|
|
|
interface
|
|
|
|
{$I cxVer.inc}
|
|
|
|
uses
|
|
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
|
|
{$IFDEF DELPHI6}
|
|
Variants,
|
|
{$ENDIF}
|
|
ComCtrls, CommCtrl, DB, dxtree;
|
|
|
|
const
|
|
WM_DX = WM_APP + 100;
|
|
WM_UPDATEIMAGES = WM_DX + 1;
|
|
|
|
type
|
|
EDBTreeViewError = class(Exception);
|
|
|
|
TdxDBTreeView = class;
|
|
|
|
TDataLinkTreeView = class(TDataLink)
|
|
private
|
|
FDBTreeView: TdxDBTreeView;
|
|
Filter: string;
|
|
Filtered: Boolean;
|
|
protected
|
|
procedure ActiveChanged; override;
|
|
procedure DataSetChanged; override;
|
|
procedure DataSetScrolled(Distance: Integer); override;
|
|
procedure RecordChanged(Field: TField); override;
|
|
public
|
|
constructor Create;
|
|
end;
|
|
|
|
TdxDBTreeNodes = class;
|
|
|
|
TdxDBTreeNode = class(TdxTreeNode)
|
|
private
|
|
IsInserting: Boolean;
|
|
Refreshed: Boolean;
|
|
protected
|
|
DBTreeNodes: TdxDBTreeNodes;
|
|
|
|
FKeyFieldValue: Variant;
|
|
FParentFieldValue: Variant;
|
|
FChildLoaded: Boolean;
|
|
|
|
FIndex: Integer;
|
|
FListText: string;
|
|
|
|
FBkColor: TColor;
|
|
FColor: TColor;
|
|
FFontStyle: TFontStyles;
|
|
FFontName: TFontName;
|
|
FIsCustomDraw: Boolean;
|
|
|
|
procedure SetChildLoaded(Value: Boolean);
|
|
procedure SetIsCustomDraw(Value: Boolean);
|
|
protected
|
|
procedure SetKeyFieldValue(Value: Variant);
|
|
procedure SetParentFieldValue(Value: Variant);
|
|
procedure UpdateImages;
|
|
public
|
|
constructor Create(AOwner: TdxDBTreeNodes; Value: Variant);
|
|
destructor Destroy; override;
|
|
procedure LoadChildren(Recurse: Boolean);
|
|
|
|
property BkColor: TColor read FBkColor write FBkColor;
|
|
property Color: TColor read FColor write FColor;
|
|
property FontStyle: TFontStyles read FFontStyle write FFontStyle;
|
|
property FontName: TFontName read FFontName write FFontName;
|
|
property IsCustomDraw: Boolean read FIsCustomDraw write SetIsCustomDraw;
|
|
|
|
property ChildLoaded: Boolean read FChildLoaded write SetChildLoaded;
|
|
property Index: Integer read FIndex;
|
|
property KeyFieldValue: Variant read FKeyFieldValue;
|
|
property ParentFieldValue: Variant read FParentFieldValue;
|
|
end;
|
|
|
|
TdxDBTreeNodes = class
|
|
private
|
|
FDBTreeView: TdxDBTreeView;
|
|
FList: TList;
|
|
FCustomDrawCount: Integer;
|
|
Destroying: Boolean;
|
|
|
|
function GetDBNodeFromIndex(Index: Integer): TdxDBTreeNode;
|
|
function GetMaxKeyFieldValue: Variant;
|
|
protected
|
|
procedure BeginRefreshRecord;
|
|
procedure EndRefreshRecord;
|
|
function FindNearest(Value: Variant; var Index: Integer): Boolean;
|
|
procedure Clear;
|
|
procedure Delete(ADBTreeNode: TdxDBTreeNode);
|
|
procedure NodeChangeParent(TreeNode: TTreeNode; Value: Variant);
|
|
function RefreshRecord: TdxDBTreeNode;
|
|
procedure RefreshParents;
|
|
public
|
|
constructor Create(ADBTreeView: TdxDBTreeView);
|
|
destructor Destroy; override;
|
|
function Count: Integer;
|
|
function GetKeyFieldValue(Value: TTreeNode): Variant;
|
|
function GetParentValue(Value: TTreeNode): Variant;
|
|
function GetDBTreeNode(Value: Variant): TdxDBTreeNode;
|
|
function GetTreeNode(Value: Variant): TTreeNode;
|
|
function IndexOf(Value: TTreeNode): Integer;
|
|
property Items[Index: Integer]: TdxDBTreeNode read GetDBNodeFromIndex; default;
|
|
property MaxKeyFieldValue: Variant read GetMaxKeyFieldValue;
|
|
end;
|
|
|
|
TAddNewDBTreeNodeEvent = procedure(Sender: TObject; var DBTreeNode: TdxDBTreeNode) of Object;
|
|
TDBTreeRefreshNodeEvent = procedure(Sender: TObject; DBTreeNode: TdxDBTreeNode) of Object;
|
|
TCreateNewKeyValue = procedure(Sender: TObject; var NewKeyValue: Variant) of Object;
|
|
TSetDisplayItemText = procedure(Sender: TObject; var DisplayText: string) of Object;
|
|
TdxDBTreeViewOption = (trDBCanDelete, trDBConfirmDelete, trCanDBNavigate,
|
|
trSmartRecordLoad, trSmartRecordCopy, trCheckHasChildren);
|
|
TdxDBTreeViewOptions = set of TdxDBTreeViewOption;
|
|
|
|
TdxDBTreeViewAction = (trDBInsert, trDBDelete, trDBChangeText, trDBChangeParent, trDBMove);
|
|
TdxDBTreeViewActionEvent = procedure(Sender: TObject; DBNode1, DBNode2: TdxDBTreeNode;
|
|
Action: TdxDBTreeViewAction; var Automatic: Boolean) of Object;
|
|
|
|
TdxDBTreeView = class(TCustomdxTreeView)
|
|
private
|
|
DataChangedBusy: Boolean;
|
|
CNNotifyFlag: Boolean;
|
|
|
|
FDataLink: TDataLinkTreeView;
|
|
FDBTreeNodes: TdxDBTreeNodes;
|
|
FAddNewItem: TAddNewDBTreeNodeEvent;
|
|
FCreateNewKeyValue: TCreateNewKeyValue;
|
|
FOnSetDisplayItemText: TSetDisplayItemText;
|
|
FOnInsertNodeError: TNotifyEvent;
|
|
FRaiseOnError: Boolean;
|
|
FOnDBAction: TdxDBTreeViewActionEvent;
|
|
FOnRefreshNode: TDBTreeRefreshNodeEvent;
|
|
|
|
FKeyFieldName: string;
|
|
FListFieldName: string;
|
|
FParentFieldName: string;
|
|
FDisplayFieldName: string;
|
|
FImageIndexFieldName: string;
|
|
FStateIndexFieldName: string;
|
|
FRootValue: Variant;
|
|
FSeparatedSt: string;
|
|
FOptions: TdxDBTreeViewOptions;
|
|
|
|
FImageIndexField: TField;
|
|
FKeyField: TField;
|
|
FListField: TField;
|
|
FDisplayFields: TList;
|
|
FParentField: TField;
|
|
FStateIndexField: TField;
|
|
|
|
FEditInstance: Pointer;
|
|
FDefEditProc: Pointer;
|
|
FEditHandle: HWND;
|
|
|
|
procedure AssignFields;
|
|
procedure DataLinkActiveChanged;
|
|
procedure DataLinkRecordChanged(Field: TField);
|
|
procedure DataChanged;
|
|
procedure RecordEdit(Field: TField);
|
|
procedure RecordInsert(Field: TField);
|
|
|
|
function GetDataSource: TDataSource;
|
|
{$IFNDEF DELPHI6}
|
|
function GetRootValue: string;
|
|
{$ENDIF}
|
|
function GetSeletectedDBTreeNode: TdxDBTreeNode;
|
|
procedure Scroll;
|
|
procedure SetDataSource(Value: TDataSource);
|
|
procedure SetDisplayFieldName(const Value: string);
|
|
procedure SetImageIndexFieldName(const Value: string);
|
|
procedure SetKeyFieldName(const Value: string);
|
|
procedure SetListFieldName(const Value: string);
|
|
procedure SetRootValue(const Value: {$IFNDEF DELPHI6}string{$ELSE}Variant{$ENDIF});
|
|
procedure SetStateIndexFieldName(const Value: string);
|
|
procedure SetOptions(const Value: TdxDBTreeViewOptions);
|
|
procedure SetParentFieldName(const Value: string);
|
|
procedure SetSeparatedSt(const Value: string);
|
|
|
|
function GetDisplayText: string;
|
|
|
|
procedure DoCNNotify(var Message: TWMNotify);
|
|
procedure DoWMPaint(var Message: TMessage);
|
|
procedure DoVMInsertItem(var Message: TMessage);
|
|
procedure DoVMSelectItem(var Message: TMessage);
|
|
procedure DoVMSetItem(var Message: TMessage);
|
|
procedure DoVMExpand(var Message: TMessage);
|
|
procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
|
|
procedure VM_INSERTITEM(var Message: TMessage); message TVM_INSERTITEM;
|
|
procedure VM_SELECTITEM(var Message: TMessage); message TVM_SELECTITEM;
|
|
procedure VM_SETITEM(var Message: TMessage); message TVM_SETITEM;
|
|
procedure VM_EXPAND(var Message: TMessage); message TVM_EXPAND;
|
|
procedure WMPAINT(var Message: TMessage); message WM_PAINT;
|
|
procedure WMUpdateImages(var Message: TMessage); message WM_UPDATEIMAGES;
|
|
procedure EditWndProc(var Message: TMessage);
|
|
procedure FrameSelectedItem;
|
|
procedure DeleteDBNode(AKeyValue: Variant);
|
|
|
|
procedure InsertTreeNode(Node, Parent: TdxDBTreeNode);
|
|
procedure SetNewTreeNodeParent(Node, NewParent: TdxDBTreeNode);
|
|
protected
|
|
function DoDBAction(DBNode1, DBNode2: TdxDBTreeNode; Action: TdxDBTreeViewAction): Boolean; dynamic;
|
|
|
|
procedure CreateWnd; override;
|
|
procedure DestroyWnd; override;
|
|
|
|
procedure CreateHandle; override;
|
|
procedure Change(Node: TTreeNode); override;
|
|
procedure DoCustomDraw(TreeNode: TTreeNode; AFont: TFont;
|
|
var AColor, ABkColor: TColor); override;
|
|
function GetListItemText(TreeNode: TTreeNode): string; override;
|
|
procedure Edit(const Item: TTVItem); override;
|
|
procedure InsertTreeNodeStructure(ListS, ListD: TList; Flag: Boolean); override;
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
function GetNextMaxKeyValue: Variant;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
function CreateNode: TTreeNode; override;
|
|
|
|
procedure GetNodeStructure(TreeNode: TTreeNode; List: TList); override;
|
|
|
|
function GetImageIndexField: TField;
|
|
function GetKeyField: TField;
|
|
function GetListField: TField;
|
|
function GetParentField: TField;
|
|
function GetStateIndexField: TField;
|
|
|
|
procedure GotoKeyFieldValue(Value: Variant);
|
|
function IsCustomDraw: Boolean; override;
|
|
procedure RefreshItems;
|
|
|
|
property DBSelected: TdxDBTreeNode read GetSeletectedDBTreeNode;
|
|
property DBTreeNodes: TdxDBTreeNodes read FDBTreeNodes;
|
|
property Items;
|
|
property Selected;
|
|
published
|
|
property DataSource: TDataSource read GetDataSource write SetDataSource;
|
|
property DisplayField: string read FDisplayFieldName write SetDisplayFieldName;
|
|
property ImageIndexField: string read FImageIndexFieldName write SetImageIndexFieldName;
|
|
property KeyField: string read FKeyFieldName write SetKeyFieldName;
|
|
property ListField: string read FListFieldName write SetListFieldName;
|
|
property ParentField: string read FParentFieldName write SetParentFieldName;
|
|
{$IFNDEF DELPHI6}
|
|
property RootValue: string read GetRootValue write SetRootValue;
|
|
{$ELSE}
|
|
property RootValue: Variant read FRootValue write SetRootValue;
|
|
{$ENDIF}
|
|
property SeparatedSt: string read FSeparatedSt write SetSeparatedSt;
|
|
property StateIndexField: string read FStateIndexFieldName write SetStateIndexFieldName;
|
|
property RaiseOnError: Boolean read FRaiseOnError write FRaiseOnError;
|
|
property ShowButtons;
|
|
property BorderStyle;
|
|
property DragCursor;
|
|
property ShowLines;
|
|
property ShowRoot;
|
|
property ReadOnly;
|
|
property DragMode;
|
|
property HideSelection;
|
|
property Indent;
|
|
property OnEditing;
|
|
property OnEdited;
|
|
property OnExpanding;
|
|
property OnExpanded;
|
|
property OnCollapsing;
|
|
property OnCompare;
|
|
property OnCollapsed;
|
|
property OnChanging;
|
|
property OnChange;
|
|
property OnDeletion;
|
|
property OnGetImageIndex;
|
|
property OnGetSelectedIndex;
|
|
property Align;
|
|
property Enabled;
|
|
property Font;
|
|
property Color;
|
|
property ParentColor;
|
|
property ParentCtl3D;
|
|
property Ctl3D;
|
|
property Options: TdxDBTreeViewOptions read FOptions write SetOptions default [];
|
|
property SortType;
|
|
property SelectedIndex;
|
|
property TabOrder;
|
|
property TabStop default True;
|
|
property Visible;
|
|
property OnAddNewItem: TAddNewDBTreeNodeEvent read FAddNewItem write FAddNewItem;
|
|
property OnCreateNewKeyValue: TCreateNewKeyValue read FCreateNewKeyValue
|
|
write FCreateNewKeyValue;
|
|
property OnSetDisplayItemText: TSetDisplayItemText read FOnSetDisplayItemText
|
|
write FOnSetDisplayItemText;
|
|
property OnInsertNodeError: TNotifyEvent read FOnInsertNodeError write FOnInsertNodeError;
|
|
property OnDBAction: TdxDBTreeViewActionEvent read FOnDBAction write FOnDBAction;
|
|
property OnRefreshNode: TDBTreeRefreshNodeEvent read FOnRefreshNode write FOnRefreshNode;
|
|
property OnClick;
|
|
property OnEnter;
|
|
property OnExit;
|
|
property OnDragDrop;
|
|
property OnDragOver;
|
|
property OnStartDrag;
|
|
property OnEndDrag;
|
|
property OnMouseDown;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
property OnDblClick;
|
|
property OnKeyDown;
|
|
property OnKeyPress;
|
|
property OnKeyUp;
|
|
property PopupMenu;
|
|
property ParentFont;
|
|
property ParentShowHint;
|
|
property ShowHint;
|
|
property Images;
|
|
property StateImages;
|
|
{$IFDEF DELPHI6}
|
|
property OnContextPopup;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
implementation
|
|
uses TypInfo {$IFNDEF DELPHI3}, DBTables {$ENDIF}, dxlocate
|
|
;
|
|
|
|
function VarEquals(const V1, V2: Variant): Boolean;
|
|
begin
|
|
try
|
|
Result := V1 = V2;
|
|
except
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
function VarFirstMore(const V1, V2: Variant): Boolean;
|
|
begin
|
|
try
|
|
Result := V1 >= V2;
|
|
except
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
function VarFirstMoreEx(const V1, V2: Variant): Boolean;
|
|
begin
|
|
try
|
|
Result := V1 > V2;
|
|
except
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
{TDataLinkTreeView}
|
|
constructor TDataLinkTreeView.Create;
|
|
begin
|
|
inherited Create;
|
|
{$IFDEF DELPHI5}
|
|
VisualControl := True;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TDataLinkTreeView.ActiveChanged;
|
|
begin
|
|
if DataSet <> nil then
|
|
begin
|
|
Filter := DataSet.Filter;
|
|
Filtered := DataSet.Filtered;
|
|
end
|
|
else
|
|
begin
|
|
Filter := '';
|
|
Filtered := False;
|
|
end;
|
|
if FDBTreeView <> nil then
|
|
FDBTreeView.DataLinkActiveChanged;
|
|
end;
|
|
|
|
procedure TDataLinkTreeView.DataSetChanged;
|
|
begin
|
|
if (DataSet <> nil) and ((Filter <> DataSet.Filter)
|
|
or (Filtered <> DataSet.Filtered)) then
|
|
begin
|
|
Filter := DataSet.Filter;
|
|
Filtered := DataSet.Filtered;
|
|
FDBTreeView.DataLinkActiveChanged;
|
|
end
|
|
else
|
|
FDBTreeView.DataChanged;
|
|
end;
|
|
|
|
procedure TDataLinkTreeView.DataSetScrolled(Distance: Integer);
|
|
begin
|
|
FDBTreeView.Scroll;
|
|
end;
|
|
|
|
procedure TDataLinkTreeView.RecordChanged(Field: TField);
|
|
begin
|
|
FDBTreeView.DataLinkRecordChanged(Field);
|
|
end;
|
|
|
|
{TdxDBTreeNode}
|
|
constructor TdxDBTreeNode.Create(AOwner: TdxDBTreeNodes; Value: Variant);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
inherited Create(AOwner.FDBTreeView.Items);
|
|
DBTreeNodes := AOwner;
|
|
|
|
FBkColor := clWindow;
|
|
FColor := DBTreeNodes.FDBTreeView.Font.Color;
|
|
FFontStyle := DBTreeNodes.FDBTreeView.Font.Style;
|
|
FFontName := DBTreeNodes.FDBTreeView.Font.Name;
|
|
FIsCustomDraw := False;
|
|
|
|
FKeyFieldValue := Value;
|
|
DBTreeNodes.FindNearest(Value, findex);
|
|
if findex < 0 then
|
|
findex := 0;
|
|
for i := fIndex to DBTreeNodes.FList.Count - 1 do
|
|
Inc(DBTreeNodes[i].findex);
|
|
DBTreeNodes.FList.Insert(findex, Self);
|
|
end;
|
|
|
|
destructor TdxDBTreeNode.Destroy;
|
|
var
|
|
AKeyValue: Variant;
|
|
begin
|
|
if not DBTreeNodes.Destroying and not (csDestroying in DBTreeNodes.FDBTreeView.ComponentState) then
|
|
begin
|
|
AKeyValue := FKeyFieldValue;
|
|
with DBTreeNodes.FDBTreeView do
|
|
if (FKeyField <> nil) and (FParentField <> nil) and not DataChangedBusy
|
|
and not CNNotifyFlag and not CopyTreeNodeStructFlag and HandleAllocated then
|
|
begin
|
|
if not DBTreeNodes.FDBTreeView.DoDBAction(Self, nil, trDBDelete) then
|
|
AKeyValue := Null;
|
|
if (trSmartRecordLoad in Options) then
|
|
Self.LoadChildren(True);
|
|
end;
|
|
DBTreeNodes.FList.Remove(Self);
|
|
end
|
|
else
|
|
AKeyValue := Null;
|
|
inherited Destroy;
|
|
if not VarIsNull(AKeyValue)then
|
|
DBTreeNodes.FDBTreeView.DeleteDBNode(AKeyValue);
|
|
end;
|
|
|
|
procedure TdxDBTreeNode.SetKeyFieldValue(Value: Variant);
|
|
var
|
|
newind, i: Integer;
|
|
begin
|
|
if FKeyFieldValue <> Value then
|
|
begin
|
|
FKeyFieldValue := Value;
|
|
DBTreeNodes.FindNearest(Value, newind);
|
|
if newind <> fIndex then
|
|
begin
|
|
if newind > fIndex then
|
|
for i := fIndex + 1 to newind do
|
|
Inc(DBTreeNodes[i].findex)
|
|
else
|
|
for i := newind to fIndex - 1 do
|
|
Dec(DBTreeNodes[i].findex);
|
|
DBTreeNodes.FList.Delete(findex);
|
|
findex := newind;
|
|
DBTreeNodes.FList.Insert(findex, Self);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeNode.SetParentFieldValue(Value: Variant);
|
|
var
|
|
DBNode: TdxDBTreeNode;
|
|
begin
|
|
if FParentFieldValue <> Value then
|
|
begin
|
|
FParentFieldValue := Value;
|
|
DBNode := DBTreeNodes.GetDBTreeNode(Value);
|
|
Self.MoveTo(DBNode, naAddChild);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeNode.UpdateImages;
|
|
begin
|
|
with DBTreeNodes.FDBTreeView do
|
|
begin
|
|
if FKeyFieldValue <> FKeyField.Value then Exit;
|
|
if FImageIndexField <> nil then
|
|
begin
|
|
ImageIndex := 0;
|
|
if not VarIsNull(FImageIndexField.Value) then
|
|
ImageIndex := FImageIndexField.AsInteger;
|
|
end;
|
|
if FStateIndexField <> nil then
|
|
begin
|
|
StateIndex := -1;
|
|
if not VarIsNull(FStateIndexField.Value) then
|
|
StateIndex := FStateIndexField.AsInteger;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeNode.LoadChildren(Recurse: Boolean);
|
|
var
|
|
DataSet: TDataSet;
|
|
Flag, FlagDis: Boolean;
|
|
bm: TBookMark;
|
|
ASortType: TSortType;
|
|
begin
|
|
Flag := DBTreeNodes.FDBTreeView.DataChangedBusy;
|
|
DBTreeNodes.FDBTreeView.DataChangedBusy := True;
|
|
DataSet := DBTreeNodes.FDBTreeView.FDataLink.DataSet;
|
|
FlagDis := DataSet.ControlsDisabled;
|
|
if not flagDis then
|
|
DataSet.DisableControls;
|
|
bm := DataSet.GetBookmark;
|
|
HasChildren := DBTrDataSetLocate(DataSet, DBTreeNodes.FDBTreeView.FParentFieldName, KeyFieldValue, []);
|
|
if HasChildren then
|
|
while not DataSet.EOF
|
|
and VarEquals(DBTreeNodes.FDBTreeView.FParentField.Value, KeyFieldValue) do
|
|
begin
|
|
if DBTreeNodes.GetDBTreeNode(DBTreeNodes.FDBTreeView.FKeyField.Value) = nil then
|
|
DBTreeNodes.RefreshRecord;
|
|
if Recurse then
|
|
DBTreeNodes.FDBTreeView.DBSelected.LoadChildren(True);
|
|
DataSet.Next;
|
|
end;
|
|
DataSet.GotoBookmark(bm);
|
|
DataSet.FreeBookmark(bm);
|
|
if not flagDis then
|
|
DataSet.EnableControls;
|
|
DBTreeNodes.FDBTreeView.DataChangedBusy := Flag;
|
|
ASortType := DBTreeNodes.FDBTreeView.SortType;
|
|
if ASortType in [stText, stData, stBoth] then
|
|
AlphaSort;
|
|
end;
|
|
|
|
procedure TdxDBTreeNode.SetChildLoaded(Value: Boolean);
|
|
var
|
|
flag: Boolean;
|
|
begin
|
|
if Value <> FChildLoaded then
|
|
begin
|
|
FChildLoaded := Value;
|
|
if Value then
|
|
LoadChildren(False)
|
|
else
|
|
begin
|
|
flag := HasChildren;
|
|
DeleteChildren;
|
|
HasChildren := flag;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeNode.SetIsCustomDraw(Value: Boolean);
|
|
begin
|
|
if FIsCustomDraw <> Value then
|
|
begin
|
|
FIsCustomDraw := Value;
|
|
if Value then
|
|
Inc(DBTreeNodes.FCustomDrawCount)
|
|
else
|
|
Dec(DBTreeNodes.FCustomDrawCount);
|
|
end;
|
|
end;
|
|
|
|
{TdxDBTreeNodes}
|
|
constructor TdxDBTreeNodes.Create(ADBTreeView: TdxDBTreeView);
|
|
begin
|
|
FDBTreeView := ADBTreeView;
|
|
FList := TList.Create;
|
|
FCustomDrawCount := 0;
|
|
end;
|
|
|
|
destructor TdxDBTreeNodes.Destroy;
|
|
begin
|
|
Destroying := True;
|
|
Clear;
|
|
FList.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TdxDBTreeNodes.BeginRefreshRecord;
|
|
Var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to Count - 1 do
|
|
Items[i].Refreshed := False;
|
|
end;
|
|
|
|
procedure TdxDBTreeNodes.EndRefreshRecord;
|
|
Var
|
|
i: Integer;
|
|
begin
|
|
i := 0;
|
|
while i < Count do
|
|
if not Items[i].Refreshed then
|
|
begin
|
|
Delete(Items[i]);
|
|
i := 0;
|
|
end
|
|
else Inc(i);
|
|
end;
|
|
|
|
function TdxDBTreeNodes.FindNearest(Value: Variant; var Index: Integer): Boolean;
|
|
var
|
|
Min, Max: LongInt;
|
|
begin
|
|
Index := -1;
|
|
Result := False;
|
|
if (FList.Count = 0) or VarIsNull(Value)
|
|
or VarFirstMoreEx(TdxDBTreeNode(FList.List[0]).FKeyFieldValue, Value) then
|
|
Exit;
|
|
|
|
if VarFirstMoreEx(Value, MaxKeyFieldValue) then
|
|
begin
|
|
Index := FList.Count;
|
|
Exit;
|
|
end;
|
|
|
|
Min := 0;
|
|
Max := FList.Count - 1;
|
|
|
|
repeat
|
|
if Max - Min = 1 then
|
|
begin
|
|
if Min = Index then Min := Max;
|
|
if Max = Index then Max := Min;
|
|
end;
|
|
Index := Min + ((Max - Min) div 2);
|
|
if VarEquals(Value, TdxDBTreeNode(FList.List[Index]).FKeyFieldValue) then
|
|
Break;
|
|
if VarFirstMore(Value, TdxDBTreeNode(FList.List[Index]).FKeyFieldValue) then
|
|
Min := Index
|
|
else
|
|
Max := Index;
|
|
until Min = Max;
|
|
if VarEquals(Value, TdxDBTreeNode(FList.List[Index]).KeyFieldValue) then
|
|
Result := True
|
|
else
|
|
if (Index < FList.Count - 1) and VarFirstMore(Value, TdxDBTreeNode(FList.List[Index]).FKeyFieldValue) then
|
|
Inc(Index);
|
|
end;
|
|
|
|
function TdxDBTreeNodes.RefreshRecord: TdxDBTreeNode;
|
|
var
|
|
DBParentNode: TdxDBTreeNode;
|
|
AText: string;
|
|
bm: TBookMark;
|
|
FlagDis: Boolean;
|
|
OldBusyFlag: Boolean;
|
|
begin
|
|
Result := nil;
|
|
if varIsNull(FDBTreeView.FKeyField.Value) then
|
|
Exit;
|
|
OldBusyFlag := FDBTreeView.DataChangedBusy;
|
|
FDBTreeView.DataChangedBusy := True;
|
|
|
|
AText := FDBTreeView.GetDisplayText;
|
|
Result := GetDBTreeNode(FDBTreeView.FKeyField.Value);
|
|
DBParentNode := GetDBTreeNode(FDBTreeView.FParentField.Value);
|
|
if Result = nil then
|
|
begin
|
|
if DBParentNode = nil then
|
|
Result := TdxDBTreeNode(FDBTreeView.Items.Add(nil, AText))
|
|
else
|
|
Result := TdxDBTreeNode(FDBTreeView.Items.AddChild(DBParentNode, AText));
|
|
end
|
|
else
|
|
begin
|
|
if (Result.Parent <> DBParentNode) and (Result <> DBParentNode) and
|
|
(Result.Parent <> nil) then
|
|
begin
|
|
if DBParentNode <> nil then
|
|
begin
|
|
Result.MoveTo(DBParentNode, naAddChild);
|
|
DBParentNode.HasChildren := True;
|
|
end
|
|
else
|
|
Result.MoveTo(nil, naAdd);
|
|
end;
|
|
if Result.Text <> AText then
|
|
Result.Text := AText;
|
|
end;
|
|
|
|
Result.FParentFieldValue := FDBTreeView.FParentField.Value;
|
|
|
|
if trSmartRecordLoad in FDBTreeView.Options then
|
|
begin
|
|
if trCheckHasChildren in FDBTreeView.Options then
|
|
begin
|
|
FlagDis := FDBTreeView.FDataLink.DataSet.ControlsDisabled;
|
|
if not FlagDis then
|
|
FDBTreeView.FDataLink.DataSet.DisableControls;
|
|
bm := FDBTreeView.FDataLink.DataSet.GetBookmark;
|
|
Result.HasChildren := DBTrDataSetLocate(FDBTreeView.FDataLink.DataSet,
|
|
FDBTreeView.FParentFieldName, Result.FKeyFieldValue, []);
|
|
FDBTreeView.FDataLink.DataSet.GotoBookmark(bm);
|
|
FDBTreeView.FDataLink.DataSet.FreeBookmark(bm);
|
|
if not flagDis then
|
|
FDBTreeView.FDataLink.DataSet.EnableControls;
|
|
end
|
|
else
|
|
Result.HasChildren := True;
|
|
end;
|
|
|
|
Result.FListText := FDBTreeView.FListField.Text;
|
|
Result.UpdateImages;
|
|
Result.Refreshed := True;
|
|
if Assigned(FDBTreeView.FOnRefreshNode) then
|
|
FDBTreeView.FOnRefreshNode(FDBTreeView, Result);
|
|
|
|
if (Count < 100) and (Count > FDBTreeView.FDataLink.BufferCount) then
|
|
FDBTreeView.FDataLink.BufferCount := Count
|
|
else
|
|
FDBTreeView.FDataLink.BufferCount := 100;
|
|
|
|
FDBTreeView.DataChangedBusy := OldBusyFlag;
|
|
end;
|
|
|
|
procedure TdxDBTreeNodes.RefreshParents;
|
|
var
|
|
i: Integer;
|
|
ParentNode: TTreeNode;
|
|
Node: TTreeNode;
|
|
List: TList;
|
|
begin
|
|
List := TList.Create;
|
|
try
|
|
Node := FDBTreeView.Items.GetFirstNode;
|
|
while Node <> nil do
|
|
begin
|
|
List.Add(Node);
|
|
Node := Node.GetNextSibling;
|
|
end;
|
|
|
|
for i := 0 to List.Count - 1 do
|
|
if TdxDBTreeNode(List[i]).Refreshed then
|
|
begin
|
|
ParentNode := GetTreeNode(TdxDBTreeNode(List[i]).ParentFieldValue);
|
|
if (ParentNode <> nil) and (ParentNode <> TdxDBTreeNode(List[i])) then
|
|
begin
|
|
ParentNode.HasChildren := True;
|
|
TdxDBTreeNode(List[i]).MoveTo(ParentNode, naAddChild);
|
|
end;
|
|
end;
|
|
finally
|
|
List.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeNodes.Clear;
|
|
begin
|
|
with FDBTreeView do
|
|
begin
|
|
if HandleAllocated then
|
|
Items.BeginUpdate;
|
|
try
|
|
Items.Clear;
|
|
finally
|
|
if HandleAllocated then
|
|
Items.EndUpdate;
|
|
end;
|
|
end;
|
|
FList.Clear;
|
|
end;
|
|
|
|
procedure TdxDBTreeNodes.Delete(ADBTreeNode: TdxDBTreeNode);
|
|
begin
|
|
if ADBTreeNode <> nil then
|
|
ADBTreeNode.Free;
|
|
end;
|
|
|
|
function TdxDBTreeNodes.Count: Integer;
|
|
begin
|
|
Result := FList.Count;
|
|
end;
|
|
|
|
function TdxDBTreeNodes.GetDBNodeFromIndex(Index: Integer): TdxDBTreeNode;
|
|
begin
|
|
if (Index > - 1) and (Index < Count) then
|
|
Result := TdxDBTreeNode(FList[Index])
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TdxDBTreeNodes.GetMaxKeyFieldValue: Variant;
|
|
begin
|
|
Result := Null;
|
|
if FList.Count > 0 then
|
|
Result := Items[FList.Count - 1].KeyFieldValue;
|
|
end;
|
|
|
|
function TdxDBTreeNodes.GetKeyFieldValue(Value: TTreeNode): Variant;
|
|
begin
|
|
if Value = nil then
|
|
Result := Null
|
|
else
|
|
Result := TdxDBTreeNode(Value).KeyFieldValue;
|
|
end;
|
|
|
|
function TdxDBTreeNodes.GetParentValue(Value: TTreeNode): Variant;
|
|
begin
|
|
if Value = nil then
|
|
Result := Null
|
|
else
|
|
Result := TdxDBTreeNode(Value).ParentFieldValue;
|
|
end;
|
|
|
|
function TdxDBTreeNodes.GetDBTreeNode(Value: Variant): TdxDBTreeNode;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if FindNearest(Value, i) then
|
|
Result := Items[i]
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TdxDBTreeNodes.GetTreeNode(Value: Variant): TTreeNode;
|
|
begin
|
|
Result := GetDBTreeNode(Value);
|
|
end;
|
|
|
|
function TdxDBTreeNodes.IndexOf(Value: TTreeNode): Integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := -1;
|
|
if Value <> nil then
|
|
for i := 0 to Count - 1 do
|
|
if Items[i] = Value then
|
|
begin
|
|
Result := i;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeNodes.NodeChangeParent(TreeNode: TTreeNode; Value: Variant);
|
|
var
|
|
t: TTreeNode;
|
|
Flag: Boolean;
|
|
dbtr: TdxDBTreeNode;
|
|
St: string;
|
|
begin
|
|
dbtr := TdxDBTreeNode(TreeNode);
|
|
if dbtr = nil then
|
|
Exit;
|
|
if not VarEquals(dbtr.ParentFieldValue, Value) then
|
|
dbtr.FParentFieldValue := Value;
|
|
t := GetTreeNode(Value);
|
|
if t = TreeNode.Parent then
|
|
Exit;
|
|
|
|
Flag := FDBTreeView.DataChangedBusy;
|
|
FDBTreeView.DataChangedBusy := True;
|
|
if (t <> nil) and (dbtr <> t) then
|
|
begin
|
|
TreeNode.Focused := False;
|
|
if trSmartRecordLoad in FDBTreeView.Options then
|
|
TdxDBTreeNode(t).ChildLoaded := True;
|
|
t.HasChildren := True;
|
|
TreeNode.MoveTo(t, naAddChild);
|
|
end
|
|
else
|
|
TreeNode.MoveTo(nil, naAdd);
|
|
St := fDBTreeView.GetDisplayText;
|
|
if TreeNode.Text <> St then
|
|
TreeNode.Text := St;
|
|
FDBTreeView.DataChangedBusy := Flag;
|
|
FDBTreeView.Repaint;
|
|
end;
|
|
|
|
{TdxDBTreeView}
|
|
constructor TdxDBTreeView.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FRootValue := NULL;
|
|
FDataLink := TDataLinkTreeView.Create;
|
|
FDataLink.FDBTreeView := Self;
|
|
FDBTreeNodes := TdxDBTreeNodes.Create(Self);
|
|
{$IFDEF DELPHI6}
|
|
FEditInstance := Classes.MakeObjectInstance(EditWndProc);
|
|
{$ELSE}
|
|
FEditInstance := MakeObjectInstance(EditWndProc);
|
|
{$ENDIF}
|
|
CNNotifyFlag := False;
|
|
|
|
FDisplayFields := TList.Create;
|
|
FSeparatedSt := ' - ';
|
|
Options := [trDBCanDelete, trDBConfirmDelete, trCanDBNavigate,
|
|
trSmartRecordCopy, trCheckHasChildren];
|
|
FRaiseOnError := True;
|
|
end;
|
|
|
|
destructor TdxDBTreeView.Destroy;
|
|
begin
|
|
{$IFDEF DELPHI6}
|
|
Classes.FreeObjectInstance(FEditInstance);
|
|
{$ELSE}
|
|
FreeObjectInstance(FEditInstance);
|
|
{$ENDIF}
|
|
FDisplayFields.Free;
|
|
FDBTreeNodes.Free;
|
|
FDataLink.FDBTreeView := nil;
|
|
FDataLink.Free;
|
|
FDataLink := nil;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TdxDBTreeView.DoDBAction(DBNode1, DBNode2: TdxDBTreeNode; Action: TdxDBTreeViewAction): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnDBAction) then
|
|
FOnDBAction(Self, DBNode1, DBNode2, Action, Result);
|
|
end;
|
|
|
|
function TdxDBTreeView.GetImageIndexField: TField;
|
|
begin
|
|
Result := FImageIndexField;
|
|
end;
|
|
|
|
function TdxDBTreeView.GetKeyField: TField;
|
|
begin
|
|
Result := FKeyField;
|
|
end;
|
|
|
|
function TdxDBTreeView.GetListField: TField;
|
|
begin
|
|
Result := FListField;
|
|
end;
|
|
|
|
function TdxDBTreeView.GetParentField: TField;
|
|
begin
|
|
Result := FParentField;
|
|
end;
|
|
|
|
function TdxDBTreeView.GetStateIndexField: TField;
|
|
begin
|
|
Result := FStateIndexField;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.GotoKeyFieldValue(Value: Variant);
|
|
var
|
|
TreeNode: TTreeNode;
|
|
PValue: PVariant;
|
|
List: TList;
|
|
bm: TBookmark;
|
|
i: Integer;
|
|
FlagDis, FlagValueExist: Boolean;
|
|
begin
|
|
if VarIsNull(Value) then
|
|
Exit;
|
|
|
|
TreeNode := FDBTreeNodes.GetTreeNode(Value);
|
|
if TreeNode <> nil then
|
|
begin
|
|
TreeNode.MakeVisible;
|
|
Selected := TreeNode;
|
|
end
|
|
else
|
|
if (trSmartRecordLoad in Options) and not DataChangedBusy then
|
|
begin
|
|
DataChangedBusy := True;
|
|
|
|
if not (VarEquals(FKeyField.Value, Value)) then
|
|
FlagValueExist := DBTrDataSetLocate(FDataLink.DataSet, FKeyFieldName, Value, [])
|
|
else
|
|
FlagValueExist := True;
|
|
|
|
if FlagValueExist then
|
|
begin
|
|
List := TList.Create;
|
|
bm := FDataLink.DataSet.GetBookmark;
|
|
FlagDis := FDataLink.DataSet.ControlsDisabled;
|
|
|
|
if not flagDis then
|
|
FDataLink.DataSet.DisableControls;
|
|
|
|
while (TreeNode = nil) do
|
|
if DBTrDataSetLocate(FDBTreeNodes.FDBTreeView.FDataLink.DataSet, FKeyFieldName, FParentField.Value, [])
|
|
and not (VarEquals(FKeyField.Value, FParentField.Value)) then
|
|
begin
|
|
New(PValue);
|
|
PValue^ := FKeyField.Value;
|
|
List.Add(PValue);
|
|
TreeNode := FDBTreeNodes.GetTreeNode(PValue^);
|
|
end
|
|
else
|
|
Break;
|
|
if TreeNode = nil then
|
|
begin
|
|
DBTreeNodes.RefreshRecord;
|
|
TreeNode := DBSelected;
|
|
DBSelected.ChildLoaded := True;
|
|
end;
|
|
if TreeNode <> nil then
|
|
for i := List.Count - 1 downto 0 do
|
|
begin
|
|
PValue := List[i];
|
|
DBTrDataSetLocate(FDataLink.DataSet, FKeyFieldName, PValue^, []);
|
|
DBSelected.ChildLoaded := True;
|
|
end;
|
|
GotoKeyFieldValue(Value);
|
|
if not flagDis then
|
|
FDataLink.DataSet.EnableControls;
|
|
FDataLink.DataSet.GotoBookmark(bm);
|
|
FDataLink.DataSet.FreeBookmark(bm);
|
|
for i := 0 to List.Count - 1 do
|
|
Dispose(PVariant(List[i]));
|
|
List.Free;
|
|
end;
|
|
|
|
DataChangedBusy := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.CreateHandle;
|
|
var
|
|
Flag: Boolean;
|
|
begin
|
|
Flag := DataChangedBusy;
|
|
DataChangedBusy := True;
|
|
inherited CreateHandle;
|
|
DataChangedBusy := Flag;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.CreateWnd;
|
|
begin
|
|
inherited CreateWnd;
|
|
RefreshItems;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.DestroyWnd;
|
|
var
|
|
Flag: Boolean;
|
|
begin
|
|
Flag := DataChangedBusy;
|
|
DataChangedBusy := True;
|
|
DBTreeNodes.Clear;
|
|
inherited DestroyWnd;
|
|
DataChangedBusy := Flag;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.InsertTreeNode(Node, Parent: TdxDBTreeNode);
|
|
var
|
|
Flag, FlagDis: Boolean;
|
|
St: string;
|
|
begin
|
|
|
|
PostMessage(Handle, WM_UPDATEIMAGES, Integer(Node), 0);
|
|
|
|
Flag := DataChangedBusy;
|
|
DataChangedBusy := True;
|
|
Node.IsInserting := False;
|
|
if not DoDBAction(Node, Parent, trDBInsert) then
|
|
begin
|
|
DataChangedBusy := flag;
|
|
Exit;
|
|
end;
|
|
|
|
FlagDis := FDataLink.DataSet.ControlsDisabled;
|
|
|
|
if not flagDis then
|
|
FdataLink.DataSet.DisableControls;
|
|
|
|
try
|
|
if Parent <> nil then
|
|
begin
|
|
if trSmartRecordLoad in FOptions then
|
|
Parent.ChildLoaded := True;
|
|
Node.FParentFieldValue := Parent.KeyFieldValue;
|
|
end
|
|
else
|
|
begin
|
|
if not VarIsNull(FRootValue) then
|
|
Node.FParentFieldValue := FRootValue
|
|
else
|
|
Node.FParentFieldValue := Node.FKeyFieldValue;
|
|
end;
|
|
FdataLink.DataSet.Append;
|
|
FParentField.Value := node.FParentFieldValue;
|
|
if (FListField <> FKeyField) and (FListField <> FParentField) then
|
|
FListField.Text := Node.Text;
|
|
if FListField.IsNull then
|
|
FListField.Text := ' ';
|
|
if not (FKeyField is TAutoIncField) then
|
|
begin
|
|
if VarIsNull(FKeyField.Value) then
|
|
FKeyField.Value := Node.FKeyFieldValue
|
|
else
|
|
Node.SetKeyFieldValue(FKeyField.Value);
|
|
end;
|
|
FDataLink.DataSet.Post;
|
|
if FKeyField is TAutoIncField then
|
|
Node.SetKeyFieldValue(FKeyField.Value);
|
|
St := GetDisplayText;
|
|
if Node.Text <> St then
|
|
Node.Text := St;
|
|
|
|
if Assigned(FAddNewItem) then
|
|
FAddNewItem(nil, Node);
|
|
if not flagDis then
|
|
FDataLink.DataSet.EnableControls;
|
|
DataChangedBusy := Flag;
|
|
Selected := Node;
|
|
Node.MakeVisible;
|
|
except
|
|
DataChangedBusy := True;
|
|
{$IFNDEF DELPHI5}
|
|
TreeView_DeleteItem(Handle, Node.ItemId);
|
|
DataChangedBusy := Flag;
|
|
{$ENDIF}
|
|
if not flagDis then
|
|
FDataLink.DataSet.EnableControls;
|
|
{$IFDEF DELPHI5}
|
|
DataChangedBusy := Flag;
|
|
{$ENDIF}
|
|
if Assigned(FOnInsertNodeError) then
|
|
FOnInsertNodeError(Self)
|
|
else
|
|
if FRaiseOnError then
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.SetNewTreeNodeParent(Node, NewParent: TdxDBTreeNode);
|
|
var
|
|
Flag, FlagDis: Boolean;
|
|
KeyValue: Variant;
|
|
St: string;
|
|
begin
|
|
Flag := DataChangedBusy;
|
|
DataChangedBusy := True;
|
|
|
|
if not DoDBAction(Node, NewParent, trDBChangeParent) then
|
|
begin
|
|
DataChangedBusy := flag;
|
|
Exit;
|
|
end;
|
|
|
|
FlagDis := FDataLink.DataSet.ControlsDisabled;
|
|
if not flagDis then
|
|
FdataLink.DataSet.DisableControls;
|
|
if NewParent <> nil then
|
|
node.FParentFieldValue := NewParent.FKeyFieldValue
|
|
else
|
|
begin
|
|
if (trSmartRecordLoad in FOptions) and not VarIsNull(FRootValue) then
|
|
Node.FParentFieldValue := FRootValue
|
|
else
|
|
Node.FParentFieldValue := Node.FKeyFieldValue;
|
|
end;
|
|
if not VarEquals(FKeyField.Value, Node.FKeyFieldValue) then
|
|
begin
|
|
KeyValue := FKeyField.Value;
|
|
DBTrDataSetLocate(FDataLink.DataSet, FKeyFieldName, Node.FKeyFieldValue, []);
|
|
end
|
|
else
|
|
KeyValue := NULL;
|
|
FDataLink.DataSet.Edit;
|
|
FParentField.Value := Node.FParentFieldValue;
|
|
FdataLink.DataSet.Post;
|
|
|
|
St := GetDisplayText;
|
|
if Node.Text <> St then
|
|
Node.Text := St;
|
|
|
|
if not VarIsNULL(KeyValue) then
|
|
DBTrDataSetLocate(FDataLink.DataSet, FKeyFieldName, KeyValue, []);
|
|
if not flagDis then
|
|
FDataLink.DataSet.EnableControls;
|
|
DataChangedBusy := Flag;
|
|
end;
|
|
|
|
function TdxDBTreeView.CreateNode: TTreeNode;
|
|
begin
|
|
if (FKeyField <> nil) and (FParentField <> nil) then
|
|
begin
|
|
if DataChangedBusy then
|
|
Result := TdxDBTreeNode.Create(FDBTreeNodes, FKeyField.Value)
|
|
else
|
|
begin
|
|
Result := TdxDBTreeNode.Create(FDBTreeNodes, GetNextMaxKeyValue);
|
|
TdxDBTreeNode(Result).IsInserting := True;
|
|
end;
|
|
if (Result <> nil) and (SelectedIndex <> -1) then
|
|
Result.SelectedIndex := SelectedIndex;
|
|
end
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.Change(Node: TTreeNode);
|
|
var
|
|
V: Variant;
|
|
tr, tr1: TTreenode;
|
|
Flag: Boolean;
|
|
begin
|
|
if Node = nil then
|
|
Exit;
|
|
if DataChangedBusy then
|
|
begin
|
|
inherited;
|
|
Exit;
|
|
end;
|
|
DataChangedBusy := True;
|
|
if FKeyField <> nil then
|
|
begin
|
|
V := FDBTreeNodes.GetKeyFieldValue(Node);
|
|
if not VarIsNull(V) and (VarType(V) <> varEmpty)
|
|
and not VarEquals(FKeyField.Value, V)
|
|
and (dsInsert <> FKeyField.DataSet.State)
|
|
and not ((FdataLink.DataSet.EOF) and (FdataLink.DataSet.BOF)) then
|
|
begin
|
|
Flag := FDataLink.DataSet.State = dsEdit;
|
|
tr1 := nil;
|
|
if Flag then
|
|
begin
|
|
tr := DBTreeNodes.GetTreeNode(FKeyField.Value);
|
|
if tr <> Selected then
|
|
begin
|
|
SendMessage(Handle, WM_SETREDRAW, Integer(False), 0);
|
|
tr1 := Selected;
|
|
Selected := tr;
|
|
end
|
|
else
|
|
Flag := False;
|
|
end;
|
|
try
|
|
DBTrDataSetLocate(FdataLink.DataSet, FKeyFieldName, V, []);
|
|
except
|
|
end;
|
|
if Flag then
|
|
begin
|
|
Selected := tr1;
|
|
SendMessage(Handle, WM_SETREDRAW, Integer(True), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
DataChangedBusy := False;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.Edit(const Item: TTVItem);
|
|
var
|
|
Flag: Boolean;
|
|
begin
|
|
inherited;
|
|
if (FListField <> nil) and (FDisplayFields.Count > 0) then
|
|
begin
|
|
Flag := DataChangedBusy;
|
|
DataChangedBusy := True;
|
|
if (not ReadOnly) and (FListField.DataSet <> nil) and (Selected <> nil)
|
|
and ((FListField.DataSet.State = dsEdit) or (FListField.DataSet.State = dsInsert)) and
|
|
(FListField.Text <> Selected.Text) then
|
|
FListField.Text := Selected.Text
|
|
else
|
|
if Selected.Text <> FListField.Text then
|
|
Selected.Text := FListField.Text;
|
|
if (Selected <> nil) and (Selected.Text <> GetDisplayText) then
|
|
Selected.Text := GetDisplayText;
|
|
DataChangedBusy := Flag;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.Notification(AComponent: TComponent;
|
|
Operation: TOperation);
|
|
begin
|
|
inherited Notification(AComponent, Operation);
|
|
if (Operation = opRemove) and (FDataLink <> nil) and (AComponent = DataSource) then
|
|
DataSource := nil;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.RefreshItems;
|
|
var
|
|
bm: TBookMark;
|
|
i: Integer;
|
|
FlagDis: Boolean;
|
|
OldSortType: TSortType;
|
|
begin
|
|
DataChangedBusy := True;
|
|
|
|
if (FKeyField <> nil) and (FListField <> nil) and (FParentField <> nil) then
|
|
begin
|
|
Items.BeginUpdate;
|
|
DBTreeNodes.BeginRefreshRecord;
|
|
OldSortType := SortType;
|
|
SortType := stNone;
|
|
FlagDis := FDataLink.DataSet.ControlsDisabled;
|
|
if not flagDis then
|
|
FDataLink.DataSet.DisableControls;
|
|
bm := FDataLink.DataSet.GetBookmark;
|
|
if not (trSmartRecordLoad in Options) then
|
|
begin
|
|
i := mrNo;
|
|
if (csDesigning in ComponentState) and (FDataLink.DataSet.RecordCount > 999) then
|
|
i := MessageDlg(dxDBTreeViewSmartLoadS, mtConfirmation, [mbYes, mbNo], 0);
|
|
if i = mrNo then
|
|
begin
|
|
FDataLink.DataSet.First;
|
|
while not FDataLink.DataSet.EOF do
|
|
begin
|
|
FDBTreeNodes.RefreshRecord;
|
|
FDataLink.DataSet.Next;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if FDBTreeNodes.Count > 0 then
|
|
begin
|
|
for i := 0 to FDBTreeNodes.Count - 1 do
|
|
begin
|
|
FDBTreeNodes[i].FChildLoaded := False;
|
|
if not (VarEquals(FKeyField.Value, FDBTreeNodes[i].FKeyFieldValue)) then
|
|
DBTrDataSetLocate(FDataLink.DataSet, FKeyFieldName, FDBTreeNodes[i].FKeyFieldValue, []);
|
|
FDBTreeNodes.RefreshRecord;
|
|
FDataLink.DataSet.Next;
|
|
end;
|
|
end
|
|
else
|
|
FDataLink.DataSet.First;
|
|
if DBTrDataSetLocate(FDataLink.DataSet, FParentFieldName, FRootValue, []) then
|
|
while (not FDataLink.DataSet.EOF) and VarEquals(FParentField.Value, FRootValue) do begin
|
|
FDBTreeNodes.RefreshRecord;
|
|
FDataLink.DataSet.Next;
|
|
end;
|
|
end;
|
|
FDataLink.DataSet.GotoBookmark(bm);
|
|
FDataLink.DataSet.FreeBookmark(bm);
|
|
if not flagDis then
|
|
FDataLink.DataSet.EnableControls;
|
|
FDBTreeNodes.RefreshParents;
|
|
DBTreeNodes.EndRefreshRecord;
|
|
Items.EndUpdate;
|
|
SortType := OldSortType;
|
|
end
|
|
else
|
|
DBTreeNodes.Clear;
|
|
|
|
Scroll;
|
|
DataChangedBusy := False;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.AssignFields;
|
|
|
|
function IsIntegerField(AField: TField): Boolean;
|
|
begin
|
|
Result := AField.DataType in [ftSmallint, ftInteger, ftWord, ftFloat, ftCurrency, ftAutoInc];
|
|
end;
|
|
|
|
begin
|
|
FDisplayFields.Clear;
|
|
if FDataLink.Active then
|
|
begin
|
|
if FKeyFieldName <> '' then
|
|
FKeyField := FDataLink.DataSet.FieldByName(FKeyFieldName);
|
|
if FListFieldName <> '' then
|
|
FListField := FDataLink.DataSet.FieldByName(FListFieldName);
|
|
if FParentFieldName <> '' then
|
|
FParentField := FDataLink.DataSet.FieldByName(FParentFieldName);
|
|
if FImageIndexFieldName <> '' then
|
|
begin
|
|
FImageIndexField := FDataLink.DataSet.FieldByName(FImageIndexFieldName);
|
|
if (FImageIndexField <> nil) and not IsIntegerField(FImageIndexField) then
|
|
FImageIndexField := nil;
|
|
end;
|
|
if FStateIndexFieldName <> '' then
|
|
begin
|
|
FStateIndexField := FDataLink.DataSet.FieldByName(FStateIndexFieldName);
|
|
if (FStateIndexField <> nil) and not IsIntegerField(FStateIndexField) then
|
|
FStateIndexField := nil;
|
|
end;
|
|
|
|
FDataLink.DataSet.GetFieldList(FDisplayFields, FDisplayFieldName);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.DataLinkActiveChanged;
|
|
begin
|
|
FKeyField := nil;
|
|
FListField := nil;
|
|
FParentField := nil;
|
|
FImageIndexField := nil;
|
|
FStateIndexField := nil;
|
|
|
|
FDisplayFields.Clear;
|
|
AssignFields;
|
|
if (FKeyField <> nil) and not VarIsNull(FRootValue) then
|
|
case FKeyField.DataType of
|
|
ftSmallint: VarCast(FRootValue, FRootValue, varSmallint);
|
|
ftInteger, ftWord, ftAutoInc: VarCast(FRootValue, FRootValue, varInteger);
|
|
ftFloat, ftCurrency: VarCast(FRootValue, FRootValue, varDouble);
|
|
else
|
|
VarCast(FRootValue, FRootValue, varString);
|
|
end;
|
|
|
|
if HandleAllocated then
|
|
RefreshItems;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.DataLinkRecordChanged(Field: TField);
|
|
begin
|
|
if (Field <> nil) and (Field.DataSet <> nil) then
|
|
case Field.DataSet.State of
|
|
dsEdit: RecordEdit(Field);
|
|
dsInsert: RecordInsert(Field);
|
|
end;
|
|
end;
|
|
|
|
function TdxDBTreeView.GetDataSource: TDataSource;
|
|
begin
|
|
Result := FDataLink.DataSource;
|
|
end;
|
|
|
|
{$IFNDEF DELPHI6}
|
|
function TdxDBTreeView.GetRootValue: string;
|
|
begin
|
|
if VarIsNull(FRootValue) then
|
|
Result := ''
|
|
else
|
|
Result := string(FRootValue);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function TdxDBTreeView.GetSeletectedDBTreeNode: TdxDBTreeNode;
|
|
begin
|
|
Result := nil;
|
|
if (FKeyField <> nil) and (FKeyField.Value <> NULL) then
|
|
Result := FDBTreeNodes.GetDBTreeNode(FKeyField.Value);
|
|
end;
|
|
|
|
procedure TdxDBTreeView.Scroll;
|
|
begin
|
|
if not (trCanDBNavigate in Options) then
|
|
Exit;
|
|
if FKeyField <> nil then
|
|
GotoKeyFieldValue(FKeyField.Value);
|
|
end;
|
|
|
|
procedure TdxDBTreeView.SetDataSource(Value: TDataSource);
|
|
begin
|
|
FDataLink.DataSource := Value;
|
|
if Value <> nil then
|
|
Value.FreeNotification(Self);
|
|
end;
|
|
|
|
procedure TdxDBTreeView.SetDisplayFieldName(const Value: string);
|
|
begin
|
|
if FDisplayFieldName <> Value then
|
|
begin
|
|
FDisplayFieldName := Value;
|
|
DataLinkActiveChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.SetImageIndexFieldName(const Value: string);
|
|
begin
|
|
if FImageIndexFieldName <> Value then
|
|
begin
|
|
FImageIndexFieldName := Value;
|
|
DataLinkActiveChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.SetKeyFieldName(const Value: string);
|
|
begin
|
|
if FKeyFieldName <> Value then
|
|
begin
|
|
FKeyFieldName := Value;
|
|
DataLinkActiveChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.SetListFieldName(const Value: string);
|
|
begin
|
|
if FListFieldName <> Value then
|
|
begin
|
|
FListFieldName := Value;
|
|
DataLinkActiveChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.SetStateIndexFieldName(const Value: string);
|
|
begin
|
|
if FStateIndexFieldName <> Value then
|
|
begin
|
|
FStateIndexFieldName := Value;
|
|
DataLinkActiveChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.SetOptions(const Value: TdxDBTreeViewOptions);
|
|
begin
|
|
if Value <> FOptions then
|
|
begin
|
|
FOptions := Value;
|
|
inherited Options := [];
|
|
if trDBCanDelete in FOptions then
|
|
inherited Options := inherited Options + [trCanDelete];
|
|
if trDBConfirmDelete in FOptions then
|
|
inherited Options := inherited Options + [trConfirmDelete];
|
|
RefreshItems;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.SetParentFieldName(const Value: string);
|
|
begin
|
|
if FParentFieldName <> Value then
|
|
begin
|
|
FParentFieldName := Value;
|
|
DataLinkActiveChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.SetRootValue(const Value: {$IFNDEF DELPHI6}string{$ELSE}Variant{$ENDIF});
|
|
var
|
|
{$IFNDEF DELPHI6}
|
|
V: Variant;
|
|
{$ENDIF}
|
|
OldFlag: Boolean;
|
|
begin
|
|
{$IFNDEF DELPHI6}
|
|
V := Value;
|
|
if not VarIsNull(FRootValue) then
|
|
try
|
|
FRootValue := VarAsType(V, VarType(FRootValue))
|
|
except
|
|
FRootValue := Null;
|
|
end
|
|
else
|
|
FRootValue := V;
|
|
{$ELSE}
|
|
FRootValue := Value;
|
|
{$ENDIF}
|
|
if trSmartRecordLoad in FOptions then
|
|
begin
|
|
OldFlag := DataChangedBusy;
|
|
DataChangedBusy := True;
|
|
Items.Clear;
|
|
DataLinkActiveChanged;
|
|
DataChangedBusy := OldFlag;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.SetSeparatedSt(const Value: string);
|
|
begin
|
|
if FSeparatedSt <> Value then
|
|
begin
|
|
FSeparatedSt := Value;
|
|
if FDisplayFields.Count > 0 then
|
|
DataLinkActiveChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.DataChanged;
|
|
begin
|
|
if DataChangedBusy or not HandleAllocated or (FDataLink.DataSet.State = dsInsert)
|
|
or (FDataLink.DataSet.State = dsEdit) then
|
|
Exit;
|
|
if IsEditing and (Selected <> nil) then
|
|
Selected.EndEdit(True);
|
|
AssignFields;
|
|
RefreshItems;
|
|
Scroll;
|
|
end;
|
|
|
|
function TdxDBTreeView.GetDisplayText: string;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := '';
|
|
if FDisplayFields.Count > 0 then
|
|
begin
|
|
for i := 0 to FDisplayFields.Count - 1 do
|
|
begin
|
|
if i > 0 then
|
|
Result := Result + FSeparatedSt;
|
|
Result := Result + TField(FDisplayFields[i]).Text;
|
|
end;
|
|
end
|
|
else
|
|
if FListField <> nil then
|
|
Result := FListField.Text;
|
|
if Assigned(FOnSetDisplayItemText) then
|
|
FOnSetDisplayItemText(Self, Result);
|
|
end;
|
|
|
|
var
|
|
RecordEditFlag: Boolean;
|
|
|
|
procedure TdxDBTreeView.RecordEdit(Field: TField);
|
|
var
|
|
TreeNode: TTreeNode;
|
|
V: Variant;
|
|
flag: Boolean;
|
|
|
|
procedure RepaintNode(ANode: TTreeNode);
|
|
var
|
|
R: TRect;
|
|
begin
|
|
if HandleAllocated and (ANode <> nil) and ANode.IsVisible then
|
|
begin
|
|
R := ANode.DisplayRect(False);
|
|
InvalidateRect(Handle, @R, False);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if RecordEditFlag then Exit;
|
|
if FKeyField <> nil then
|
|
begin
|
|
TreeNode := Selected;
|
|
if TreeNode = nil then
|
|
Exit;
|
|
|
|
if (Field = FListField) and (TreeNode.Text <> Field.Text ) then
|
|
TreeNode.Text := Field.Text;
|
|
|
|
if FImageIndexField = Field then
|
|
begin
|
|
if not VarIsNull(FImageIndexField.Value) then
|
|
TreeNode.ImageIndex := FImageIndexField.AsInteger
|
|
else
|
|
TreeNode.ImageIndex := -1;
|
|
RepaintNode(TreeNode);
|
|
end;
|
|
|
|
if FStateIndexField = Field then
|
|
begin
|
|
if not VarIsNull(FStateIndexField.Value) then
|
|
TreeNode.StateIndex := FStateIndexField.AsInteger
|
|
else
|
|
TreeNode.StateIndex := -1;
|
|
RepaintNode(TreeNode);
|
|
end;
|
|
|
|
if Field = FParentField then
|
|
begin
|
|
V := FDBTreeNodes.GetParentValue(TreeNode);
|
|
if not VarIsNull(Field.Value) and not VarIsNull(V) and
|
|
not VarEquals(Field.Value, V) then
|
|
begin
|
|
try
|
|
if trSmartRecordLoad in FOptions then
|
|
begin
|
|
RecordEditFlag := True;
|
|
flag := DataChangedBusy;
|
|
DataChangedBusy := True;
|
|
FDataLink.DataSet.Post;
|
|
DataChangedBusy := flag;
|
|
end;
|
|
FDBTreeNodes.NodeChangeParent(TreeNode, Field.Value);
|
|
except
|
|
Field.Value := V;
|
|
end;
|
|
RecordEditFlag := False;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.RecordInsert(Field: TField);
|
|
var
|
|
DBTreeNode: TdxDBTreeNode;
|
|
begin
|
|
if (FKeyField <> nil) and (FKeyField.Value <> NULL) then
|
|
begin
|
|
if not DataChangedBusy then
|
|
FDBTreeNodes.RefreshRecord;
|
|
DBTreeNode := DBSelected;
|
|
if DBTreeNode <> nil then
|
|
begin
|
|
Selected := DBTreeNode;
|
|
if Selected <> nil then
|
|
Selected.MakeVisible;
|
|
end;
|
|
if (DBTreeNode <> nil) and (DBTreeNode.ParentFieldValue <> NULL) and
|
|
Assigned(FAddNewItem) then
|
|
FAddNewItem(nil, DBTreeNode);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.FrameSelectedItem;
|
|
var
|
|
Rect: TRect;
|
|
DC: HDC;
|
|
wnd: HWND;
|
|
C1, C2, OldColor: TColor;
|
|
AHandle: HFont;
|
|
ASize: TSize;
|
|
const
|
|
TextOffset = 2;
|
|
begin
|
|
if not Focused and not DataChangedBusy and (Selected <> nil) then
|
|
begin
|
|
if HandleAllocated then
|
|
DoCustomDraw(Selected, Font, C1, C2);
|
|
TreeView_GetItemRect(Selected.Handle, Selected.ItemId, Rect, true);
|
|
Wnd := handle;
|
|
DC := GetDeviceContext(Wnd);
|
|
AHandle := SelectObject(DC, Font.Handle);
|
|
GetTextExtentPoint(DC, PChar(Selected.Text), Length(Selected.Text), ASize);
|
|
SelectObject(DC, AHandle);
|
|
Rect.Right := Rect.Left + ASize.cx + TextOffset * 2;
|
|
OldColor := Brush.Color;
|
|
Brush.Color := Font.Color;
|
|
FrameRect(DC, Rect, Brush.Handle);
|
|
Brush.Color := OldColor;
|
|
ReleaseDC(Wnd, DC);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.DeleteDBNode(AKeyValue: Variant);
|
|
var
|
|
flag, FlagDis: Boolean;
|
|
begin
|
|
if (FKeyField = nil) or (FParentField = nil) or DataChangedBusy or CNNotifyFlag
|
|
or CopyTreeNodeStructFlag or not HandleAllocated then
|
|
Exit;
|
|
|
|
FlagDis := FDataLink.DataSet.ControlsDisabled;
|
|
if not flagDis then
|
|
FDataLink.DataSet.DisableControls;
|
|
if not (FDataLink.DataSet.EOF and FDataLink.DataSet.BOF) then
|
|
begin
|
|
try
|
|
flag := DBTrDataSetLocate(FdataLink.DataSet, FKeyFieldName, AKeyValue, []);
|
|
except
|
|
flag := False;
|
|
end;
|
|
if flag and VarEquals(AKeyValue, FKeyField.Value) then
|
|
FDataLink.DataSet.Delete;
|
|
end;
|
|
|
|
DataChangedBusy := True;
|
|
if not flagDis then
|
|
FDataLink.DataSet.EnableControls;
|
|
DataChangedBusy := False;
|
|
Change(Selected);
|
|
end;
|
|
|
|
procedure TdxDBTreeView.DoCustomDraw(TreeNode: TTreeNode; AFont: TFont;
|
|
var AColor, ABkColor: TColor);
|
|
begin
|
|
if Assigned(OnCustomDraw) then
|
|
inherited DoCustomDraw(TreeNode, AFont, AColor, ABkColor)
|
|
else
|
|
begin
|
|
if TdxDBTreeNode(TreeNode).IsCustomDraw then
|
|
with TdxDBTreeNode(TreeNode) do
|
|
begin
|
|
AFont.Style := FontStyle;
|
|
AFont.Name := FontName;
|
|
AColor := Color;
|
|
ABkColor := BkColor;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.GetNodeStructure(TreeNode: TTreeNode; List: TList);
|
|
begin
|
|
if (trSmartRecordLoad in FOptions) and CopyTreeNodeStructFlag then
|
|
TdxDBTreeNode(TreeNode).LoadChildren(True);
|
|
inherited GetNodeStructure(TreeNode, List);
|
|
end;
|
|
|
|
type
|
|
TInsertFieldStruct = class
|
|
private
|
|
Buffer: Pointer;
|
|
{$IFNDEF DELPHI3}
|
|
Stream: TBlobStream;
|
|
{$ELSE}
|
|
Stream: TStream;
|
|
{$ENDIF}
|
|
FieldName: string;
|
|
public
|
|
constructor Create(Size: Integer);
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
constructor TInsertFieldStruct.Create(Size: Integer);
|
|
begin
|
|
inherited Create;
|
|
GetMem(Buffer, Size);
|
|
end;
|
|
|
|
destructor TInsertFieldStruct.Destroy;
|
|
begin
|
|
FreeMem(Buffer);
|
|
if Stream <> nil then
|
|
Stream.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TdxDBTreeView.GetNextMaxKeyValue: Variant;
|
|
begin
|
|
Result := DBTreeNodes.MaxKeyFieldValue;
|
|
if Assigned(FCreateNewKeyValue) then
|
|
FCreateNewKeyValue(nil, Result)
|
|
else
|
|
try
|
|
if not VarIsNULL(Result) then
|
|
Result := Result + 1
|
|
else
|
|
Result := 0;
|
|
except
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.InsertTreeNodeStructure(ListS, ListD: TList; Flag: Boolean);
|
|
var
|
|
i, index: Integer;
|
|
MaxKeyFieldValue: Variant;
|
|
tr, tr1: TTreeNode;
|
|
dbtr, dbtr1: TdxDBTreeNode;
|
|
ifs: TInsertFieldStruct;
|
|
List: TList;
|
|
FlagBuzy, FlagDis: Boolean;
|
|
sDBTreeView: TdxDBTreeView;
|
|
sDBTreeKeyValue: Variant;
|
|
FCopiedFields: TList;
|
|
{$IFDEF DELPHI3}
|
|
AStream: TStream;
|
|
{$ENDIF}
|
|
|
|
function IsBlobField(AField: TField): Boolean;
|
|
begin
|
|
Result := AField is TBlobField;
|
|
end;
|
|
|
|
begin
|
|
if (ListS.Count > 0) and (TTreeNode(ListS[0]).TreeView is TdxDBTreeView) then
|
|
sDBTreeView := TdxDBTreeView(TTreeNode(ListS[0]).TreeView)
|
|
else
|
|
sDBTreeView := nil;
|
|
FlagBuzy := DataChangedBusy;
|
|
DataChangedBusy := True;
|
|
|
|
if not DoDBAction(TdxDBTreeNode(ListS[0]), TdxDBTreeNode(ListD[0]), trDBMove) then
|
|
begin
|
|
DataChangedBusy := FlagBuzy;
|
|
Exit;
|
|
end;
|
|
|
|
FlagDis := FDataLink.DataSet.ControlsDisabled;
|
|
if not flagDis then
|
|
FdataLink.DataSet.DisableControls;
|
|
if (ListD.Count > 0) and (trSmartRecordLoad in FOptions) then
|
|
begin
|
|
tr := TTreeNode(ListD[0]);
|
|
if (tr <> nil) and (tr.Parent <> nil) then
|
|
TdxDBTreeNode(tr.Parent).ChildLoaded := True;
|
|
end;
|
|
sDBTreeKeyValue := varNull;
|
|
FCopiedFields := TList.Create;
|
|
if Flag and (trSmartRecordCopy in FOptions) and (ListS.Count > 0) and (sDBTreeView <> nil) then
|
|
begin
|
|
sDBTreeKeyValue := sDBTreeView.FKeyField.Value;
|
|
for index := 0 to sDBTreeView.FDataLink.DataSet.FieldCount - 1 do
|
|
if (CompareText(sDBTreeView.FDataLink.DataSet.Fields[index].FieldName, FKeyFieldName) <> 0)
|
|
and (CompareText(sDBTreeView.FDataLink.DataSet.Fields[index].FieldName, FParentFieldName) <> 0)
|
|
and (FDataLink.DataSet.FindField(sDBTreeView.FDataLink.DataSet.Fields[index].FieldName) <> nil) then
|
|
FCopiedFields.Add(sDBTreeView.FDataLink.DataSet.Fields[index]);
|
|
end;
|
|
|
|
MaxKeyFieldValue := DBTreeNodes.MaxKeyFieldValue;
|
|
for i := 0 to ListD.Count - 1 do
|
|
begin
|
|
tr := TTreeNode(ListD[i]);
|
|
dbtr := TdxDBTreeNode(TTreeNode(ListD[i]));
|
|
if tr.Parent <> nil then
|
|
dbtr.FParentFieldValue := DBTreeNodes.GetKeyFieldValue(tr.Parent)
|
|
else
|
|
if not VarIsNull(FRootValue) or (trSmartRecordLoad in FOptions) then
|
|
dbtr.FParentFieldValue := FRootValue
|
|
else
|
|
dbtr.FParentFieldValue := dbtr.FKeyFieldValue;
|
|
dbtr := TdxDBTreeNode(tr);
|
|
if (FDisplayFields.Count > 0) and (sDBTreeView = Self) then
|
|
begin
|
|
tr1 := TTreeNode(ListS[i]);
|
|
if tr1 <> nil then
|
|
begin
|
|
DBTrDataSetLocate(FDataLink.DataSet, FKeyFieldName, TdxDBTreeNode(tr1).FKeyFieldValue, []);
|
|
tr.Text := FListField.Text;
|
|
end;
|
|
end;
|
|
FDataLink.DataSet.Append;
|
|
FParentField.Value := dbtr.FParentFieldValue;
|
|
if (FListField <> FKeyField) and (FListField <> FParentField) then
|
|
FListField.Value := tr.Text;
|
|
|
|
if FKeyField.DataType <> ftAutoInc then
|
|
FKeyField.Value := dbtr.FKeyFieldValue;
|
|
FDataLink.DataSet.Post;
|
|
if (FKeyField.DataType = ftAutoInc) and not FKeyField.IsNull then
|
|
dbtr.FKeyFieldValue := FKeyField.Value;
|
|
|
|
if FCopiedFields.Count > 0 then
|
|
begin
|
|
tr1 := TTreeNode(ListS[i]);
|
|
List := TList.Create;
|
|
if tr1 <> nil then
|
|
begin
|
|
dbtr1 := TdxDBTreeNode(tr1);
|
|
if sDBTreeView <> Self then
|
|
sDBTreeView.DataChangedBusy := True;
|
|
DBTrDataSetLocate(sDBTreeView.FDataLink.DataSet, sDBTreeView.FKeyFieldName,
|
|
dbtr1.FKeyFieldValue, []);
|
|
if sDBTreeView <> Self then
|
|
sDBTreeView.DataChangedBusy := False;
|
|
for index := 0 to FCopiedFields.Count - 1 do
|
|
begin
|
|
ifs := TInsertFieldStruct.Create(TField(FCopiedFields[Index]).DataSize + 1);
|
|
try
|
|
ifs.Stream := nil;
|
|
if IsBlobField(TField(FCopiedFields[Index])) then
|
|
begin
|
|
{$IFNDEF DELPHI3}
|
|
ifs.Stream := TBlobStream.Create(TBlobField(FCopiedFields[Index]), bmRead);
|
|
{$ELSE}
|
|
AStream := sDBTreeView.FDataLink.DataSet.CreateBlobStream(TField(FCopiedFields[Index]), bmRead);
|
|
ifs.Stream := TMemoryStream.Create;
|
|
ifs.Stream.CopyFrom(AStream, AStream.Size);
|
|
AStream.Free;
|
|
{$ENDIF}
|
|
ifs.FieldName := TField(FCopiedFields[Index]).FieldName;
|
|
List.Add(ifs);
|
|
end
|
|
else
|
|
if TField(FCopiedFields[Index]).GetData(ifs.Buffer) then
|
|
begin
|
|
ifs.FieldName := TField(FCopiedFields[Index]).FieldName;
|
|
List.Add(ifs)
|
|
end
|
|
else
|
|
ifs.Free;
|
|
except
|
|
ifs.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if List.Count > 0 then
|
|
try
|
|
DBTrDataSetLocate(FDataLink.DataSet, FKeyFieldName, dbtr.FKeyFieldValue, []);
|
|
FDataLink.DataSet.Edit;
|
|
for index := 0 to List.Count - 1 do
|
|
begin
|
|
ifs := TInsertFieldStruct(List[index]);
|
|
try
|
|
if ifs.Stream <> nil then
|
|
{$IFNDEF DELPHI3}
|
|
TBlobField(FDataLink.DataSet.FindField(ifs.FieldName)).LoadFromStream(ifs.Stream)
|
|
{$ELSE}
|
|
begin
|
|
AStream := FDataLink.DataSet.CreateBlobStream(FDataLink.DataSet.FindField(ifs.FieldName), bmWrite);
|
|
ifs.Stream.Position := 0;
|
|
AStream.CopyFrom(ifs.Stream, ifs.Stream.Size);
|
|
AStream.Free;
|
|
end
|
|
{$ENDIF}
|
|
else FDataLink.DataSet.FindField(ifs.FieldName).SetData(ifs.Buffer);
|
|
except
|
|
end;
|
|
end;
|
|
FDataLink.DataSet.Post;
|
|
except
|
|
end;
|
|
while List.Count > 0 do
|
|
begin
|
|
ifs := TInsertFieldStruct(List[0]);
|
|
List.Remove(ifs);
|
|
ifs.Free;
|
|
end;
|
|
List.Free;
|
|
end;
|
|
|
|
tr.Text := GetDisplayText;
|
|
if Assigned(FAddNewItem) then
|
|
FAddNewItem(nil, dbtr);
|
|
end;
|
|
tr := TTreeNode(ListD[0]);
|
|
if (tr <> nil) and (tr.Parent <> nil) then
|
|
DBTrDataSetLocate(FDataLink.DataSet, FKeyFieldName,
|
|
TdxDBTreeNode(tr.Parent).FKeyFieldValue, []);
|
|
|
|
if (sDBTreeView <> nil) and (sDBTreeView <> Self) then
|
|
begin
|
|
sDBTreeView.DataChangedBusy := True;
|
|
DBTrDataSetLocate(sDBTreeView.FDataLink.DataSet, sDBTreeView.FKeyFieldName,
|
|
sDBTreeKeyValue, []);
|
|
sDBTreeView.DataChangedBusy := False;
|
|
end;
|
|
|
|
FCopiedFields.Free;
|
|
|
|
if not flagDis then
|
|
FdataLink.DataSet.EnableControls;
|
|
DataChangedBusy := FlagBuzy;
|
|
end;
|
|
|
|
function TdxDBTreeView.IsCustomDraw: Boolean;
|
|
begin
|
|
Result := (inherited IsCustomDraw) or (DBTreeNodes.FCustomDrawCount > 0);
|
|
end;
|
|
|
|
function TdxDBTreeView.GetListItemText(TreeNode: TTreeNode): string;
|
|
begin
|
|
if FDisplayFields.Count > 0 then
|
|
Result := TdxDBTreeNode(TreeNode).FListText
|
|
else
|
|
Result := inherited GetListItemText(TreeNode);
|
|
end;
|
|
|
|
procedure TdxDBTreeView.DoCNNotify(var Message: TWMNotify);
|
|
var
|
|
TreeNode: TTreeNode;
|
|
dbtr: TdxDBTreeNode;
|
|
OldCNNotifyFlag: Boolean;
|
|
begin
|
|
if trSmartRecordLoad in FOptions then
|
|
with Message.NMHdr^, PNMTreeView(Pointer(Message.NMHdr))^do
|
|
begin
|
|
if (code = TVN_ITEMEXPANDING) and (Action = TVE_EXPAND) then
|
|
begin
|
|
dbtr := TdxDBTreeNode(GetNodeFromItem(ItemNew));
|
|
if dbtr <> nil then
|
|
begin
|
|
if CanExpand(dbtr) then
|
|
dbtr.ChildLoaded := True
|
|
else
|
|
Message.Result := 1;
|
|
end;
|
|
Exit;
|
|
end;
|
|
if (code = TVN_ITEMEXPANDED) and (action = TVE_COLLAPSE) then
|
|
begin
|
|
inherited;
|
|
dbtr := TdxDBTreeNode(GetNodeFromItem(ItemNew));
|
|
if dbtr <> nil then
|
|
begin
|
|
OldCNNotifyFlag := CNNotifyFlag;
|
|
CNNotifyFlag := True;
|
|
dbtr.ChildLoaded := False;
|
|
CNNotifyFlag := OldCNNotifyFlag;
|
|
end;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
with Message.NMHdr^ do
|
|
begin
|
|
if (code = TVN_BEGINLABELEDIT) and (FListField <> nil) then
|
|
begin
|
|
with PTVDispInfo(Pointer(Message.NMHdr))^do
|
|
TreeNode := GetNodeFromItem(item);
|
|
if TreeNode.Text <> FListField.Text then
|
|
begin
|
|
TreeNode.Text := FListField.Text;
|
|
SendMessage(TreeView_GetEditControl(handle), WM_SETTEXT, 0, Integer(PChar(TreeNode.Text)));
|
|
end;
|
|
if FDataLink.DataSet.CanModify then
|
|
FDataLink.Edit;
|
|
FEditHandle := TreeView_GetEditControl(Handle);
|
|
SendMessage(FEditHandle, EM_SETLIMITTEXT, FListField.DisplayWidth, 0);
|
|
FDefEditProc := Pointer(GetWindowLong(FEditHandle, GWL_WNDPROC));
|
|
SetWindowLong(FEditHandle, GWL_WNDPROC, Integer(FEditInstance));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.DoVMInsertItem(var Message: TMessage);
|
|
var
|
|
tn, oldtnp, newtnp: TTreeNode;
|
|
str: TTVInsertStruct;
|
|
begin
|
|
if not DataChangedBusy then
|
|
begin
|
|
tn := Items.GetNode(HTreeItem(Message.Result));
|
|
if tn <> nil then
|
|
begin
|
|
str := PTVInsertStruct(Message.lParam)^;
|
|
newtnp := Items.GetNode(str.hparent);
|
|
if TdxDBTreeNode(tn).IsInserting then
|
|
begin
|
|
if not CopyTreeNodeStructFlag then
|
|
InsertTreeNode(TdxDBTreeNode(tn), TdxDBTreeNode(newtnp));
|
|
TdxDBTreeNode(tn).IsInserting := False;
|
|
end
|
|
else
|
|
begin
|
|
oldtnp := DBTreeNodes.GetTreeNode(TdxDBTreeNode(tn).FParentFieldValue);
|
|
if newtnp <> oldtnp then
|
|
SetNewTreeNodeParent(TdxDBTreeNode(tn), TdxDBTreeNode(newtnp));
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.DoVMSelectItem(var Message: TMessage);
|
|
begin
|
|
FrameSelectedItem;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.DoVMSetItem(var Message: TMessage);
|
|
var
|
|
tr: TTreeNode;
|
|
FlagDis: Boolean;
|
|
begin
|
|
if not DataChangedBusy and not CopyTreeNodeStructFlag and not IsEditing
|
|
and (PTVITEM(Message.lparam)^.mask and TVIF_TEXT = 1)
|
|
and (PTVITEM(Message.lparam)^.hItem <> nil)
|
|
and (not ReadOnly) and (FListField <> nil) and (FDisplayFields.Count = 0)
|
|
and (FDataLink.DataSet.CanModify) and not FListField.ReadOnly then
|
|
begin
|
|
DataChangedBusy := True;
|
|
FlagDis := FDataLink.DataSet.ControlsDisabled;
|
|
if not FlagDis then
|
|
FDataLink.DataSet.DisableControls;
|
|
SendMessage(Handle, WM_SETREDRAW, Integer(False), 0);
|
|
DataChangedBusy := False;
|
|
tr := Selected;
|
|
TreeView_SelectItem(Handle, PTVITEM(Message.lparam)^.hItem);
|
|
DataChangedBusy := True;
|
|
if (FListField.Text <> Selected.Text)
|
|
and DoDBAction(TdxDBTreeNode(selected), nil, trDBChangeText) then
|
|
begin
|
|
FDataLink.DataSet.Edit;
|
|
FListField.Text := Selected.Text;
|
|
FDataLink.DataSet.Post;
|
|
end;
|
|
Selected := tr;
|
|
SendMessage(Handle, WM_SETREDRAW, Integer(True), 0);
|
|
if not FlagDis then
|
|
FDataLink.DataSet.EnableControls;
|
|
DataChangedBusy := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.DoVMExpand(var Message: TMessage);
|
|
begin
|
|
if (Message.wParam = TVE_COLLAPSE) and (Selected <> nil) then
|
|
Change(Selected);
|
|
end;
|
|
|
|
procedure TdxDBTreeView.DoWMPaint(var Message: TMessage);
|
|
begin
|
|
if not Focused and (Selected <> nil) and (Selected.IsVisible) and not IsEditing then
|
|
FrameSelectedItem;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.CNNotify(var Message: TWMNotify);
|
|
begin
|
|
DoCNNotify(Message);
|
|
inherited;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.VM_INSERTITEM(var Message: TMessage);
|
|
begin
|
|
inherited;
|
|
DoVMInsertItem(Message);
|
|
end;
|
|
|
|
procedure TdxDBTreeView.VM_SELECTITEM(var Message: TMessage);
|
|
begin
|
|
inherited;
|
|
DoVMSelectItem(Message);
|
|
end;
|
|
|
|
procedure TdxDBTreeView.VM_SETITEM(var Message: TMessage);
|
|
begin
|
|
inherited;
|
|
DoVMSetItem(Message);
|
|
end;
|
|
|
|
procedure TdxDBTreeView.VM_EXPAND(var Message: TMessage);
|
|
begin
|
|
inherited;
|
|
DoVMExpand(Message);
|
|
end;
|
|
|
|
procedure TdxDBTreeView.WMPaint(var Message: TMessage);
|
|
begin
|
|
inherited;
|
|
DoWMPaint(Message);
|
|
end;
|
|
|
|
procedure TdxDBTreeView.WMUpdateImages(var Message: TMessage);
|
|
var
|
|
ANode: TdxDBTreeNode;
|
|
begin
|
|
ANode := TdxDBTreeNode(Message.WParam);
|
|
if ANode is TdxDBTreeNode then
|
|
ANode.UpdateImages;
|
|
end;
|
|
|
|
procedure TdxDBTreeView.EditWndProc(var Message: TMessage);
|
|
begin
|
|
with Message do
|
|
begin
|
|
case Msg of
|
|
WM_CHAR:
|
|
if not (FDataLink.DataSet.CanModify) or FListField.ReadOnly then
|
|
Exit
|
|
else
|
|
if not FListField.IsValidChar(Char(wParam)) then
|
|
begin
|
|
MessageBeep(0);
|
|
Exit;
|
|
end;
|
|
end;
|
|
Result := CallWindowProc(FDefEditProc, FEditHandle, Msg, WParam, LParam);
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|