home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / outlines.zip / CustomDirOutline.pas < prev    next >
Pascal/Delphi Source File  |  1999-09-30  |  11KB  |  429 lines

  1. Unit CustomDirOutline;
  2.  
  3. // This is a small enhancement of the sample TDirectoryOutline
  4. // Changes are:
  5. // 1) Leaf/open/close bitmaps are used as inherited from TOutline
  6. //    instead of being specially loaded. THerefore they can be changed
  7. // 2) Fix to Click method to make root directory selectable
  8. // 3) Added Reload method
  9. // 4) Does not change or use current directory
  10. // 5) Has ChangeToParent, AtRoot, and ChangeToRoot methods
  11. Interface
  12.  
  13. Uses
  14.   SysUtils, Classes, Graphics, StdCtrls, Forms, Dialogs,
  15.   CustomOutline, Outline;
  16.  
  17. type
  18.   TCustomDirOutline=Class(TCustomOutline)
  19.      Protected
  20.         FDirectory:String;
  21.         FDrive:Char;
  22.         FOnChange:TNotifyEvent;
  23.         FLookAhead: boolean;
  24.         Procedure SetDrive(NewDrive:Char);
  25.         Procedure SetDirectory(Const NewDir:String);
  26.         Procedure FillLevel(Node:TOutlineNode);
  27.         Procedure CheckForSomeDirs(Node:TOutlineNode);
  28.         Procedure BuildTree;Virtual;
  29.         Procedure WalkTree(Const Dir:String);
  30.         Procedure SetupShow;Override;
  31.         Procedure BuildOneLevel(ParentLevel:Longint);Virtual;
  32.         Procedure Change;Virtual;
  33.      Public
  34.         Procedure Expand(Index: Longint);Override;
  35.         Procedure SetupComponent;Override;
  36.         Destructor Destroy;Override;
  37.         Procedure Click;Override;
  38.         Procedure Reload;
  39.      Public
  40.         Property Drive:Char read FDrive write SetDrive;
  41.         // Note unlike original TDirOutline, setting this property
  42.         // does *not* allow relative paths.
  43.         Property Directory:String  read FDirectory write SetDirectory;
  44.  
  45.         // Returns true if already at a root dir
  46.         Function AtRoot: boolean;
  47.         // Returns true if could be done
  48.         Function ChangeToParent: boolean;
  49.         Function Parent: string;
  50.         Procedure ChangeToRoot;
  51.  
  52.         Property Lines;
  53.         Property OnChange:TNotifyEvent read FOnChange write FOnChange;
  54.      published
  55.         // If this property is false, all dirs will have a + symbol
  56.         // until they are expanded
  57.         // If true, the control will look into each dir and see if there
  58.         // are any subdirs to correct show or hide the +
  59.         property LookAhead: boolean read FLookAhead write FLookAhead;
  60.   End;
  61.  
  62. Exports TCustomDirOutline, 'User', 'CustomDirOutline.bmp';
  63.  
  64. Implementation
  65.  
  66. // Returns true if already at a root dir
  67. Function TCustomDirOutline.AtRoot: boolean;
  68. Var
  69.   TestString: string;
  70. Begin
  71.   TestString:= Directory;
  72.   System.Delete( TestString, 1, 2 ); // remove x: off the start
  73.  
  74.   Result:= ( TestString='' ) or ( TestString='\' );
  75. End;
  76.  
  77. Function TCustomDirOutline.Parent: string;
  78. Var
  79.   i: longint;
  80. Begin
  81.   Result:= '';
  82.   if AtRoot then
  83.     exit;
  84.   Result:= Directory;
  85.   if Result[ length( Result ) ]='\' then
  86.     System.Delete( Result, length( Result ), 1 );
  87.   for i:= length( Result ) downto 2 do
  88.   begin
  89.     if Result[ i ]='\' then
  90.     begin
  91.       Result:= copy( Result, 1, i );
  92.       exit;
  93.     end;
  94.   end;
  95. End;
  96.  
  97. // Returns true if could be done
  98. Function TCustomDirOutline.ChangeToParent: boolean;
  99. Begin
  100.   Result:= false;
  101.   if AtRoot then
  102.     exit;
  103.   Directory:= Parent;
  104.   Result:= true;
  105. End;
  106.  
  107. Procedure TCustomDirOutline.ChangeToRoot;
  108. Begin
  109.   Directory:= copy( Directory, 1, 3 );
  110. End;
  111.  
  112. Procedure TCustomDirOutline.Change;
  113. Begin
  114.    If FOnChange<>Nil Then FOnChange(Self);
  115. End;
  116.  
  117. // Looks at the path for the given node and adds one directory
  118. // if there is one.
  119. Procedure TCustomDirOutline.CheckForSomeDirs(Node:TOutlineNode);
  120. Var
  121.   Root:ShortString;
  122.   SearchRec: TSearchRec;
  123.   Status:Integer;
  124. Begin
  125.    Node.Clear;
  126.    Root:=Node.FullPath;
  127.    If Root[Length(Root)] In ['\','/'] Then dec(Root[0]);
  128.  
  129.    Status:=FindFirst(Root+'\*.*',faDirectory,SearchRec);
  130.    While Status=0 Do
  131.    Begin
  132.      If SearchRec.Attr And faDirectory = faDirectory Then
  133.      Begin
  134.        If ((SearchRec.Name<>'.')And(SearchRec.Name<>'..')) Then //no .. and .
  135.        Begin
  136.          // Found a directory
  137.          // All we care about is adding one node if needed
  138.          AddChild(Node.Index,SearchRec.Name);
  139.          FindClose( SearchRec );
  140.          exit;
  141.        End;
  142.      End;
  143.      Status:=FindNext(SearchRec);
  144.    End;
  145.  
  146. end;
  147.  
  148. Procedure TCustomDirOutline.FillLevel(Node:TOutlineNode);
  149. Var
  150.   TempIndex:Longint;
  151.   Root:ShortString;
  152.   SearchRec: TSearchRec;
  153.   Status:Integer;
  154.   s,s1:String;
  155. Begin
  156.   // We always start from scratch. So it's up to date.
  157.    Node.Clear;
  158.    Root:=Node.FullPath;
  159.    If Root[Length(Root)] In ['\','/'] Then dec(Root[0]);
  160.  
  161.    Status:=FindFirst(Root+'\*.*',faDirectory,SearchRec);
  162.    While Status=0 Do
  163.    Begin
  164.      If SearchRec.Attr And faDirectory = faDirectory Then
  165.      Begin
  166.        If ((SearchRec.Name<>'.')And(SearchRec.Name<>'..')) Then //no .. and .
  167.        Begin
  168.           If Node.HasItems Then //must sort
  169.           Begin
  170.             TempIndex:=Node.GetFirstChild;
  171.             s:=SearchRec.Name;
  172.             UpcaseStr(s);
  173.             If TempIndex<>-1 Then
  174.             Begin
  175.                  s1:=Items[TempIndex].Text;
  176.                  UpcaseStr(s1);
  177.             End;
  178.             While (TempIndex<>-1)And(s1<s) Do
  179.             Begin
  180.                 TempIndex:=Node.GetNextChild(TempIndex);
  181.                 If TempIndex<>-1 Then
  182.                 Begin
  183.                    s1:=Items[TempIndex].Text;
  184.                    UpcaseStr(s1);
  185.                 End;
  186.             End;
  187.             If TempIndex<>-1 Then Insert(TempIndex, SearchRec.Name)
  188.             Else Add(Node.GetLastChild, SearchRec.Name);
  189.           End
  190.           Else AddChild(Node.Index,SearchRec.Name);
  191.         End;
  192.      End;
  193.      Status:=FindNext(SearchRec);
  194.    End;
  195.  
  196. end;
  197.  
  198.  
  199. Procedure TCustomDirOutline.BuildOneLevel(ParentLevel:Longint);
  200. Var Index:LongInt;
  201.     RootNode:TOutlineNode;
  202.     FList:TList;
  203.     t:longint;
  204. Begin
  205.    FillLevel(Items[ParentLevel]);
  206.  
  207.    RootNode := Items[ParentLevel];
  208.    FList.Create;
  209.    Index:=RootNode.GetFirstChild;
  210.    While Index<>-1 Do
  211.    Begin
  212.         FList.Add(Items[Index]);
  213.         Index:=RootNode.GetNextChild(Index);
  214.    End;
  215.  
  216.    // Depending on look ahead, either look for any directories at the
  217.    // next level to correctly set the +, or
  218.    // go and put dummy entries so the + will always show up
  219.    For t:=0 To FList.Count-1 Do
  220.      if FLookAhead then
  221.        CheckForSomeDirs(TOutlineNode(FList[t]))
  222.      else
  223.        AddChild( TOutlineNode( FList[t] ).Index, 'dummy');
  224.  
  225.    FList.Destroy;
  226. End;
  227.  
  228. Procedure TCustomDirOutline.SetupComponent;
  229. Begin
  230.   Inherited SetupComponent;
  231.   BorderStyle:= bsNone;
  232.   PlusMinusSize.CX:= 14;
  233.   PlusMinusSize.CY:= 14;
  234.   ShowPlusMinus:= False;
  235.   FLookAhead:= false;
  236.   Name:='DirectoryOutline';
  237. End;
  238.  
  239. Destructor TCustomDirOutline.Destroy;
  240. Begin
  241.    Inherited Destroy;
  242. End;
  243.  
  244. Procedure TCustomDirOutline.Click;
  245. Begin
  246.   inherited Click;
  247.   Try
  248.     If SelectedItem=-1 Then
  249.       Beep(1200,400);
  250.     if SelectedItem=1 then
  251.       // Selecting root dir... FullPath will not be quite enough...
  252.       Directory:=FDrive+':\'
  253.     else
  254.       Directory :=Items[SelectedItem].FullPath;
  255.   Except
  256.   End;
  257. End;
  258.  
  259. Procedure TCustomDirOutline.SetDrive(NewDrive:Char);
  260. Begin
  261.    FDrive:=Upcase(NewDrive);
  262.    FDirectory:=FDrive+':\';
  263.    If Not (csLoading In ComponentState) Then
  264.      BuildTree;
  265. End;
  266.  
  267. Procedure TCustomDirOutline.SetDirectory(Const NewDir:String);
  268. Var
  269.   TempPath: ShortString;
  270.   Node:TOutlineNode;
  271.   t:LongInt;
  272.  
  273.   Function FindNode(Node:TOutlineNode):TOutlineNode;
  274.   Var s:String;
  275.       t:LongInt;
  276.       Node1:TOutlineNode;
  277.   Begin
  278.       s:=Node.FullPath;
  279.       UpcaseStr(s);
  280.       If s=TempPath Then
  281.       Begin
  282.           result:=Node;
  283.           exit;
  284.       End;
  285.  
  286.       For t:=0 To Node.ItemCount-1 Do
  287.       Begin
  288.           Node1:=Node.Items[t];
  289.           Node1:=FindNode(Node1);
  290.           If Node1<>Nil Then
  291.           Begin
  292.                Result:=Node1;
  293.                exit;
  294.           End;
  295.       End;
  296.       Result:=Nil;
  297.   End;
  298.  
  299. Begin
  300.   If (NewDir='') Then exit;
  301.  
  302.   If NewDir[ Length( NewDir ) ] In ['\','/'] Then
  303.     Dec( NewDir[0]);
  304.   TempPath := NewDir;
  305.  
  306.   FDirectory:=TempPath;
  307.   If FDirectory[1]<>Drive Then Drive:=FDirectory[1]
  308.   Else
  309.   Begin
  310.       WalkTree(TempPath);
  311.       Change;
  312.   End;
  313.  
  314.   TempPath:=FDirectory;
  315.   UpcaseStr(TempPath);
  316.   For t:=0 To ItemCount-1 Do
  317.   Begin
  318.     Node:=Items[t];
  319.     Node:=FindNode(Node);
  320.     If Node<>Nil Then
  321.       Break;
  322.   End;
  323.   If Node<>Nil Then
  324.     If SelectedNode<>Node Then
  325.       SetAndShowSelectedItem( Node.Index );
  326.  
  327. End;
  328.  
  329. Procedure TCustomDirOutline.SetupShow;
  330. Var CurDir:String;
  331. Begin
  332.   Inherited SetupShow;
  333.  
  334.   If FDrive=#0 Then  //test if unassigned
  335.   Begin
  336.     {$I-}
  337.     GetDir(0, CurDir);
  338.     {$I+}
  339.     If IoResult<>0 Then exit;
  340.     FDrive := Upcase(CurDir[1]);
  341.     FDirectory := CurDir;
  342.   End;
  343.  
  344.   BuildTree;
  345. End;
  346.  
  347. Procedure TCustomDirOutline.BuildTree;
  348. Var
  349.   RootIndex: Longint;
  350. Begin
  351.   Clear;
  352.   If FDrive=#0 Then
  353.     exit;
  354.   RootIndex:= Add( 0, Drive+':' );
  355.   WalkTree( FDirectory );
  356.   Change;
  357. End;
  358.  
  359. Procedure TCustomDirOutline.WalkTree(Const Dir:String);
  360. Var
  361.   b:LongInt;
  362.   CurPath,NextDir,s:ShortString;
  363.   TempItem,TempIndex: Longint;
  364. begin
  365.   TempItem := 1; { start at root }
  366.  
  367.   CurPath := Dir;
  368.   b:=Pos(':',CurPath);
  369.   If b>0 then
  370.     CurPath:=Copy(CurPath,b+1,255);
  371.   If CurPath<>'' Then
  372.     If CurPath[1]='\' Then
  373.       System.Delete(CurPath,1,1);
  374.  
  375.   NextDir := CurPath;
  376.   Repeat
  377.     b:=Pos('\',CurPath);
  378.     If b=0 Then
  379.       b:=Pos('/',CurPath);
  380.     If b > 0 then
  381.     Begin
  382.       NextDir:=Copy(CurPath,1,b-1);
  383.       CurPath:=Copy(CurPath,b+1,255);
  384.     End
  385.     Else
  386.     Begin
  387.       NextDir:=CurPath;
  388.       CurPath:='';
  389.     End;
  390.  
  391.     // Expands this dir, forcing it's subdirs to be read
  392.     Items[TempItem].Expanded:=True;
  393.  
  394.     TempIndex:=Items[TempItem].GetFirstChild;
  395.     UpcaseStr(NextDir);
  396.     If CurPath='' Then
  397.       TempIndex:=-1
  398.     Else While TempIndex<>-1 Do
  399.     Begin
  400.       s:=Items[TempIndex].Text;
  401.       UpcaseStr(s);
  402.       If s=NextDir Then Break;
  403.       TempIndex:=Items[TempItem].GetNextChild(TempIndex);
  404.     End;
  405.     If TempIndex<>-1 Then
  406.       TempItem:=TempIndex
  407.     Else
  408.       CurPath:=''; //break
  409.   Until CurPath='';
  410. End;
  411.  
  412. Procedure TCustomDirOutline.Expand(Index:Longint);
  413. Begin
  414.   BuildOneLevel(Index);
  415.   Inherited Expand(Index);
  416. End;
  417.  
  418. Procedure TCustomDirOutline.Reload;
  419. Var
  420.   OldDir: string;
  421. Begin
  422.   OldDir:= Directory;
  423.   BuildTree;
  424.   Directory:= OldDir;
  425. End;
  426.  
  427. initialization
  428. end.
  429.