home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 1999 February / DPPCPRO0299.ISO / February / Delphi / Install / DATA.Z / PRJEXPL.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-06-11  |  28.0 KB  |  992 lines

  1. { Project Explorer
  2.  
  3.   This demo shows how to use many of the new APIs available in the Tools API.
  4.  
  5.   What it demos:
  6.     How to get notified when certain events occur in Delphi.
  7.     Add a menu item to an arbitrary location in the Delphi main menu tree.
  8.     How to obtain and use interfaces to the for the form designer.
  9.     Accessing components on the form and get and set properties.
  10. }
  11.  
  12. unit PrjExpl;
  13.  
  14. interface
  15.  
  16. uses
  17.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  18.   IniFiles, ComCtrls, EditIntf, ExptIntf, ToolIntf, Menus;
  19.  
  20. type
  21.   TProjectExplorer = class(TForm)
  22.     TreeView1: TTreeView;
  23.     StatusBar1: TStatusBar;
  24.     PopupMenu1: TPopupMenu;
  25.     EditItem: TMenuItem;
  26.     SelectItem: TMenuItem;
  27.     N1: TMenuItem;
  28.     RenameItem: TMenuItem;
  29.     DeleteItem: TMenuItem;
  30.     procedure FormCreate(Sender: TObject);
  31.     procedure FormDestroy(Sender: TObject);
  32.     procedure TreeView1Expanding(Sender: TObject; Node: TTreeNode;
  33.       var AllowExpansion: Boolean);
  34.     procedure TreeView1KeyPress(Sender: TObject; var Key: Char);
  35.     procedure TreeView1Change(Sender: TObject; Node: TTreeNode);
  36.     procedure TreeView1Editing(Sender: TObject; Node: TTreeNode;
  37.       var AllowEdit: Boolean);
  38.     procedure TreeView1Edited(Sender: TObject; Node: TTreeNode;
  39.       var NewText: string);
  40.     procedure EditItemClick(Sender: TObject);
  41.     procedure PopupMenu1Popup(Sender: TObject);
  42.     procedure RenameItemClick(Sender: TObject);
  43.     procedure SelectItemClick(Sender: TObject);
  44.     procedure DeleteItemClick(Sender: TObject);
  45.   private
  46.     procedure SaveWindowState(Desktop: TIniFile);
  47.     procedure LoadWindowState(Desktop: TIniFile);
  48.   public
  49.     { Public declarations }
  50.   end;
  51.  
  52.   TFormBrowserExpert = class;
  53.   TModuleNotifier = class;
  54.  
  55.   TModuleEntry = class
  56.     FileName: string;
  57.     UnitName: string;
  58.     FormName: string;
  59.     ModuleNode: TTreeNode;
  60.     FormNode: TTreeNode;
  61.     ModuleInterface: TIModuleInterface;
  62.     ModuleNotifier: TModuleNotifier;
  63.     FormHandle: Pointer;
  64.     constructor Create(const AFileName, AUnitName, AFormName: string);
  65.     destructor Destroy; override;
  66.   end;
  67.  
  68.   TAddInNotifier = class(TIAddInNotifier)
  69.   private
  70.     FFormBrowser: TFormBrowserExpert;
  71.   public
  72.     constructor create(AFormBrowser: TFormBrowserExpert);
  73.     procedure FileNotification(NotifyCode: TFileNotification;
  74.       const FileName: string; var Cancel: Boolean); override;
  75.   end;
  76.  
  77.   TModuleNotifier = class(TIModuleNotifier)
  78.   private
  79.     FFormBrowser: TFormBrowserExpert;
  80.     FModuleEntry: TModuleEntry;
  81.   public
  82.     constructor Create(AFormBrowser: TFormBrowserExpert; ModuleEntry: TModuleEntry);
  83.     destructor Destroy; override;
  84.     procedure Notify(NotifyCode: TNotifyCode); override;
  85.     procedure ComponentRenamed(ComponentHandle: Pointer;
  86.       const OldName, NewName: string); override;
  87.   end;
  88.  
  89.   TProjectNotifier = class(TIModuleNotifier)
  90.   private
  91.     FFormBrowser: TFormBrowserExpert;
  92.   public
  93.     constructor Create(AFormBrowser: TFormBrowserExpert);
  94.     procedure Notify(NotifyCode: TNotifyCode); override;
  95.     procedure ComponentRenamed(ComponentHandle: Pointer;
  96.       const OldName, NewName: string); override;
  97.   end;
  98.  
  99.   TFormBrowserExpert = class(TIExpert)
  100.   private
  101.     ViewProjectExplorerItem: TIMenuItemIntf;
  102.     AddInNotifier: TAddInNotifier;
  103.     ProjectNotifier: TProjectNotifier;
  104.     ProjectModule: TIModuleInterface;
  105.     ModuleList: TStringList;
  106.   public
  107.     constructor Create;
  108.     destructor Destroy; override;
  109.     function EnumProc(const FileName, UnitName, FormName: string): Boolean;
  110.     procedure OpenProject(const FileName: string);
  111.     procedure CloseProject;
  112.     procedure AddedToProject(const FileName: string);
  113.     procedure RemovedFromProject(const FileName: string);
  114.     procedure LoadDesktop(const FileName: string);
  115.     procedure SaveDesktop(const FileName: string);
  116.     procedure ViewProjectExplorerClick(Sender: TIMenuItemIntf);
  117.     function GetName: string; override;
  118.     function GetStyle: TExpertStyle; override;
  119.     function GetIDString: string; override;
  120.   end;
  121.  
  122. var
  123.   ProjectExplorer: TProjectExplorer = nil;
  124.   FormBrowserExpert: TFormBrowserExpert = nil;
  125.  
  126. function InitExpert(ToolServices: TIToolServices; RegisterProc: TExpertRegisterProc;
  127.   var Terminate: TExpertTerminateProc): Boolean; stdcall;
  128.  
  129. implementation
  130.  
  131. {$R *.DFM}
  132. {$R *.RES}
  133. {$I PRJEXPL.INC}
  134.  
  135. function GetComponentName(Component: TIComponentInterface): string;
  136. begin
  137.   Result := '';
  138.   Component.GetPropValueByName('Name', Result);  
  139. end;
  140.  
  141. procedure SetComponentName(Component: TIComponentInterface; const Value: string);
  142. begin
  143.   Component.SetPropByName('Name', Value);
  144. end;
  145.  
  146. procedure CreateForm(InstanceClass: TComponentClass; var Reference);
  147. begin
  148.   if TComponent(Reference) = nil then
  149.   begin
  150.     TComponent(Reference) := TComponent(InstanceClass.NewInstance);
  151.     try
  152.       TComponent(Reference).Create(Application);
  153.     except
  154.       TComponent(Reference) := nil;
  155.       TComponent(Reference).Free;
  156.       raise
  157.     end;
  158.   end;
  159. end;
  160.  
  161. { TModuleEntry }
  162.  
  163. constructor TModuleEntry.Create(const AFileName, AUnitName, AFormName: string);
  164. begin
  165.   FileName := AFileName;
  166.   UnitName := AUnitName;
  167.   FormName := AFormName;
  168. end;
  169.  
  170. destructor TModuleEntry.Destroy;
  171. begin
  172.   ModuleNotifier.Free;
  173.   ModuleInterface.Free;
  174.   inherited Destroy;
  175. end;
  176.  
  177. { TAddInNotifier }
  178.  
  179. constructor TAddInNotifier.Create(AFormBrowser: TFormBrowserExpert);
  180. begin
  181.   inherited Create;
  182.   FFormBrowser := AFormBrowser;
  183. end;
  184.  
  185. procedure TAddInNotifier.FileNotification(NotifyCode: TFileNotification;
  186.   const FileName: string; var Cancel: Boolean);
  187. begin
  188.   if ProjectExplorer <> nil then
  189.     if NotifyCode = fnProjectOpened then
  190.       FFormBrowser.OpenProject(FileName)
  191.     else if NotifyCode = fnAddedToProject then
  192.       FFormBrowser.AddedToProject(FileName)
  193.     else if NotifyCode = fnRemovedFromProject then
  194.       FFormBrowser.RemovedFromProject(FileName);  
  195.   if NotifyCode = fnProjectDesktopLoad then
  196.     FFormBrowser.LoadDesktop(FileName)
  197.   else if NotifyCode = fnProjectDesktopSave then
  198.     FFormBrowser.SaveDesktop(FileName);
  199. end;
  200.  
  201. function FindNode(TreeView: TCustomTreeView; Node: TTreeNode;
  202.   ComponentHandle: Pointer): TTreeNode;
  203.  
  204.   function SearchNodes(Node: TTreeNode): TTreeNode;
  205.   var
  206.     ChildNode: TTreeNode;
  207.   begin
  208.     Result := nil;
  209.     if Node.Data = ComponentHandle then
  210.       Result := Node
  211.     else
  212.     begin
  213.       ChildNode := Node.GetFirstChild;
  214.       while ChildNode <> nil do
  215.       begin
  216.         Result := SearchNodes(ChildNode);
  217.         if Result <> nil then
  218.           Break
  219.         else ChildNode := Node.GetNextChild(ChildNode);
  220.       end;
  221.     end;
  222.   end;
  223.  
  224. begin
  225.   if Node = nil then Node := TTreeView(TreeView).Items.GetFirstNode;
  226.   Result := SearchNodes(Node);
  227. end;
  228.  
  229. { TModuleNotifier }
  230.  
  231. constructor TModuleNotifier.Create(AFormBrowser: TFormBrowserExpert; ModuleEntry: TModuleEntry);
  232. begin
  233.   inherited Create;
  234.   FFormBrowser := AFormBrowser;
  235.   FModuleEntry := ModuleEntry;
  236.   FModuleEntry.ModuleInterface.AddNotifier(Self);
  237. end;
  238.  
  239. destructor TModuleNotifier.Destroy;
  240. begin
  241.   with FModuleEntry do
  242.   begin
  243.     ModuleInterface.RemoveNotifier(Self);
  244.     ModuleNotifier := nil;
  245.     ModuleInterface := nil;
  246.     FormHandle := nil;
  247.   end;
  248.   inherited Destroy;
  249. end;
  250.  
  251. procedure TModuleNotifier.Notify(NotifyCode: TNotifyCode);
  252. begin
  253.   if NotifyCode = ncModuleDeleted then
  254.   begin
  255.     with FModuleEntry do
  256.       if FormNode <> nil then
  257.       begin
  258.         FormNode.DeleteChildren;
  259.         FormNode.HasChildren := True;
  260.       end;
  261.     Free;
  262.   end;
  263. end;
  264.  
  265. procedure TModuleNotifier.ComponentRenamed(ComponentHandle: Pointer;
  266.   const OldName, NewName: string);
  267. var
  268.   Component, ParentComponent: TIComponentInterface;
  269.   Node, ParentNode: TTreeNode;
  270. begin
  271.   try
  272.     Node := nil;
  273.     with FModuleEntry do
  274.       if ComponentHandle = FormHandle then
  275.         Node := FormNode
  276.       else Node := FindNode(FormNode.TreeView, FormNode, ComponentHandle);
  277.     if (Node <> nil) and (NewName <> '') then
  278.       Node.Text := NewName
  279.     else if (Node <> nil) and (NewName = '') then
  280.       Node.Free
  281.     else if (Node = nil) and (NewName <> '') then
  282.       with FModuleEntry.ModuleInterface.GetFormInterface do
  283.       try
  284.         Component := GetComponentFromHandle(ComponentHandle);
  285.         if Component <> nil then
  286.           try
  287.             ParentNode := FModuleEntry.FormNode;
  288.             if Component.IsTControl then
  289.             begin
  290.               ParentComponent := GetCreateParent;
  291.               try
  292.                 if ParentComponent.GetComponentHandle <> FModuleEntry.FormHandle then
  293.                   ParentNode := FindNode(FModuleEntry.FormNode.TreeView,
  294.                     FModuleEntry.FormNode, ParentComponent.GetComponentHandle);
  295.               finally
  296.                 ParentComponent.Free;
  297.               end;
  298.             end;
  299.             if ParentNode <> nil then
  300.               ParentNode.Owner.AddChildObject(ParentNode, NewName,
  301.                 ComponentHandle).MakeVisible;
  302.           finally
  303.             Component.Free;
  304.           end;
  305.       finally
  306.         Free;
  307.       end;
  308.   except
  309.   end;
  310. end;
  311.  
  312. { TProjectNotifier }
  313.  
  314. constructor TProjectNotifier.Create(AFormBrowser: TFormBrowserExpert);
  315. begin
  316.   inherited Create;
  317.   FFormBrowser := AFormBrowser;
  318. end;
  319.  
  320. procedure TProjectNotifier.Notify(NotifyCode: TNotifyCode);
  321. begin
  322.   if NotifyCode = ncModuleDeleted then
  323.   begin
  324.     if ProjectExplorer <> nil then ProjectExplorer.Hide;
  325.     FFormBrowser.CloseProject;
  326.   end;
  327. end;
  328.  
  329. procedure TProjectNotifier.ComponentRenamed(ComponentHandle: Pointer;
  330.   const OldName, NewName: string);
  331. begin
  332. //  Nothing to do here but needs to be overridden anyway
  333. end;
  334.  
  335. { TFormBrowserExpert }
  336.  
  337. constructor TFormBrowserExpert.Create;
  338. var
  339.   MainMenu: TIMainMenuIntf;
  340.   ProjManMenu: TIMenuItemIntf;
  341.   ViewMenu: TIMenuItemIntf;
  342.   MenuItems: TIMenuItemIntf;
  343. begin
  344.   inherited Create;
  345.   ModuleList := TStringList.Create;
  346.   MainMenu := ToolServices.GetMainMenu;
  347.   if MainMenu <> nil then
  348.   try
  349.     MenuItems := MainMenu.GetMenuItems;
  350.     if MenuItems <> nil then
  351.     try
  352.       ProjManMenu := MainMenu.FindMenuItem('ViewPrjMgrItem');
  353.       if ProjManMenu <> nil then
  354.       try
  355.         ViewMenu := ProjManMenu.GetParent;
  356.         if ViewMenu <> nil then
  357.         try
  358.           ViewProjectExplorerItem := ViewMenu.InsertItem(ProjManMenu.GetIndex + 1,
  359.             LoadStr(sMenuItemCaption), 'ViewProjectExplorerItem', '', 0, 0, 0,
  360.             [mfVisible, mfEnabled], ViewProjectExplorerClick);
  361.         finally
  362.           ViewMenu.Free;
  363.         end;
  364.       finally
  365.         ProjManMenu.Free;
  366.       end;
  367.     finally
  368.       MenuItems.Free;
  369.     end;
  370.   finally
  371.     MainMenu.Free;
  372.   end;
  373.   AddInNotifier := TAddInNotifier.Create(Self);
  374.   ToolServices.AddNotifier(AddInNotifier);
  375. end;
  376.  
  377. destructor TFormBrowserExpert.Destroy;
  378. begin
  379.   ToolServices.RemoveNotifier(AddInNotifier);
  380.   CloseProject;
  381.   ViewProjectExplorerItem.Free;
  382.   AddInNotifier.Free;
  383.   ModuleList.Free;
  384.   inherited Destroy;
  385. end;
  386.  
  387. function TFormBrowserExpert.EnumProc(const FileName, UnitName,
  388.   FormName: string): Boolean;
  389. begin
  390.   ModuleList.AddObject(UnitName,
  391.     TModuleEntry.Create(FileName, UnitName, FormName));
  392.   Result := True;
  393. end;
  394.  
  395. function ProjEnumProc(Param: Pointer; const FileName, UnitName,
  396.   FormName: string): Boolean; stdcall;
  397. begin
  398.   try
  399.     Result := TFormBrowserExpert(Param).EnumProc(FileName, UnitName, FormName);
  400.   except
  401.     Result := False;
  402.   end;
  403. end;
  404.  
  405. procedure TFormBrowserExpert.OpenProject(const FileName: string);
  406. var
  407.   I: Integer;
  408.   Node: TTreeNode;
  409. begin
  410.   CloseProject;
  411.   ToolServices.EnumProjectUnits(ProjEnumProc, Self);
  412.   ProjectModule := ToolServices.GetModuleInterface(FileName);
  413.   if ProjectModule <> nil then
  414.   begin
  415.     ProjectNotifier := TProjectNotifier.Create(Self);
  416.     ProjectModule.AddNotifier(ProjectNotifier);
  417.     if (ProjectExplorer <> nil) and (ModuleList.Count > 0) then
  418.       with ProjectExplorer, ToolServices do
  419.       begin
  420.         with TModuleEntry(ModuleList.Objects[0]) do
  421.         begin
  422.           Node := TreeView1.Items.Add(nil, UnitName);
  423.           ModuleNode := Node;
  424.         end;
  425.         for I := 1 to ModuleList.Count - 1 do
  426.           with TModuleEntry(ModuleList.Objects[I]) do
  427.             if UnitName <> '' then
  428.             begin
  429.               ModuleNode := TreeView1.Items.AddChildObject(Node, UnitName,
  430.                 ModuleList.Objects[I]);
  431.               if FormName <> '' then
  432.               begin
  433.                 FormNode := TreeView1.Items.AddChildObject(ModuleNode, FormName,
  434.                   ModuleList.Objects[I]);
  435.                 FormNode.HasChildren := True;
  436.               end;
  437.             end;
  438.         Node.Expanded := True;
  439.       end;
  440.   end;
  441. end;
  442.  
  443. procedure TFormBrowserExpert.CloseProject;
  444. var
  445.   I: Integer;
  446. begin
  447.   if ProjectModule <> nil then
  448.   begin
  449.     if ProjectExplorer <> nil then
  450.       ProjectExplorer.TreeView1.Items.Clear;
  451.     for I := 0 to ModuleList.Count - 1 do
  452.       TModuleEntry(ModuleList.Objects[I]).Free;
  453.     ModuleList.Clear;
  454.     ProjectModule.RemoveNotifier(ProjectNotifier);
  455.     ProjectNotifier.Free;
  456.     ProjectModule.Free;
  457.     ProjectNotifier := nil;
  458.     ProjectModule := nil;
  459.   end;
  460. end;
  461.  
  462. function FindNewProjectItem(Param: Pointer; const ModFileName, ModUnitName,
  463.   ModFormName: string): Boolean; stdcall;
  464. begin
  465.   try
  466.     with TModuleEntry(Param) do
  467.       if AnsiCompareText(FileName, ModFileName) = 0 then
  468.       begin
  469.         Result := False;
  470.         UnitName := ModUnitName;
  471.         FormName := ModFormName;
  472.       end else Result := True;
  473.   except
  474.     Result := False;
  475.   end;
  476. end;
  477.  
  478. procedure TFormBrowserExpert.AddedToProject(const FileName: string);
  479. var
  480.   NewModuleEntry: TModuleEntry;
  481. begin
  482.   if ModuleList.Count > 0 then
  483.   begin
  484.     NewModuleEntry := TModuleEntry.Create(FileName, '', '');
  485.     ToolServices.EnumProjectUnits(FindNewProjectItem, NewModuleEntry);
  486.     ModuleList.AddObject(FileName, NewModuleEntry);
  487.     if ProjectExplorer <> nil then
  488.       with ProjectExplorer, NewModuleEntry do
  489.       begin
  490.         ModuleNode :=
  491.           TreeView1.Items.AddChildObject(TModuleEntry(ModuleList.Objects[0]).ModuleNode,
  492.           NewModuleEntry.UnitName, NewModuleEntry);
  493.         if FormName <> '' then
  494.         begin
  495.           FormNode := TreeView1.Items.AddChildObject(NewModuleEntry.ModuleNode,
  496.             FormName, NewModuleEntry);
  497.           FormNode.HasChildren := True;
  498.         end;
  499.       end;
  500.   end;
  501. end;
  502.  
  503. procedure TFormBrowserExpert.RemovedFromProject(const FileName: string);
  504. var
  505.   I: Integer;
  506.   ModuleEntry: TModuleEntry;
  507. begin
  508.   for I := 0 to ModuleList.Count - 1 do
  509.   begin
  510.     ModuleEntry := TModuleEntry(ModuleList.Objects[I]);
  511.     if AnsiCompareText(ModuleEntry.FileName, FileName) = 0 then
  512.     begin
  513.       ModuleList.Delete(I);
  514.       ModuleEntry.ModuleNode.Free;
  515.       ModuleEntry.Free;
  516.       Break;
  517.     end;
  518.   end;
  519. end;
  520.  
  521. const
  522.   isProjectFormViewer = 'ProjectExplorer';
  523.  
  524.   ivCreate = 'Create';
  525.   ivVisible = 'Visible';
  526.   ivState = 'State';
  527.   ivTop = 'Top';
  528.   ivLeft = 'Left';
  529.   ivWidth = 'Width';
  530.   ivHeight = 'Height';
  531.   ivMaxLeft = 'MaxLeft';
  532.   ivMaxTop = 'MaxTop';
  533.   ivMaxWidth = 'MaxWidth';
  534.   ivMaxHeight = 'MaxHeight';
  535.  
  536. procedure TFormBrowserExpert.LoadDesktop(const FileName: string);
  537. var
  538.   Desktop: TIniFile;
  539. begin
  540.   Desktop := TIniFile.Create(FileName);
  541.   try
  542.     if DeskTop.ReadBool(isProjectFormViewer, ivCreate, False) then
  543.     begin
  544.       CreateForm(TProjectExplorer, ProjectExplorer);
  545.       ProjectExplorer.LoadWindowState(Desktop);
  546.     end else if ProjectExplorer <> nil then ProjectExplorer.Hide;
  547.   finally
  548.     Desktop.Free;
  549.   end;
  550. end;
  551.  
  552. procedure TFormBrowserExpert.SaveDesktop(const FileName: string);
  553. var
  554.   Desktop: TIniFile;
  555. begin
  556.   Desktop := TIniFile.Create(FileName);
  557.   try
  558.     if ProjectExplorer <> nil then ProjectExplorer.SaveWindowState(Desktop);
  559.   finally
  560.     Desktop.Free;
  561.   end;
  562. end;
  563.  
  564. procedure TFormBrowserExpert.ViewProjectExplorerClick(Sender: TIMenuItemIntf);
  565. begin
  566.   CreateForm(TProjectExplorer, ProjectExplorer);
  567.   ProjectExplorer.Show;
  568. end;
  569.  
  570. function TFormBrowserExpert.GetName: string;
  571. begin
  572.   Result := LoadStr(sExpertName);
  573. end;
  574.  
  575. function TFormBrowserExpert.GetStyle: TExpertStyle;
  576. begin
  577.   Result := esAddIn;
  578. end;
  579.  
  580. function TFormBrowserExpert.GetIDString: string;
  581. begin
  582.   Result := 'Borland.ProjectExplorer';
  583. end;
  584.  
  585. { TProjectExplorer }
  586.  
  587. procedure TProjectExplorer.FormCreate(Sender: TObject);
  588. var
  589.   ProjectName: string;
  590. begin
  591.   ProjectName := ToolServices.GetProjectName;
  592.   if ProjectName <> '' then
  593.     FormBrowserExpert.OpenProject(ProjectName);
  594. end;
  595.  
  596. procedure TProjectExplorer.FormDestroy(Sender: TObject);
  597. begin
  598.   ProjectExplorer := nil;
  599. end;
  600.  
  601. function OpenModule(ModuleEntry: TModuleEntry; Ask: Boolean): Boolean;
  602. begin
  603.   with ModuleEntry do
  604.   begin
  605.     Result := False;
  606.     if ModuleInterface = nil then
  607.     begin
  608.       if not ToolServices.IsFileOpen(FileName) then
  609.         if not Ask or (MessageDlg(Format(LoadStr(sFileNotLoaded), [FileName]),
  610.           mtConfirmation, [mbYes, mbNo], 0) = mrYes) then
  611.         begin
  612.           if not ToolServices.OpenFile(FileName) then Exit;
  613.         end else Exit;
  614.       ModuleInterface := ToolServices.GetModuleInterface(FileName);
  615.       ModuleNotifier := TModuleNotifier.Create(FormBrowserExpert, ModuleEntry);
  616.       Result := True;
  617.     end else Result := True;
  618.   end;
  619. end;
  620.  
  621. procedure AddChildControl(Node: TTreeNode; IsRoot: Boolean; Component: TIComponentInterface); forward;
  622.  
  623. function GetChildProc(Param: Pointer; Component: TIComponentInterface): Boolean; stdcall;
  624. begin
  625.   try
  626.     try
  627.       AddChildControl(TTreeNode(Param), False, Component);
  628.     finally
  629.       Component.Free; // Release the component interface.
  630.     end;    
  631.     Result := True;
  632.   except
  633.     Result := False;
  634.   end;
  635. end;
  636.  
  637. procedure AddChildControl(Node: TTreeNode; IsRoot: Boolean; Component: TIComponentInterface);
  638. var
  639.   ChildNode: TTreeNode;
  640.   Control: TIComponentInterface;
  641.   I: Integer;
  642. begin
  643.   if IsRoot then
  644.     ChildNode := Node
  645.   else ChildNode := ProjectExplorer.TreeView1.Items.AddChildObject(Node,
  646.     GetComponentName(Component), Component.GetComponentHandle);
  647.   Component.GetChildren(ChildNode, GetChildProc);
  648. end;
  649.  
  650. procedure TProjectExplorer.TreeView1Expanding(Sender: TObject;
  651.   Node: TTreeNode; var AllowExpansion: Boolean);
  652. var
  653.   ModuleEntry: TModuleEntry;
  654.   Component: TIComponentInterface;
  655.   I: Integer;
  656. begin
  657.   if Node.Level = 2 then
  658.   begin
  659.     ModuleEntry := TModuleEntry(Node.Data);
  660.     with ModuleEntry do
  661.     begin
  662.       if ModuleInterface = nil then
  663.         if OpenModule(ModuleEntry, True) then
  664.         begin
  665.           TreeView1.Items.BeginUpdate;
  666.           try
  667.             with ModuleInterface.GetFormInterface do
  668.             try
  669.               Component := GetFormComponent;
  670.               try
  671.                 FormHandle := Component.GetComponentHandle;
  672.                 AddChildControl(Node, True, Component);
  673.               finally
  674.                 Component.Free;
  675.               end;
  676.             finally
  677.               Free;
  678.             end;
  679.           finally
  680.             TreeView1.Items.EndUpdate;
  681.           end;
  682.           if Node.GetFirstChild = nil then
  683.             Node.HasChildren := False;
  684.         end;
  685.     end;
  686.   end;
  687. end;
  688.  
  689. procedure TProjectExplorer.TreeView1KeyPress(Sender: TObject; var Key: Char);
  690. begin
  691.   with TreeView1 do
  692.     if not IsEditing and (Selected <> nil) and (Selected.Level < 3) and
  693.       (Key = '*') then Key := #0;
  694. end;
  695.  
  696. function GetModuleEntry(Node: TTreeNode): TModuleEntry;
  697. begin
  698.   while Node.Level > 2 do
  699.     Node := Node.Parent;
  700.   Result := TModuleEntry(Node.Data);
  701. end;
  702.  
  703. function GetNodeComponent(Node: TTreeNode): TIComponentInterface;
  704. var
  705.   ModuleEntry: TModuleEntry;
  706.   FormInterface: TIFormInterface;
  707.   Handle: Pointer;
  708. begin
  709.   Result := nil;
  710.   if (Node <> nil) and (Node.Level >= 2) then
  711.   begin
  712.     ModuleEntry := GetModuleEntry(Node);
  713.     if ModuleEntry.ModuleInterface <> nil then
  714.     begin
  715.       FormInterface := ModuleEntry.ModuleInterface.GetFormInterface;
  716.       try
  717.         if Node.Level = 2 then
  718.           Handle := ModuleEntry.FormHandle
  719.         else Handle := Node.Data;
  720.         Result := FormInterface.GetComponentFromHandle(Handle);
  721.       finally
  722.         FormInterface.Free;
  723.       end;
  724.     end;
  725.   end;
  726. end;
  727.  
  728. procedure TProjectExplorer.TreeView1Change(Sender: TObject; Node: TTreeNode);
  729. var
  730.   ModuleEntry: TModuleEntry;
  731.   Component: TIComponentInterface;
  732. begin
  733.   if Node = nil then Exit;
  734.   if Node.Level > 2 then
  735.   begin
  736.     Component := GetNodeComponent(Node);
  737.     if Component <> nil then
  738.     try
  739.       StatusBar1.SimpleText := Component.GetComponentType;
  740.     finally
  741.       Component.Free;
  742.     end else StatusBar1.SimpleText := '';
  743.   end else if (Node.Level = 1) or (Node.Level = 2) then
  744.   begin
  745.     ModuleEntry := TModuleEntry(Node.Data);
  746.     if Node.Level = 1 then
  747.       StatusBar1.SimpleText := ModuleEntry.FileName
  748.     else StatusBar1.SimpleText := ChangeFileExt(ModuleEntry.FileName, '.dfm');
  749.   end else if Node.Level = 0 then
  750.     if FormBrowserExpert.ProjectModule <> nil then
  751.       with FormBrowserExpert.ProjectModule.GetEditorInterface do
  752.       try
  753.         StatusBar1.SimpleText := FileName;
  754.       finally
  755.         Free;
  756.       end;
  757. end;
  758.  
  759. procedure TProjectExplorer.TreeView1Editing(Sender: TObject; Node: TTreeNode;
  760.   var AllowEdit: Boolean);
  761. var
  762.   Component: TIComponentInterface;
  763. begin
  764.   if Node <> nil then
  765.   begin
  766.     Component := GetNodeComponent(Node);
  767.     try
  768.       if (Node.Level < 2) or (Component = nil) then
  769.         AllowEdit := False;
  770.     finally
  771.       Component.Free;
  772.     end;
  773.   end;        
  774. end;
  775.  
  776. procedure TProjectExplorer.TreeView1Edited(Sender: TObject; Node: TTreeNode;
  777.   var Newtext: string);
  778. var
  779.   Component: TIComponentInterface;
  780. begin
  781.   if Node.Level >= 2 then
  782.   begin
  783.     Component := GetNodeComponent(Node);
  784.     try
  785.       SetComponentName(Component, NewText);
  786.     finally
  787.       Component.Free;
  788.     end;
  789.     NewText := Node.Text;
  790.   end;
  791. end;
  792.  
  793. procedure TProjectExplorer.PopupMenu1Popup(Sender: TObject);
  794. var
  795.   Node: TTreeNode;
  796.   NodeComponent: TIComponentInterface;
  797. begin
  798.   Node := TreeView1.Selected;
  799.   EditItem.Enabled := Node <> nil;
  800.   NodeComponent := GetNodeComponent(Node);
  801.   try
  802.     SelectItem.Enabled := (Node <> nil) and (Node.Level > 1) and
  803.       (NodeComponent <> nil);
  804.     RenameItem.Enabled := (Node <> nil) and (Node.Level > 1) and
  805.       (NodeComponent <> nil);
  806.     DeleteItem.Enabled := (Node <> nil) and (Node.Level > 2) and
  807.       (NodeComponent <> nil);
  808.   finally
  809.     NodeComponent.Free;
  810.   end;
  811. end;
  812.  
  813. procedure TProjectExplorer.EditItemClick(Sender: TObject);
  814. var
  815.   Node: TTreeNode;
  816.   ModuleEntry: TModuleEntry;
  817.   Component: TIComponentInterface;
  818. begin
  819.   Node := TreeView1.Selected;
  820.   if Node <> nil then
  821.     if Node.Level >= 2 then
  822.     begin
  823.       ModuleEntry := GetModuleEntry(Node);
  824.       Component := GetNodeComponent(Node);
  825.       try
  826.         if (Node.Level = 2) and (Component = nil) then
  827.         begin
  828.           if OpenModule(ModuleEntry, False) then
  829.             ModuleEntry.ModuleInterface.ShowForm;
  830.         end else if Component <> nil then
  831.         begin
  832.           Component.Select;
  833.           Component.Focus;
  834.         end;
  835.       finally
  836.         Component.Free;
  837.       end;
  838.     end else if Node.Level = 1 then
  839.     begin
  840.       ModuleEntry := TModuleEntry(Node.Data);
  841.       if OpenModule(ModuleEntry, False) then
  842.         ModuleEntry.ModuleInterface.ShowSource;
  843.     end else if Node.Level = 0 then
  844.       if FormBrowserExpert.ProjectModule <> nil then
  845.         FormBrowserExpert.ProjectModule.ShowSource;
  846. end;
  847.  
  848. procedure TProjectExplorer.SelectItemClick(Sender: TObject);
  849. var
  850.   Node: TTreeNode;
  851.   ModuleEntry: TModuleEntry;
  852.   Component: TIComponentInterface;
  853. begin
  854.   Node := TreeView1.Selected;
  855.   if Node <> nil then
  856.     if Node.Level >= 2 then
  857.     begin
  858.       Component := GetNodeComponent(Node);
  859.       try
  860.         Component.Select;
  861.       finally
  862.         Component.Free;
  863.       end;
  864.     end;
  865. end;
  866.  
  867. procedure TProjectExplorer.RenameItemClick(Sender: TObject);
  868. var
  869.   Node: TTreeNode;
  870. begin
  871.   Node := TreeView1.Selected;
  872.   if Node <> nil then Node.EditText;
  873. end;
  874.  
  875. procedure TProjectExplorer.DeleteItemClick(Sender: TObject);
  876. var
  877.   Node: TTreeNode;
  878.   Component: TIComponentInterface;
  879. begin
  880.   Node := TreeView1.Selected;
  881.   if Node <> nil then
  882.     if Node.Level > 2 then
  883.     begin
  884.       Component := GetNodeComponent(Node);
  885.       try
  886.         Component.Delete;
  887.       finally
  888.         Component.Free;
  889.       end;
  890.     end;
  891. end;
  892.  
  893. procedure TProjectExplorer.SaveWindowState(Desktop: TIniFile);
  894. var
  895.   WindowPlacement: TWindowPlacement;
  896. begin
  897.   if Visible then with Desktop do
  898.   begin
  899.     WriteBool(isProjectFormViewer, ivCreate, True);
  900.     WriteBool(isProjectFormViewer, ivVisible, Visible);
  901.     WriteInteger(isProjectFormViewer, ivState, Ord(WindowState));
  902.  
  903.     if WindowState in [wsMinimized, wsMaximized] then  { 3.1 only }
  904.     begin
  905.       WindowPlacement.length := SizeOf(WindowPlacement);
  906.       GetWindowPlacement(Handle, @WindowPlacement);
  907.       with WindowPlacement.rcNormalPosition do
  908.       begin
  909.         WriteInteger(isProjectFormViewer, ivLeft, left);
  910.         WriteInteger(isProjectFormViewer, ivTop, top);
  911.         WriteInteger(isProjectFormViewer, ivWidth, right - left);
  912.         WriteInteger(isProjectFormViewer, ivHeight, bottom - top);
  913.         WriteInteger(isProjectFormViewer, ivMaxLeft, WindowPlacement.ptMaxPosition.x);
  914.         WriteInteger(isProjectFormViewer, ivMaxTop, WindowPlacement.ptMaxPosition.y);
  915.         if WindowState = wsMaximized then
  916.         begin
  917.           WriteInteger(isProjectFormViewer, ivMaxWidth, Width);
  918.           WriteInteger(isProjectFormViewer, ivMaxHeight, Height);
  919.         end;
  920.       end;
  921.     end
  922.     else
  923.     begin
  924.       WriteInteger(isProjectFormViewer, ivLeft, Left);
  925.       WriteInteger(isProjectFormViewer, ivTop, Top);
  926.       WriteInteger(isProjectFormViewer, ivWidth, Width);
  927.       WriteInteger(isProjectFormViewer, ivHeight, Height);
  928.     end;
  929.   end;
  930. end;
  931.  
  932. procedure TProjectExplorer.LoadWindowState(Desktop: TIniFile);
  933. var
  934.   X, Y, W, H: Integer;
  935.   I: Integer;
  936.   Visible: Boolean;
  937.   WindowState: TWindowState;
  938.   WindowPlacement: TWindowPlacement;
  939. begin
  940.   if Desktop.ReadBool(isProjectFormViewer, ivCreate, False) then with Desktop do
  941.   begin
  942.     Position := poDesigned;
  943.     Visible := ReadBool(isProjectFormViewer, ivVisible, False);
  944.     WindowState := TWindowState(ReadInteger(isProjectFormViewer, ivState, Ord(wsNormal)));
  945.     X := ReadInteger(isProjectFormViewer, ivLeft, Left);
  946.     Y := ReadInteger(isProjectFormViewer, ivTop, Top);
  947.     W := ReadInteger(isProjectFormViewer, ivWidth, Width);
  948.     H := ReadInteger(isProjectFormViewer, ivHeight, Height);
  949.  
  950.     with WindowPlacement do
  951.     begin
  952.       length := SizeOf(WindowPlacement);
  953.       rcNormalPosition.left := X;
  954.       rcNormalPosition.top := Y;
  955.       rcNormalPosition.right := X + W;
  956.       rcNormalPosition.bottom := Y + H;
  957.       ptMaxPosition.x := ReadInteger(isProjectFormViewer, ivMaxLeft, -GetSystemMetrics(SM_CXFRAME));
  958.       ptMaxPosition.y := ReadInteger(isProjectFormViewer, ivMaxTop, -GetSystemMetrics(SM_CYFRAME));
  959.       case WindowState of
  960.         wsMinimized: showCmd := SW_SHOWMINIMIZED;
  961.         wsMaximized: showCmd := SW_SHOWMAXIMIZED;
  962.         wsNormal: showCmd := SW_NORMAL;
  963.       end;
  964.       flags := 0;
  965.     end;
  966.     SetWindowPlacement(Handle, @WindowPlacement);
  967.     if WindowState = wsMaximized then
  968.     begin
  969.       W := ReadInteger(isProjectFormViewer, ivMaxWidth, Width);
  970.       H := ReadInteger(isProjectFormViewer, ivMaxHeight, Height);
  971.       SetBounds(Left, Top, W, H);
  972.     end;
  973.     Self.Visible := Visible;
  974.   end;
  975. end;
  976.  
  977. function InitExpert(ToolServices: TIToolServices; RegisterProc: TExpertRegisterProc;
  978.   var Terminate: TExpertTerminateProc): Boolean;
  979. begin
  980.   Result := True;
  981.   try
  982.     ExptIntf.ToolServices := ToolServices;
  983.     Application.Handle := ToolServices.GetParentHandle;
  984.     FormBrowserExpert := TFormBrowserExpert.Create;
  985.     RegisterProc(FormBrowserExpert);
  986.   except
  987.     ToolServices.RaiseException(ReleaseException);
  988.   end;
  989. end;
  990.  
  991. end.
  992.