home *** CD-ROM | disk | FTP | other *** search
/ Delphi 2 - Developers' Solutions / Delphi 2 Developers' Solutions.iso / dds / chap02 / howto09 / delphi10 / drwsutl2.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-10-14  |  78.5 KB  |  2,087 lines

  1. unit Drwsutl2;
  2.  
  3. interface
  4.  
  5. uses
  6.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  7.   Forms, Dialogs, StdCtrls, Buttons, ExtCtrls, ShellAPI, FileCtrl, DRWSUtl1;
  8.  
  9. const
  10.   EOC_CHANGEDIR = 1;  { Error Operation Code for change directory failure }
  11.   EOC_SOURCECOPY = 2; { Error Operation Code for source copy failure      }
  12.   EOC_DESTCOPY = 3;   { Error Operation Code for destination copy failure }
  13.   EOC_DELETEFILE = 4; { Error Operation Code for file delete failure      }
  14.   EOC_DELETEDIR = 5;  { Error Operation Code for directory delete failure }
  15.   EOC_RENAMEFILE = 6; { Error Operation Code for renaming failure         }
  16.   EOC_MAKEDIR = 7;    { Error Operation Code for MkDir failure            }
  17.   EOC_SETATTR = 8;    { Error Operation Code for Set Attributes failure   }
  18.  
  19.   FAC_COPY = 1;       { File Action Code for recursive copying            }
  20.   FAC_MOVE = 2;       { File Action Code for recursive moving             }
  21.   FAC_DELETE = 3;     { File Action Code for recursive deletion           }
  22. type
  23.   { This is a descendant of TFileListbox }
  24.   { Which puts icons of files into the   }
  25.   { Objects array rather than the stand- }
  26.   { ard bitmaps.                         }
  27.   TIconFileListBox = class( TFileListBox )
  28.   public
  29.     { public methods and data }
  30.     procedure ReadFileNames; override;
  31.     function GetNextSelection( SourceDirectory : String;
  32.               var CurrentItem : Integer ) : String;
  33.     constructor Create(AOwner : TComponent); override; { override create    }
  34.     procedure TheDblClick( Sender : TObject );{ This holds override dblclick }
  35.   end;
  36.   TFileWorkBench = class( TComponent )
  37.   public
  38.     GlobalError        : Integer;  { This is used by FMXUCopyFile for er code }
  39.     GlobalErrorType    : Integer;  { This holds the Operation code            }
  40.     function ForceTrailingBackSlash( const TheFileName : String ) : String;
  41.     function StripNonRootTrailingBackSlash(
  42.               const TheFileName : String ) : String;
  43.     procedure GetFileAttributes( TheFile : String; var IsDirectory , IsArchive ,
  44.                 IsVolumeID , IsHidden , IsReadOnly , IsSysFile : Boolean );
  45.     procedure HandleIOException( TheOpCode : Integer; ThePath : String;
  46.                                  TheMessage : String; TheCode : Integer );
  47.     procedure HandleDOSError( TheOpCode : Integer; ThePath : String;
  48.                 TheCode : Integer );
  49.     function CopyFile( TargetPath ,
  50.                DestinationPath : String ) : Boolean;
  51.     procedure ChangeTheDirectory( NewPath : String );
  52.     procedure ChangeTheDriveAndDirectory( NewDrive : Integer );
  53.     procedure CopyTheFile( OldPath , NewPath : String );
  54.     procedure MoveTheFile( OldPath , NewPath : String );
  55.     procedure DeleteTheFile( ThePath : String );
  56.     procedure RenameTheFile( OldPath , NewName : String );
  57.     procedure CreateNewDirectory( NewPath : String );
  58.     procedure RemoveDirectory( ThePath : String );
  59.     procedure SetFileAttributes( TheFile  : String; TheAttributes : Integer );
  60.     procedure RecursivelyCopyDirectory( OldPath , NewPath : String );
  61.     procedure RecursivelyMoveDirectory( OldPath , NewPath : String );
  62.     procedure RecursivelyDeleteDirectory( ThePath : String );
  63.     procedure HandleRecursiveAction( StartingPath , NewPath : String;
  64.                ActionCode : Integer );
  65.   end;
  66.   TFileIconPanel = class( TPanel )
  67.   private
  68.     { Private declarations }
  69.     FHighlightColor : TColor;                 { This holds bright edge bevel }
  70.     FShadowColor    : TColor;                 { This holds dark edge bevel   }
  71.     procedure TheClick( Sender : TObject );   { This holds override click    }
  72.     procedure TheDblClick( Sender : TObject );{ This holds override dblclick }
  73.     procedure TheMouseDown(Sender: TObject;
  74.       Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  75.     procedure TheMouseUp(Sender: TObject;
  76.       Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  77.   protected                                   { event method procedure.      }
  78.     { Protected declarations }
  79.     procedure Paint; override;                { This allows custom painting  }
  80.   public
  81.     { Public declarations }
  82.     FTheIcon : TIcon;                         { This is the display icon    }
  83.     FTheName : String;                        { This is the filename        }
  84.     FTheLabel : TLabel;                       { This is the display label   }
  85.     Selected : Boolean;                       { This holds selection status }
  86.     constructor Create(AOwner : TComponent); override; { override create    }
  87.     procedure Initialize( PanelX              ,             { Left          }
  88.                           PanelY              ,             { Top           }
  89.                           PanelWidth          ,             { Width         }
  90.                           PanelHeight         ,             { Height        }
  91.                           PanelBevelWidth     ,             { Bevel Width   }
  92.                           LabelFontSize         : Integer;  { Font size     }
  93.                           PanelColor          ,             { Main color    }
  94.                           PanelHighlightColor ,             { Bright color  }
  95.                           PanelShadowColor    ,             { Dark color    }
  96.                           LabelTextColor        : TColor;   { Text color    }
  97.                           TheFilename         ,             { Filename      }
  98.                           LabelFontName         : String;   { Font name     }
  99.                           LabelFontStyle        : TFontStyles;  { Font style}
  100.                           ExtraData             : Integer       );  { Drive }
  101.     destructor Destroy; override;             { override destroy to free    }
  102.   end;
  103.   TFileIconPanelScrollBox = class( TScrollBox )
  104.   public
  105.     { Public methods and data }
  106.     TheFWB              : TFileWorkBench; { Used for file manipulation         }
  107.     IconsNeedRefreshing : Boolean;                   { Flag to redo display    }
  108.     TheIconSize        : Integer;   { Holds Individual Icon size               }
  109.     TheIconSpacing     : Integer;   { Holds total icon footprint               }
  110.     MaxIconsInARow     : Integer;   { Set for screen size.                     }
  111.     TheStoredHandle    : HWnd;
  112.     procedure Update;                                { Called to reset display }
  113.     constructor Create( AOwner : TComponent ); override;  { Override inherited }
  114.     procedure ClearTheFIPs;                          { Clears the FIPs safely  }
  115.     procedure AddDriveIcons( var XCounter , YCounter : Integer ); { Add drives }
  116.     procedure GetColorsForFileIcon( TheFile : String;
  117.                var BC , HC , SC , TC : TColor );
  118.     procedure GetIconsForEntireDirectory( TargetPath  : String );
  119.     function GetNextSelection( SourceDirectory : String;
  120.               var CurrentItem : Integer ) : String;
  121.     procedure DisplayRecursiveSearchResults(
  122.       TheStartingDirectory : String );
  123.   end;
  124.  
  125.   { This procedure gets an icon for a file using FindExecutable  }
  126.   { and ExtractIcon. (assumes file/dir is passed)                }
  127.   procedure GetIconForFile( TheName : String; var TheIcon : TIcon );
  128.   { This procedure spaces out the bitbtn components on a tpanel }
  129.   procedure SpacePanelButtons( WhichPanel : TPanel );
  130.     procedure FMXUCopyFile(const FileName, DestName: String; var GlobalErrorType ,
  131.                GlobalErrorCode : Integer );
  132.  
  133. implementation
  134. {$R DRWSUTL2.RES}                 { Import custom resource file }
  135.  
  136. { It has been edited to return viable error codes!             }
  137. procedure FMXUCopyFile(const FileName, DestName: String; var GlobalErrorType ,
  138.             GlobalErrorCode : Integer );
  139. var
  140.   CopyBuffer: Pointer; { buffer for copying }
  141.   BytesCopied: Longint;
  142.   TheAttr : Integer;
  143.   Source, Dest: Integer; { handles }
  144. const
  145.   ChunkSize: Longint = 8192; { copy in 8K chunks }
  146. begin
  147.   GetMem(CopyBuffer, ChunkSize); { allocate the buffer }
  148.   Source := FileOpen(FileName, fmShareDenyWrite); { open source file }
  149.   if Source < 0 then
  150.   begin  { error creating source file }
  151.     GlobalErrorType := EOC_SOURCECOPY;
  152.     GlobalErrorCode := -IOResult;
  153.     if GlobalErrorCode = 0 then GlobalErrorCode := -157;
  154.     FreeMem( CopyBuffer, ChunkSize );
  155.     exit;
  156.   end;
  157.   Dest := FileCreate(DestName); { create output file; overwrite existing }
  158.   if Dest < 0 then
  159.   begin  { error creating destination file }
  160.     FileClose( Source );
  161.     GlobalErrorType := EOC_DESTCOPY;
  162.     GlobalErrorCode := -IOResult;
  163.     if GlobalErrorCode = 0 then GlobalErrorCode := -159;
  164.     FreeMem( CopyBuffer , ChunkSize );
  165.     exit;
  166.   end;
  167.   {$I-}
  168.   repeat
  169.     BytesCopied := FileRead(Source, CopyBuffer^, ChunkSize); { read chunk}
  170.     if BytesCopied > 0 then { if we read anything... }
  171.     FileWrite(Dest, CopyBuffer^, BytesCopied); { ...write chunk }
  172.   until BytesCopied < ChunkSize; { until we run out of chunks }
  173.   {$I+}
  174.   GlobalErrorCode := -IOResult;  { get any error code which happens during copying }
  175.   FileClose(Dest); { close the destination file }
  176.   FileClose(Source); { close the source file }
  177.   FreeMem(CopyBuffer, ChunkSize); { free the buffer }
  178. end;
  179.  
  180. { This procedure spaces out the bitbtn components on a tpanel }
  181. procedure SpacePanelButtons( WhichPanel : TPanel );
  182. var TheCalculatedSpacing     ,            { Holds primary spacing }
  183.     TheFullCalculatedSpacing   : Integer; { Holds full spacing    }
  184.     Counter_1                  : Integer; { Loop counter          }
  185.     TotalIBs                   : Integer; { Gets total buttons    }
  186. begin
  187.   { Set up spacing values }
  188.   TotalIBs := WhichPanel.ControlCount;
  189.   TheCalculatedSpacing := (( WhichPanel.Width - 6 - ( TotalIbs * 49 ))
  190.    div ( TotalIbs + 1 ));
  191.   TheFullCalculatedSpacing := TheCalculatedSpacing + 49;
  192.   { Loop through all imported buttons and set their Left values }
  193.   for Counter_1 := 1 to WhichPanel.ControlCount do
  194.   begin
  195.     if Counter_1 = 1 then
  196.     begin
  197.       TBitBtn( WhichPanel.Controls[ Counter_1 - 1 ] ).Left := 3 +
  198.        TheCalculatedSpacing;
  199.     end
  200.     else
  201.     begin
  202.       TBitBtn( WhichPanel.Controls[ Counter_1 - 1 ] ).Left := 3 +
  203.        (( Counter_1 - 1 ) * TheFullCalculatedSpacing ) + TheCalculatedSpacing;
  204.     end;
  205.   end;
  206. end;
  207.  
  208. { This procedure gets an icon for a file using FindExecutable  }
  209. { and ExtractIcon. (assumes file/dir is passed)                }
  210. procedure GetIconForFile( TheName : String; var TheIcon : TIcon );
  211. var TheExt           : String; { File extension holder }
  212.     TheOtherPChar  ,           { Windows ASCIIZ string }
  213.     TheResultPChar ,           { Windows ASCIIZ string }
  214.     ThePChar         : PChar;  { Windows ASCIIZ string }
  215. begin
  216.   { Check for directory and if so get directory icon from RES file }
  217.   if (( FileGetAttr( TheName ) and faDirectory ) = faDirectory ) then
  218.   begin
  219.     { Set up the PChar to communicate with Windows }
  220.     GetMem( TheOtherPChar , 255 );
  221.     { Convert Pascal-style string to ASCIIZ Pchar }
  222.     StrPCopy( TheOtherPChar , 'DIRECTORY' );
  223.     { Use API call to return icon handle of Icon Resource in FILECTRL.RES }
  224.     TheIcon.Handle := LoadIcon( hInstance , TheOtherPChar );
  225.     { Release memory from PChar }
  226.     FreeMem( TheOtherPChar , 255 );
  227.     { Leave }
  228.     exit;
  229.   end;
  230.   { Assume archive file; get its extension }
  231.   TheExt := Uppercase( ExtractFileExt( TheName ));
  232.   { If not an executable/image file then use FindExecutable to get icon }
  233.   if (( TheExt <> '.EXE' ) and ( TheExt <> '.BAT' ) and
  234.       ( TheExt <> '.PIF' ) and ( TheExt <> '.COM' )) then
  235.   begin
  236.     { Grab three chunks of memory }
  237.     GetMem( TheOtherPChar , 255 );
  238.     GetMem( TheResultPChar , 255 );
  239.     GetMem( ThePChar , 255 );
  240.     { Set up the name and its directory in Windows string formats }
  241.     StrPCopy( ThePChar, TheName );
  242.     StrPCopy( TheOtherPChar , ExtractFilePath( TheName ));
  243.     { Use FindExecutable API call to get path and name of owning file }
  244.     if FindExecutable( ThePChar , TheOtherPChar , TheResultPChar ) > 31 then
  245.     begin
  246.       { If get a result of 32 or more then try to get first icon of owner }
  247.       { Using ExtractIcon API call; 0 indicates first icon.               }
  248.       TheIcon.Handle := ExtractIcon( hInstance , TheResultPchar , 0 );
  249.       { If a handle is 0 then no icon in owner, get default icon from RES file }
  250.       if TheIcon.Handle = 0 then
  251.       begin
  252.         GetMem( TheOtherPChar , 255 );
  253.         StrPCopy( TheOtherPChar , 'NOICON' );
  254.         TheIcon.Handle := LoadIcon( hInstance , TheOtherPChar );
  255.         FreeMem( TheOtherPChar , 255 );
  256.         exit;
  257.       end;
  258.     end
  259.     else
  260.     { if no assigned executable, then get default icon from RES file }
  261.     begin
  262.       GetMem( TheOtherPChar , 255 );
  263.       StrPCopy( TheOtherPChar , 'NOICON' );
  264.       TheIcon.Handle := LoadIcon( hInstance , TheOtherPChar );
  265.       FreeMem( TheOtherPChar , 255 );
  266.       exit;
  267.     end;
  268.     FreeMem( TheOtherPChar , 255 );
  269.     FreeMem( TheResultPChar , 255 );
  270.     FreeMem( ThePChar , 255 );
  271.   end
  272.   else
  273.   { Assume Windows Executable file, so get icon from it with ExtractIcon API }
  274.   begin
  275.     GetMem( ThePChar , 255 );
  276.     StrPCopy( ThePChar , TheName );
  277.     { If no icons in file then get default icon (note use FFFF for -1) }
  278.     if ExtractIcon( hInstance , ThePchar , 65535 ) = 0 then
  279.     begin
  280.       Freemem( ThePChar , 255 );
  281.       GetMem( TheOtherPChar , 255 );
  282.       StrPCopy( TheOtherPChar , 'NOICON' );
  283.       TheIcon.Handle := LoadIcon( hInstance , TheOtherPChar );
  284.       FreeMem( TheOtherPChar , 255 );
  285.       exit;
  286.     end
  287.     else
  288.     begin
  289.       { Try to get first icon for file }
  290.       TheIcon.Handle := ExtractIcon( hInstance , ThePChar , 0 );
  291.       FreeMem( ThePChar , 255 );
  292.       { If handle is 0 invalid icon format so use default from RES file }
  293.       if TheIcon.Handle = 0 then
  294.       begin
  295.         GetMem( TheOtherPChar , 255 );
  296.         StrPCopy( TheOtherPChar , 'NOICON' );
  297.         TheIcon.Handle := LoadIcon( hInstance , TheOtherPChar );
  298.         FreeMem( TheOtherPChar , 255 );
  299.         exit;
  300.       end;
  301.     end;
  302.   end;
  303. end;
  304.  
  305. { This procedure does a fully error-trapped change directory }
  306. procedure TFileWorkBench.ChangeTheDirectory( NewPath : String );
  307. var CurrentDirectory : String;
  308. begin
  309.   if NewPath = '..' then
  310.   begin { Back up one level }
  311.     {$I+}
  312.     try
  313.       { Find the current directory }
  314.       GetDir( 0 , CurrentDirectory );
  315.       { Use EFP to move up one level }
  316.       CurrentDirectory := ExtractFilePath( CurrentDirectory );
  317.       { Strip trailing \ if not root }
  318.       CurrentDirectory := StripNonRootTrailingBackSlash( CurrentDirectory );
  319.       { Try the change to the new drive }
  320.       ChDir( CurrentDirectory );
  321.     except
  322.       { if any exception occurs instantiate exception and show }
  323.       On E:EInOutError do
  324.       begin
  325.         { Call custom error display/lookup procedure }
  326.         HandleIOException( EOC_CHANGEDIR , CurrentDirectory ,
  327.          E.Message , E.ErrorCode );
  328.       end;
  329.     end;
  330.   end
  331.   else
  332.   begin { Change to explicit path }
  333.     {$I+}
  334.     try
  335.       { Get target directory path }
  336.       CurrentDirectory := NewPath;
  337.       { Strip trailing \ if not root }
  338.       CurrentDirectory := StripNonRootTrailingBackSlash( CurrentDirectory );
  339.       { Try the change to the new drive }
  340.       ChDir( CurrentDirectory );
  341.     except
  342.       { if any exception occurs instantiate exception and show }
  343.       On E:EInOutError do
  344.       begin
  345.         { Call custom error display/lookup procedure }
  346.         HandleIOException( EOC_CHANGEDIR , CurrentDirectory ,
  347.          E.Message , E.ErrorCode );
  348.       end;
  349.     end;
  350.   end;
  351. end;
  352.  
  353. { This procedure does a fully error-trapped change directory }
  354. procedure TFileWorkBench.ChangeTheDriveAndDirectory( NewDrive : Integer );
  355. var CurrentDirectory : String;
  356. begin
  357.   {$I+}
  358.   try
  359.     { Find the working directory on new drive }
  360.     GetDir( NewDrive , CurrentDirectory );
  361.     { Try the change to the new drive }
  362.     ChDir( CurrentDirectory );
  363.   except
  364.     { if any exception occurs instantiate exception and show }
  365.     On E:EInOutError do
  366.     begin
  367.       { Call custom error display/lookup procedure }
  368.       HandleIOException( EOC_CHANGEDIR , CurrentDirectory ,
  369.        E.Message , E.ErrorCode );
  370.     end;
  371.   end;
  372. end;
  373.  
  374. { This procedure copies a single file with error trapping }
  375. procedure TFileWorkBench.CopyTheFile( OldPath , NewPath : String );
  376. var AResult : Boolean; { Internal data flag }
  377. begin
  378.   { If Copyfile returns false an error occurred }
  379.   AResult := CopyFile( OldPath , NewPath +
  380.    ExtractFileName( OldPath ));
  381.   { Display meaningful error message }
  382.   if not AResult then HandleDOSError( GlobalErrorType , OldPath, GlobalError );
  383. end;
  384.  
  385. { This procedure moves a file by copying and delete it }
  386. procedure TFileWorkBench.MoveTheFile( OldPath , NewPath : String );
  387. var AResult : Boolean; { Internal data flag }
  388.     TheFile : File;    { Use to get errors  }
  389. begin
  390.   { If Copyfile returns false an error occurred }
  391.   AResult := CopyFile( OldPath , NewPath +
  392.     ExtractFileName( OldPath ));
  393.   { Display meaningful error message }
  394.   if not AResult then HandleDOSError( GlobalErrorType ,
  395.     OldPath , GlobalError );
  396.   { After valid copying, delete source file }
  397.   {$I+}
  398.   if AResult then try
  399.     { Use this trick to get valid exception handling }
  400.     AssignFile( TheFile , OldPath );
  401.     { Use erase because Deletefile doesn't give exceptions! }
  402.     Erase( TheFile );
  403.   except
  404.     { if any exception occurs instantiate exception and show }
  405.     On E:EInOutError do
  406.     begin
  407.       { Call custom error display/lookup procedure }
  408.       HandleIOException( EOC_DELETEFILE , OldPath ,
  409.        E.Message , E.ErrorCode );
  410.     end;
  411.   end;
  412. end;
  413.  
  414. { This procedure safely deletes a single file }
  415. procedure TFileWorkBench.DeleteTheFile( ThePath : String );
  416. var TheFile : File; { Internal file handle }
  417. begin
  418.   {$I+}
  419.   try
  420.     { Use this trick to get valid exception handling }
  421.     AssignFile( TheFile , ThePath );
  422.     { Use erase because Deletefile doesn't give exceptions! }
  423.     Erase( TheFile );
  424.   except
  425.     { if any exception occurs instantiate exception and show }
  426.     On E:EInOutError do
  427.     begin
  428.       { Call custom error display/lookup procedure }
  429.       HandleIOException( EOC_DELETEFILE , ThePath ,
  430.        E.Message , E.ErrorCode );
  431.     end;
  432.   end;
  433. end;
  434.  
  435. { This procedure renames a file with full error trapping }
  436. procedure TFileWorkBench.RenameTheFile( OldPath , NewName : String );
  437. var TheFile : File; { Internal file handle }
  438. begin
  439.   {$I+}
  440.   try
  441.     { Use this trick to get valid exception handling }
  442.     AssignFile( TheFile , OldPath );
  443.     { Use this because RenameFile doesn't give exceptions! }
  444.     Rename( TheFile , NewName );
  445.   except
  446.     { if any exception occurs instantiate exception and show }
  447.     On E:EInOutError do
  448.     begin
  449.       { Call custom error display/lookup procedure }
  450.       HandleIOException( EOC_RENAMEFILE , OldPath  ,
  451.        E.Message , E.ErrorCode );
  452.     end;
  453.   end;
  454. end;
  455.  
  456. { This procedure creates a new directory with full error trapping }
  457. procedure TFileWorkBench.CreateNewDirectory( NewPath : String );
  458. begin
  459.   {$I+}
  460.   try
  461.     Mkdir( NewPath );
  462.   except
  463.     { if any exception occurs instantiate exception and show }
  464.     On E:EInOutError do
  465.     begin
  466.       { Call custom error display/lookup procedure }
  467.       HandleIOException( EOC_MAKEDIR , NewPath  ,
  468.        E.Message , E.ErrorCode );
  469.     end;
  470.   end;
  471. end;
  472.  
  473. { This procedure remove a directory with full error trapping }
  474. procedure TFileWorkBench.RemoveDirectory( ThePath : String );
  475. begin
  476.   {$I+}
  477.   try
  478.     Rmdir( ThePath );
  479.   except
  480.     { if any exception occurs instantiate exception and show }
  481.     On E:EInOutError do
  482.     begin
  483.       { Call custom error display/lookup procedure }
  484.       HandleIOException( EOC_DELETEDIR , ThePath  ,
  485.        E.Message , E.ErrorCode );
  486.     end;
  487.   end;
  488. end;
  489.  
  490. { Use this to set the attributes of a file with error trapping }
  491. procedure TFileWorkBench.SetFileAttributes( TheFile  : String;
  492.            TheAttributes : Integer );
  493. var TheResult : Integer; { Holds error code if any }
  494. begin
  495.   { Attempt to set the attributes }
  496.   TheResult := FileSetAttr( TheFile , TheAttributes );
  497.   { if negative number error, so signal }
  498.   if TheResult < 0 then
  499.    HandleDOSError( EOC_SETATTR , TheFile , -TheResult );
  500. end;
  501.  
  502. { This procedure recursively copies a directory to a new path }
  503. procedure TFileWorkBench.RecursivelyCopyDirectory( OldPath , NewPath : String );
  504. var TheDir : String; { Holds source directory }
  505. begin
  506.   { Get the source directory to copy }
  507.   TheDir := ExtractFileName( OldPath );
  508.   { Force a backslash to the newpath variable }
  509.   NewPath := ForceTrailingBackSlash( NewPath );
  510.   { Add the source directory to the target path }
  511.   NewPath := NewPath + TheDir;
  512.   { Create a new directory with the new name }
  513.   CreateNewDirectory( NewPath );
  514.   { Force a backslash for compatibility }
  515.   NewPath := FOrcetrailingBackSlash( NewPath );
  516.   { Do the recursive call }
  517.   HandleRecursiveAction( OldPath , NewPath , FAC_COPY );
  518. end;
  519.  
  520. { This procedure recursively moves a directory tree }
  521. procedure TFileWorkBench.RecursivelyMoveDirectory( OldPath , NewPath : String );
  522. var TheDir    : String; { Holds source directory  }
  523.     SavedPath : String; { Holds saved dir to kill }
  524. begin
  525.   { Get the source directory to move }
  526.   TheDir := ExtractFileName( OldPath );
  527.   { Force a backslash to the newpath variable }
  528.   NewPath := ForceTrailingBackSlash( NewPath );
  529.   { Save the starting path just in case }
  530.   SavedPath := OldPath;
  531.   { Add the source directory to the target path }
  532.   NewPath := NewPath + TheDir;
  533.   { Create a new directory with the new name }
  534.   CreateNewDirectory( NewPath );
  535.   { Force a backslash for compatibility }
  536.   NewPath := FOrcetrailingBackSlash( NewPath );
  537.   { Do the recursive call }
  538.   HandleRecursiveAction( OldPath , NewPath , FAC_MOVE );
  539.   { Remove the source directory }
  540.   RemoveDirectory( SavedPath );
  541. end;
  542.  
  543. { This procedure handles recursively deleting an entire directory tree }
  544. procedure TFileWorkBench.RecursivelyDeleteDirectory( ThePath : String );
  545. begin
  546.   HandleRecursiveAction( ThePath , '' , FAC_DELETE );
  547. end;
  548.  
  549.  
  550. { This is the generic routine to copy, move, and delete whole directory trees }
  551. procedure TFileWorkBench.HandleRecursiveAction( StartingPath , NewPath : String;
  552.            ActionCode : Integer );
  553. { VITAL!!! These variables MUST be local for recursrion to work! }
  554. var
  555.     Finished        : Boolean;         { Loop flag              }
  556.     TheSR           : TSearchRec;      { Searchrecord for FF/FN }
  557.     TheResult       : Integer;         { return variable        }
  558.     TargetPath ,
  559.     FileMask   ,
  560.     TheWorkingDirectory ,
  561.     TheStoredWorkingDirectory ,
  562.     ModifiedDirectory  : String;       { path for FF/FN         }
  563.     TheFIP          : TFileIconPanel;  { generic FIP holder     }
  564.     ButtonColor   ,                    { main panel color       }
  565.     ButtonHLColor ,                    { bright panel color     }
  566.     ButtonSColor  ,                    { dark panel color       }
  567.     Textcolor       : TColor;          { label text color       }
  568.     TheFile         : File;
  569.  
  570. begin
  571.   { Set up the initial variables }
  572.   Finished := false;
  573.   TheWorkingDirectory := StartingPath;
  574.   TheStoredWorkingDirectory := TheWorkingDirectory;
  575.   TheWorkingDirectory := TheWorkingDirectory + '\*.*';
  576.   TargetPath := ExtractFilePath( TheWorkingDirectory );
  577.   { Make the call to FindFirst set to get any file }
  578.   TheResult := FindFirst( TheWorkingDirectory , faAnyFile , TheSR );
  579.   { loop through all files in the directory and delete them }
  580.   while not Finished do
  581.   begin
  582.     { Make call to FindNext, using only SearchRecord from FindFirst }
  583.     TheResult := FindNext( TheSR );
  584.     { A -1 result means no more files so exit }
  585.     if TheResult < 0 then finished := true else
  586.     begin
  587.       if (( FileGetAttr( TargetPath + TheSR.Name ) and faDirectory )
  588.        <> faDirectory ) then
  589.       begin { A File }
  590.         case ActionCode of
  591.           FAC_COPY :
  592.               begin
  593.                 CopyTheFile( TargetPath + TheSR.Name , NewPath );
  594.               end;
  595.           FAC_MOVE :
  596.               begin
  597.                 MoveTheFile( TargetPath + TheSR.Name , NewPath );
  598.               end;
  599.           FAC_DELETE :
  600.               begin { Delete }
  601.                 if MessageDlg( 'Delete file ' + TargetPath + TheSR.Name + '?',
  602.                    mtConfirmation , mbYesNoCancel , 0 ) = mrYes then
  603.                     DeleteTheFile( TargetPath + TheSR.Name );
  604.               end;
  605.         end;
  606.       end;
  607.     end;
  608.   end;
  609.   { Call FindClose for Windows NT/Windows 95 compatibility }
  610.   FindClose( TheSR );
  611.   { Set up the variables to do recursive calls on all directories}
  612.   Finished := false;
  613.   ModifiedDirectory := TheStoredWorkingdirectory + '\*.*';
  614.   { Make the call to FindFirst set to get any file, ignore result }
  615.   TheResult := FindFirst( ModifiedDirectory , faDirectory , TheSR );
  616.   while not Finished do
  617.   begin
  618.     { Make call to FindNext, using only SearchRecord from FindFirst }
  619.     TheResult := FindNext( TheSR );
  620.     { A -1 result means no more files so exit }
  621.     if TheResult < 0 then
  622.       finished := true
  623.     else
  624.     begin
  625.       if TheSR.Name <> '..' then { Ignore backup in this case }
  626.       begin
  627.         if (( FileGetAttr( TargetPath + TheSR.Name ) and faDirectory )
  628.          = faDirectory ) then
  629.         begin
  630.           { Send in the new directory name }
  631.           ModifiedDirectory := TheStoredWorkingDirectory  + '\' +
  632.            TheSR.Name;
  633.           { Reproduce directory structure for recursion in copy/move }
  634.           NewPath := NewPath + TheSR.Name;
  635.           case ActionCode of
  636.             FAC_COPY , FAC_MOVE :
  637.                begin { Create ahead for move and copy }
  638.                  { Make the new directory for moving and copying }
  639.                  CreateNewDirectory( NewPath );
  640.                  { Force a backslash for compatibility }
  641.                  NewPath := ForceTrailingBackSlash( NewPath );
  642.                end;
  643.             FAC_DELETE :
  644.                begin  { No prior action needed for Delete }
  645.                end;
  646.           end;
  647.           { Do the recursive call }
  648.           HandleRecursiveAction( ModifiedDirectory , NewPath , ActionCode );
  649.           case ActionCode of
  650.             FAC_COPY :
  651.                begin { no action for copy }
  652.                end;
  653.             FAC_MOVE , FAC_DELETE :
  654.                begin  { Delete }
  655.                  { Get a confirmation }
  656.                  if MessageDlg( 'Remove Directory ' + TargetPath + TheSR.Name
  657.                   + '?', mtConfirmation , mbYesNoCancel , 0 ) = mrYes then
  658.                    RemoveDirectory( TargetPath + TheSR.Name );
  659.                end;
  660.           end;
  661.         end;
  662.       end;
  663.     end;
  664.   end;
  665. end;
  666.  
  667. { This is a generic copy routine taken from Delphi sample code }
  668. { This function calls the sample Copy code and handles errors }
  669. function TFileWorkBench.CopyFile( TargetPath ,
  670.           DestinationPath : String ) : Boolean;
  671. begin
  672.   { Set global error value to no error }
  673.   GlobalError := 0;
  674.   { Call the sample procedure to do the copy }
  675.   FMXUCopyFile( TargetPath, DestinationPath , GlobalErrorType , GlobalError );
  676.   { If no error return true else return false }
  677.   if GlobalError < 0 then CopyFile := false else
  678.    CopyFile := true;
  679. end;
  680.  
  681. { This procedure handles displaying a user-friendly Dialog box with a }
  682. { Message for Delphi IO exception errors.                             }
  683. procedure TFileWorkBench.HandleIOException( TheOpCode : Integer;
  684.            ThePath : String; TheMessage : String; TheCode : Integer );
  685. var ErrorMessageString : String;  { Holds internal data }
  686.     OperationString    : String;  { Holds internal data }
  687. begin
  688.   { clear to check for unrecognized code }
  689.   ErrorMessageString := '';
  690.   { Check against imported code }
  691.   case TheCode of
  692.     2    : ErrorMessageString := 'File not found';
  693.     3    : ErrorMessageString := 'Path not found';
  694.     4    : ErrorMessageString := 'Too many open files';
  695.     5    : ErrorMessageString := 'File access denied';
  696.     6    : ErrorMessageString := 'Invalid file handle';
  697.     12    : ErrorMessageString := 'Invalid file access code';
  698.     15    : ErrorMessageString := 'Invalid drive number';
  699.     16  : ErrorMessageString := 'Cannot remove current directory';
  700.     17    : ErrorMessageString := 'Cannot rename across drives';
  701.     100    : ErrorMessageString := 'Disk read error';
  702.     101    : ErrorMessageString := 'Disk write error';
  703.     102    : ErrorMessageString := 'File not assigned';
  704.     103    : ErrorMessageString := 'File not open';
  705.     104    : ErrorMessageString := 'File not open for input';
  706.     105    : ErrorMessageString := 'File not open for output';
  707.   end;
  708.   case TheOpCode of
  709.     EOC_CHANGEDIR : OperationString := 'Unable to Change Directory due to ';
  710.     EOC_SOURCECOPY : OperationString := 'Unable to Copy due to Source File ';
  711.     EOC_DESTCOPY : OperationString := 'Unable to Copy due to Destination File ';
  712.     EOC_DELETEFILE : OperationString := 'Unable to Delete File due to ';
  713.     EOC_DELETEDIR : OperationString := 'Unable to Delete Directory due to ';
  714.     EOC_RENAMEFILE : OperationString := 'Unable to Rename File due to ';
  715.     EOC_MAKEDIR : OperationString := 'Unable to Create New Directory due to ';
  716.     EOC_SETATTR : OperationString := 'Unable to Set File Attributes due to ';
  717.   end;
  718.   { If not recognized use message; not a DOS error; reset cursor for neatness }
  719.   if ErrorMessageString = '' then
  720.   begin
  721.     Screen.Cursor := crDefault;
  722.     MessageDlg( OperationString + ExtractFileName( ThePath ) + ' ' +
  723.      TheMessage , mtError , [mbOK],0);
  724.   end
  725.   else
  726.   begin
  727.     { Recognized DOS exception, reset cursor for neatness }
  728.     Screen.Cursor := crDefault;
  729.     MessageDlg( OperationString + ExtractFileName( ThePath ) + ' ' +
  730.      ErrorMessageString , mtError , [mbOK], 0 );
  731.   end;
  732. end;
  733.  
  734. { This procedure handles displaying a user-friendly Dialog box with a }
  735. { Message for DOS error codes.                                        }
  736. procedure TFileWorkBench.HandleDOSError( TheOpCode : Integer;
  737.            ThePath : String;  TheCode : Integer );
  738. var ErrorMessageString : String;  { internal message holder }
  739.     OperationString : String;     { internal message holder }
  740. begin
  741.   { clear the message holder to check for unrecognized code }
  742.   ErrorMessageString := '';
  743.   { Negate the code back to normal number and check to set string }
  744.   case -TheCode of
  745.     2    : ErrorMessageString := 'File not found';
  746.     3    : ErrorMessageString := 'Path not found';
  747.     4    : ErrorMessageString := 'Too many open files';
  748.     5    : ErrorMessageString := 'File access denied';
  749.     6    : ErrorMessageString := 'Invalid file handle';
  750.     12    : ErrorMessageString := 'Invalid file access code';
  751.     15    : ErrorMessageString := 'Invalid drive number';
  752.     16  : ErrorMessageString := 'Cannot remove current directory';
  753.     17    : ErrorMessageString := 'Cannot rename across drives';
  754.     100    : ErrorMessageString := 'Disk read error';
  755.     101    : ErrorMessageString := 'Disk write error';
  756.     102    : ErrorMessageString := 'File not assigned';
  757.     103    : ErrorMessageString := 'File not open';
  758.     104    : ErrorMessageString := 'File not open for input';
  759.     105    : ErrorMessageString := 'File not open for output';
  760.     157 : ErrormessageString := 'Could not open Source File';
  761.     159 : ErrormessageString := 'Could not open Target File';
  762.   end;
  763.   case TheOpCode of
  764.     EOC_CHANGEDIR : OperationString := 'Unable to Change Directory due to ';
  765.     EOC_SOURCECOPY : OperationString := 'Unable to Copy due to Source File ';
  766.     EOC_DESTCOPY : OperationString := 'Unable to Copy due to Destination File ';
  767.     EOC_DELETEFILE : OperationString := 'Unable to Delete File due to ';
  768.     EOC_DELETEDIR : OperationString := 'Unable to Delete Directory due to ';
  769.     EOC_RENAMEFILE : OperationString := 'Unable to Rename File due to ';
  770.     EOC_MAKEDIR : OperationString := 'Unable to Create New Directory due to ';
  771.     EOC_SETATTR : OperationString := 'Unable to Set File Attributes due to ';
  772.   end;
  773.   { If the string is empty an unrecognized code was sent in }
  774.   if ErrorMessageString = '' then
  775.   begin
  776.     { Sent up db based on source or target error; reset cursor for neatness }
  777.     Screen.Cursor := crDefault;
  778.     MessageDlg( OperationString + ExtractFileName( ThePath ) + ' Error Code: ' +
  779.      IntToStr( TheCode ) , mtError , [mbOK],0);
  780.   end
  781.   else  { Code is recognized, use message from case statement }
  782.   begin
  783.     { Format the output for source or target error }
  784.     Screen.Cursor := crDefault;
  785.     MessageDlg( OperationString + ExtractFileName( ThePath ) + ' ' +
  786.      ErrorMessageString , mtError , [mbOK], 0 );
  787.   end;
  788. end;
  789.  
  790. { This procedure sets the imported booleans to the file's attributes }
  791. procedure TFileWorkBench.GetFileAttributes( TheFile : String; var IsDirectory ,
  792.            IsArchive , IsVolumeID , IsHidden , IsReadOnly ,
  793.             IsSysFile : Boolean );
  794. var TheResult : Integer; { Traps for error code on VolumeID }
  795. begin
  796.   { Clear the imported flags for default }
  797.   IsDirectory := false;
  798.   IsArchive := false;
  799.   IsVolumeID := false;
  800.   IsHidden := False;
  801.   IsReadOnly := false;
  802.   IsSysFile := false;
  803.   { Make the Dos call }
  804.   TheResult := FileGetAttr( TheFile );
  805.   if TheResult < 0 then
  806.   begin
  807.     { Volume ID returns -2 (?) }
  808.     IsVolumeID := true;
  809.     { It has no other properties }
  810.     exit;
  811.   end;
  812.   { Use AND test to set all other properties }
  813.   if (( TheResult and faDirectory ) = faDirectory ) then IsDirectory := true;
  814.   if (( TheResult and faArchive ) = faArchive ) then IsArchive := true;
  815.   if (( TheResult and faVolumeID ) = faVolumeID ) then IsVolumeID := true;
  816.   if (( TheResult and faReadOnly ) = faReadOnly ) then IsReadOnly := true;
  817.   if (( TheResult and faHidden ) = faHidden ) then IsHidden := true;
  818.   if (( TheResult and faSysFile ) = faSysFile ) then IsSysFile := true;
  819. end;
  820.  
  821. { This function makes sure a pathname has a trailing \ }
  822. function TFileWorkBench.ForceTrailingBackSlash(
  823.           const TheFileName : String ) : String;
  824. var TempString : String;  { Used to hold function result }
  825. begin
  826.   { If no trailing \ add one (root will already have one.) }
  827.   if TheFileName[ Length( TheFileName ) ] <> '\' then
  828.    TempString := TheFileName + '\' else TempString := TheFileName;
  829.   { Return modified or non-modified string }
  830.   ForceTrailingBackslash := TempString;
  831. end;
  832.  
  833. { This function makes sure a non-root dir has no trailing \ }
  834. function TFileWorkBench.StripNonRootTrailingBackSlash(
  835.           const TheFileName : String ) : String;
  836. var TempString : String ; { Used to hold function result }
  837. begin
  838.   { Default is no change }
  839.   TempString := TheFileName;
  840.   { If not root then }
  841.   if Length( TheFileName ) > 3 then
  842.   begin
  843.     { If has a trailing backslash remove it }
  844.     if TheFileName[ Length( TheFileName )] = '\' then
  845.     begin
  846.       TempString := Copy( TheFileName , 1 ,
  847.        Length( TheFileName ) - 1 );
  848.     end;
  849.   end;
  850.   { Export the final result }
  851.   StripNonRootTrailingBackSlash := TempString;
  852. end;
  853.  
  854. { This gets the next selected listbox item }
  855. function TIconFileListBox.GetNextSelection( SourceDirectory : String;
  856.           var CurrentItem : Integer ): String;
  857. var TheResult : String;  { Internal storage }
  858.     finished  : boolean; { Loop flag        }
  859. begin
  860.   { If out of items to check signal and exit }
  861.   if CurrentItem > Items.Count then TheResult := '' else
  862.   begin
  863.     { Otherwise scan from current position till match or end }
  864.     finished := false;
  865.     while not finished do
  866.     begin
  867.       { Check against selected property }
  868.       if Selected[ CurrentItem - 1 ] then
  869.       begin
  870.         { If selected then return it and abort loop }
  871.         TheResult := SourceDirectory + Items[ CurrentItem - 1 ];
  872.         finished := true;
  873.         { Increment current position }
  874.         CurrentItem := CurrentItem + 1;
  875.      end
  876.       else
  877.       begin
  878.         { Increment current position }
  879.         CurrentItem := CurrentItem + 1;
  880.         { Otherwise check for end of data and abort if out of entries }
  881.         if CurrentItem > Items.Count then
  882.         begin
  883.           TheResult := '';
  884.           finished := true;
  885.         end;
  886.       end;
  887.     end;
  888.   end;
  889.   { Return stored result }
  890.   GetNextSelection := TheResult;
  891. end;
  892.  
  893. { Modified from VCL Source Copyright 1995 }
  894. { Borland International, Inc.             }
  895. { Use this to override display with icons }
  896. procedure TIconFileListBox.ReadFileNames;
  897. var
  898.   AttrIndex   : TFileAttr;
  899.   i           : Integer;
  900.   FileExt     : string;
  901.   MaskPtr     : PChar;
  902.   Ptr         : PChar;
  903.   AttrWord    : Word;
  904.   TempPicture : TPicture;
  905.   TempBmp     : TBitmap;
  906.   TempIcon    : TIcon;
  907. const
  908.   Attributes: array[TFileAttr] of Word =
  909.   ( DDL_READONLY , DDL_HIDDEN , DDL_SYSTEM , $0008 , DDL_DIRECTORY ,
  910.     DDL_ARCHIVE  , DDL_EXCLUSIVE );
  911. begin
  912.   { if no handle allocated yet, this call will force         }
  913.   { one to be allocated incorrectly (i.e. at the wrong time. }
  914.   { In due time, one will be allocated appropriately.        }
  915.   AttrWord := DDL_READWRITE;
  916.   if HandleAllocated then
  917.   begin
  918.     { Set attribute flags based on values in FileType }
  919.     for AttrIndex := ftReadOnly to ftArchive do
  920.      if AttrIndex in FileType then
  921.       AttrWord := AttrWord or Attributes[ AttrIndex ];
  922.  
  923.     { Use Exclusive bit to exclude normal files }
  924.     if not ( ftNormal in FileType ) then
  925.       AttrWord := AttrWord or DDL_EXCLUSIVE;
  926.  
  927.     ChDir( FDirectory ); { go to the directory we want }
  928.     Clear;               { clear the list }
  929.  
  930.     MaskPtr := FMask;
  931.     while MaskPtr <> nil do
  932.     begin
  933.       Ptr := StrScan ( MaskPtr , ';' );
  934.       if Ptr <> nil then  Ptr^ := #0;
  935.       { build the list }
  936.       SendMessage( Handle , LB_DIR , AttrWord , Longint( MaskPtr ));
  937.       if Ptr <> nil then
  938.       begin
  939.         Ptr^ := ';';
  940.         Inc ( Ptr );
  941.       end;
  942.       MaskPtr := Ptr;
  943.     end;
  944.     { Now add the bitmaps }
  945.     {---------------------------- begin custom code --------------------------}
  946.     { Create the TPicture for exchange purposes }
  947.     TempPicture := TPicture.Create;
  948.     { Set it to icon widths }
  949.     TempPicture.Bitmap.Width := 32;
  950.     TempPicture.Bitmap.Height := 32;
  951.     { Run down the list }
  952.     for i := 0 to Items.Count - 1 do
  953.     begin
  954.       { Create a new temporary icon }
  955.       TempIcon := TIcon.Create;
  956.       { Call the custom DRWS routine to get icon for a file }
  957.       GetIconForFile( Items[ i ] , TempIcon );
  958.       { Put the icon on the bitmap for the picture via draw }
  959.       { Note 1 , 1 due to bug in Draw?                      }
  960.       TempPicture.Bitmap.Canvas.Draw( 1 , 1 , TempIcon );
  961.       { Create a temporary bitmap }
  962.       TempBmp := TBitmap.Create;
  963.       { Set its width to those of the previous object's bitmaps }
  964.       TempBmp.Width := 16;
  965.       TempBmp.Height := 15;
  966.       { Resize the icon's bitmap to the smaller size with stretchdraw }
  967.       TempBmp.Canvas.StretchDraw( Rect( 1 , 1 , 15 , 14 ) ,
  968.        TempPicture.Bitmap );
  969.       { Set the Objects list to the bitmap }
  970.       Items.Objects[ i ] := TempBmp;
  971.       { Free the icon each iteration; don't free the TempBmp as list does }
  972.       TempIcon.Free;
  973.     end;
  974.     { Free the TPicture exchange element }
  975.     TempPicture.Free;
  976.     {------------------------ end custom code --------------------------------}
  977.     Change;
  978.   end;
  979. end;
  980.  
  981. { Use this to respond to dbl-clicking FLB filename }
  982. procedure TIconFileListBox.TheDblClick(Sender: TObject);
  983. begin
  984.   { Call shellexec as a wrapper around ShellExecute API call }
  985.   { False indicates failure, signal error                    }
  986.   if not ShellExec( ExpandFileName( Items[ ItemIndex ] ), '' , '', false ,
  987.    SW_SHOWNORMAL , false ) then MessageDlg('Could not Shell out to ' +
  988.     Items[ ItemIndex ] , mtError, [mbOK], 0);
  989. end;
  990.  
  991. { Create method for FIP                                }
  992. constructor TIconFileListBox.Create( AOwner : TComponent );
  993. begin
  994.   { call inherited -- VITAL! }
  995.   inherited Create( AOwner );
  996.   { set the mouse method }
  997.   OnDblClick := TheDblClick;
  998. end;
  999.  
  1000. { Create method for FIP                                }
  1001. constructor TFileIconPanel.Create( AOwner : TComponent );
  1002. begin
  1003.   { call inherited -- VITAL! }
  1004.   inherited Create( AOwner );
  1005.   { create icon and label components, making self owner/displayer }
  1006.   FTheIcon := TIcon.Create;
  1007.   FTheLabel := TLabel.Create( Self );
  1008.   FThelabel.Parent := Self;
  1009.   { Set own and labels mouse methods to stored methods }
  1010.   OnClick := TheClick;
  1011.   OnDblClick := TheDblClick;
  1012.   OnMouseUp := TheMouseUp;
  1013.   OnMouseDown := TheMouseDown;
  1014.   FTheLabel.OnClick := TheClick;
  1015.   FTheLabel.OnDblClick := TheDblClick;
  1016.   FTheLabel.OnMouseUp := TheMouseUp;
  1017.   FTheLabel.OnMouseDown := TheMouseDown;
  1018.   { Set alignment and autosize properties of the label }
  1019.   FTheLabel.Autosize := false;
  1020.   FTheLabel.Alignment := taCenter;
  1021.   { Set selected to false }
  1022.   Selected := false;
  1023. end;
  1024.  
  1025. { Initialization method for FIP                                         }
  1026. procedure TFileIconPanel.Initialize( PanelX              ,
  1027.                                      PanelY              ,
  1028.                                      PanelWidth          ,
  1029.                                      PanelHeight         ,
  1030.                                      PanelBevelWidth     ,
  1031.                                      LabelFontSize         : Integer;
  1032.                                      PanelColor          ,
  1033.                                      PanelHighlightColor ,
  1034.                                      PanelShadowColor    ,
  1035.                                      LabelTextColor        : TColor;
  1036.                                      TheFilename         ,
  1037.                                      LabelFontName         : String;
  1038.                                      LabelFontStyle        : TFontStyles;
  1039.                                      ExtraData             : Integer );
  1040.  
  1041. var TheLabelHeight ,             { Holder for label pixel height }
  1042.     TheLabelWidth    : Integer;  { Holder for label pixel width  }
  1043.     TheOtherPChar    : PChar;    { Windows ASCIIZ string         }
  1044. begin
  1045.   { Set the basic properties based on imported parameters }
  1046.   Left := PanelX;
  1047.   Top := PanelY;
  1048.   Width := PanelWidth;
  1049.   Height := PanelHeight;
  1050.   Color := PanelColor;
  1051.   BevelWidth := PanelBevelWidth;
  1052.   FHighlightColor := PanelHighlightColor;
  1053.   FShadowColor := PanelShadowColor;
  1054.   FTheName := TheFilename;
  1055.   { If the ExtraData field is non-0 then a drive is being sent in }
  1056.   if ExtraData <> 0 then
  1057.   begin
  1058.     { Use the data field value to determine which icon to get from RES file }
  1059.     case ExtraData of
  1060.       1 : begin
  1061.             GetMem( TheOtherPChar , 255 );
  1062.             StrPCopy( TheOtherPChar , 'FLOPPY35' );
  1063.             FTheIcon.Handle := LoadIcon( hInstance , TheOtherPChar );
  1064.             FreeMem( TheOtherPChar , 255 );
  1065.           end;
  1066.       2 : begin
  1067.             GetMem( TheOtherPChar , 255 );
  1068.             StrPCopy( TheOtherPChar , 'FIXEDHD' );
  1069.             FTheIcon.Handle := LoadIcon( hInstance , TheOtherPChar );
  1070.             FreeMem( TheOtherPChar , 255 );
  1071.           end;
  1072.       3 : begin
  1073.             GetMem( TheOtherPChar , 255 );
  1074.             StrPCopy( TheOtherPChar , 'NETWORKHD' );
  1075.             FTheIcon.Handle := LoadIcon( hInstance , TheOtherPChar );
  1076.             FreeMem( TheOtherPChar , 255 );
  1077.           end;
  1078.       4 : begin
  1079.             GetMem( TheOtherPChar , 255 );
  1080.             StrPCopy( TheOtherPChar , 'CDROM' );
  1081.             FTheIcon.Handle := LoadIcon( hInstance , TheOtherPChar );
  1082.             FreeMem( TheOtherPChar , 255 );
  1083.           end;
  1084.       5 : begin
  1085.             GetMem( TheOtherPChar , 255 );
  1086.             StrPCopy( TheOtherPChar , 'RAM' );
  1087.             FTheIcon.Handle := LoadIcon( hInstance , TheOtherPChar );
  1088.             FreeMem( TheOtherPChar , 255 );
  1089.           end;
  1090.     end;
  1091.     { The FileNme property is already set up for the caption; use directly }
  1092.     FTheLabel.Caption := TheFilename;
  1093.     { Set up the hint for later use (make sure to set ShowHint) }
  1094.     Hint := 'Change to ' + TheFileName;
  1095.     ShowHint := true;
  1096.     { Set up all imported label properties and center it for drawing }
  1097.     with FTheLabel do
  1098.     begin
  1099.       Font.Name := LabelFontName;
  1100.       Font.Size := LabelFontSize;
  1101.       Font.Style := LabelFontStyle;
  1102.       Font.Color := LabelTextColor;
  1103.       Canvas.Brush.Color := PanelColor;
  1104.       Canvas.Font := Font;
  1105.       TheLabelHeight := Canvas.Textheight( Caption ) + 4;
  1106.       TheLabelWidth := Canvas.Textwidth( Caption ) + 4;
  1107.       Left := (( Self.Width - TheLabelWidth ) div 2 ) + 1;
  1108.       Top := ((( Round( Self.Height * 0.25 ) - 6 ) - TheLabelHeight) div 2) + 1;
  1109.       Top := Top + Round( Self.Height * 0.75 );
  1110.       Height := TheLabelHeight;
  1111.       Width := TheLabelWidth;
  1112.     end;
  1113.   end
  1114.   else
  1115.   begin
  1116.     { A file or directory has been sent in; use GetIconForFile to obtain an }
  1117.     { icon either from the file, its owner, or a RES file default.          }
  1118.     GetIconForFile( FTheName , FTheIcon );
  1119.     { Check for the Backup caption and set it specially }
  1120.     if ExtractfileName( FThename ) = '..' then
  1121.     begin
  1122.       FTheLabel.Caption := '..';
  1123.       Hint := 'Up One Level';
  1124.     end
  1125.     else
  1126.     begin
  1127.       { Otherwise just get the filename for the label caption }
  1128.       { And the full path for the hint (used later.)          }
  1129.       FTheLabel.caption := ExtractFileName( UpperCase( FTheName ));
  1130.       Hint := FTheName;
  1131.     end;
  1132.     { Activate showhint so hints are seen }
  1133.     ShowHint := true;
  1134.     { Set label properties with imported values and center for display }
  1135.     with FTheLabel do
  1136.     begin
  1137.       Font.Name := LabelFontName;
  1138.       Font.Size := LabelFontSize;
  1139.       Font.Style := LabelFontStyle;
  1140.       Font.Color := LabelTextColor;
  1141.       Canvas.Brush.Color := PanelColor;
  1142.       Canvas.Font := Font;
  1143.       TheLabelHeight := Canvas.Textheight( Caption ) + 4;
  1144.       TheLabelWidth := Canvas.Textwidth( Caption ) + 4;
  1145.       Left := (( Self.Width - TheLabelWidth ) div 2 ) + 1;
  1146.       Top := ((( Round( Self.Height * 0.25 ) - 6 ) - TheLabelHeight) div 2) + 1;
  1147.       Top := Top + Round( Self.Height * 0.75 );
  1148.       Height := TheLabelHeight;
  1149.       Width := TheLabelWidth;
  1150.     end;
  1151.   end;
  1152. end;
  1153.  
  1154. { Destroy method for FIP }
  1155. destructor TFileIconPanel.Destroy;
  1156. begin
  1157.   { free component resources }
  1158.   FTheIcon.Free;
  1159.   FTheLabel.Free;
  1160.   { call inherited -- VITAL! }
  1161.   inherited Destroy;
  1162. end;
  1163.  
  1164. { Mousedown method for FIP; used to allow dragging }
  1165. procedure TFileIconPanel.TheMouseDown(Sender: TObject;
  1166.   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  1167. begin
  1168.   { Begin a conditional drag operation (false allows timer) }
  1169.   BeginDrag( false );
  1170. end;
  1171.  
  1172. { Mouseup Method for FIP; used to allow dragging }
  1173. procedure TFileIconPanel.TheMouseUp(Sender: TObject;
  1174.   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  1175. begin
  1176.   { End a drag operation without dropping; if dragged OK }
  1177.   { already handled.                                     }
  1178.   EndDrag( false );
  1179. end;
  1180.  
  1181. { TheClick method for FIP; used for event responses }
  1182. procedure TFileIconPanel.TheClick( Sender : TObject );
  1183. begin
  1184.   { Currently ignore drive clicks }
  1185.   if Pos( 'DRIVE' , FTheName ) > 0 then exit;
  1186.   { Flip status of bevels }
  1187.   if BevelOuter = bvRaised then BevelOuter := bvLowered else
  1188.    BevelOuter := bvRaised;
  1189.   { Flip selected variable }
  1190.   Selected := not Selected;
  1191.   { Set redisplay }
  1192.   Invalidate;
  1193. end;
  1194.  
  1195. { TheDblClick method for FIP; used for event responses }
  1196. procedure TFileIconPanel.TheDblClick( Sender : TObject );
  1197. var CurrentDirectory : String;    { Use to store dirs }
  1198.     TheDrive         : String;    { Get drive letter  }
  1199.     WhichDrive       : Integer;   { Get drive number  }
  1200.     ErrorCheck       : Integer;
  1201.     TheFWB           : TFileWorkBench;
  1202. begin
  1203.   { Create FileWorkBench for later use }
  1204.   TheFWB := TFileWorkBench.Create( Self );
  1205.   { Check for label or FIP sender }
  1206.   if Sender is TFileIconPanel then
  1207.   begin
  1208.     if FTheLabel.Caption = '..' then
  1209.     begin { deal with backup request }
  1210.       { Change to new directory }
  1211.       TheFWB.ChangeTheDirectory( '..' );
  1212.       { Call special method due to SendMessage problem! }
  1213.       TFileIconPanelScrollBox( Parent ).Update;
  1214.     end
  1215.     else
  1216.     begin
  1217.       { Check for DRIVE id in name }
  1218.       if Pos( 'DRIVE' , FTheName ) <> 0 then
  1219.       begin { Double Click on a Drive Icon }
  1220.         { Pull out the letter from name }
  1221.         TheDrive := Copy( FtheName , 7 , 1 );
  1222.         { Convert it to a number }
  1223.         WhichDrive := ( Ord( TheDrive[ 1 ] ) - Ord( 'A' )) + 1;
  1224.         TheFWB.ChangeTheDriveAndDirectory( WhichDrive );
  1225.         { Call special method due to SendMessage problem! }
  1226.         TFileIconPanelScrollBox( Parent ).Update;
  1227.       end
  1228.       else
  1229.       begin { Double click on a dir/file icon }
  1230.         if (( FileGetAttr( FTheName ) and faDirectory ) = faDirectory ) then
  1231.         begin { A directory, change to it }
  1232.           { Since full path in name, simply change to it! }
  1233.           TheFWB.ChangeTheDirectory( FTheName );
  1234.           { Call special method due to SendMessage problem! }
  1235.           TFileIconPanelScrollBox( Parent ).Update;
  1236.         end
  1237.         else
  1238.         begin { A file; attempt to shellexecute it }
  1239.           { Call shellexec as a wrapper around ShellExecute API call }
  1240.           { False indicates failure, signal error                    }
  1241.           if not ShellExec( FTheName , '' , '', false , SW_SHOWNORMAL , false )
  1242.            then MessageDlg('Could not Shell out to ' + FTheName , mtError,
  1243.             [mbOK], 0);
  1244.         end;
  1245.       end;
  1246.     end;
  1247.   end
  1248.   else
  1249.   begin
  1250.     with Sender as TLabel do
  1251.     begin
  1252.       if Caption = '..' then
  1253.       begin { Deal with backup request }
  1254.         { Change to new directory }
  1255.         TheFWB.ChangeTheDirectory( '..' );
  1256.         { Call special method due to SendMessage problem! }
  1257.         TFileIconPanelScrollBox( Parent ).Update;
  1258.       end
  1259.       else
  1260.       begin
  1261.         with Parent as TFileIconPanel do
  1262.         begin
  1263.           { Check for DRIVE id in name }
  1264.           if Pos( 'DRIVE' , FTheName ) <> 0 then
  1265.           begin { Double Click on a Drive Icon }
  1266.             { Pull out the letter from name }
  1267.             TheDrive := Copy( FtheName , 7 , 1 );
  1268.             { Convert it to a number }
  1269.             WhichDrive := ( Ord( TheDrive[ 1 ] ) - Ord( 'A' )) + 1;
  1270.             { Call the method to change to default dir on new drive }
  1271.             TheFWB.ChangeTheDriveAndDirectory( WhichDrive );
  1272.             { Call special method due to SendMessage problem! }
  1273.             TFileIconPanelScrollBox( Parent ).Update;
  1274.           end
  1275.           else
  1276.           begin { Double click on a dir/file icon }
  1277.             if (( FileGetAttr( FTheName ) and faDirectory ) = faDirectory ) then
  1278.             begin { A directory, change to it }
  1279.               { Since full path in name, simply change to it! }
  1280.               TheFWB.ChangeTheDirectory( FTheName );
  1281.               { Call special method due to SendMessage problem! }
  1282.               TFileIconPanelScrollBox( Parent ).Update;
  1283.             end
  1284.             else
  1285.             begin { A file; attempt to shellexecute it }
  1286.               { Call shellexec as a wrapper around ShellExecute API call }
  1287.               { False indicates failure, signal error                    }
  1288.               if not ShellExec( FTheName , '' , '', false , SW_SHOWNORMAL ,
  1289.                false ) then MessageDlg('Could not Shell out to ' + FTheName ,
  1290.                 mtError, [mbOK], 0);
  1291.             end;
  1292.           end;
  1293.         end;
  1294.       end;
  1295.     end;
  1296.   end;
  1297.   TheFWB.Free; { This prevents resource leak }
  1298. end;
  1299.  
  1300. { Paint method for FIP; overrides normal paint }
  1301. procedure TFileIconPanel.Paint;
  1302. var
  1303.   TheOtherRect   : TRect;   { Holds clientrect   }
  1304.   TopColor     ,            { Holds bright color }
  1305.   BottomColor    : TColor;  { Holds dark color   }
  1306.  
  1307. { These methods are from Borland Intl., copyright 1995 }
  1308. procedure Frame3D(    Canvas       : TCanvas;
  1309.                   var TheRect      : TRect;
  1310.                       TopColor   ,
  1311.                       BottomColor  : TColor;
  1312.                       Width        : Integer );
  1313.  
  1314. procedure DoRect;
  1315. var
  1316.   TopRight, BottomLeft: TPoint;
  1317. begin
  1318.   with Canvas, TheRect do
  1319.   begin
  1320.     TopRight.X := Right;
  1321.     TopRight.Y := Top;
  1322.     BottomLeft.X := Left;
  1323.     BottomLeft.Y := Bottom;
  1324.     Pen.Color := TopColor;
  1325.     PolyLine([BottomLeft, TopLeft, TopRight]);
  1326.     Pen.Color := BottomColor;
  1327.     Dec(BottomLeft.X);
  1328.     PolyLine([TopRight, BottomRight, BottomLeft]);
  1329.   end;
  1330. end;
  1331.  
  1332. begin
  1333.   Canvas.Pen.Width := 1;
  1334.   Dec(TheRect.Bottom); Dec(TheRect.Right);
  1335.   while Width > 0 do
  1336.   begin
  1337.     Dec(Width);
  1338.     DoRect;
  1339.     InflateRect(TheRect, -1, -1);
  1340.   end;
  1341.   Inc(TheRect.Bottom); Inc(TheRect.Right);
  1342. end;
  1343.  
  1344. procedure AdjustColors(Bevel: TPanelBevel);
  1345. begin
  1346.   TopColor := FHighlightColor;
  1347.   if Bevel = bvLowered then TopColor := FShadowColor;
  1348.   BottomColor := FShadowColor;
  1349.   if Bevel = bvLowered then BottomColor := FHighlightColor;
  1350. end;
  1351.  
  1352. { Custom code begins here }
  1353. begin
  1354.   { Get the rectangle of the control with API/method call }
  1355.   TheOtherRect := GetClientRect;
  1356.   { draw basic rectangle with basic color }
  1357.   with Canvas do
  1358.   begin
  1359.     Brush.Color := Color;
  1360.     FillRect(TheOtherRect);
  1361.   end;
  1362.   { Set up for top "icon" frame  and draw it with frame3d }
  1363.   TheOtherRect.Right := Width;
  1364.   TheOtherRect.Bottom := Round( Height * 0.75 ) - 6 ;
  1365.   if BevelOuter <> bvNone then
  1366.   begin
  1367.     AdjustColors(BevelOuter);
  1368.     Frame3D(Canvas, TheOtherRect, TopColor, BottomColor, BevelWidth);
  1369.   end;
  1370.   Frame3D(Canvas, TheOtherRect, Color, Color, BorderWidth);
  1371.   if BevelInner <> bvNone then
  1372.   begin
  1373.     AdjustColors(BevelInner);
  1374.     Frame3D(Canvas, TheOtherRect, TopColor, BottomColor, BevelWidth);
  1375.   end;
  1376.   { Do the same for the lower "label" frame }
  1377.   TheOtherRect.Top := Round( Height * 0.75 ) - 5;
  1378.   TheOtherRect.Left := 0;
  1379.   TheOtherRect.Bottom := Height;
  1380.   TheOtherRect.Right := Width;
  1381.   if BevelOuter <> bvNone then
  1382.   begin
  1383.     AdjustColors(BevelOuter);
  1384.     Frame3D(Canvas, TheOtherRect, TopColor, BottomColor, BevelWidth);
  1385.   end;
  1386.   Frame3D(Canvas, TheOtherRect, Color, Color, BorderWidth);
  1387.   if BevelInner <> bvNone then
  1388.   begin
  1389.     AdjustColors(BevelInner);
  1390.     Frame3D(Canvas, TheOtherRect, TopColor, BottomColor, BevelWidth);
  1391.   end;
  1392.   { Then draw the icon using canvas draw method }
  1393.   Canvas.Draw( (( Width - 32 ) div 2 ) + 1 ,
  1394.   ((( Round( Height * 0.75 ) - 6 ) - 32 ) div 2 ) + 1 , FTheIcon );
  1395. end;
  1396.  
  1397. { This procedure clears a scrollbox of all FileIconPanels }
  1398. procedure TFileIconPanelScrollbox.ClearTheFIPs;
  1399. var Counter_1 : Integer;
  1400.     TheComponent : TComponent;
  1401. begin
  1402.   { Note that must use while loop since component count continually }
  1403.   { decreases as removes are made!                                  }
  1404.   while ComponentCount > 0 do
  1405.   begin
  1406.     { Save the component as a generic TComponent }
  1407.     TheComponent := Components[ 0 ];
  1408.     { Call removecomponent to pull it out of the owner list for sb }
  1409.     { This avoids GPF when freeing the sb.                         }
  1410.     RemoveComponent( Components[ 0 ]);
  1411.     if ControlCount > 0 then
  1412.      RemoveControl( Controls[ 0 ] );
  1413.     { Typecast the pointer and free it to release memory and res. }
  1414.     TFileIconPanel( TheComponent ).visible := false;
  1415.     Application.MainForm.InsertComponent( TheComponent );
  1416.   end;
  1417. end;
  1418.  
  1419. { This procedure scans for drives and obtains their type and creates file }
  1420. { icon panels to represent them.                                          }
  1421. procedure TFileIconPanelScrollBox.AddDriveIcons( var XCounter ,
  1422.            YCounter : Integer );
  1423. type
  1424.   { This if from filectrl unit; reproduce here for completeness }
  1425.   TDriveType = (dtUnknown, dtNoDrive, dtFloppy, dtFixed, dtNetwork, dtCDROM,
  1426.                 dtRAM);
  1427. var
  1428.   DriveNum        : Integer;         { Used to get next drive via DOS fn   }
  1429.   IconType        : Integer;         { Used to hold icon type (defacto dt) }
  1430.   DriveChar       : Char;            { Used to hold drive letter           }
  1431.   DriveType       : TDriveType;      { Used for set-valued drive type      }
  1432.   Finished        : Boolean;         { Loop flag                           }
  1433.   TheFIP          : TFileIconPanel;  { Generic FileIconPanel variable      }
  1434.   ButtonColor   ,                    { Main panel color                    }
  1435.   ButtonHLColor ,                    { Bright panel color                  }
  1436.   ButtonSColor  ,                    { Dark panel color                    }
  1437.   Textcolor       : TColor;          { Label text color                    }
  1438.  
  1439. { This code is from the FileCtrl Unit; copyright Borland Intl 1995      }
  1440. { Check whether drive is a CD-ROM.  Returns True if MSCDEX is installed }
  1441. {  and the drive is using a CD driver                                   }
  1442.  
  1443. function IsCDROM(DriveNum: Integer): Boolean; assembler;
  1444. asm
  1445.   MOV   AX,1500h { look for MSCDEX }
  1446.   XOR   BX,BX
  1447.   INT   2fh
  1448.   OR    BX,BX
  1449.   JZ    @Finish
  1450.   MOV   AX,150Bh { check for using CD driver }
  1451.   MOV   CX,DriveNum
  1452.   INT   2fh
  1453.   OR    AX,AX
  1454.   @Finish:
  1455. end;
  1456.  
  1457. { This code is from the FileCtrl Unit; copyright Borland Intl 1995      }
  1458. { Check whether drive is a RAM drive.                                   }
  1459. function IsRAMDrive(DriveNum: Integer): Boolean; assembler;
  1460. var
  1461.   TempResult: Boolean;
  1462. asm
  1463.   MOV   TempResult,False
  1464.   PUSH  DS
  1465.   MOV   BX,SS
  1466.   MOV   DS,BX
  1467.   SUB   SP,0200h
  1468.   MOV   BX,SP
  1469.   MOV   AX,DriveNum
  1470.   MOV   CX,1
  1471.   XOR   DX,DX
  1472.   INT   25h  { read boot sector }
  1473.   ADD   SP,2
  1474.   JC    @ItsNot
  1475.   MOV   BX,SP
  1476.   CMP   BYTE PTR SS:[BX+15h],0F8h  { reverify fixed disk }
  1477.   JNE   @ItsNot
  1478.   CMP   BYTE PTR SS:[BX+10h],1  { check for single FAT }
  1479.   JNE   @ItsNot
  1480.   MOV   TempResult,True
  1481.   @ItsNot:
  1482.   ADD   SP,0200h
  1483.   POP   DS
  1484.   MOV   AL, TempResult
  1485. end;
  1486.  
  1487. { This code is from the FileCtrl Unit; copyright Borland Intl 1995      }
  1488. { Finds the type of a drive letter.                                     }
  1489. function FindDriveType(DriveNum: Integer): TDriveType;
  1490. begin
  1491.   Result := TDriveType(GetDriveType(DriveNum));
  1492.   if (Result = dtFixed) or (Result = dtNetwork) then
  1493.   begin
  1494.     if IsCDROM(DriveNum) then Result := dtCDROM
  1495.     else if (Result = dtFixed) then
  1496.     begin
  1497.         { do not check for RAMDrive under Windows NT }
  1498.       if ((GetWinFlags and $4000) = 0) and IsRAMDrive(DriveNum) then
  1499.         Result := dtRAM;
  1500.     end;
  1501.   end;
  1502. end;
  1503.  
  1504. begin
  1505.   { Set the button colors to an aquamarine color scheme for drives }
  1506.   ButtonColor := clTeal;
  1507.   ButtonHLColor := clAqua;
  1508.   ButtonSColor := clNavy;
  1509.   TextColor := clblack;
  1510.   { Set initial variables before looping for all drives }
  1511.   finished := false;
  1512.   DriveNum := 0;
  1513.   while not finished do
  1514.   begin
  1515.     { Start with no drive found }
  1516.     IconType := 0;
  1517.     { Call the Borland method to get the drive info }
  1518.     DriveType := FindDriveType(DriveNum);
  1519.     { Set its letter and make it uppercase }
  1520.     DriveChar := Chr(DriveNum + ord('a'));
  1521.     DriveChar := Upcase(DriveChar);
  1522.     { Assign an icon based on the drive type; if no drive exists type is nil }
  1523.     case DriveType of
  1524.       dtFloppy  : IconType := 1;
  1525.       dtFixed   : IconType := 2;
  1526.       dtNetwork : IconType := 3;
  1527.       dtCDROM   : IconType := 4;
  1528.       dtRAM     : IconType := 5;
  1529.     end;
  1530.     { Set to check next drive letter }
  1531.     DriveNum := DriveNum + 1;
  1532.     { But if no match then out of drives so set exit flag }
  1533.     if IconType = 0 then finished := true;
  1534.     { If drive was valid then set up the new FileIconPanel on the imported }
  1535.     { Scrollbox                                                            }
  1536.     if not finished then
  1537.     begin
  1538.       { Create the FileIconPanel and set its parent for memory mgmt and display}
  1539.       TheFIP := TFileIconPanel.Create( Self );
  1540.       TheFIP.Parent := Self;
  1541.       { Call its initialize method with imported position values and the   }
  1542.       { preset color scheme, a drive caption, and a minimum font. Note the }
  1543.       { setting of the ExtraData field to non-zero; this signals a drive   }
  1544.       { rather than a file being sent in.                                  }
  1545.       TheFIP.Initialize((( XCounter - 1 ) * TheIconSpacing ),
  1546.        (( YCounter - 1  ) * TheIconSpacing ) , TheIconSize , TheIconSize , 3 ,
  1547.         7 , ButtonColor, ButtonHLColor,
  1548.        ButtonSColor , TextColor , 'DRIVE ' + DriveChar + ':' , 'MS Serif' , [] ,
  1549.        IconType );
  1550.       { Increment the column counter; if it exceeds max move to new row      }
  1551.       { Note that these are 'var' parameters and will export final position. }
  1552.       XCounter := XCounter + 1;
  1553.       if XCounter > MaxIconsInARow then
  1554.       begin
  1555.         XCounter := 1;
  1556.         YCounter := YCounter + 1;
  1557.       end;
  1558.     end;
  1559.   end;
  1560. end;
  1561.  
  1562. { This procedure assigns colors to FIP's based on file attributes }
  1563. procedure TFileIconPanelScrollBox.GetColorsForFileIcon( TheFile : String;
  1564.            var BC , HC , SC , TC : TColor );
  1565. var AmADir      ,             { Booleans hold file attribs }
  1566.     AmAnArchive ,
  1567.     AmAVolumeId ,
  1568.     AmHidden    ,
  1569.     AmReadOnly  ,
  1570.     AmSystem      : Boolean;
  1571. begin
  1572.   { Make the call to internal fileworkbench to set attributes }
  1573.   TheFWB.GetFileAttributes( TheFile , AmADir , AmAnArchive , AmAVolumeId ,
  1574.    AmHidden , AmReadOnly , AmSystem );
  1575.   { Volume ID has no subtypes }
  1576.   if AmAVolumeID then
  1577.   begin
  1578.     BC := clOlive;
  1579.     HC := clYellow;
  1580.     SC := clBlack;
  1581.     TC := clWhite;
  1582.     exit;
  1583.   end;
  1584.   { Check all directory combinations }
  1585.   if AmADir then
  1586.   begin
  1587.     BC := clNavy;
  1588.     HC := clBlue;
  1589.     SC := clBlack;
  1590.     TC := clWhite;
  1591.     if AmHidden then
  1592.     begin
  1593.       if AmReadOnly then
  1594.       begin
  1595.         if AmSystem then
  1596.         begin { One HECK of a file! }
  1597.           BC := clBlack;
  1598.           HC := clSilver;
  1599.           SC := clGray;
  1600.           TC := clWhite;
  1601.         end
  1602.         else
  1603.         begin { Dir,RO,Hid }
  1604.           BC := clMaroon;
  1605.           HC := clFuchsia;
  1606.           SC := clGreen;
  1607.           TC := clWhite;
  1608.         end;
  1609.       end
  1610.       else
  1611.       begin { Dir,Hid }
  1612.         BC := clPurple;
  1613.         HC := clFuchsia;
  1614.         SC := clBlack;
  1615.         TC := clWhite;
  1616.       end;
  1617.     end
  1618.     else
  1619.     begin
  1620.       if AmReadOnly then
  1621.       begin
  1622.         if AmSystem then
  1623.         begin { Dir,RO,Sys }
  1624.           BC := clMaroon;
  1625.           HC := clLime;
  1626.           SC := clGreen;
  1627.           TC := clWhite;
  1628.         end
  1629.         else
  1630.         begin { Dir,RO }
  1631.           BC := clGreen;
  1632.           HC := clLime;
  1633.           SC := clBlack;
  1634.           TC := clWhite;
  1635.         end;
  1636.       end
  1637.       else
  1638.       begin
  1639.         if AmSystem then
  1640.         begin { Dir,Sys }
  1641.           BC := clMaroon;
  1642.           HC := clRed;
  1643.           SC := clBlack;
  1644.           TC := clWhite;
  1645.         end;
  1646.       end;
  1647.     end;
  1648.   end
  1649.   else { Archive Only; check all combinations }
  1650.   begin
  1651.     BC := clSilver;
  1652.     HC := clWhite;
  1653.     SC := clGray;
  1654.     TC := clBlack;
  1655.     if AmHidden then
  1656.     begin
  1657.       if AmReadOnly then
  1658.       begin
  1659.         if AmSystem then
  1660.         begin { Hid,RO,Sys }
  1661.           BC := clRed;
  1662.           HC := clLime;
  1663.           SC := clPurple;
  1664.           TC := clBlack;
  1665.         end
  1666.         else
  1667.         begin { RO,Hid }
  1668.           BC := clLime;
  1669.           HC := clFuchsia;
  1670.           SC := clMaroon;
  1671.           TC := clBlack;
  1672.         end;
  1673.       end
  1674.       else
  1675.       begin { Hid }
  1676.         BC := clFuchsia;
  1677.         HC := clWhite;
  1678.         SC := clPurple;
  1679.         TC := clBlack;
  1680.       end;
  1681.     end
  1682.     else
  1683.     begin
  1684.       if AmReadOnly then
  1685.       begin
  1686.         if AmSystem then
  1687.         begin { RO,Sys }
  1688.           BC := clRed;
  1689.           HC := clLime;
  1690.           SC := clMaroon;
  1691.           TC := clBlack;
  1692.         end
  1693.         else
  1694.         begin { RO }
  1695.           BC := clLime;
  1696.           HC := clWhite;
  1697.           SC := clGreen;
  1698.           TC := clBlack;
  1699.         end;
  1700.       end
  1701.       else
  1702.       begin
  1703.         if AmSystem then
  1704.         begin { System }
  1705.           BC := clRed;
  1706.           HC := clWhite;
  1707.           SC := clMaroon;
  1708.           TC := clBlack;
  1709.         end;
  1710.       end;
  1711.     end;
  1712.   end;
  1713. end;
  1714.  
  1715. { This procedure gets all icons for an given directory, including drives and }
  1716. { standard subdirectories. It does not get special combinations or h/ro/sys  }
  1717. procedure TFileIconPanelScrollbox.GetIconsForEntireDirectory(
  1718.             TargetPath  : String );
  1719. var Finished        : Boolean;         { Loop flag              }
  1720.     TheSR           : TSearchRec;      { Searchrecord for FF/FN }
  1721.     TheResult       : Integer;         { return variable        }
  1722.     TempPath        : String;          { path for FF/FN         }
  1723.     TheFIP          : TFileIconPanel;  { generic FIP holder     }
  1724.     RowCounter    ,                    { position in row of FIP }
  1725.     ColumnCounter   : Integer;         { position in col of FIP }
  1726.     ButtonColor   ,                    { main panel color       }
  1727.     ButtonHLColor ,                    { bright panel color     }
  1728.     ButtonSColor  ,                    { dark panel color       }
  1729.     Textcolor       : TColor;          { label text color       }
  1730.     IsADir ,                           { Variable for file attr }
  1731.     IsAnArchive ,
  1732.     IsAVolumeID,
  1733.     IsAReadOnlyFile,
  1734.     IsAHiddenFile ,
  1735.     IsASystemFile     : Boolean;
  1736.     MaxTextLength     : Integer;       { Used to safely set size}
  1737. begin
  1738.   { hide during refresh }
  1739.   Visible := false;
  1740.   { Get the icon sizes }
  1741.   TheFIP := TFileIconPanel.Create( Self );
  1742.   TheFIP.Parent := Self;
  1743.   TheFIP.FTheLabel.Canvas.Font.Name := 'MS Serif';
  1744.   TheFIP.FTheLabel.Canvas.Font.Size := 7;
  1745.   MaxTextLength := TheFIP.FTheLabel.Canvas.TextWidth( 'COMMAND.COM' );
  1746.   TheFIP.Free;
  1747.   TheIconSize := MaxTextLength + 13;
  1748.   TheIconSpacing := TheIconSize + 5;
  1749.   { Set up maximum icons per row based on screen size }
  1750.   MaxIconsInARow := ( Screen.Width div TheIconSpacing );
  1751.   { Set up the position counters }
  1752.   RowCounter := 1;
  1753.   ColumnCounter := 1;
  1754.   { Get the drives for the current machine }
  1755.   AddDriveIcons( ColumnCounter , RowCounter  );
  1756.   { Set up the initial variables }
  1757.   Finished := false;
  1758.   TempPath := TargetPath + '*.*';
  1759.   { Make the call to FindFirst set to get any file; will return '.' }
  1760.   { so discard it.                                                  }
  1761.   TheResult := FindFirst( TempPath , faAnyFile , TheSR );
  1762.   { loop through all files in the directory and look for directories }
  1763.   while not Finished do
  1764.   begin
  1765.     { Make call to FindNext, using only SearchRecord from FindFirst }
  1766.     TheResult := FindNext( TheSR );
  1767.     { A -1 result means no more files so exit }
  1768.     if TheResult < 0 then finished := true else
  1769.     begin
  1770.       { Otherwise check for a directory attribute }
  1771.       if (( FileGetAttr( TargetPath + TheSR.Name ) and faDirectory ) =
  1772.        faDirectory ) then
  1773.       begin
  1774.         GetColorsForFileIcon( TargetPath + TheSR.Name , ButtonColor ,
  1775.          ButtonHLColor , ButtonSColor , TextColor );
  1776.         { If found create a new FileIconPanel on the imported scrollbox }
  1777.         { Note sending 0 ExtraData parameter to indicate file not drive }
  1778.         TheFIP := TFileIconPanel.Create( Self );
  1779.         TheFIP.Parent := Self;
  1780.         TheFIP.Initialize((( ColumnCounter - 1 ) * TheIconSpacing ),
  1781.          (( RowCounter - 1  ) * TheIconSpacing ) , TheIconSize, TheIconSize ,
  1782.           3 , 7 , ButtonColor, ButtonHLColor , ButtonSColor , TextColor ,
  1783.            TargetPath + TheSr.Name , 'MS Serif' , [] , 0 );
  1784.         { Increment column counter and move to new row if past limit }
  1785.         ColumnCounter := ColumnCounter + 1;
  1786.         if ColumnCounter > MaxIconsInARow then
  1787.         begin
  1788.           ColumnCounter := 1;
  1789.           RowCounter := RowCounter + 1;
  1790.         end;
  1791.       end;
  1792.     end;
  1793.   end;
  1794.   { Call FindClose for Windows NT/Windows 95 compatibility }
  1795.   FindClose( TheSR );
  1796.   { Set up new initialization variables }
  1797.   Finished := false;
  1798.   TempPath := TargetPath + '*.*';
  1799.   { Make needed call to FindFirst and discard '.' }
  1800.   TheResult := FindFirst( TempPath , faAnyFile , TheSR );
  1801.   while not Finished do
  1802.   begin
  1803.     { Loop through file again, this time getting only archive files }
  1804.     TheResult := FindNext( TheSR );
  1805.     { Result of -1 indicates no more files }
  1806.     if TheResult < 0 then Finished := true else
  1807.     begin
  1808.       { If faArchive file then add new FileIconPanel }
  1809.       TheFWB.GetFileAttributes(( Targetpath + TheSR.Name ) , IsADir ,
  1810.        IsAnArchive , IsAVolumeId , IsAHiddenFile , IsAReadOnlyFile ,
  1811.         IsASystemFile );
  1812.       if (( IsAnArchive ) and ( not IsADir )) then
  1813.       begin
  1814.         GetColorsForFileIcon( TargetPath + TheSR.Name , ButtonColor ,
  1815.          ButtonHLColor , ButtonSColor , TextColor );
  1816.         { Initialize new FileIconPanel and call initialize, sending 0 ED }
  1817.         TheFIP := TFileIconPanel.Create( Self );
  1818.         TheFIP.Parent := Self;
  1819.         TheFIP.Initialize((( ColumnCounter - 1 ) * TheIconSpacing ),
  1820.          (( RowCounter - 1  ) * TheIconSpacing ) , TheIconSize , TheIconSize ,
  1821.           3 , 7 , ButtonColor, ButtonHLColor , ButtonSColor , TextColor ,
  1822.            TargetPath + TheSr.Name , 'MS Serif' , [] , 0 );
  1823.         { Increment column counter and if needed row counter }
  1824.         ColumnCounter := ColumnCounter + 1;
  1825.         if ColumnCounter > MaxIconsInARow then
  1826.         begin
  1827.           ColumnCounter := 1;
  1828.           RowCounter := RowCounter + 1;
  1829.         end;
  1830.       end;
  1831.     end;
  1832.   end;
  1833.   { Call findclose for w95 and exit }
  1834.   FindClose( TheSR );
  1835.   { Reset to visible }
  1836.   Visible := true;
  1837. end;
  1838.  
  1839. { Update method for FIPscrollbox }
  1840. procedure TFileIconPanelScrollBox.Update;
  1841. begin
  1842.   IconsNeedRefreshing := true;
  1843.   { Force a repaint }
  1844.   InvalidateRect( TheStoredHandle , nil , true );
  1845. end;
  1846.  
  1847. { Create method for FIPScrollbox }
  1848. constructor TFileIconPanelScrollBox.Create( AOwner : TComponent );
  1849. begin
  1850.   inherited Create( AOwner );
  1851.   TheFWB := TFileWorkBench.Create( Self );
  1852. end;
  1853.  
  1854. { This function returns the next selected file's name }
  1855. function TFileIconPanelScrollBox.GetNextSelection( SourceDirectory : String;
  1856.                            var CurrentItem : Integer ) : String;
  1857. var TheResult    : String;      { Holds result of function }
  1858.     TheComponent : TComponent;  { Used for typecast        }
  1859.     finished     : boolean;     { Loop control variable    }
  1860.     TheComponentCount : Integer;
  1861. begin
  1862.   TheComponentCount := ComponentCount;
  1863.   { If past end of components exit with no result }
  1864.   if CurrentItem > TheComponentCount then TheResult := '' else
  1865.   begin
  1866.     { Set loop counter and run till find match or run out }
  1867.     finished := false;
  1868.     while not finished do
  1869.     begin
  1870.       { Pull component out of the list and check it }
  1871.       TheComponent := Components[ CurrentItem - 1 ];
  1872.       { Increment counter for later }
  1873.       CurrentItem := CurrentItem + 1;
  1874.       { Do the typecast with AS }
  1875.       if TheComponent is TFileIconPanel then
  1876.       with TheComponent as TFileIconPanel do
  1877.       begin
  1878.         { If its selected make sure OK }
  1879.         if Selected then
  1880.         begin
  1881.           { Don't accept backup for this level of operation }
  1882.           if FTheLabel.Caption <> '..' then
  1883.           begin
  1884.             { Otherwise return the name and abort the loop }
  1885.             TheResult := FTheName;
  1886.             finished := true;
  1887.           end;
  1888.         end
  1889.         else
  1890.         begin
  1891.           { Check to see if out of components }
  1892.           if CurrentItem > TheComponentCount then
  1893.           begin
  1894.             { If so signal error and abort }
  1895.             TheResult := '';
  1896.             finished := true;
  1897.           end;
  1898.         end;
  1899.       end;
  1900.     end;
  1901.   end;
  1902.   GetNextSelection := TheResult;
  1903. end;
  1904.  
  1905. { This procedure places a selection of files in the display based on wildcards }
  1906. procedure TFileIconPanelScrollBox.DisplayRecursiveSearchResults(
  1907.            TheStartingDirectory : String );
  1908. var XCounter ,
  1909.     YCounter   : Integer;
  1910.  
  1911. { This procedure does a recursive file search by first getting all matches (in-}
  1912. { cluding directories) and adding them to the list. Then it checks for ALL the }
  1913. { subdirectories and does the same trick on them til there are no more matches }
  1914. { and no more subdirectories, at which point it exits and recurses back up.    }
  1915. procedure RecursiveFileSearch( TheWorkingDirectory : String; var XCounter ,
  1916.                                YCounter : Integer );
  1917.  
  1918. { VITAL!!! These variables MUST be local for recursrion to work! }
  1919. var
  1920.     Finished        : Boolean;         { Loop flag              }
  1921.     TheSR           : TSearchRec;      { Searchrecord for FF/FN }
  1922.     TheResult       : Integer;         { return variable        }
  1923.     TargetPath ,
  1924.     FileMask   ,
  1925.     TheStoredWorkingDirectory ,
  1926.     ModifiedDirectory  : String;       { path for FF/FN         }
  1927.     TheFIP          : TFileIconPanel;  { generic FIP holder     }
  1928.     ButtonColor   ,                    { main panel color       }
  1929.     ButtonHLColor ,                    { bright panel color     }
  1930.     ButtonSColor  ,                    { dark panel color       }
  1931.     Textcolor       : TColor;          { label text color       }
  1932.  
  1933. begin
  1934.   { Set up the initial variables }
  1935.   Finished := false;
  1936.   TheStoredWorkingDirectory := TheWorkingDirectory;
  1937.   Targetpath := ExtractFilePath( TheWorkingDirectory );
  1938.   FileMask := ExtractFileName( TheWorkingDirectory );
  1939.   { Make the call to FindFirst set to get any file }
  1940.   TheResult := FindFirst( TheWorkingDirectory , faAnyFile , TheSR );
  1941.   if TheResult < 0 then finished := true;
  1942.   if (( TheSr.Name <> '.' ) and ( TheSr.Name <> '..' ) and ( TheResult >= 0 ))
  1943.   then begin
  1944.     if (( FileGetAttr( TargetPath + TheSR.Name ) and faDirectory ) =
  1945.      faDirectory ) then
  1946.     begin { A directory }
  1947.       GetColorsForFileIcon( TargetPath + TheSR.Name , ButtonColor ,
  1948.        ButtonHLColor , ButtonSColor , TextColor );
  1949.       { If found create a new FileIconPanel on the imported scrollbox }
  1950.       { Note sending 0 ExtraData parameter to indicate file not drive }
  1951.       TheFIP := TFileIconPanel.Create( Self );
  1952.       TheFIP.Parent := Self;
  1953.       TheFIP.Initialize((( XCounter - 1 ) * TheIconSpacing ),
  1954.        (( YCounter - 1  ) * TheIconSpacing ) , TheIconSize , TheIconSize , 3 ,
  1955.         7 , ButtonColor, ButtonHLColor , ButtonSColor , TextColor , TargetPath
  1956.          + TheSr.Name , 'MS Serif' , [] , 0 );
  1957.       { Increment column counter and move to new row if past limit }
  1958.       XCounter := XCounter + 1;
  1959.       if XCounter > MaxIconsInARow then
  1960.       begin
  1961.         XCounter := 1;
  1962.         YCounter := YCounter + 1;
  1963.       end;
  1964.     end
  1965.     else
  1966.     begin { A File }
  1967.       { Set up the default color scheme for files }
  1968.       GetColorsForFileIcon( TargetPath + TheSR.Name , ButtonColor ,
  1969.        ButtonHLColor , ButtonSColor , TextColor );
  1970.       { If found create a new FileIconPanel on the imported scrollbox }
  1971.       { Note sending 0 ExtraData parameter to indicate file not drive }
  1972.       TheFIP := TFileIconPanel.Create( Self );
  1973.       TheFIP.Parent := Self;
  1974.       TheFIP.Initialize((( XCounter - 1 ) * TheIconSpacing ),
  1975.        (( YCounter - 1  ) * TheIconSpacing ) , TheIconSize, TheIconSize , 3 ,
  1976.         7 , ButtonColor, ButtonHLColor , ButtonSColor , TextColor , TargetPath
  1977.          + TheSr.Name , 'MS Serif' , [] , 0 );
  1978.       { Increment column counter and move to new row if past limit }
  1979.       XCounter := XCounter + 1;
  1980.       if XCounter > MaxIconsInARow then
  1981.       begin
  1982.         XCounter := 1;
  1983.         YCounter := YCounter + 1;
  1984.       end;
  1985.     end;
  1986.   end;
  1987.   { loop through all files in the directory and look for matches }
  1988.   while not Finished do
  1989.   begin
  1990.     { Make call to FindNext, using only SearchRecord from FindFirst }
  1991.     TheResult := FindNext( TheSR );
  1992.     { A -1 result means no more files so exit }
  1993.     if TheResult < 0 then finished := true else
  1994.     begin
  1995.       if (( FileGetAttr( TargetPath + TheSR.Name ) and faDirectory ) =
  1996.        faDirectory ) then
  1997.       begin { A directory }
  1998.         { Set up the blue color scheme for directories }
  1999.         GetColorsForFileIcon( TargetPath + TheSR.Name , ButtonColor ,
  2000.          ButtonHLColor , ButtonSColor , TextColor );
  2001.         { If found create a new FileIconPanel on the imported scrollbox }
  2002.         { Note sending 0 ExtraData parameter to indicate file not drive }
  2003.         TheFIP := TFileIconPanel.Create( Self );
  2004.         TheFIP.Parent := Self;
  2005.         TheFIP.Initialize((( XCounter - 1 ) * TheIconSpacing ),
  2006.          (( YCounter - 1  ) * TheIconSpacing ) , TheIconSize , TheIconSize , 3 ,
  2007.            7 , ButtonColor, ButtonHLColor , ButtonSColor , TextColor ,
  2008.             TargetPath + TheSr.Name , 'MS Serif' , [] , 0 );
  2009.         { Increment column counter and move to new row if past limit }
  2010.         XCounter := XCounter + 1;
  2011.         if XCounter > MaxIconsInARow then
  2012.         begin
  2013.           XCounter := 1;
  2014.           YCounter := YCounter + 1;
  2015.         end;
  2016.       end
  2017.       else
  2018.       begin { A File }
  2019.         { Set up the default color scheme for files }
  2020.         GetColorsForFileIcon( TargetPath + TheSR.Name , ButtonColor ,
  2021.          ButtonHLColor , ButtonSColor , TextColor );
  2022.         { If found create a new FileIconPanel on the imported scrollbox }
  2023.         { Note sending 0 ExtraData parameter to indicate file not drive }
  2024.         TheFIP := TFileIconPanel.Create( Self );
  2025.         TheFIP.Parent := Self;
  2026.         TheFIP.Initialize((( XCounter - 1 ) * TheIconSpacing ),
  2027.          (( YCounter - 1  ) * TheIconSpacing ) , TheIconSize , TheIconSize , 3 ,
  2028.           7 , ButtonColor, ButtonHLColor , ButtonSColor , TextColor ,
  2029.            TargetPath + TheSr.Name , 'MS Serif' , [] , 0 );
  2030.         { Increment column counter and move to new row if past limit }
  2031.         XCounter := XCounter + 1;
  2032.         if XCounter > MaxIconsInARow then
  2033.         begin
  2034.           XCounter := 1;
  2035.           YCounter := YCounter + 1;
  2036.         end;
  2037.       end;
  2038.     end;
  2039.   end;
  2040.   { Call FindClose for Windows NT/Windows 95 compatibility }
  2041.   FindClose( TheSR );
  2042.   { Set up the variables to do recursive calls on all directories}
  2043.   Finished := false;
  2044.   ModifiedDirectory := ExtractFilePath( TheWorkingdirectory ) + '*.*';
  2045.   { Make the call to FindFirst set to get any file, ignore result }
  2046.   TheResult := FindFirst( ModifiedDirectory , faDirectory , TheSR );
  2047.   while not Finished do
  2048.   begin
  2049.     { Make call to FindNext, using only SearchRecord from FindFirst }
  2050.     TheResult := FindNext( TheSR );
  2051.     { A -1 result means no more files so exit }
  2052.     if TheResult < 0 then finished := true
  2053.     else
  2054.     begin
  2055.       if TheSR.Name <> '..' then { Ignore backup in this case }
  2056.       begin
  2057.         { Do second check due to bug in FindNext }
  2058.         if (( FileGetAttr( TargetPath + TheSR.Name ) and faDirectory )
  2059.         = faDirectory ) then
  2060.         begin
  2061.           { Set up modified directory to recurse into }
  2062.           ModifiedDirectory := ExtractFilePath( TheStoredWorkingDirectory ) +
  2063.            TheSR.Name + '\' + FileMask;
  2064.           { Perform the recursion }
  2065.           RecursiveFileSearch( ModifiedDirectory , XCounter , YCounter );
  2066.         end;
  2067.       end;
  2068.     end;
  2069.   end;
  2070. end;
  2071.  
  2072. begin
  2073.   { Keep the scrollbox from updating during refresh }
  2074.   Visible := false;
  2075.   { Make the clear call }
  2076.   ClearTheFIPs;
  2077.   XCounter := 1;
  2078.   YCounter := 1;
  2079.   { Get the drives for the current machine }
  2080.   AddDriveIcons( XCounter , YCounter );
  2081.   RecursiveFileSearch( TheStartingDirectory , XCounter , YCounter );
  2082.   { Make the scrollbox visible again }
  2083.   Visible := true;
  2084. end;
  2085.  
  2086. end.
  2087.