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