home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue54 / Persist / tiTreeViewPlus.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2000-01-08  |  10.3 KB  |  365 lines

  1. { * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2.   Purpose: A TTreeView with a family of contained forms for editing the nodes
  3.  
  4.   Revision History:
  5.   Dec 1999, PWH, Created
  6.  
  7.   Useage:
  8.   a) Drop on a form
  9.   b) Set the DataProperty to a TPersistent, which may contain other TPersistents
  10.      RTTI will be used to display any published 'Caption' properties in the list
  11.      as nodes.
  12.   c) Call RegisterChildForm( pDataClassRef ; pFormClassRef )
  13.      passing a DataType ( must be TPersisistent descendant) and
  14.      a FormType ( must be a TForm )
  15.   d) Write some code in the OnSave, OnCancel, OnClose, etc events.
  16.  
  17. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * }
  18.  
  19. {
  20.   ToDo 4 -cTTreeView:
  21.   a) Hide popup menu choices if no code is assigned to the event.
  22.   b) Deactivate <Save> and <Cancel> if data is not dirty.
  23.   c) Speed buttons linked to popup menu.
  24.   d) Ability to drag & drop tree nodes automatically.
  25.   e) Custom Glyphs on tree nodes (probably using a TCollection)
  26. }
  27.  
  28. unit tiTreeViewPlus;
  29.  
  30. interface
  31. uses
  32.   Classes
  33.   ,Controls
  34.   ,Extctrls
  35.   ,ComCtrls
  36.   ,tiTreeView
  37.   ,ImgList
  38.   ,Forms
  39.   ,Dialogs    // ShowMessage, for debugging
  40.   ;
  41.  
  42. type
  43.  
  44.   { ToDo 1 -cGUI: Validate current child form before saving }
  45.  
  46.   TtiTVDataClassRef = class of TPersistent ;
  47.   TtiTVFormClassRef = class of TForm ;
  48.  
  49.   TtiTreeViewPlus = class( TCustomPanel )
  50.   private
  51.     FTV               : TtiTreeView ;
  52.     FSplitter         : TSplitter ;
  53.     FOnGetDataPage    : TTVGetDataPageEvent ;
  54.     FslChildForms     : TStringList ;
  55.     FCurrentChildForm : TForm ;
  56.  
  57.     { ToDo 1 -ctiTreeView: VisibleMenuItems and EnabledMenuItems set properties }
  58.  
  59.     function  GetItems: TTreeNodes ;
  60.     function  GetData: TPersistent;
  61.     procedure SetData(const Value: TPersistent);
  62.     function  GetImages: TCustomImageList;
  63.     procedure SetImages(const Value: TCustomImageList);
  64.     function  GetOnNew: TtiTVNewEvent;
  65.     procedure SetOnNew(const Value: TtiTVNewEvent);
  66.     function  GetOnSave: TNotifyEvent;
  67.     procedure SetOnSave(const Value: TNotifyEvent);
  68.     function  GetOnDelete: TtiTVDeleteEvent;
  69.     procedure SetOnDelete(const Value: TtiTVDeleteEvent);
  70.     function  GetOnClose: TNotifyEvent;
  71.     procedure SetOnClose(const Value: TNotifyEvent);
  72.     function  GetOnCancel: TNotifyEvent;
  73.     procedure SetOnCancel(const Value: TNotifyEvent);
  74.     function  GetSplitterPos: integer;
  75.     procedure SetSplitterPos(const Value: integer);
  76.  
  77.     // The currently selected node has changed, so this proc will be executed
  78.     procedure DoOnGetDataPage( pData : TObject ; pNode : TTreeNode ) ;
  79.     procedure DoOnChanging(Sender: TObject; Node: TTreeNode; var AllowChange: Boolean);
  80.     function  GetSelected: TTreeNode;
  81.     procedure SetSelected( pData : TTreeNode ) ;
  82.  
  83.   protected
  84.   published
  85.     property Align ;
  86.     property Anchors ;
  87.     property SplitterPos   : integer      read GetSplitterPos write SetSplitterPos ;
  88.     property Images        : TCustomImageList read GetImages write SetImages ;
  89.     property OnGetDataPage : TTVGetDataPageEvent read FOnGetDataPage write FOnGetDataPage  ;
  90.     property OnNew         : TtiTVNewEvent read GetOnNew    write SetOnNew    ;
  91.     property OnSave        : TNotifyEvent read GetOnSave   write SetOnSave   ;
  92.     property OnDelete      : TtiTVDeleteEvent read GetOnDelete write SetOnDelete ;
  93.     property OnClose       : TNotifyEvent read GetOnClose  write SetOnClose  ;
  94.     property OnCancel      : TNotifyEvent read GetOnCancel write SetOnCancel ;
  95.  
  96.     // We can't publish OnChangeas is is used internally
  97.     // property OnChange ;
  98.  
  99.   public
  100.     Constructor Create( owner : TComponent ) ; override ;
  101.     Destructor  destroy ; override ;
  102.     Procedure   UpdateNodeText( const psValue : string ) ;
  103.     Property    Items : TTreeNodes  read GetItems ;
  104.     Property    Data  : TPersistent read GetData write SetData ;
  105.     Property    Selected : TTreeNode read GetSelected write SetSelected ;
  106.     Procedure   FullExpand ;
  107.     Procedure   RegisterChildForm( pDataClassRef : TtiTVDataClassRef ; pFormClassRef : TtiTVFormClassRef ) ;    // Property    TopItem ;
  108.     Procedure   DoNew ;
  109.     procedure   DoDelete ;
  110.  
  111.     // Use RTTI to test the Valid property on the child form. The GetValid function
  112.     // must also save any data from the from to its Data property.
  113.     function    IsCurrentChildFormValid: boolean;
  114.   end ;
  115.  
  116. implementation
  117. uses
  118.    TypInfo
  119.   ,SysUtils
  120.    ;
  121.  
  122. { TtiTreeViewPlus }
  123.  
  124. constructor TtiTreeViewPlus.create(owner: TComponent);
  125. begin
  126.   inherited Create( owner ) ;
  127.   ControlStyle := ControlStyle - [csSetCaption] ;
  128.   BevelInner  := bvNone ;
  129.   BevelOuter  := bvNone ;
  130.   BorderStyle := bsNone ;
  131.   Align       := alClient ;
  132.  
  133.   FSplitter        := TSplitter.Create( self ) ;
  134.   FSplitter.Parent := self ;
  135.   FSplitter.Left   := 150 ;
  136.  
  137.   FTV        := TtiTreeView.Create( self ) ;
  138.   FTV.Parent := self ;
  139.   FTV.Align  := alLeft ;
  140.   FTV.OnGetDataPage := DoOnGetDataPage ;
  141.   FTV.OnChanging    := DoOnChanging ;
  142.  
  143. {  FPanelParent             := TPanel.Create( self ) ;
  144.   FPanelParent.Parent      := self ;
  145.   FPanelParent.BorderStyle := bsNone ;
  146.   FPanelParent.BevelInner  := bvNone ;
  147.   FPanelParent.Align       := alClient ;
  148. }
  149.   FslChildForms    := TStringList.Create ;
  150.  
  151. end;
  152.  
  153. destructor TtiTreeViewPlus.destroy;
  154. var
  155.   i : integer ;
  156. begin
  157.   FTV.Free ;
  158.   FSplitter.Free ;
  159.   for i := 0 to FslChildForms.Count - 1 do
  160.     TObject( FslChildForms.Objects[i] ).Free ;
  161.   FslChildForms.Free ;
  162.   inherited;
  163. end;
  164.  
  165. procedure TtiTreeViewPlus.DoOnChanging(Sender: TObject; Node: TTreeNode; var AllowChange: Boolean);
  166. begin
  167.   AllowChange := IsCurrentChildFormValid ;
  168. end;
  169.  
  170. function TtiTreeViewPlus.IsCurrentChildFormValid : boolean ;
  171. begin
  172.   result := true ;
  173.   if FCurrentChildForm <> nil then
  174.     if IsPublishedProp( FCurrentChildForm, 'Valid' ) then
  175.       result := GetPropValue( FCurrentChildForm, 'Valid', false )
  176. end ;
  177.  
  178. procedure TtiTreeViewPlus.DoOnGetDataPage(pData: TObject; pNode: TTreeNode);
  179. var
  180.   i : integer ;
  181. begin
  182.  
  183.   // If CurrentChildForm was assigned, then do some cleaning up.
  184.   if FCurrentChildForm <> nil then begin
  185.     SetObjectProp( FCurrentChildForm, 'Data',     nil ) ;
  186.     SetObjectProp( FCurrentChildForm, 'TreeNode', nil ) ;
  187.     FCurrentChildForm.Visible := false ;
  188.     FCurrentChildForm := nil ;
  189.   end ;
  190.  
  191.   // If the OnGetDataPage event was assinged, then execute it
  192.   if Assigned( FOnGetDataPage ) then
  193.     FOnGetDataPage( pData, pNode ) ;
  194.  
  195.   // Find a childForm for editing the Data class attached to the selected node.
  196.   i := FslChildForms.IndexOf( upperCase( pData.ClassName )) ;
  197.  
  198.   // There was a form for this node, so setup the form
  199.   if i <> -1 then begin
  200.     FCurrentChildForm := TForm( FslChildForms.Objects[ i ]) ;
  201.     SetObjectProp( FCurrentChildForm, 'Data', pData ) ;
  202.     SetObjectProp( FCurrentChildForm, 'TreeNode', pNode ) ;
  203.     FCurrentChildForm.Visible := true ;
  204.   end ;
  205.  
  206. end;
  207.  
  208. function TtiTreeViewPlus.GetData: TPersistent;
  209. begin
  210.   result := FTV.Data ;
  211. end;
  212.  
  213. function TtiTreeViewPlus.GetImages: TCustomImageList;
  214. begin
  215.   result := FTV.Images ;
  216. end;
  217.  
  218. function TtiTreeViewPlus.GetItems : TTreeNodes ;
  219. begin
  220.   result := FTV.Items ;
  221. end;
  222.  
  223. function TtiTreeViewPlus.GetOnCancel: TNotifyEvent;
  224. begin
  225.   result := FTV.OnCancel ;
  226. end;
  227.  
  228. function TtiTreeViewPlus.GetOnClose: TNotifyEvent;
  229. begin
  230.   result := FTV.OnClose ;
  231. end;
  232.  
  233. function TtiTreeViewPlus.GetOnDelete: TtiTVDeleteEvent;
  234. begin
  235.   result := FTV.OnDelete ;
  236. end;
  237.  
  238. function TtiTreeViewPlus.GetOnNew: TtiTVNewEvent;
  239. begin
  240.   result := FTV.OnNew ;
  241. end;
  242.  
  243. function TtiTreeViewPlus.GetOnSave: TNotifyEvent;
  244. begin
  245.   result := FTV.OnSave ;
  246. end;
  247.  
  248. function TtiTreeViewPlus.GetSplitterPos: integer;
  249. begin
  250. //  result := FSplitter.Left ;
  251.   result := FTV.Width ;
  252. end;
  253.  
  254. procedure TtiTreeViewPlus.RegisterChildForm(pDataClassRef: TtiTVDataClassRef;  pFormClassRef: TtiTVFormClassRef);
  255. var
  256.   lForm : TForm ;
  257.   lsMessage : string ;
  258. begin
  259.   lForm             := pFormClassRef.Create( nil ) ;
  260.   lsMessage := '' ;
  261.  
  262.   if not IsPublishedProp( lForm, 'Data' ) then begin
  263.     if lsMessage <> '' then lsMessage := lsMessage + #13 ;
  264.     lsMessage := lsMessage +
  265.       '''Data'' property not published' ;
  266.   end ;
  267.  
  268.   if not IsPublishedProp( lForm, 'TreeNode' ) then begin
  269.     if lsMessage <> '' then lsMessage := lsMessage + #13 ;
  270.     lsMessage := lsMessage +
  271.       '''TreeNode'' property not published' ;
  272.   end ;
  273.  
  274.   if lsMessage <> '' then begin
  275.      lsMessage := lsMessage + #13 + #13 +
  276.        'Called in TtiTreeViewPlus.DoOnGetDataPage' ;
  277.     raise exception.create( lsMessage ) ;
  278.   end ;
  279.  
  280.   if lsMessage = '' then begin
  281.     lForm.Parent      := self ;
  282.     lForm.BorderStyle := bsNone ;
  283.     lForm.Align       := alClient ;
  284.     lForm.Visible     := false ;
  285.     FslChildForms.AddObject( upperCase( pDataClassRef.ClassName ),
  286.                              lForm ) ;
  287.   end else begin
  288.     lForm.Free ;
  289.   end ;
  290.  
  291. end;
  292.  
  293. procedure TtiTreeViewPlus.SetData(const Value: TPersistent);
  294. begin
  295.   FTV.Data := Value ;
  296. end;
  297.  
  298. procedure TtiTreeViewPlus.SetImages(const Value: TCustomImageList);
  299. begin
  300.   FTV.Images := Value ;
  301. end;
  302.  
  303. procedure TtiTreeViewPlus.SetOnCancel(const Value: TNotifyEvent);
  304. begin
  305.   FTV.OnCancel := Value ;
  306. end;
  307.  
  308. procedure TtiTreeViewPlus.SetOnClose(const Value: TNotifyEvent);
  309. begin
  310.   FTV.OnClose := Value ;
  311. end;
  312.  
  313. procedure TtiTreeViewPlus.SetOnDelete(const Value: TtiTVDeleteEvent);
  314. begin
  315.   FTV.OnDelete := Value ;
  316. end;
  317.  
  318. procedure TtiTreeViewPlus.SetOnNew(const Value: TtiTVNewEvent);
  319. begin
  320.   FTV.OnNew := Value ;
  321. end;
  322.  
  323. procedure TtiTreeViewPlus.SetOnSave(const Value: TNotifyEvent);
  324. begin
  325.   FTV.OnSave := Value ;
  326. end;
  327.  
  328. procedure TtiTreeViewPlus.SetSplitterPos(const Value: integer);
  329. begin
  330. //  FSplitter.Left := Value ;
  331.   FTV.Width := Value ;
  332. end;
  333.  
  334. procedure TtiTreeViewPlus.UpdateNodeText(const psValue: string);
  335. begin
  336.   FTV.UpdateNodeText( psValue ) ;
  337. end;
  338.  
  339. function TtiTreeViewPlus.GetSelected: TTreeNode;
  340. begin
  341.   result := FTV.Selected ;
  342. end;
  343.  
  344. procedure TtiTreeViewPlus.SetSelected(pData: TTreeNode);
  345. begin
  346.   FTV.Selected := pData ;
  347. end;
  348.  
  349. procedure TtiTreeViewPlus.FullExpand;
  350. begin
  351.   FTV.FullExpand ;
  352. end;
  353.  
  354. procedure TtiTreeViewPlus.DoNew ;
  355. begin
  356.   FTV.DoNew ;
  357. end;
  358.  
  359. procedure TtiTreeViewPlus.DoDelete ;
  360. begin
  361.   FTV.DoDelete ;
  362. end;
  363.  
  364. end.
  365.