home *** CD-ROM | disk | FTP | other *** search
/ PC Open 19 / pcopen19.iso / Zipped / CALMIR21.ZIP / SOURCE.ZIP / SRC / WASTEBIN.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-02-20  |  21.2 KB  |  764 lines

  1. {**************************************************************************}
  2. {                                                                          }
  3. {    Calmira shell for Microsoft« Windows(TM) 3.1                          }
  4. {    Source Release 2.1                                                    }
  5. {    Copyright (C) 1997-1998 Li-Hsin Huang                                 }
  6. {                                                                          }
  7. {    This program is free software; you can redistribute it and/or modify  }
  8. {    it under the terms of the GNU General Public License as published by  }
  9. {    the Free Software Foundation; either version 2 of the License, or     }
  10. {    (at your option) any later version.                                   }
  11. {                                                                          }
  12. {    This program is distributed in the hope that it will be useful,       }
  13. {    but WITHOUT ANY WARRANTY; without even the implied warranty of        }
  14. {    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         }
  15. {    GNU General Public License for more details.                          }
  16. {                                                                          }
  17. {    You should have received a copy of the GNU General Public License     }
  18. {    along with this program; if not, write to the Free Software           }
  19. {    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             }
  20. {                                                                          }
  21. {**************************************************************************}
  22.  
  23. unit Wastebin;
  24.  
  25. { Wastepaper bin
  26.  
  27.   TTrash object
  28.  
  29.   This is an abstract base class that defines how a piece of trash
  30.   is stored, deleted and restored.  The code for performing the disk
  31.   operations is placed in the descendants, TFileTrash and TFolderTrash.
  32.  
  33.   Methods
  34.  
  35.     Create - initializes a new object from a TDirItem that is about
  36.       to be binned.
  37.     Load - initializes a new object from an entry in the INI file.
  38.     RestoreTo - moves the trash back into "normal" disk space.
  39.       A pathname is required and if none is given, the object is
  40.       moved back to where it originally came from.
  41.     Delete - removes the item from disk, freeing up space
  42.     Draw - paints a row of the bin's listbox.  The integer parameters
  43.       specify where the size and date fields begin
  44.  
  45.   Protected methods
  46.  
  47.     These are called to implement disk operations.
  48.  
  49.     DoTrash - moves a TDirItem to the bin (currently implemented in the
  50.       base class).
  51.     DoDelete - called by Delete
  52.     DoRestore - called by RestoreTo
  53.     GetIcon - returns the TIcon to represent the trash item.
  54.     CanReplaceFile - called by RestoreTo if the destination already
  55.       exists.  TFileTrash asks for confirmation, TFolderTrash just
  56.       raises an exception.
  57.  
  58.   Properties
  59.     Filename - the full name of the original file or folder
  60.     Tempname - the current name of the file or folder
  61.     Size - for files, this gives the file size.  For folders, this is
  62.       the total size of the structure including sub-folders
  63.     Date - a string containing the formatted date
  64.     Release - True if the trash object should be removed from the bin
  65.       the next time it is updated -- either because the referenced
  66.       file/folder has been deleted or restored, or is otherwise invalid.
  67.  
  68.  
  69.   TBin form
  70.  
  71.   When items are dropped from a TIconWindow, the TDirItems are
  72.   converted into TTrash objects, which are stored into the INI file
  73.   and recreated the next time the program loads.  The trash is kept
  74.   in Listbox.Items.Objects during normal use.
  75.  
  76.   Methods
  77.  
  78.     UpdateBin - deletes all TTrash objects with their Release flag
  79.       set to True, then changes the form's icon to show if there is
  80.       something in the bin.
  81.     SaveTrash - deletes unwanted trash according to the BinAction
  82.       setting, and writes the remaining filenames to the INI file.
  83.       This is usually called when the program ends.
  84.     RestoreTo - calles the RestoreTo method of every selected
  85.       TTrash object
  86. }
  87.  
  88. interface
  89.  
  90. uses
  91.   SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, Buttons, Messages,
  92.   Fileman, ExtCtrls, Menus, Dropclnt, DragDrop, WinTypes, CalForm,
  93.   Graphics, Directry, Settings, Sysmenu;
  94.  
  95. type
  96.   TTrashDate = string[15];
  97.  
  98.   TTrash = class
  99.   protected
  100.     FFilename: TFilename;
  101.     FTempname: TFilename;
  102.     FSize : Longint;
  103.     FDate : TTrashDate;
  104.     FRelease : Boolean;
  105.     procedure DoTrash(Item: TDirItem); virtual;
  106.     function DoDelete: Boolean; virtual; abstract;
  107.     function DoRestore(const dest: TFilename): Boolean; virtual; abstract;
  108.     function GetIcon: TIcon; virtual; abstract;
  109.     function CanReplaceFile(const s: TFilename): Boolean; virtual; abstract;
  110.   public
  111.     constructor Create(Item : TDirItem); virtual;
  112.     constructor Load(const AFilename, ATempname: TFilename); virtual;
  113.     procedure Draw(Canvas: TCanvas; Rect: TRect;
  114.        LocStart, SizeStart, DateStart: Integer);
  115.     function Delete: Boolean;
  116.     procedure RestoreTo(dest: TFilename);
  117.     property Filename : TFilename read FFilename;
  118.     property Tempname : TFilename read FTempname;
  119.     property Size : Longint read FSize;
  120.     property Date : TTrashDate read FDate;
  121.     property Release: Boolean read FRelease;
  122.   end;
  123.  
  124.  
  125.   TFolderTrash = class(TTrash)
  126.   protected
  127.     function DoDelete: Boolean; override;
  128.     function DoRestore(const dest: TFilename): Boolean; override;
  129.     function GetIcon: TIcon; override;
  130.     function CanReplaceFile(const s: TFilename): Boolean; override;
  131.   public
  132.     constructor Create(Item : TDirItem); override;
  133.     constructor Load(const AFilename, ATempname: TFilename); override;
  134.   end;
  135.  
  136.  
  137.   TFileTrash = class(TTrash)
  138.   protected
  139.     function DoDelete: Boolean; override;
  140.     function DoRestore(const dest: TFilename): Boolean; override;
  141.     function GetIcon: TIcon; override;
  142.     function CanReplaceFile(const s: TFilename): Boolean; override;
  143.   public
  144.     constructor Create(Item : TDirItem); override;
  145.   end;
  146.  
  147.   TTrashClass = class of TTrash;
  148.  
  149.   TBin = class(TCalForm)
  150.     Listbox: TListBox;
  151.     Menu: TPopupMenu;
  152.     Delete: TMenuItem;
  153.     Empty: TMenuItem;
  154.     Header: THeader;
  155.     N1: TMenuItem;
  156.     Properties: TMenuItem;
  157.     Restore: TMenuItem;
  158.     SystemMenu: TSystemMenu;
  159.     procedure FormClose(Sender: TObject; var Action: TCloseAction);
  160.     procedure FormDragOver(Sender, Source: TObject; X, Y: Integer;
  161.       State: TDragState; var Accept: Boolean);
  162.     procedure FormCreate(Sender: TObject);
  163.     procedure FormDragDrop(Sender, Source: TObject; X, Y: Integer);
  164.     procedure DeleteClick(Sender: TObject);
  165.     procedure EmptyClick(Sender: TObject);
  166.     procedure HeaderSized(Sender: TObject; ASection, AWidth: Integer);
  167.     procedure ListboxDrawItem(Control: TWinControl; Index: Integer;
  168.       Rect: TRect; State: TOwnerDrawState);
  169.     procedure FormResize(Sender: TObject);
  170.     procedure FormDestroy(Sender: TObject);
  171.     procedure FormPaint(Sender: TObject);
  172.     procedure PropertiesClick(Sender: TObject);
  173.     procedure RestoreClick(Sender: TObject);
  174.     procedure MenuPopup(Sender: TObject);
  175.     procedure ListboxDblClick(Sender: TObject);
  176.   private
  177.     { Private declarations }
  178.     LocStart, SizeStart, DateStart: Integer;
  179.     procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
  180.   public
  181.     { Public declarations }
  182.     procedure UpdateBin;
  183.     procedure SaveTrash;
  184.     procedure RestoreTo(const foldername: TFilename);
  185.     procedure Configure;
  186.     procedure ReadINISettings;
  187.     procedure SettingsChanged(Changes : TSettingChanges); override;
  188.   end;
  189.  
  190.   EBinError = class(Exception);
  191.  
  192. const
  193.   SC_EMPTYBIN = SC_VSCROLL + 1024;
  194.   DefaultBin : TFilename = '';
  195.  
  196. var
  197.   Bin: TBin;
  198.  
  199. implementation
  200.  
  201. {$R *.DFM}
  202.  
  203. uses IconWin, FileCtrl, Desk, MultiGrd, Resource, Progress,
  204.   ShellAPI, FileFind, Files, MiscUtil, Drives, Strings, CompSys, WinProcs,
  205.   BinProp, Locale, Embed;
  206.  
  207. const
  208.   IsFolderToTrash : array[Boolean] of TTrashClass = (TFileTrash, TFolderTrash);
  209.   { returns the appropriate class to use depending on whether the
  210.     source is a folder or not }
  211.  
  212. var
  213.   BinFolders : TStringList;
  214.  
  215.  
  216. { Decides which directory a file or folder should be stored in }
  217.  
  218. function GetBinFolder(const filename: TFilename): TFilename;
  219. begin
  220.   Result := BinFolders.Values[filename[1]];
  221.   if Result = '' then Result := DefaultBin;
  222. end;
  223.  
  224.  
  225.  
  226.  
  227.  
  228. { TTrash }
  229.  
  230. constructor TTrash.Create(Item : TDirItem);
  231. begin
  232.   inherited Create;
  233.   FRelease := False;
  234.   FFilename := Item.Fullname;
  235.   FSize := Item.Size;
  236.   FDate := DateToStr(Item.TimeStamp);
  237. end;
  238.  
  239.  
  240. { Suppresses all user confirmation before trashing the item }
  241.  
  242. procedure TTrash.DoTrash(Item : TDirItem);
  243. begin
  244.   YesToAll;
  245.   try
  246.     try
  247.       Item.MoveAndRename(FTempName);
  248.     except
  249.       on EAbort do { don't show special message if user presses Cancel }
  250.         raise;
  251.       on Exception do
  252.         raise EBinError.Create(FmtLoadStr(SCannotMoveToBin, [Filename]));
  253.     end;
  254.   finally
  255.     NoToAll;
  256.   end;
  257. end;
  258.  
  259.  
  260. constructor TTrash.Load(const AFilename, ATempname: TFilename);
  261. var
  262.   rec: TSearchRec;
  263. begin
  264.   inherited Create;
  265.   FRelease := False;
  266.   FFilename := AFilename;
  267.   FTempname := ATempname;
  268.   FRelease := FindFirst(Tempname, faAnyFile, rec) <> 0;
  269.   FSize := rec.size;
  270.   FDate := DateToStr(TimeStampToDate(rec.time));
  271. end;
  272.  
  273.  
  274. { Calls ForceDirectories to make sure that the destination folder
  275.   exists before restoring.  Strictly speaking, more than one icon
  276.   window may be invalidated by this procedure, but it's not important
  277.   enough to worry about, so only the destination window is refreshed }
  278.  
  279. procedure TTrash.RestoreTo(dest: TFilename);
  280. begin
  281.   if dest = '' then dest := ExtractFilePath(Filename)
  282.   else dest := MakePath(dest);
  283.   ForceDirectories(dest);
  284.   AppendStr(dest, ExtractFilename(Filename));
  285.   if FFileExists(dest) and not CanReplaceFile(dest) then Exit;
  286.  
  287.   try
  288.     DoRestore(dest);
  289.     FRelease := True;
  290.   except
  291.     raise EBinError.Create(FmtLoadStr(SCannotRestoreItem, [Filename]));
  292.   end;
  293.  
  294.   Desktop.RefreshList.Add(ExtractFileDir(dest));
  295. end;
  296.  
  297.  
  298. function TTrash.Delete: Boolean;
  299. begin
  300.   YesToAll;
  301.   try
  302.     try
  303.       FileSetAttr(TempName, 0);
  304.       Result := DoDelete;
  305.     except
  306.       Result := False;
  307.       raise;
  308.     end;
  309.   finally
  310.     FRelease := Result;
  311.     NoToAll;
  312.   end;
  313. end;
  314.  
  315.  
  316. { The abstract function GetIcon is called to retrieve a folder or file image }
  317.  
  318. procedure TTrash.Draw(Canvas: TCanvas; Rect: TRect;
  319.   LocStart, SizeStart, DateStart: Integer);
  320. var
  321.   namestr, sizestr : string[15];
  322. begin
  323.   with Canvas do begin
  324.     FillRect(Rect);
  325.     sizestr := FormatByte(Size, ListKBDecimals);
  326.     namestr := ExtractFilename(Filename);
  327.  
  328.     if BinIcons then begin
  329.       Draw(Rect.Left + 2, Rect.Top, GetIcon);
  330.       Inc(Rect.Left, 20);
  331.     end;
  332.  
  333.     Inc(Rect.Top);
  334.     TextOut(Rect.Left + 2, Rect.Top, namestr);
  335.     TextOut(LocStart, Rect.Top,
  336.       MinimizeName(MakeDirname(Copy(Filename, 1, Length(Filename) - Length(namestr))),
  337.         Canvas, SizeStart - LocStart));
  338.     TextOut(DateStart - 10 - TextWidth(sizestr), Rect.Top, sizestr);
  339.     TextOut(DateStart, Rect.Top, Date);
  340.   end;
  341. end;
  342.  
  343.  
  344. { TFolderTrash }
  345.  
  346. constructor TFolderTrash.Create(Item : TDirItem);
  347. begin
  348.   { The file manager's directory copying facilities will update the
  349.     BytesTransferred variable for a quick way to find the total size }
  350.  
  351.   inherited Create(Item);
  352.   FTempname := MangleFilename(GetBinFolder(FFilename), ExtractFilename(FFilename));
  353.   BytesTransferred := 0;
  354.   DoTrash(Item);
  355.   FSize := BytesTransferred;
  356. end;
  357.  
  358. constructor TFolderTrash.Load(const AFilename, ATempname: TFilename);
  359. begin
  360.   inherited Load(AFilename, ATempname);
  361.   FSize := DirInfo(Tempname, True).Size;
  362. end;
  363.  
  364. function TFolderTrash.DoDelete: Boolean;
  365. begin
  366.   Result := DeleteDirectory(FTempname);
  367. end;
  368.  
  369. function TFolderTrash.DoRestore(const dest: TFilename): Boolean;
  370. begin
  371.   Result := MoveDirectory(Tempname, dest);
  372. end;
  373.  
  374. function TFolderTrash.GetIcon: TIcon;
  375. begin
  376.   Result := TinyFolder;
  377. end;
  378.  
  379. function TFolderTrash.CanReplaceFile(const s: TFilename): Boolean;
  380. begin
  381.   raise EBinError.CreateResFmt(SCannotRestoreFolderOverFile, [s]);
  382. end;
  383.  
  384. { TFileTrash }
  385.  
  386. constructor TFileTrash.Create(Item : TDirItem);
  387. begin
  388.   inherited Create(Item);
  389.   FTempname := MangleFilename(GetBinFolder(FFilename), ExtractFilename(FFilename));
  390.   DoTrash(Item);
  391. end;
  392.  
  393. function TFileTrash.DoDelete: Boolean;
  394. begin
  395.   Result := DeleteFile(FTempname);
  396. end;
  397.  
  398. function TFileTrash.DoRestore(const dest: TFilename): Boolean;
  399. begin
  400.   Result := MoveFile(Tempname, dest, -1);
  401. end;
  402.  
  403. function TFileTrash.GetIcon: TIcon;
  404. begin
  405.   Result := TinyFile;
  406. end;
  407.  
  408. function TFileTrash.CanReplaceFile(const s: TFilename): Boolean;
  409. begin
  410.   case MsgDialogResFmt(SQueryReplaceFile, [s],
  411.    mtConfirmation, mbYesNoCancel, 0) of
  412.     mrYes     : Result := True;
  413.     mrNo      : Result := False;
  414.     mrCancel  : Abort;
  415.   end;
  416. end;
  417.  
  418. { TBin }
  419.  
  420. procedure TBin.FormClose(Sender: TObject; var Action: TCloseAction);
  421. begin
  422.   Action := caMinimize;
  423. end;
  424.  
  425.  
  426. procedure TBin.FormDragOver(Sender, Source: TObject; X, Y: Integer;
  427.   State: TDragState; var Accept: Boolean);
  428. begin
  429.    Accept := (Source is TMultiGrid) and (Source <> Computer.Grid) and
  430.              (Source <> FindList);
  431. end;
  432.  
  433.  
  434. procedure TBin.FormCreate(Sender: TObject);
  435. var
  436.   i: Integer;
  437.   t: TTrash;
  438.   s: TFilename;
  439.   rec : TSearchRec;
  440. begin
  441.   BinFolders := TStringList.Create;
  442.   WindowState := wsMinimized;
  443.   Listbox.DragCursor := crDropFile;
  444.   ReadINISettings;
  445.   Configure;
  446.  
  447.   with SystemMenu do begin
  448.     DeleteCommand(SC_SIZE);
  449.     DeleteCommand(SC_MAXIMIZE);
  450.     AddSeparator;
  451.     AddLoadStr(SMenuBinEmpty, SC_EMPTYBIN);
  452.   end;
  453.  
  454.   MinimumWidth := 128;
  455.   MinimumHeight := 128;
  456.  
  457.   ini.ReadSection('Trash', Listbox.Items);
  458.   with Listbox.Items do
  459.     for i := 0 to Count-1 do begin
  460.       s := Strings[i];
  461.       FindFirst(s, faAnyFile and not faVolumeID, rec);
  462.       t := IsFolderToTrash[rec.attr and faDirectory > 0].Load(
  463.         ini.ReadString('Trash', s, ''), s);
  464.       Strings[i] := t.Filename;
  465.       Objects[i] := t;
  466.     end;
  467.   UpdateBin;
  468.  
  469.   if Caption = '' then Exit;
  470.   LoadMinPosition(ini, 'Bin');
  471.   LoadPosition(ini, 'Bin');
  472.   Update;
  473. end;
  474.  
  475.  
  476. { The bin accepts drops from icon windows only.  For each item selected,
  477.   a corresponding TTrash object is created, which is responsible for
  478.   moving the original.  Filenames and trash objects are stored in the
  479.   listbox }
  480.  
  481. procedure TBin.FormDragDrop(Sender, Source: TObject; X, Y: Integer);
  482. var
  483.   win: TIconWindow;
  484.   i : Integer;
  485.   waste : TTrash;
  486.   item : TDirItem;
  487. begin
  488.   win := (Source as TMultiGrid).Owner as TIconWindow;
  489.   try
  490.     if BinAction = baDelete then
  491.       win.Delete.Click
  492.  
  493.     else with win.CompileSelection(False) do begin
  494.       Desktop.SetCursor(crHourGlass);
  495.       ProgressBox.Init(foBinning, Count);
  496.  
  497.       for i := 0 to Count-1 do begin
  498.         item := TDirItem(Items[i]);
  499.         waste := IsFolderToTrash[item is TFolder].Create(item);
  500.         Listbox.Items.AddObject(waste.Filename, waste);
  501.         ProgressBox.UpdateGauge;
  502.         ProgressBox.CheckForAbort;
  503.       end;
  504.     end;
  505.   finally
  506.     UpdateBin;
  507.     ProgressBox.Hide;
  508.     win.Dir.Flush;
  509.     Desktop.ReleaseCursor;
  510.     PlaySound(Sounds.Values['BinDropFiles']);
  511.   end;
  512. end;
  513.  
  514.  
  515. { Called before the program quits, and also deletes unwanted trash.
  516.   UpdateBin and FormDestroy are responsible for freeing the TTrash
  517.   objects when they are not needed. }
  518.  
  519. procedure TBin.SaveTrash;
  520. var
  521.   i: Integer;
  522.   used, space: Longint;
  523. begin
  524.   ini.WriteHeader('Bin', Header);
  525.  
  526.   with Listbox.Items do
  527.     try
  528.       { count how many bytes are used }
  529.       used := 0;
  530.       for i := 0 to Count-1 do Inc(used, TTrash(Objects[i]).Size);
  531.  
  532.       case BinAction of
  533.         baCollect: space := Longint(BinCapacity) * 1024 * 1024;
  534.         baEmpty  : space := -1;
  535.       end;
  536.  
  537.       { keep deleting until within the limit }
  538.       i := 0;
  539.       while (used > space) and (i < Count) do begin
  540.         with TTrash(Objects[i]) do if Delete then Dec(used, Size);
  541.         Inc(i);
  542.       end;
  543.     finally
  544.       { clear out deleted entries and write the remainder to disk }
  545.       UpdateBin;
  546.       ini.EraseSection('Trash');
  547.       for i := 0 to Count-1 do with TTrash(Objects[i]) do
  548.         ini.WriteString('Trash', Tempname, Filename);
  549.     end;
  550. end;
  551.  
  552.  
  553. procedure TBin.UpdateBin;
  554. var i: Integer;
  555. begin
  556.   { Free unused trash objects }
  557.   i := 0;
  558.   with Listbox.Items do begin
  559.     for i := Count-1 downto 0 do
  560.       if TTrash(Objects[i]).Release then begin
  561.         Objects[i].Free;
  562.         Delete(i);
  563.       end;
  564.  
  565.     { Change the icon }
  566.     if Count = 0 then Icon.Assign(icons.Get('EmptyBin'))
  567.     else Icon.Assign(icons.Get('FullBin'));
  568.   end;
  569.  
  570.   with Listbox do begin
  571.     Itemindex := -1;
  572.     Enabled := Items.Count > 0;
  573.   end;
  574. end;
  575.  
  576.  
  577. procedure TBin.RestoreTo(const foldername: TFilename);
  578. var
  579.   i, Count: Integer;
  580.   path : TFilename;
  581. begin
  582.   { if no folder is specified, trash is restored to its original location }
  583.   try
  584.     with Listbox do begin
  585.       for i := 0 to Items.Count-1 do Inc(Count, Integer(Selected[i]));
  586.       ProgressBox.Init(foRestoring, Count);
  587.  
  588.       if foldername = '' then path := '' else path := MakePath(foldername);
  589.  
  590.       for i := 0 to Items.Count-1 do begin
  591.         if Selected[i] then TTrash(Items.Objects[i]).RestoreTo(path);
  592.         ProgressBox.UpdateGauge;
  593.         ProgressBox.CheckForAbort;
  594.       end;
  595.     end;
  596.   finally
  597.     UpdateBin;
  598.     ProgressBox.Hide;
  599.     Desktop.RefreshNow;
  600.     PlaySound(Sounds.Values['BinRestore']);
  601.   end;
  602. end;
  603.  
  604.  
  605. procedure TBin.DeleteClick(Sender: TObject);
  606. var
  607.   i: Integer;
  608. begin
  609.   with Listbox.Items do
  610.     for i := 0 to Count-1 do
  611.       if Listbox.Selected[i] then TTrash(Objects[i]).Delete;
  612.   UpdateBin;
  613. end;
  614.  
  615.  
  616. procedure TBin.EmptyClick(Sender: TObject);
  617. var
  618.   i: Integer;
  619. begin
  620.   if Listbox.Items.Count = 0 then Exit;
  621.   ProgressBox.Init(foEmptying, Listbox.Items.Count);
  622.   try
  623.     PlaySound(Sounds.Values['BinEmpty']);
  624.     with Listbox.Items do
  625.       for i := 0 to Count-1 do begin
  626.         TTrash(Objects[i]).Delete;
  627.         ProgressBox.UpdateGauge;
  628.         ProgressBox.CheckForAbort;
  629.       end;
  630.   finally
  631.     UpdateBin;
  632.     ProgressBox.Hide;
  633.   end;
  634. end;
  635.  
  636.  
  637.  
  638. procedure TBin.WMSysCommand(var Msg: TWMSysCommand);
  639. begin
  640.   inherited;
  641.   if Msg.CmdType and $FFF0 = SC_EMPTYBIN then Empty.Click;
  642. end;
  643.  
  644.  
  645. procedure TBin.HeaderSized(Sender: TObject; ASection, AWidth: Integer);
  646. begin
  647.   GetHeaderDivisions(Header, [@LocStart, @SizeStart, @DateStart]);
  648.   Listbox.Invalidate;
  649. end;
  650.  
  651.  
  652. procedure TBin.ListboxDrawItem(Control: TWinControl; Index: Integer;
  653.   Rect: TRect; State: TOwnerDrawState);
  654. begin
  655.   with Listbox do
  656.     TTrash(Items.Objects[Index]).Draw(Canvas, Rect, LocStart, SizeStart, DateStart);
  657. end;
  658.  
  659.  
  660. procedure TBin.FormResize(Sender: TObject);
  661. begin
  662.   Listbox.Width := ClientWidth - 8;
  663.   Listbox.Height := ClientHeight - Header.Height - 7;
  664.   Header.Width := Listbox.Width;
  665.   Invalidate;
  666. end;
  667.  
  668.  
  669. procedure TBin.FormDestroy(Sender: TObject);
  670. var
  671.   i: Integer;
  672. begin
  673.   with Listbox.Items do for i := 0 to Count-1 do Objects[i].Free;
  674.   BinFolders.Free;
  675. end;
  676.  
  677.  
  678. procedure TBin.Configure;
  679. begin
  680.   Caption := BinCaption;
  681.   if BinCaption = '' then Hide;
  682.   Color := Colors[ccWinFrame];
  683.   Listbox.ItemHeight := LineHeight;
  684.   Invalidate;
  685. end;
  686.  
  687.  
  688. procedure TBin.ReadINISettings;
  689. var
  690.   i: Integer;
  691. begin
  692.   ini.ReadHeader('Bin', Header);
  693.   HeaderSized(Header, 0, Header.SectionWidth[0]);
  694.  
  695.   BinFolders.Clear;
  696.   ini.ReadSectionValues('Bin Locations', BinFolders);
  697.   for i := 0 to BinFolders.Count-1 do
  698.     BinFolders[i] := MakePath(BinFolders[i]);
  699. end;
  700.  
  701.  
  702. procedure TBin.FormPaint(Sender: TObject);
  703. var
  704.   R: TRect;
  705. begin
  706.   Border3D(Canvas, ClientWidth-1, ClientHeight-1);
  707.  
  708.   { This bevelling code is here because Delphi seems to have a bug
  709.     that disrupts the OnDragOver event (even for a minimized form)
  710.     when a bevel is in the way.  Try putting a TBevel over the header
  711.     and dragging a file over the bin icon...
  712.   }
  713.  
  714.   R := Header.BoundsRect;
  715.   InflateRect(R, 1, 1);
  716.   Frame3D(Canvas, R, clBtnShadow, clBtnHighlight, 1);
  717. end;
  718.  
  719.  
  720. procedure TBin.PropertiesClick(Sender: TObject);
  721. begin
  722.   ShowModalDialog(TBinPropDlg);
  723. end;
  724.  
  725.  
  726. procedure TBin.RestoreClick(Sender: TObject);
  727. begin
  728.   RestoreTo('');
  729. end;
  730.  
  731.  
  732. procedure TBin.MenuPopup(Sender: TObject);
  733. begin
  734.   with Listbox do begin
  735.     Restore.Enabled := SelCount > 0;
  736.     Delete.Enabled := SelCount > 0;
  737.     Empty.Enabled := Items.Count > 0;
  738.   end;
  739. end;
  740.  
  741.  
  742. procedure TBin.SettingsChanged(Changes : TSettingChanges);
  743. begin
  744.   if scIniFile in Changes then ReadINISettings;
  745.   if [scSystem, scDisplay, scDesktop, scBin] * Changes <> [] then Configure;
  746. end;
  747.  
  748.  
  749. procedure TBin.ListboxDblClick(Sender: TObject);
  750. begin
  751.   with Listbox do
  752.     if (ItemIndex <> -1) and (Items.Objects[ItemIndex] is TFolderTrash) then
  753.       Desktop.OpenFolder(TFolderTrash(Items.Objects[ItemIndex]).TempName);
  754. end;
  755.  
  756. initialization
  757.   DefaultBin := Lowercase(ApplicationPath + 'BIN');
  758.   if not FDirectoryExists(DefaultBin) then begin
  759.     MkDir(DefaultBin);
  760.     FileSetAttr(DefaultBin, faHidden);
  761.   end;
  762.   AppendStr(DefaultBin, '\');
  763. end.
  764.