home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 April A / Pcwk4a98.iso / PROGRAM / DELPHI16 / Calmira / Src / SRC / WASTEBIN.PAS < prev    next >
Pascal/Delphi Source File  |  1997-02-15  |  21KB  |  755 lines

  1. {**************************************************************************}
  2. {                                                                          }
  3. {    Calmira shell for Microsoft« Windows(TM) 3.1                          }
  4. {    Source Release 1.0                                                    }
  5. {    Copyright (C) 1997  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, FormDrag,
  93.   Graphics, Directry, Settings, Sysmenu;
  94.  
  95. const
  96.   SC_EMPTYBIN = SC_VSCROLL + 999;
  97.  
  98. type
  99.   TTrashDate = string[15];
  100.  
  101.   TTrash = class
  102.   protected
  103.     FFilename: TFilename;
  104.     FTempname: TFilename;
  105.     FSize : Longint;
  106.     FDate : TTrashDate;
  107.     FRelease : Boolean;
  108.     procedure DoTrash(Item: TDirItem); virtual;
  109.     function DoDelete: Boolean; virtual; abstract;
  110.     function DoRestore(const dest: TFilename): Boolean; virtual; abstract;
  111.     function GetIcon: TIcon; virtual; abstract;
  112.     function CanReplaceFile(const s: TFilename): Boolean; virtual; abstract;
  113.   public
  114.     constructor Create(Item : TDirItem); virtual;
  115.     constructor Load(const AFilename, ATempname: TFilename); virtual;
  116.     function Delete: Boolean;
  117.     procedure RestoreTo(dest: TFilename);
  118.     procedure Draw(Canvas: TCanvas; Rect: TRect; x1, x2: Integer);
  119.     property Filename : TFilename read FFilename;
  120.     property Tempname : TFilename read FTempname;
  121.     property Size : Longint read FSize;
  122.     property Date : TTrashDate read FDate;
  123.     property Release: Boolean read FRelease;
  124.   end;
  125.  
  126.  
  127.   TFolderTrash = class(TTrash)
  128.   protected
  129.     function DoDelete: Boolean; override;
  130.     function DoRestore(const dest: TFilename): Boolean; override;
  131.     function GetIcon: TIcon; override;
  132.     function CanReplaceFile(const s: TFilename): Boolean; override;
  133.   public
  134.     constructor Create(Item : TDirItem); override;
  135.     constructor Load(const AFilename, ATempname: TFilename); override;
  136.   end;
  137.  
  138.  
  139.   TFileTrash = class(TTrash)
  140.   protected
  141.     function DoDelete: Boolean; override;
  142.     function DoRestore(const dest: TFilename): Boolean; override;
  143.     function GetIcon: TIcon; override;
  144.     function CanReplaceFile(const s: TFilename): Boolean; override;
  145.   public
  146.     constructor Create(Item : TDirItem); override;
  147.   end;
  148.  
  149.   TTrashClass = class of TTrash;
  150.  
  151.   TBin = class(TCalForm)
  152.     Listbox: TListBox;
  153.     Menu: TPopupMenu;
  154.     Delete: TMenuItem;
  155.     Empty: TMenuItem;
  156.     Header: THeader;
  157.     Dragger: TFormDrag;
  158.     N1: TMenuItem;
  159.     Properties: TMenuItem;
  160.     Restore: TMenuItem;
  161.     SystemMenu: TSystemMenu;
  162.     procedure FormClose(Sender: TObject; var Action: TCloseAction);
  163.     procedure FormDragOver(Sender, Source: TObject; X, Y: Integer;
  164.       State: TDragState; var Accept: Boolean);
  165.     procedure FormCreate(Sender: TObject);
  166.     procedure FormDragDrop(Sender, Source: TObject; X, Y: Integer);
  167.     procedure DeleteClick(Sender: TObject);
  168.     procedure EmptyClick(Sender: TObject);
  169.     procedure HeaderSized(Sender: TObject; ASection, AWidth: Integer);
  170.     procedure ListboxDrawItem(Control: TWinControl; Index: Integer;
  171.       Rect: TRect; State: TOwnerDrawState);
  172.     procedure FormResize(Sender: TObject);
  173.     procedure FormDestroy(Sender: TObject);
  174.     procedure FormPaint(Sender: TObject);
  175.     procedure PropertiesClick(Sender: TObject);
  176.     procedure RestoreClick(Sender: TObject);
  177.     procedure MenuPopup(Sender: TObject);
  178.   private
  179.     { Private declarations }
  180.     SizeStart, DateStart: Integer;
  181.     procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
  182.   public
  183.     { Public declarations }
  184.     procedure UpdateBin;
  185.     procedure SaveTrash;
  186.     procedure RestoreTo(const foldername: TFilename);
  187.     procedure Configure;
  188.     procedure ReadINISettings;
  189.     procedure SettingsChanged(Changes : TSettingChanges); override;
  190.   end;
  191.  
  192.   EBinError = class(Exception);
  193.  
  194. const
  195.   DefaultBin : TFilename = '';
  196.  
  197. var
  198.   Bin: TBin;
  199.  
  200. implementation
  201.  
  202. {$R *.DFM}
  203.  
  204. uses IconWin, FileCtrl, Desk, MultiGrd, Resource, Busy,
  205.   ShellAPI, FileFind, Files, MiscUtil, Drives, Strings, Sys, WinProcs,
  206.   BinProp;
  207.  
  208. const
  209.   IsFolderToTrash : array[Boolean] of TTrashClass = (TFileTrash, TFolderTrash);
  210.   { returns the appropriate class to use depending on whether the
  211.     source is a folder or not }
  212.  
  213. var
  214.   BinFolders : TStringList;
  215.  
  216.  
  217. { Decides which directory a file or folder should be stored in }
  218.  
  219. function GetBinFolder(const filename: TFilename): TFilename;
  220. begin
  221.   Result := BinFolders.Values[filename[1]];
  222.   if Result = '' then Result := DefaultBin;
  223. end;
  224.  
  225.  
  226. function MangleFilename(const path, original: TFilename): TFilename;
  227. var
  228.   n, p : Integer;
  229.   body : string[8];
  230.   ext  : string[3];
  231.   num  : string[5];
  232.   R : TSearchRec;
  233. begin
  234.   { Appends a twiddle (tilde) and number to the end of a filename
  235.     when a naming conflict occurs.  For example, if autoexec.bat exists,
  236.     the second copy in the bin is called autoex~1.bat }
  237.  
  238.   p := Pos('.', original);
  239.  
  240.   if p = 0 then begin
  241.     body := original;
  242.     ext := '';
  243.   end else begin
  244.     body := Copy(original, 1, p-1);
  245.     ext := Copy(original, p+1, 255);
  246.   end;
  247.  
  248.   Result := path + original;
  249.   n := 0;
  250.  
  251.   while FindFirst(Result, faAnyFile and not faVolumeID, R) = 0 do begin
  252.     Inc(n);
  253.     num := IntToStr(n);
  254.     Result := Format('%s%s~%d.%s', [Path, Copy(body, 1, 7 - Length(num)), n, ext]);
  255.   end;
  256.  
  257.   if Result[Length(Result)] = '.' then Dec(Result[0]);
  258. end;
  259.  
  260.  
  261. { TTrash }
  262.  
  263. constructor TTrash.Create(Item : TDirItem);
  264. begin
  265.   inherited Create;
  266.   FRelease := False;
  267.   FFilename := Item.Fullname;
  268.   FSize := Item.Size;
  269.   FDate := DateToStr(Item.TimeStamp);
  270. end;
  271.  
  272.  
  273. { Suppresses all user confirmation before trashing the item }
  274.  
  275. procedure TTrash.DoTrash(Item : TDirItem);
  276. begin
  277.   YesToAll;
  278.   try
  279.     try
  280.       Item.MoveAndRename(FTempName);
  281.     except
  282.       raise EBinError.Create(Format('Unable to move %s to bin', [Filename]));
  283.     end;
  284.   finally
  285.     NoToAll;
  286.   end;
  287. end;
  288.  
  289.  
  290. constructor TTrash.Load(const AFilename, ATempname: TFilename);
  291. var
  292.   rec: TSearchRec;
  293. begin
  294.   inherited Create;
  295.   FRelease := False;
  296.   FFilename := AFilename;
  297.   FTempname := ATempname;
  298.   FRelease := FindFirst(Tempname, faAnyFile, rec) <> 0;
  299.   FSize := rec.size;
  300.   FDate := DateToStr(TimeStampToDate(rec.time));
  301. end;
  302.  
  303.  
  304. { Calls ForceDirectories to make sure that the destination folder
  305.   exists before restoring.  Strictly speaking, more than one icon
  306.   window may be invalidated by this procedure, but it's not important
  307.   enough to worry about, so only the destination window is refreshed }
  308.  
  309. procedure TTrash.RestoreTo(dest: TFilename);
  310. begin
  311.   if dest = '' then dest := ExtractFilePath(Filename)
  312.   else dest := MakePath(dest);
  313.   ForceDirectories(dest);
  314.   AppendStr(dest, ExtractFilename(Filename));
  315.   if FFileExists(dest) and not CanReplaceFile(dest) then Exit;
  316.  
  317.   try
  318.     DoRestore(dest);
  319.     FRelease := True;
  320.   except
  321.     raise EBinError.Create(Format('Unable to restore %s', [Filename]));
  322.   end;
  323.  
  324.   Desktop.RefreshList.Add(ExtractFileDir(dest));
  325. end;
  326.  
  327.  
  328. function TTrash.Delete: Boolean;
  329. begin
  330.   YesToAll;
  331.   try
  332.     try
  333.       FileSetAttr(TempName, 0);
  334.       Result := DoDelete;
  335.     except
  336.       Result := False;
  337.       raise;
  338.     end;
  339.   finally
  340.     FRelease := Result;
  341.     NoToAll;
  342.   end;
  343. end;
  344.  
  345.  
  346. { The abstract function GetIcon is called to retrieve a folder or file image }
  347.  
  348. procedure TTrash.Draw(Canvas: TCanvas; Rect: TRect; x1, x2: Integer);
  349. var
  350.   sizestr : string[31];
  351. begin
  352.   with Canvas do begin
  353.     FillRect(Rect);
  354.     sizestr := FormatByte(Size);
  355.  
  356.     if BinIcons then begin
  357.       Draw(Rect.Left + 2, Rect.Top, GetIcon);
  358.       Inc(Rect.Left, 20);
  359.       Dec(x1, 18);
  360.     end;
  361.  
  362.     Inc(Rect.Top);
  363.     TextOut(Rect.Left + 2, Rect.Top, MinimizeName(Filename, Canvas, x1));
  364.     TextOut(x2 - 6 - TextWidth(sizestr), Rect.Top, sizestr);
  365.     TextOut(x2, Rect.Top, Date);
  366.   end;
  367. end;
  368.  
  369.  
  370. { TFolderTrash }
  371.  
  372. constructor TFolderTrash.Create(Item : TDirItem);
  373. begin
  374.   { The file manager's directory copying facilities will update the
  375.     BytesTransferred variable for a quick way to find the total size }
  376.  
  377.   inherited Create(Item);
  378.   FTempname := MangleFilename(GetBinFolder(FFilename), ExtractFilename(FFilename));
  379.   BytesTransferred := 0;
  380.   DoTrash(Item);
  381.   FSize := BytesTransferred;
  382. end;
  383.  
  384. constructor TFolderTrash.Load(const AFilename, ATempname: TFilename);
  385. begin
  386.   inherited Load(AFilename, ATempname);
  387.   FSize := DirInfo(Tempname, True).Size;
  388. end;
  389.  
  390. function TFolderTrash.DoDelete: Boolean;
  391. begin
  392.   Result := DeleteDirectory(FTempname);
  393. end;
  394.  
  395. function TFolderTrash.DoRestore(const dest: TFilename): Boolean;
  396. begin
  397.   Result := MoveDirectory(Tempname, dest);
  398. end;
  399.  
  400. function TFolderTrash.GetIcon: TIcon;
  401. begin
  402.   Result := TinyFolder;
  403. end;
  404.  
  405. function TFolderTrash.CanReplaceFile(const s: TFilename): Boolean;
  406. begin
  407.   raise EBinError.CreateFmt('Cannot restore folder %s because there '+
  408.     'is a file with that name', [s]);
  409. end;
  410.  
  411. { TFileTrash }
  412.  
  413. constructor TFileTrash.Create(Item : TDirItem);
  414. begin
  415.   inherited Create(Item);
  416.   FTempname := MangleFilename(GetBinFolder(FFilename), ExtractFilename(FFilename));
  417.   DoTrash(Item);
  418. end;
  419.  
  420. function TFileTrash.DoDelete: Boolean;
  421. begin
  422.   Result := DeleteFile(FTempname);
  423. end;
  424.  
  425. function TFileTrash.DoRestore(const dest: TFilename): Boolean;
  426. begin
  427.   Result := MoveFile(Tempname, dest, -1);
  428. end;
  429.  
  430. function TFileTrash.GetIcon: TIcon;
  431. begin
  432.   Result := TinyFile;
  433. end;
  434.  
  435. function TFileTrash.CanReplaceFile(const s: TFilename): Boolean;
  436. begin
  437.   case MsgDialog(Format('Replace existing %s?', [s]),
  438.    mtConfirmation, mbYesNoCancel, 0) of
  439.     mrYes     : Result := True;
  440.     mrNo      : Result := False;
  441.     mrCancel  : Abort;
  442.   end;
  443. end;
  444.  
  445. { TBin }
  446.  
  447. procedure TBin.FormClose(Sender: TObject; var Action: TCloseAction);
  448. begin
  449.   Action := caMinimize;
  450. end;
  451.  
  452.  
  453. procedure TBin.FormDragOver(Sender, Source: TObject; X, Y: Integer;
  454.   State: TDragState; var Accept: Boolean);
  455. begin
  456.    Accept := (Source is TMultiGrid) and (Source <> SysWindow.Grid);
  457. end;
  458.  
  459.  
  460. procedure TBin.FormCreate(Sender: TObject);
  461. var
  462.   i: Integer;
  463.   t: TTrash;
  464.   s: TFilename;
  465.   rec : TSearchRec;
  466. begin
  467.   BinFolders := TStringList.Create;
  468.   WindowState := wsMinimized;
  469.   Listbox.DragCursor := crDropFile;
  470.   ReadINISettings;
  471.   Configure;
  472.  
  473.   with SystemMenu do begin
  474.     DeleteCommand(SC_SIZE);
  475.     DeleteCommand(SC_MAXIMIZE);
  476.     AddSeparator;
  477.     Add('Empty', SC_EMPTYBIN);
  478.   end;
  479.  
  480.   ini.ReadSection('Trash', Listbox.Items);
  481.   with Listbox.Items do
  482.     for i := 0 to Count-1 do begin
  483.       s := Strings[i];
  484.       FindFirst(s, faAnyFile and not faVolumeID, rec);
  485.       t := IsFolderToTrash[rec.attr and faDirectory > 0].Load(
  486.         ini.ReadString('Trash', s, ''), s);
  487.       Strings[i] := t.Filename;
  488.       Objects[i] := t;
  489.     end;
  490.   UpdateBin;
  491.  
  492.   if not BinDisable then begin
  493.     LoadPosition(ini, 'Bin');
  494.     Update;
  495.   end;
  496. end;
  497.  
  498.  
  499. { The bin accepts drops from icon windows only.  For each item selected,
  500.   a corresponding TTrash object is created, which is responsible for
  501.   moving the original.  Filenames and trash objects are stored in the
  502.   listbox }
  503.  
  504. procedure TBin.FormDragDrop(Sender, Source: TObject; X, Y: Integer);
  505. var
  506.   win: TIconWindow;
  507.   i : Integer;
  508.   waste : TTrash;
  509.   item : TDirItem;
  510. begin
  511.   win := (Source as TMultiGrid).Owner as TIconWindow;
  512.   try
  513.     if BinAction = baDelete then
  514.       win.Delete.Click
  515.  
  516.     else with win.CompileSelection(False) do begin
  517.       if (FileCount > 1) or (FolderCount > 0) then
  518.         BusyBox.ShowMessage('Binning selected items...');
  519.  
  520.       for i := 0 to Count-1 do begin
  521.         item := TDirItem(Items[i]);
  522.         waste := IsFolderToTrash[item is TFolder].Create(item);
  523.         Listbox.Items.AddObject(waste.Filename, waste);
  524.       end;
  525.     end;
  526.   finally
  527.     UpdateBin;
  528.     BusyBox.Hide;
  529.     win.Dir.Flush;
  530.     PlaySound(Sounds.Values['BinDropFiles']);
  531.   end;
  532. end;
  533.  
  534.  
  535. { Called before the program quits, and also deletes unwanted trash.
  536.   UpdateBin and FormDestroy are responsible for freeing the TTrash
  537.   objects when they are not needed. }
  538.  
  539. procedure TBin.SaveTrash;
  540. var
  541.   i: Integer;
  542.   used, space: Longint;
  543. begin
  544.   with Listbox.Items do
  545.     try
  546.       { count how many bytes are used }
  547.       used := 0;
  548.       for i := 0 to Count-1 do Inc(used, TTrash(Objects[i]).Size);
  549.  
  550.       case BinAction of
  551.         baCollect: space := Longint(BinCapacity) * 1024 * 1024;
  552.         baEmpty  : space := -1;
  553.       end;
  554.  
  555.       { keep deleting until within the limit }
  556.       i := 0;
  557.       while (used > space) and (i < Count) do begin
  558.         with TTrash(Objects[i]) do if Delete then Dec(used, Size);
  559.         Inc(i);
  560.       end;
  561.     finally
  562.       { clear out deleted entries and write the remainder to disk }
  563.       UpdateBin;
  564.       ini.EraseSection('Trash');
  565.       for i := 0 to Count-1 do with TTrash(Objects[i]) do
  566.         ini.WriteString('Trash', Tempname, Filename);
  567.     end;
  568. end;
  569.  
  570.  
  571. procedure TBin.UpdateBin;
  572. var i: Integer;
  573. begin
  574.   { Free unused trash objects }
  575.   i := 0;
  576.   with Listbox.Items do begin
  577.     for i := Count-1 downto 0 do
  578.       if TTrash(Objects[i]).Release then begin
  579.         Objects[i].Free;
  580.         Delete(i);
  581.       end;
  582.  
  583.     { Change the icon }
  584.     if Count = 0 then Icon.Assign(icons.Get('EmptyBin'))
  585.     else Icon.Assign(icons.Get('FullBin'));
  586.   end;
  587.  
  588.   Listbox.Itemindex := -1;
  589. end;
  590.  
  591.  
  592. procedure TBin.RestoreTo(const foldername: TFilename);
  593. var
  594.   i: Integer;
  595.   path : TFilename;
  596. begin
  597.   { if no folder is specified, trash is restored to its original location }
  598.   try
  599.     with Listbox do begin
  600.       if Items.Count > 1 then BusyBox.ShowMessage('Restoring files...');
  601.       if foldername = '' then path := '' else path := MakePath(foldername);
  602.  
  603.       for i := 0 to Items.Count-1 do
  604.         if Selected[i] then TTrash(Items.Objects[i]).RestoreTo(path);
  605.     end;
  606.   finally
  607.     UpdateBin;
  608.     BusyBox.Hide;
  609.     Desktop.RefreshNow;
  610.     PlaySound(Sounds.Values['BinRestore']);
  611.   end;
  612. end;
  613.  
  614.  
  615. procedure TBin.DeleteClick(Sender: TObject);
  616. var
  617.   i: Integer;
  618. begin
  619.   with Listbox.Items do
  620.     for i := 0 to Count-1 do
  621.       if Listbox.Selected[i] then TTrash(Objects[i]).Delete;
  622.   UpdateBin;
  623. end;
  624.  
  625.  
  626. procedure TBin.EmptyClick(Sender: TObject);
  627. var
  628.   i: Integer;
  629. begin
  630.   BusyBox.ShowMessage('Emptying bin...');
  631.   try
  632.     PlaySound(Sounds.Values['BinEmpty']);
  633.     with Listbox.Items do
  634.       for i := 0 to Count-1 do TTrash(Objects[i]).Delete;
  635.   finally
  636.     UpdateBin;
  637.     BusyBox.Hide;
  638.   end;
  639. end;
  640.  
  641.  
  642.  
  643. procedure TBin.WMSysCommand(var Msg: TWMSysCommand);
  644. begin
  645.   inherited;
  646.   if Msg.CmdType = SC_EMPTYBIN then Empty.Click;
  647. end;
  648.  
  649.  
  650. procedure TBin.HeaderSized(Sender: TObject; ASection, AWidth: Integer);
  651. begin
  652.   { Adjust listbox columns and redraw }
  653.   with Header do begin
  654.     SizeStart := SectionWidth[0];
  655.     DateStart := SizeStart + SectionWidth[1];
  656.   end;
  657.   Listbox.Invalidate;
  658. end;
  659.  
  660.  
  661. procedure TBin.ListboxDrawItem(Control: TWinControl; Index: Integer;
  662.   Rect: TRect; State: TOwnerDrawState);
  663. begin
  664.   with Listbox do
  665.     TTrash(Items.Objects[Index]).Draw(Canvas, Rect, SizeStart-6, DateStart);
  666. end;
  667.  
  668.  
  669. procedure TBin.FormResize(Sender: TObject);
  670. begin
  671.   Listbox.Width := ClientWidth - 8;
  672.   Listbox.Height := ClientHeight - Header.Height - 7;
  673.   Header.Width := Listbox.Width;
  674.   Invalidate;
  675. end;
  676.  
  677.  
  678. procedure TBin.FormDestroy(Sender: TObject);
  679. var
  680.   i: Integer;
  681. begin
  682.   with Listbox.Items do for i := 0 to Count-1 do Objects[i].Free;
  683.   BinFolders.Free;
  684.   ini.WriteHeader('Bin', Header);
  685. end;
  686.  
  687.  
  688. procedure TBin.Configure;
  689. begin
  690.   Caption := BinCaption;
  691.   Color := Colors[ccWinFrame];
  692.   Dragger.Hollow := HollowDrag;
  693.   Listbox.ItemHeight := LineHeight;
  694.   Invalidate;
  695. end;
  696.  
  697.  
  698. procedure TBin.ReadINISettings;
  699. var
  700.   i: Integer;
  701. begin
  702.   ini.ReadHeader('Bin', Header);
  703.   HeaderSized(Header, 0, Header.SectionWidth[0]);
  704.  
  705.   BinFolders.Clear;
  706.   ini.ReadSectionValues('Bin Locations', BinFolders);
  707.   for i := 0 to BinFolders.Count-1 do
  708.     BinFolders[i] := MakePath(BinFolders[i]);
  709. end;
  710.  
  711.  
  712. procedure TBin.FormPaint(Sender: TObject);
  713. begin
  714.   Border3D(Canvas, ClientWidth-1, ClientHeight-1);
  715. end;
  716.  
  717.  
  718. procedure TBin.PropertiesClick(Sender: TObject);
  719. begin
  720.   ShowModalDialog(TBinPropDlg);
  721. end;
  722.  
  723.  
  724. procedure TBin.RestoreClick(Sender: TObject);
  725. begin
  726.   RestoreTo('');
  727. end;
  728.  
  729.  
  730. procedure TBin.MenuPopup(Sender: TObject);
  731. begin
  732.   with Listbox do begin
  733.     Restore.Enabled := SelCount > 0;
  734.     Delete.Enabled := SelCount > 0;
  735.     Empty.Enabled := Items.Count > 0;
  736.   end;
  737. end;
  738.  
  739.  
  740. procedure TBin.SettingsChanged(Changes : TSettingChanges);
  741. begin
  742.   if scIniFile in Changes then ReadINISettings;
  743.   if [scSystem, scDisplay, scDesktop, scBin] * Changes <> [] then Configure;
  744. end;
  745.  
  746.  
  747. initialization
  748.   DefaultBin := Lowercase(ApplicationPath + 'BIN');
  749.   if not FDirectoryExists(DefaultBin) then begin
  750.     MkDir(DefaultBin);
  751.     FileSetAttr(DefaultBin, faHidden);
  752.   end;
  753.   AppendStr(DefaultBin, '\');
  754. end.
  755.