home *** CD-ROM | disk | FTP | other *** search
- {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- TechInsite Pty. Ltd.
- PO Box 429, Abbotsford, Melbourne. 3067 Australia
- Phone: +61 3 9419 6456
- Fax: +61 3 9419 1682
- Web: www.techinsite.com.au
- EMail: peter_hinrichsen@techinsite.com.au
-
- Created: 01/07/1999
-
- Notes: A TTreeView for browsing a nested list of TPersistent(s) and
- TList(s)
-
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
- unit tiTreeView;
-
- interface
- uses
- ComCtrls
- ,CommCtrl
- ,Classes
- ,Menus
- ;
-
- type
-
- TtiTreeView = class ;
-
- {
- TtiTVDataMapping = class( TCollectionItem )
- private
- FsListPropName: string;
- FsDataClassName: string;
- published
- property DataClassName : string read FsDataClassName write FsDataClassName ;
- property ListPropName : string read FsListPropName write FsListPropName ;
- public
- end ;
-
- TtiTreeView = class ;
-
- TtiTVDataMappings = class( TCollection )
- private
- FOwner : TtiTreeView;
- function GetItem(Index: Integer): TtiTVDataMapping;
- procedure SetItem(Index: Integer; const Value: TtiTVDataMapping);
- published
- public
- constructor Create(AOwner: TtiTreeView);
- function Add : TtiTVDataMapping ;
- property Owner: TtiTreeView read FOwner;
- property Items[Index: Integer]: TtiTVDataMapping read GetItem write SetItem;
- end ;
- }
-
- //----------------------------------------------------------------------------
- TTVPopupMenu = class( TPopupMenu )
- private
- FmiNew : TMenuItem ;
- FmiDel : TMenuItem ;
- FmiSep1 : TMenuItem ;
- FmiSave : TMenuItem ;
- FmiCancel : TMenuItem ;
- FmiSep2 : TMenuItem ;
- FmiClose : TMenuItem ;
- FTV : TtiTreeView ;
- procedure DoNew( sender : TObject ) ;
- procedure DoDelete( sender : TObject ) ;
- procedure DoCancel( sender : TObject ) ;
- procedure DoSave( sender : TObject ) ;
- procedure DoClose( sender : TObject ) ;
- procedure DoOnPopup( sender : TObject ) ;
- public
- Constructor Create( Owner : TComponent ) ; override ;
- Destructor Destroy ; override ;
- Property TV : TtiTreeView read FTV write FTV ;
- end ;
-
- TtiTVNewEvent = procedure( ptiTreeView : TtiTreeView ;
- pNode : TTreeNode ;
- pParentNode : TTreeNode ;
- pData : TObject ) of object ;
- TtiTVDeleteEvent = procedure( ptiTreeView : TtiTreeView ;
- pNode : TTreeNode ;
- pData : TObject ) of object ;
- TTVGetDataPageEvent = procedure( pData : TObject ; pNode : TTreeNode ) of object ;
- TTVUpdateNodeText = procedure( const psValue : string ) of object ;
-
- //----------------------------------------------------------------------------
- TtiTreeView = class( TCustomTreeView )
- private
- FData: TPersistent ;
- FOnGetDataPage: TTVGetDataPageEvent;
- FNodesLoaded : TList ;
-
- FPopupMenu : TTVPopupMenu ;
- FOnCancel : TNotifyEvent;
- FOnClose : TNotifyEvent;
- FOnDelete : TtiTVDeleteEvent ;
- FOnSave : TNotifyEvent;
-
- FOnNew: TtiTVNewEvent;
-
- procedure SetData(const Value: TPersistent );
- procedure DoOnExpanding(Sender: TObject; Node: TTreeNode ; var AllowExpansion: Boolean );
-
- function HasNodeChildren( pValue: TObject ) : boolean;
- procedure DoSave ;
- procedure DoClose ;
- procedure DoCancel ;
- procedure AddNodeChildren( pNode: TTreeNode ; pData : TObject ) ;
- procedure GetObjectPropNames(pPersistent: TObject; pSL: TStringList);
- function CountObjectProps( pPersistent : TObject ) : integer ;
- procedure DoOnChange( sender : TObject ; node : TTreeNode ) ;
- function CanShowObjectProp(pValue: TObject): boolean;
-
- published
- property Align ;
- property Anchors ;
- property Data : TPersistent read FData write SetData ;
- property Images ;
- property OnChanging ;
-
- property OnGetDataPage : TTVGetDataPageEvent read FOnGetDataPage write FOnGetDataPage ;
- property OnNew : TtiTVNewEvent read FOnNew write FOnNew ;
- property OnSave : TNotifyEvent read FOnSave write FOnSave ;
- property OnDelete : TtiTVDeleteEvent read FOnDelete write FOnDelete ;
- property OnClose : TNotifyEvent read FOnClose write FOnClose ;
- property OnCancel : TNotifyEvent read FOnCancel write FOnCancel ;
- // We can't publish OnChange as is is used internally
- // property OnChange ;
-
- public
- Constructor create( owner : TComponent ) ; override ;
- Destructor destroy ; override ;
- Procedure UpdateNodeText( const psValue : string ) ;
- Property Items ;
- Procedure DoNew ;
- Procedure DoDelete ;
- end ;
-
- implementation
- uses
- SysUtils
- ,TypInfo
- ;
-
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- // *
- // * TtiTreeView
- // *
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- constructor TtiTreeView.create(owner: TComponent);
- begin
- inherited create( owner ) ;
- OnExpanding := DoOnExpanding ;
- OnChange := DoOnChange ;
- ReadOnly := true ;
- ChangeDelay := 500 ;
- FPopupMenu := TTVPopupMenu.Create( self ) ;
- FPopupMenu.TV := self ;
- PopupMenu := FPopupMenu ;
- FNodesLoaded := TList.Create ;
- end;
-
- //------------------------------------------------------------------------------
- destructor TtiTreeView.destroy;
- begin
- FPopupMenu.Free ;
- FNodesLoaded.Free ;
- inherited ;
- end;
-
- //------------------------------------------------------------------------------
- procedure TtiTreeView.DoOnExpanding( Sender: TObject ;
- Node: TTreeNode ;
- var AllowExpansion: Boolean ) ;
- begin
-
- if FNodesLoaded.IndexOf( Node ) = -1 then begin
- FNodesLoaded.Add( Node ) ;
-
- AddNodeChildren( Node, Node.Data ) ;
- end ;
-
- if Assigned( FOnGetDataPage ) then
- FOnGetDataPage( Data, Node ) ;
-
- end ;
-
- //------------------------------------------------------------------------------
- procedure TtiTreeView.AddNodeChildren( pNode : TTreeNode ; pData : TObject ) ;
- procedure AddChildPersistent( pNode : TTreeNode ;
- pData : TPersistent ) ;
- var
- lNode : TTreeNode ;
- lsCaption : string ;
- begin
- if IsPublishedProp( pData, 'caption' ) then begin
- lsCaption := GetPropValue( pData, 'Caption' ) ;
- lNode := self.Items.AddChildObject( pNode, lsCaption, pData ) ;
- lNode.HasChildren := HasNodeChildren( pData ) ;
- end ;
- end ;
-
- procedure AddChildList( pNode : TTreeNode ;
- pData : TList ) ;
- var
- lData : TPersistent ;
- lNode : TTreeNode ;
- lsCaption : string ;
- i : integer ;
- begin
- for i := 0 to pData.Count - 1 do begin
- if ( TObject( pData.Items[i] ) is TPersistent ) then begin
- lData := TPersistent( pData.Items[i] ) ;
- if IsPublishedProp( lData, 'caption' ) then begin
- lsCaption := GetPropValue( lData, 'Caption' ) ;
- lNode := self.Items.AddChildObject( pNode, lsCaption, lData ) ;
- lNode.HasChildren := HasNodeChildren( lData ) ;
- end ;
- end ;
- end ;
- end ;
-
- var
- lChild : TObject ;
- i : integer ;
- lslObjProps : TStringList ;
- begin
-
- lslObjProps := TStringList.Create ;
- try
- GetObjectPropNames( pData, lslObjProps ) ;
- for i := 0 to lslObjProps.Count - 1 do begin
- lChild := ( GetObjectProp( pData, lslObjProps.Strings[i] ) as TObject ) ;
- if ( lChild is TPersistent ) then
- AddChildPersistent( pNode, TPersistent( lChild ))
- else if ( lChild is TList ) then
- AddChildList( pNode, TList( lChild )) ;
- end ;
- finally
- lslObjProps.Free ;
- end ;
-
- end;
-
- //------------------------------------------------------------------------------
- function TtiTreeView.HasNodeChildren( pValue : TObject ) : boolean ;
- begin
- if ( pValue is TPersistent ) then begin
- result := CountObjectProps( pValue ) > 0 ;
- end else if ( pValue is TList ) then begin
- result := TList( pValue ).Count > 0 ;
- end else
- result := false ;
- end ;
-
- //------------------------------------------------------------------------------
- procedure TtiTreeView.SetData(const Value: TPersistent );
- var
- lsCaption : string ;
- lNode : TTreeNode ;
- lbDummy : boolean ;
- begin
-
- Items.Clear ;
- FNodesLoaded.Clear ;
-
- FData := Value;
- if Value = nil then
- exit ; //==>
-
- if IsPublishedProp( Value, 'Caption' ) then
- lsCaption := GetPropValue( Value, 'Caption' )
- else
- lsCaption := 'Top' ;
-
- lNode := Items.AddObject( nil, lsCaption, Value ) ;
- lNode.HasChildren := HasNodeChildren( Value ) ;
-
- if lNode.HasChildren then
- DoOnExpanding( nil, lNode, lbDummy ) ;
-
- lNode.Expand( false ) ;
- if Assigned( FOnGetDataPage ) then
- FOnGetDataPage( Value, lNode ) ;
-
- end;
-
- //------------------------------------------------------------------------------
- procedure TtiTreeView.UpdateNodeText(const psValue: string);
- begin
- if Selected <> nil then
- Selected.Text := psValue ;
- end;
-
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- // *
- // * TTVPopupMenu
- // *
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- constructor TTVPopupMenu.Create(Owner: TComponent);
- begin
- Inherited Create( Owner ) ;
- FmiNew := TMenuItem.Create( nil ) ;
- FmiNew.Caption := '&New' ;
- FmiNew.OnClick := DoNew ;
- FmiNew.Shortcut := TextToShortcut( 'Ctrl+N' ) ;
- Items.Add( FmiNew ) ;
-
- FmiDel := TMenuItem.Create( nil ) ;
- FmiDel.Caption := '&Delete' ;
- FmiDel.OnClick := DoDelete ;
- FmiDel.Shortcut := TextToShortcut( 'Ctrl+D' ) ;
- Items.Add( FmiDel ) ;
-
- FmiSep1 := TMenuItem.Create( nil ) ;
- FmiSep1.Caption := '-' ;
- Items.Add( FmiSep1 ) ;
-
- FmiSave := TMenuItem.Create( nil ) ;
- FmiSave.Caption := '&Save' ;
- FmiSave.OnClick := DoSave ;
- FmiSave.Shortcut := TextToShortcut( 'Ctrl+S' ) ;
- Items.Add( FmiSave ) ;
-
- FmiCancel := TMenuItem.Create( nil ) ;
- FmiCancel.Caption := '&Cancel' ;
- FmiCancel.OnClick := DoCancel ;
- FmiCancel.Shortcut := TextToShortcut( 'Ctrl+C' ) ;
- Items.Add( FmiCancel ) ;
-
- FmiSep2 := TMenuItem.Create( nil ) ;
- FmiSep2.Caption := '-' ;
- Items.Add( FmiSep2 ) ;
-
- FmiClose := TMenuItem.Create( nil ) ;
- FmiClose.Caption := 'C&lose' ;
- FmiClose.OnClick := DoClose ;
- FmiClose.Shortcut := TextToShortcut( 'Ctrl+F4' ) ;
- Items.Add( FmiClose ) ;
-
- OnPopup := DoOnPopup ;
-
- end ;
-
- //------------------------------------------------------------------------------
- destructor TTVPopupMenu.Destroy;
- begin
- FmiNew.Free ;
- FmiDel.Free ;
- FmiSep1.Free ;
- FmiSave.Free ;
- FmiCancel.Free ;
- FmiSep2.Free ;
- FmiClose.Free ;
- Inherited ;
- end;
-
- //------------------------------------------------------------------------------
- procedure TTVPopupMenu.DoCancel( sender : TObject );
- begin
- TV.DoCancel ;
- end;
-
- //------------------------------------------------------------------------------
- procedure TTVPopupMenu.DoClose( sender : TObject );
- begin
- TV.DoClose ;
- end;
-
- //------------------------------------------------------------------------------
- procedure TTVPopupMenu.DoDelete( sender : TObject );
- begin
- TV.DoDelete
- end;
-
- //------------------------------------------------------------------------------
- procedure TTVPopupMenu.DoNew( sender : TObject );
- begin
- TV.DoNew ;
- end;
-
- //------------------------------------------------------------------------------
- procedure TTVPopupMenu.DoOnPopup(sender: TObject);
- begin
- FmiNew.Enabled := Assigned( FTV.OnNew ) ;
- FmiDel.Enabled := Assigned( FTV.OnDelete ) ;
- FmiSave.Enabled := Assigned( FTV.OnSave ) ;
- FmiCancel.Enabled := Assigned( FTV.OnCancel ) ;
- FmiClose.Enabled := Assigned( FTV.OnClose ) ;
-
- // FmiSep1.Enabled := Assigned( FTV. ) ;
- // FmiSep2.Enabled := Assigned( FTV. ) ;
-
- end;
-
- procedure TTVPopupMenu.DoSave( sender : TObject );
- begin
- TV.DoSave ;
- end;
-
- //------------------------------------------------------------------------------
- procedure TtiTreeView.DoCancel;
- begin
- if Assigned( FOnCancel ) then
- FOnCancel( self ) ;
- end;
-
- //------------------------------------------------------------------------------
- procedure TtiTreeView.DoClose;
- begin
- if Assigned( FOnClose ) then
- FOnClose( self ) ;
- end;
-
- //------------------------------------------------------------------------------
- procedure TtiTreeView.DoDelete;
- var
- lNode : TTreeNode ;
- lData : TObject ;
- begin
- if Assigned( FOnDelete ) then begin
- lNode := Selected ;
- if lNode <> nil then
- lData := lNode.Data
- else
- lData := nil ;
- FOnDelete( self, lNode, lData ) ;
- DoOnChange( self, Selected ) ;
- end ;
- end;
-
- //------------------------------------------------------------------------------
- procedure TtiTreeView.DoNew ;
- var
- lNode : TTreeNode ;
- lParentNode : TTreeNode ;
- lData : TObject ;
- begin
- if Assigned( FOnNew ) then begin
- lNode := Selected ;
- if lNode <> nil then begin
- lParentNode := lNode.Parent ;
- lData := lNode.Data ;
- end else begin
- lParentNode := nil ;
- lData := nil ;
- end ;
- FOnNew( self, lNode, lParentNode, lData ) ;
- DoOnChange( self, Selected ) ;
- end ;
- end;
-
- //------------------------------------------------------------------------------
- procedure TtiTreeView.DoSave;
- begin
- if Assigned( FOnSave ) then
- FOnSave( self ) ;
- end;
-
- //------------------------------------------------------------------------------
- procedure TtiTreeView.GetObjectPropNames( pPersistent : TObject ;
- pSL : TStringList ) ;
- var
- lCount : integer ;
- lSize : integer ;
- lList : PPropList ;
- i : integer ;
- begin
- pSL.Clear ;
- lCount := GetPropList(pPersistent.ClassInfo, [tkClass], nil);
- lSize := lCount * SizeOf(Pointer);
- GetMem(lList, lSize);
- try
- GetPropList(pPersistent.ClassInfo, [tkClass], lList);
- for i := 0 to lcount - 1 do
- psl.add( lList[i].Name ) ;
- finally
- FreeMem( lList, lSize ) ;
- end ;
- end ;
-
- //------------------------------------------------------------------------------
- function TtiTreeView.CountObjectProps( pPersistent : TObject ) : integer ;
- var
- lsl : TStringList ;
- i : integer ;
- begin
- result := 0 ;
- lsl := TStringList.Create ;
- try
- GetObjectPropNames( pPersistent, lsl ) ;
- for i := 0 to lsl.Count - 1 do begin
- if CanShowObjectProp( GetObjectProp( pPersistent, lsl.Strings[i] )) then
- inc( result ) ;
- end ;
- finally
- lsl.Free ;
- end ;
- end ;
-
- //------------------------------------------------------------------------------
- function TtiTreeView.CanShowObjectProp( pValue : TObject ) : boolean ;
- begin
- result := (( pValue is TPersistent ) and
- ( IsPublishedProp( TPersistent( pValue ), 'Caption' ))) or
- (( pValue is TList ) and
- ( TList( pValue ).Count > 0 )) ;
- end ;
-
- //------------------------------------------------------------------------------
- procedure TtiTreeView.DoOnChange(sender: TObject; node: TTreeNode);
- begin
- if Assigned( FOnGetDataPage ) then
- FOnGetDataPage( Node.Data, Node ) ;
- end;
-
- end.
-