home *** CD-ROM | disk | FTP | other *** search
/ PC Open 19 / pcopen19.iso / Zipped / CALMIR21.ZIP / SOURCE.ZIP / SRC / DIRECTRY.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-02-20  |  39.6 KB  |  1,398 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 Directry;
  24.  
  25. { This unit provides the main file management objects: TDirectory,
  26.   TDirItem, TFileItem, TFile and TFolder. }
  27.  
  28. interface
  29.  
  30. uses Classes, Graphics, SysUtils, Iconic, Shorts, Dialogs, Referenc,
  31.   Settings, ObjList, WinTypes, FourDOS;
  32.  
  33. type
  34.   TDirectory = class;
  35.   TDirItem   = class;
  36.   TFileItem  = class;
  37.   TFile      = class;
  38.   TFolder    = class;
  39.  
  40.   TFileBody    = string[12];
  41.   { the 8 character name }
  42.  
  43.   TFileRelease = (frNone, frRemove, frFree);
  44.   { indicates if an item should be left alone, deleted from the
  45.     list or destroyed }
  46.  
  47.   ERenameError = class(Exception);
  48.   EAttribError = class(Exception);
  49.   EScanError = class(Exception);
  50.  
  51.   { TDirectory is a list of file and folder objects, that encapsulates
  52.     a DOS directory listing.
  53.  
  54.     Properties
  55.       Path - the full pathname with trailing backslash
  56.       Fullname - the full name without trailing backslash
  57.       Size - the number of bytes of disk space used by its contents
  58.       SortOrder - the way in which the contents are sorted
  59.       Filter - the file specification passed to FindFirst()
  60.       Mask - the Attr field passed to FindFirst()
  61.       Changed - True if the contents have changed since last update
  62.       Desc - string list containing file descriptions
  63.  
  64.     Events
  65.       OnUpdate - occurs when a file operation has been completed, to
  66.         notify the owning window to modify its controls and display
  67.  
  68.     Methods
  69.       Create - allocates and initializes a new object, and calls
  70.         Scan() to read in the contents of the directory it represents
  71.       Destroy - frees the contents as well as the directory object
  72.       Add - adds a TDirItem to the list
  73.       Remove - deletes a TDirItem from the list
  74.       Sort - sorts the contents depending on the SortOrder property
  75.       Update - writes file descriptions to disk, triggers the OnUpdate
  76.         event and sets the Changed property to False
  77.       Find - searches for the index of a given filename, and returns
  78.         true if found
  79.       AddItem - given a TSearchRec, constructs a suitable object to
  80.         represent the file or folder and adds it to the list
  81.       Flush - removes or frees file items with a flag that is frRemove
  82.         or frFree, and calls Update if required
  83.       CreateFolder - creates a subdirectory and adds a new TFolder
  84.         object to itself
  85. }
  86.  
  87.   TDirectory = class(TObjectList)
  88.   private
  89.     FPath : TFileName;
  90.     FSortOrder : TSortOrder;
  91.     FFilter  : PString;
  92.     FMask: Integer;
  93.     FOnUpdate : TNotifyEvent;
  94.     FChanged : Boolean;
  95.     FDesc : TDescriptions;
  96.     FColumns : TFileDetails;
  97.     function GetSize : Longint;
  98.     function GetFullName : TFileName;
  99.     function GetFilter: string;
  100.     procedure SetFilter(const Value: string);
  101.   protected
  102.     function ItemIndex(Item: TDirItem): Integer;
  103.   public
  104.     constructor Create(const APath: TFilename);
  105.     destructor Destroy; override;
  106.     function Add(Item: TDirItem): Integer;
  107.     function Remove(Item: TDirItem): Integer;
  108.     function Find(const s:string; var Index: Integer): Boolean;
  109.     procedure AddItem(const rec : TSearchrec);
  110.     procedure CreateFolder(const foldername : TFilename);
  111.     procedure Scan;
  112.     procedure Sort;
  113.     procedure Update;
  114.     procedure Flush;
  115.     property Path : TFileName read FPath write FPath;
  116.     property Fullname : TFileName read GetFullname;
  117.     property Size : Longint read GetSize;
  118.     property SortOrder : TSortOrder read FSortOrder write FSortOrder;
  119.     property Filter : string read GetFilter write SetFilter;
  120.     property Mask : Integer read FMask write FMask;
  121.     property OnUpdate : TNotifyEvent read FOnUpdate write FOnUpdate;
  122.     property Changed: Boolean read FChanged write FChanged;
  123.     property Desc : TDescriptions read FDesc;
  124.     property Columns : TFileDetails read FColumns write FColumns;
  125.   end;
  126.  
  127.  
  128.   { TDirItem is a versatile abstract object that gives a lot of functionality
  129.     to its descendants.  It encapsulates a single item in a directory listing,
  130.     such as a file or folder, and handles many functions common to both.
  131.  
  132.     Properties
  133.       Dir - a pointer to the owning directory object
  134.       Filename - the 8.3 character MS-DOS filename
  135.       Extension - optional 3 character extension
  136.       Attr - MS-DOS file attributes consisting of faXXX constants
  137.       TimeStamp - the DOS date/time stamp converted to a TDateTime format
  138.       Size - size in bytes
  139.       Fullname - full pathname (e.g. c:\abc\def\123.txt)
  140.       Release - determines whether this item should be removed from the
  141.         directory or destroyed when the directory is next updated
  142.       Hint - the popup hint string, which depends on the current
  143.         user preferences
  144.       HasDesc - True if the item has a file description
  145.  
  146.     Methods
  147.       Create - initializes a new item with details obtained from DOS
  148.       SetFilename (protected) - dangerous, this one!  Turns Filename into
  149.         a 'virtual' property.
  150.       GetSearchRec - returns a TSearchRec containing the item's DOS details.
  151.       Draw - paints the item's icon and caption onto a canvas
  152.       DrawAsList - draws a row of a directory listing
  153.       GetTitle - returns the DOS filenme or file description, depending
  154.         on the current user settings and presence of description
  155.       GetStartInfo - returns a string structure suitable for adding into
  156.         the start menu
  157.       AssignRef - modifies the fields of a TReference object so that it
  158.         points to the TDirItem.  Used for making shortcuts and aliases.
  159.       EditDescription - prompts the user for a new file description and
  160.         returns true if the operation is successful
  161.       AcceptsDrops - returns True if the user can drag and drop other
  162.         objects into this one
  163.       DragDrop - called when something has been dropped into the object
  164.       LessThan - returns True if this item should be listed before the
  165.         item passed as parameter.  User in sorting/searching.
  166.  
  167.       File management methods - at present, these make sure that file
  168.       descriptions are kept updated, but could be extended to provide other
  169.       housekeeping code.
  170.  
  171.       TDirItem's methods are usually overriden and the inherited method
  172.       called immediately after a successful disk operation -- the parent
  173.       and target TDirectory objects must not be changed before calling
  174.       these methods.
  175.  
  176.       Delete - deletes an object
  177.       CopyToDirectory - copies an object to another TDirectory
  178.       CopyToPath - copies the object to a disk directory with no
  179.         corresponding TDirectory object
  180.       MoveToDirectory - moves an object to another TDirectory
  181.       MoveToPath - moves the object to a disk directory with no
  182.         corresponding TDirectory object
  183.       MoveAndRename - similar to MoveToPath, but also changes the filename.
  184.         Used to put things in the bin.
  185.   }
  186.  
  187.   TDirItem = class(TIconic)
  188.   private
  189.     FName : TFileBody;
  190.     FAttr : Integer;
  191.     FTimeStamp : TDateTime;
  192.     FSize : Longint;
  193.     FDir  : TDirectory;
  194.     FRelease : TFileRelease;
  195.     FHasDesc : Boolean;
  196.     function GetHint : string;
  197.     function GetFullName : TFilename;
  198.     function GetExtension : TFileExt;
  199.     procedure SetFileAttr(attrib : Integer);
  200.     function GetDescription : string;
  201.     procedure PutDescription(const value: string);
  202.   protected
  203.     procedure SetFileName(const AName: TFileBody); virtual;
  204.   public
  205.     constructor Create(const details : TSearchRec; ADir : TDirectory);
  206.     procedure Draw(Canvas: TCanvas; const Rect: TRect); override;
  207.     procedure DrawSmallIcon(Canvas : TCanvas; const Rect : TRect); virtual; abstract;
  208.     procedure DrawAsList(Canvas: TCanvas; const Rect: TRect); virtual;
  209.     procedure DrawSmall(Canvas: TCanvas; const Rect: TRect); virtual;
  210.     function GetFmtFilename: TFileBody;
  211.     procedure Delete; virtual;
  212.     procedure CopyToDirectory(d : TDirectory); virtual;
  213.     procedure CopyToPath(const p : TFilename); virtual;
  214.     procedure MoveToDirectory(d : TDirectory); virtual;
  215.     procedure MoveToPath(const p : TFilename); virtual;
  216.     procedure MoveAndRename(const NewName : TFilename); virtual;
  217.     function EditDescription: Boolean;
  218.     function LessThan(f : TDirItem): Boolean; virtual;
  219.     function AcceptsDrops : Boolean; virtual; abstract;
  220.     procedure AssignRef(ref: TReference); override;
  221.     procedure DragDrop(Source: TObject); virtual; abstract;
  222.     function GetTitle: string; virtual;
  223.     function GetStartInfo : string; virtual; abstract;
  224.     function GetSearchRec: TSearchRec;
  225.     property Filename : TFileBody read FName write SetFileName;
  226.     property Attr : Integer read FAttr write SetFileAttr;
  227.     property TimeStamp : TDateTime read FTimeStamp;
  228.     property Size : Longint read FSize;
  229.     property FullName : TFilename read GetFullName;
  230.     property Extension: TFileExt read GetExtension;
  231.     property Dir : TDirectory read FDir;
  232.     property Release : TFileRelease read FRelease write FRelease;
  233.     property Hint : string read GetHint;
  234.     property Description: string read GetDescription write PutDescription;
  235.   end;
  236.  
  237.  
  238.   { TFileItem is an abstract base class that encapsulates a single file.
  239.     As well as overriding many of TDirItem's methods so that they manage
  240.     files, new methods are introduced that work only on files.
  241.     This abstract class is provided so that descendants such as TAlias
  242.     can represent different kinds of file, but still have basic file
  243.     operations carried out on them. }
  244.  
  245.   TFileItem = class(TDirItem)
  246.   protected
  247.     FIsProgram : Boolean;
  248.   public
  249.     procedure DrawSmallIcon(Canvas : TCanvas; const Rect : TRect); override;
  250.     procedure Open; override;
  251.     procedure Delete; override;
  252.     procedure CopyToDirectory(d : TDirectory); override;
  253.     procedure CopyToPath(const p : TFilename); override;
  254.     procedure MoveToDirectory(d : TDirectory); override;
  255.     procedure MoveToPath(const p : TFilename); override;
  256.     procedure MoveAndRename(const NewName : TFilename); override;
  257.     procedure Duplicate(const AName: TFilename); virtual;
  258.     function LessThan(f : TDirItem): Boolean; override;
  259.   end;
  260.  
  261.   { TFile is the usual class that is instantiated to represent a
  262.     disk file.  It keeps track of whether it extracted an icon
  263.     to display itself, and if so, the icon is freed along with the
  264.     object }
  265.  
  266.   TFile = class(TFileItem)
  267.   private
  268.     FOwnIcon : Boolean;
  269.   protected
  270.     procedure AssignIcon; virtual;
  271.     procedure FreeIcon; virtual;
  272.     procedure SetFilename(const AName: TFileBody); override;
  273.     property OwnIcon : Boolean read FOwnIcon write FOwnIcon;
  274.   public
  275.     constructor Create(const details : TSearchRec; ADir : TDirectory);
  276.     destructor Destroy; override;
  277.     function AcceptsDrops : Boolean; override;
  278.     procedure DragDrop(Source : TObject); override;
  279.     procedure AssignRef(ref: TReference); override;
  280.     function GetStartInfo : string; override;
  281.   end;
  282.  
  283.   { TFolder encapsulates a subdirectory.  It overrides numerous methods
  284.     of TDirItem to handle directories, and introduces CheckPath to
  285.     verify that the folder can be put into a destination folder }
  286.  
  287.   TFolder = class(TDirItem)
  288.   private
  289.     procedure CheckPath(const p: TFilename);
  290.   protected
  291.     procedure SetFilename(const AName: TFileBody); override;
  292.   public
  293.     constructor Create(const details : TSearchRec; ADir : TDirectory);
  294.     procedure DrawSmallIcon(Canvas : TCanvas; const Rect : TRect); override;
  295.     procedure Open; override;
  296.     procedure Delete; override;
  297.     procedure CopyToDirectory(d : TDirectory); override;
  298.     procedure CopyToPath(const p : TFilename); override;
  299.     procedure MoveToDirectory(d : TDirectory); override;
  300.     procedure MoveToPath(const p : TFilename); override;
  301.     procedure MoveAndRename(const NewName : TFilename); override;
  302.     function LessThan(f : TDirItem): Boolean; override;
  303.     procedure AssignRef(ref: TReference); override;
  304.     function AcceptsDrops : Boolean; override;
  305.     procedure DragDrop(Source : TObject); override;
  306.     function GetStartInfo : string; override;
  307.   end;
  308.  
  309.   { TFileList is a simple container for TDirItem objects.  It is
  310.     used to hold items during processing, and accumulates information
  311.     about the items as they are added.  This information is available
  312.     trought the integer properties.  The DeepScan flag determines
  313.     whether sub-folders are searched when a folder is added to the list }
  314.  
  315.   TFileList = class(TList)
  316.   private
  317.     FFileSize : Longint;
  318.     FFileCount : Integer;
  319.     FFolderCount : Integer;
  320.     FItemCount : Integer;
  321.     FDeepScan  : Boolean;
  322.   public
  323.     constructor Create;
  324.     procedure Clear;
  325.     function Add(Item:Pointer): Integer;
  326.     property FileSize : Longint read FFileSize;
  327.     property FileCount : Integer read FFileCount;
  328.     property FolderCount: Integer read FFolderCount;
  329.     property ItemCount: Integer read FItemCount write FItemCount;
  330.     property DeepScan : Boolean read FDeepScan write FDeepScan;
  331.   end;
  332.  
  333. const
  334.   faHidSys = faHidden or faSysFile;
  335.  
  336.   DirectoryMasks : array[Boolean] of Word =
  337.     (faDirectory, faDirectory or faHidden or faSysFile);
  338.  
  339.  
  340. implementation
  341.  
  342. uses ShellAPI, Forms, Controls, Progress, Resource, FileMan, WinProcs, Streamer,
  343.  Desk, Files, IniFiles, Strings, FileCtrl, MiscUtil, Alias, IconWin, Start,
  344.  Locale, Embed;
  345.  
  346. var
  347.   ResizeBitmap : Graphics.TBitmap;
  348.  
  349.  
  350.  
  351. { TDirectory }
  352.  
  353.  
  354. constructor TDirectory.Create(const APath: TFilename);
  355. begin
  356.   { initialize fields and scan directory }
  357.   inherited Create;
  358.   FDesc := TDescriptions.Create;
  359.   FMask := DirectoryMasks[ShowHidSys];
  360.   Path := APath;
  361.   FSortOrder := DefaultSort;
  362.   FOnUpdate := nil;
  363.   FChanged := False;
  364.   FFilter := NullStr;
  365.   FColumns := DefaultColumns;
  366.   Filter := DefaultFilter;
  367. end;
  368.  
  369.  
  370. destructor TDirectory.Destroy;
  371. begin
  372.   FDesc.Free;
  373.   DisposeStr(FFilter);
  374.   inherited Destroy;
  375. end;
  376.  
  377.  
  378. function TDirectory.GetFilter: string;
  379. begin
  380.   Result := FFilter^;
  381. end;
  382.  
  383.  
  384. procedure TDirectory.SetFilter(const Value: string);
  385. begin
  386.   AssignStr(FFilter, Value);
  387. end;
  388.  
  389.  
  390.  
  391. function TDirectory.Add(Item: TDirItem): Integer;
  392. begin
  393.   { inserts the item in sorted order }
  394.   Result := ItemIndex(Item);
  395.   Insert(Result, Item);
  396.   FChanged := True;
  397. end;
  398.  
  399.  
  400. function TDirectory.Remove(Item: TDirItem): Integer;
  401. begin
  402.   Result := inherited Remove(Item);
  403.   FChanged := True;
  404. end;
  405.  
  406.  
  407. function TDirectory.ItemIndex(Item: TDirItem): Integer;
  408. var
  409.   left, right, mid : Integer;
  410. begin
  411.   { Ordinary binary chop algorithm using the LessThan method
  412.     as comparator.  Returns the index where the item should be placed. }
  413.   left := 0;
  414.   right := Count;
  415.   while left < right do begin
  416.     mid := (left + right) shr 1;
  417.     if TDirItem(List^[mid]).LessThan(Item)
  418.     then left := mid + 1
  419.     else right := mid;
  420.   end;
  421.   Result := left;
  422. end;
  423.  
  424.  
  425.  
  426. function TDirectory.Find(const s : string; var Index: Integer): Boolean;
  427. var
  428.   i: Integer;
  429. begin
  430.   { This must use a linear search because only the filename
  431.     is provided as parameter and the directory list can be sorted in
  432.     many ways }
  433.  
  434.   for i := 0 to Count-1 do
  435.     if TDirItem(List^[i]).Filename = s then begin
  436.       Index := i;
  437.       Result := True;
  438.       Exit;
  439.     end;
  440.   Result := False;
  441. end;
  442.  
  443.  
  444. { AddItem creates a new TDirItem descendant and adds it to the directory
  445.   list.  '.' and '..' entries are discarded, and files with an extension
  446.   of ALS are assumed to be an alias, and the file is opened to check
  447.   the signature.  If no signature is found, a normal TFile is created
  448.   which is guaranteed to load. }
  449.  
  450. procedure TDirectory.AddItem(const rec : TSearchrec);
  451. var
  452.   f: TDirItem;
  453.   s: TStreamer;
  454.   sig : string[7];
  455. begin
  456.   if rec.name[1] = '.' then Exit;
  457.  
  458.   if rec.attr and faDirectory <> 0 then
  459.     f := TFolder.Create(rec, self)
  460.  
  461.   else if ExtractFileExt(rec.name) = AliasExtensionUpper then
  462.     try
  463.       s := TStreamer.Create(Path + rec.name, fmOpenRead);
  464.       sig := s.ReadString;
  465.       if (Length(sig) >= 4) and (PLongint(@sig[1])^ = AliasSigValue) then
  466.         f := TAlias.Create(rec, self, s)
  467.       else
  468.         f := TFile.Create(rec, self);
  469.     finally
  470.       s.Free;
  471.     end
  472.   else
  473.     f := TFile.Create(rec, self);
  474.  
  475.   Add(f);
  476. end;
  477.  
  478.  
  479. { The 4DOS descript.ion file is loaded before searching the directory
  480.   so that TDirItems can check for a description while they are initializing.
  481.   A slight problem occurs when there is no disk in the drive -- FindFirst
  482.   returns -3 fairly quickly when searching for *.*, but searching for
  483.   'descript.ion' seems to make some machines hang until a disk is inserted. }
  484.  
  485. procedure TDirectory.Scan;
  486. var
  487.   rec : TSearchRec;
  488.   code, dummy : Integer;
  489.   specs : TFilename;
  490. begin
  491.   UpdateScreen;
  492.   Desktop.SetCursor(crHourGlass);
  493.   try
  494.     ClearObjects;
  495.     FDesc.Clear;
  496.     if UseDescriptions then FDesc.LoadFromPath(Path);
  497.  
  498.     specs := FFilter^;
  499.  
  500.     repeat
  501.       code := FindFirst(Path + GetWord(specs, ';'), Mask, rec);
  502.  
  503.       if code = -3 then
  504.         raise EScanError.CreateResFmt(SCannotOpenFolder, [Fullname]);
  505.  
  506.       while code = 0 do begin
  507.         if (specs = '') or not Find(Lowercase(rec.Name), dummy) then
  508.           AddItem(rec);
  509.         if GetAsyncKeyState(VK_ESCAPE) < 0 then Break;
  510.         code := FindNext(rec);
  511.       end;
  512.     until specs = '';
  513.   finally
  514.     Desktop.ReleaseCursor;
  515.   end;
  516. end;
  517.  
  518.  
  519. function TDirectory.GetSize: Longint;
  520. var
  521.   i : Integer;
  522. begin
  523.   { counts the bytes in the files }
  524.   Result := 0;
  525.   for i := 0 to Count-1 do Inc(Result, TDirItem(List^[i]).Size);
  526. end;
  527.  
  528.  
  529. function TDirectory.GetFullname : TFileName;
  530. begin
  531.   Result := Path;
  532.   if Length(Result) > 3 then Dec(Result[0]);
  533. end;
  534.  
  535.  
  536. procedure TDirectory.CreateFolder(const foldername : TFilename);
  537. var
  538.   dest : TFilename;
  539.   rec  : TSearchrec;
  540. begin
  541.   dest := Path + foldername;
  542.  
  543.   if FFileExists(dest) then
  544.     raise EFileOpError.CreateResFmt(SFileAlreadyExists, [dest])
  545.  
  546.   else if FDirectoryExists(dest) then
  547.     raise EFileOpError.CreateResFmt(SFolderAlreadyExists, [dest])
  548.  
  549.   else begin
  550.     CreateDirectory(dest);
  551.     FindFirst(dest, faDirectory, rec);
  552.     AddItem(rec);
  553.     Update;
  554.   end;
  555. end;
  556.  
  557.  
  558. { The sorting is a simple insertion sort (utilising the binary comparison).
  559.   rather than quicksort, since directories don't usually have more than a
  560.   few hundred items.  A temporary TList is used to hold the contents while
  561.   they are being inserted back into the TDirectory }
  562.  
  563. procedure TDirectory.Sort;
  564. var
  565.   temp : TList;
  566.   i, n : Integer;
  567. begin
  568.   ShowHourGlass;
  569.   temp := TList.Create;
  570.   try
  571.     n := Count;
  572.     temp.Capacity := n;
  573.     System.Move(List^, temp.List^, n * Sizeof(Pointer));
  574.     Clear; { just clear the list, don't use ClearObjects! }
  575.     for i := 0 to n-1 do Add(temp.List^[i]);
  576.   finally
  577.     temp.Free;
  578.   end;
  579. end;
  580.  
  581.  
  582.  
  583. procedure TDirectory.Update;
  584. begin
  585.   if UseDescriptions then FDesc.SaveToPath(Path);
  586.   if Assigned(FOnUpdate) then FOnUpdate(self);
  587.   FChanged := False;
  588. end;
  589.  
  590. { Flush is called when a delete or move operation is complete.  It loops
  591.   through the list, removing items with an frRemove flag and freeing
  592.   those with an frFree flag.  The loop is in reverse because delete
  593.   operations are faster if you delete from the end of a list.
  594.  
  595.   Although it sounds neater, the items cannot be removed or freed during
  596.   the operation because the user might drag the progress box around.  This
  597.   would expose parts of the icon window which would call the TDirItems
  598.   to redraw themselves.  }
  599.  
  600. procedure TDirectory.Flush;
  601. var
  602.   i: Integer;
  603.   item : TDirItem;
  604. begin
  605.   for i := Count-1 downto 0 do begin
  606.     item := TDirItem(List^[i]);
  607.     case item.Release of
  608.       frNone   : Continue;
  609.       frRemove : TDirItem(List^[i]).Release := frNone;
  610.       frFree   : TDirItem(List^[i]).Free;
  611.     end;
  612.     Delete(i);
  613.     FChanged := True;
  614.   end;
  615.  
  616.   if FChanged then Update;
  617. end;
  618.  
  619.  
  620. { TDirItem }
  621.  
  622. constructor TDirItem.Create(const details : TSearchRec; ADir : TDirectory);
  623. begin
  624.   inherited Create;
  625.   with details do begin
  626.     FName := Lowercase(name);
  627.     FAttr := attr;
  628.     FSize := size;
  629.     FTimeStamp := TimestampToDate(time);
  630.   end;
  631.   FDir := ADir;
  632.   FRelease := frNone;
  633.   FHasDesc := UseDescriptions and (Dir.Desc.Get(Filename, self) > '');
  634. end;
  635.  
  636.  
  637. function TDirItem.GetFullName : TFilename;
  638. begin
  639.   Result := Dir.Path + Filename;
  640. end;
  641.  
  642.  
  643. function TDirItem.GetExtension : TFileExt;
  644. begin
  645.   Result := Copy(ExtractFileExt(Filename), 2, 3);
  646. end;
  647.  
  648.  
  649. procedure TDirItem.SetFileAttr(attrib : Integer);
  650. begin
  651.   if FAttr = attrib then Exit;
  652.   if FileSetAttr(Fullname, attrib) = 0 then FAttr := attrib
  653.   else raise EAttribError.CreateResFmt(SCannotChangeAttr, [Fullname]);
  654. end;
  655.  
  656.  
  657. { GetDescription makes use of the HasDesc flag to avoid performing a search
  658.   when it is known that there is no description.  Consequently, Put
  659.   must maintain this flag, and the description should not be set in any other
  660.   way.
  661.  
  662.   4DOS specifies that a ^D placed in the description string indicates that
  663.   everything following the marker is extra data used by third party programs.
  664.   Calmira doesn't need to store extra data, but the original data must be
  665.   maintained for compatibility. }
  666.  
  667. function TDirItem.GetDescription : string;
  668. var
  669.   p: Integer;
  670. begin
  671.   if FHasDesc then begin
  672.     Result := Dir.Desc.Get(Filename, self);
  673.     p := Pos(^D, Result);
  674.     if p > 0 then Result[0] := Chr(p-1);
  675.   end
  676.   else Result := '';
  677. end;
  678.  
  679.  
  680. procedure TDirItem.PutDescription(const value: string);
  681. var
  682.   s: string;
  683.   p: Integer;
  684. begin
  685.   s := Dir.Desc.Get(Filename, self);
  686.   p := Pos(^D, s);
  687.   if p > 0 then Dir.Desc.Put(filename, self, value + Copy(s, p+1, 255))
  688.   else Dir.Desc.Put(filename, self, value);
  689.   FHasDesc := value > '';
  690. end;
  691.  
  692.  
  693. function TDirItem.GetFmtFilename: TFileBody;
  694. var
  695.   p: Integer;
  696. begin
  697.   Result := FName;
  698.   if UpcaseFirstChar then Result[1] := Upcase(Result[1]);
  699.   if NoRegExtensions and (Icon <> FileIcon) and (Icon <> FolderIcon) then begin
  700.     p := Pos('.', Result);
  701.     if p > 0 then Result[0] := Chr(p-1);
  702.   end;
  703. end;
  704.  
  705.  
  706. procedure TDirItem.Draw(Canvas: TCanvas; const Rect: TRect);
  707. begin
  708.   if UseDescriptions and DescCaptions then InternalDraw(Canvas, Rect, GetTitle)
  709.   else InternalDraw(Canvas, Rect, GetFmtFilename);
  710. end;
  711.  
  712.  
  713. procedure TDirItem.DrawAsList(Canvas: TCanvas; const Rect: TRect);
  714. var
  715.   SizeStr, DateStr, TimeStr: string[15];
  716.   Top : Integer;
  717.   Left : Integer;
  718.   Details : TFileDetails;
  719. begin
  720.   { This procedure just writes the text information.  Descendants
  721.     are responsible for drawing the small icon on the left }
  722.  
  723.   DrawSmallIcon(Canvas, Rect);
  724.  
  725.   Details := Dir.Columns;
  726.  
  727.   with Canvas do begin
  728.     Top := Rect.Top+1;
  729.     Left := Rect.Left + 22;
  730.     Font.Color := clWindowText;
  731.     TextOut(Left, Top, Filename);
  732.     Inc(Left, NameColWidth);
  733.  
  734.     if fdSize in Details then begin
  735.       if self is TFolder then SizeStr := '<DIR>'
  736.       else SizeStr := FormatByte(Size, ListKBDecimals);
  737.       TextOut(Left + SizeColWidth - ColumnPadding - TextWidth(SizeStr), Top, SizeStr);
  738.       Inc(Left, SizeColWidth);
  739.     end;
  740.     if fdDate in Details then begin
  741.       DateTimeToString(DateStr, ShortDateFormat, TimeStamp);
  742.       TextOut(Left + DateColWidth - ColumnPadding - TextWidth(DateStr), Top, DateStr);
  743.       Inc(Left, DateColWidth);
  744.     end;
  745.     if fdTime in Details then begin
  746.       DateTimeToString(TimeStr, ShortTimeFormat, TimeStamp);
  747.       TextOut(Left + TimeColWidth - ColumnPadding - TextWidth(TimeStr), Top, TimeStr);
  748.       Inc(Left, TimeColWidth);
  749.     end;
  750.     if fdAttr in Details then begin
  751.       TextOut(Left, Top, AttrToStr(Attr));
  752.       Inc(Left, AttrColWidth);
  753.     end;
  754.  
  755.     if (fdDesc in Details) and UseDescriptions then
  756.       TextOut(Left, Top, Description);
  757.   end;
  758. end;
  759.  
  760. procedure TDirItem.DrawSmall(Canvas: TCanvas; const Rect: TRect);
  761. begin
  762.   DrawSmallIcon(Canvas, Rect);
  763.   with Canvas do begin
  764.     Font.Color := clWindowText;
  765.     TextOut(Rect.Left + 22, Rect.Top + 1, Filename);
  766.   end;
  767. end;
  768.  
  769.  
  770. function TDirItem.GetTitle: string;
  771. begin
  772.   Result := Description;
  773.   if Result = '' then Result := GetFmtFilename;
  774. end;
  775.  
  776.  
  777. { The LessThan method is the main comparison function for sorting, and
  778.   needs to work with the four orderings and handle descriptions when they
  779.   are used as captions.  The main sort key (Type, Data, Size) is compared
  780.   first and if they are equal, the captions are compared using the
  781.   auxiliary function.  CompareText must be used because descriptions can
  782.   be in upper and lower case }
  783.  
  784. function TDirItem.LessThan(f : TDirItem): Boolean;
  785.  
  786. function CaptionLessThan: Boolean;
  787. begin
  788.   if DescCaptions then Result := CompareText(GetTitle, f.GetTitle) < 0
  789.   else Result := Filename < f.Filename;
  790. end;
  791.  
  792. var
  793.   c: Integer;
  794. begin
  795.   case Dir.SortOrder of
  796.     soType :
  797.       begin
  798.         c := CompareStr(Extension, f.Extension);
  799.         Result := (c < 0) or ((c = 0) and CaptionLessThan)
  800.       end;
  801.  
  802.     soName :
  803.       Result := CaptionLessThan;
  804.  
  805.     soSize :
  806.       Result := (Size > f.Size) or ((Size = f.Size) and CaptionLessThan);
  807.  
  808.     soDate :
  809.       Result := (TimeStamp > f.TimeStamp) or
  810.         ((TimeStamp = f.TimeStamp) and CaptionLessThan);
  811.   end;
  812. end;
  813.  
  814.  
  815. { SetFilename is the property write method for the Filename property.
  816.   It is virtual so descandants can override it to constrain the renaming.
  817.   However, it is vital that overridden property access methods call
  818.   "inherited SetFilename" rather than using the "inherited Filename"
  819.   property, which would cause an infinite recursion and stack overflow }
  820.  
  821. procedure TDirItem.SetFileName(const AName: TFileBody);
  822. var
  823.   buf : string;
  824. begin
  825.   if AName <> FName then begin
  826.     if not IsValidFilename(AName) then
  827.       raise ERenameError.CreateResFmt(SInvalidFilename, [AName])
  828.  
  829.     else begin
  830.       if RenameFile(Dir.Path + FName, Dir.Path + AName) then begin
  831.         if UseDescriptions then begin
  832.           buf := Description;
  833.           Description := '';
  834.         end;
  835.         Dir.Remove(self);
  836.         FName := AName;
  837.         Dir.Add(self);
  838.         if UseDescriptions then Description := buf;
  839.       end
  840.       else
  841.         raise ERenameError.CreateResFmt(SCannotRename, [Fullname, AName]);
  842.     end;
  843.   end;
  844. end;
  845.  
  846.  
  847. function TDirItem.GetSearchRec: TSearchRec;
  848. begin
  849.   Result.name := Uppercase(Filename);
  850.   Result.attr := Attr;
  851.   Result.size := Size;
  852.   Result.time := DateTimeToFileDate(TimeStamp);
  853. end;
  854.  
  855.  
  856. procedure TDirItem.AssignRef(ref: TReference);
  857. begin
  858.   with Ref do begin
  859.     Target := Fullname;
  860.     Caption := GetTitle;
  861.   end;
  862. end;
  863.  
  864.  
  865. { The popup hints must show either the file description or the DOS
  866.   filename, depending on the context.  The idea is that the user can
  867.   use the hint to see information not displayed under the icon --
  868.   if a description is shown as the icon caption, the hint shows the
  869.   filename.  If the filename is the caption, a description is put
  870.   in the hint, if one exists. }
  871.  
  872. function TDirItem.GetHint : string;
  873.  
  874. procedure AddField(const s: string);
  875. begin
  876.   if Result > '' then AppendStr(Result, '  ');
  877.   AppendStr(Result, s);
  878. end;
  879.  
  880. begin
  881.   Result := '';
  882.   if UseDescriptions and HintDesc then begin
  883.     Result := Description;
  884.  
  885.     if Result = '' then
  886.       if GetTitle <> Filename then Result := Filename
  887.       else Result := SSNoDescription
  888.     else
  889.       if DescCaptions and (GetTitle = Result) then Result := Filename;
  890.   end;
  891.  
  892.   if HintBytes then
  893.     if self is TFolder then AddField('<DIR>')
  894.     else AddField(FormatByteLong(Size));
  895.  
  896.   if HintDate then AddField(DateToStr(TimeStamp));
  897.   if HintTime then AddField(ShortTimeToStr(TimeStamp));
  898.   if HintAttrib then begin
  899.     if Attr and faArchive > 0 then AddField('arc');
  900.     if Attr and faReadOnly > 0 then AddField('ro');
  901.     if Attr and faHidden > 0 then AddField('hid');
  902.     if Attr and faSysFile > 0 then AddField('sys');
  903.   end;
  904. end;
  905.  
  906.  
  907. procedure TDirItem.Delete;
  908. begin
  909.   FRelease := frFree;
  910.   Dir.Desc.Put(Filename, nil, '');
  911. end;
  912.  
  913.  
  914. { The following five methods are responsible for maintaining the consistency
  915.   of file descriptions.  When a description is transferred, the destination
  916.   object is not known, so nil is passed.
  917.  
  918.   Note that Dir.Desc.Get is used rather than the Description property.  This
  919.   is because the Description property filters out data following a ^D marker,
  920.   which we must keep. }
  921.  
  922. procedure TDirItem.MoveToDirectory(d: TDirectory);
  923. begin
  924.   FRelease := frRemove;
  925.   if UseDescriptions then begin
  926.     d.Desc.Put(Filename, nil, Dir.Desc.Get(Filename, self));
  927.     Dir.Desc.Put(Filename, self, '');
  928.   end;
  929. end;
  930.  
  931.  
  932. procedure TDirItem.MoveToPath(const p: TFilename);
  933. begin
  934.   FRelease := frFree;
  935.   if UseDescriptions then begin
  936.     SharedDesc.Put(Filename, nil, Dir.Desc.Get(Filename, self));
  937.     Dir.Desc.Put(Filename, self, '');
  938.   end;
  939. end;
  940.  
  941.  
  942. procedure TDirItem.CopyToDirectory(d: TDirectory);
  943. begin
  944.   if UseDescriptions then
  945.     d.Desc.Put(Filename, nil, Dir.Desc.Get(Filename, self));
  946. end;
  947.  
  948.  
  949. procedure TDirItem.CopyToPath(const p: TFilename);
  950. begin
  951.   if UseDescriptions then
  952.     SharedDesc.Put(Filename, nil, Dir.Desc.Get(Filename, self));
  953. end;
  954.  
  955.  
  956. procedure TDirItem.MoveAndRename(const NewName : TFilename);
  957. begin
  958.   FRelease := frFree;
  959.   if UseDescriptions then
  960.     Dir.Desc.Put(Filename, nil, '');
  961. end;
  962.  
  963.  
  964. function TDirItem.EditDescription: Boolean;
  965. var buf : string;
  966. begin
  967.   buf := Description;
  968.   Result := InputQuery(LoadStr(SChangeDescription),
  969.     FmtLoadStr(SDescribe, [Filename]), buf);
  970.   if Result then Description:= buf;
  971. end;
  972.  
  973.  
  974. { TFileItem }
  975.  
  976.  
  977. procedure TFileItem.CopyToPath(const p : TFilename);
  978. begin
  979.   if CopyFile(Fullname, p + Filename) then
  980.     inherited CopyToPath(p);
  981. end;
  982.  
  983.  
  984. procedure TFileItem.CopyToDirectory(d : TDirectory);
  985. var
  986.   i: Integer;
  987. begin
  988.   if CopyFile(Fullname, d.Path + Filename) then begin
  989.     { replace any existing object with the same name }
  990.     inherited CopyToDirectory(d);
  991.     if d.Find(Filename, i) then TFileItem(d[i]).Release := frFree;
  992.     d.AddItem(GetSearchRec);
  993.   end;
  994. end;
  995.  
  996.  
  997. procedure TFileItem.MoveToDirectory(d : TDirectory);
  998. var
  999.   i: Integer;
  1000. begin
  1001.   if MoveFile(FullName, d.Path + Filename, Attr) then begin
  1002.     inherited MoveToDirectory(d);
  1003.     FDir := d;
  1004.     if d.Find(Filename, i) then TDirItem(d[i]).Release := frFree;
  1005.     d.Add(self);
  1006.   end;
  1007. end;
  1008.  
  1009.  
  1010. procedure TFileItem.MoveToPath(const p : TFilename);
  1011. begin
  1012.   if MoveFile(FullName, p + Filename, Attr) then
  1013.     inherited MoveToPath(p);
  1014. end;
  1015.  
  1016.  
  1017. procedure TFileItem.MoveAndRename(const NewName : TFilename);
  1018. begin
  1019.   if MoveFile(FullName, NewName, Attr) then
  1020.     inherited MoveAndRename(NewName);
  1021. end;
  1022.  
  1023.  
  1024. procedure TFileItem.Duplicate(const AName: TFilename);
  1025. var
  1026.   rec: TSearchRec;
  1027.   i  : Integer;
  1028. begin
  1029.   if not IsValidFilename(AName) then
  1030.     raise EFileOpError.CreateResFmt(SInvalidFilename, [AName]);
  1031.  
  1032.   if CopyFile(Fullname, Dir.Path + AName) then begin
  1033.     rec := GetSearchRec;
  1034.     rec.Name := AName;
  1035.     with Dir do begin
  1036.       Desc.Put(AName, nil, Description);
  1037.       if Find(AName, i) then FreeObject(i);
  1038.       AddItem(rec);
  1039.       Update;
  1040.     end;
  1041.   end;
  1042. end;
  1043.  
  1044.  
  1045. function TFileItem.LessThan(f : TDirItem): Boolean;
  1046. begin
  1047.   { files are always placed after folders }
  1048.   Result := not (f is TFolder) and inherited LessThan(f);
  1049. end;
  1050.  
  1051.  
  1052. procedure TFileItem.DrawSmallIcon(Canvas: TCanvas; const Rect: TRect);
  1053. var
  1054.   DC : HDC;
  1055.   prevmode : Integer;
  1056. begin
  1057.   if MiniIcons and (Icon <> FileIcon) then begin
  1058.     with ResizeBitmap.Canvas do begin
  1059.       Brush.Assign(Canvas.Brush);
  1060.       FillRect(Bounds(0, 0, 32, 32));
  1061.       Draw(0, 0, Icon);
  1062.     end;
  1063.  
  1064.     DC := Canvas.Handle;
  1065.  
  1066.     prevmode := SetStretchBltMode(DC, STRETCH_ANDSCANS);
  1067.     StretchBlt(DC, Rect.Left+2, Rect.Top, 16, 16,
  1068.       ResizeBitmap.Canvas.Handle, 0, 0, 32, 32, SRCCOPY);
  1069.     SetStretchBltMode(DC, prevmode);
  1070.   end
  1071.   else
  1072.     if FIsProgram then Canvas.Draw(Rect.Left+2, Rect.Top, TinyProg)
  1073.     else Canvas.Draw(Rect.Left+2, Rect.Top, TinyFile)
  1074.  
  1075. end;
  1076.  
  1077.  
  1078. procedure TFileItem.Delete;
  1079. begin
  1080.   if EraseFile(Fullname, Attr) then inherited Delete;
  1081. end;
  1082.  
  1083.  
  1084. { TFile }
  1085.  
  1086. constructor TFile.Create(const details : TSearchRec; ADir : TDirectory);
  1087. begin
  1088.   inherited Create(details, ADir);
  1089.   AssignIcon;
  1090. end;
  1091.  
  1092.  
  1093. destructor TFile.Destroy;
  1094. begin
  1095.   FreeIcon;
  1096.   inherited Destroy;
  1097. end;
  1098.  
  1099.  
  1100. procedure TFile.FreeIcon;
  1101. begin
  1102.   if FOwnIcon then begin
  1103.     FIcon.Free;
  1104.     FIcon := nil;
  1105.     FOwnIcon := False;
  1106.   end;
  1107. end;
  1108.  
  1109.  
  1110. procedure TFile.AssignIcon;
  1111. var
  1112.   h : Word;
  1113.   ext : TFileExt;
  1114.   filestr : TFilename;
  1115. begin
  1116.   OwnIcon := False;
  1117.   ext := Extension;
  1118.   FIsProgram := ExtensionIn(ext, programs);
  1119.  
  1120.   { Try and extract an icon if the file extension is in the list
  1121.     of icon file types, otherwise get a pointer to an icon from
  1122.     the resource store }
  1123.  
  1124.   if ExtensionIn(ext, IconStrings) then with Icons do begin
  1125.     h := ExtractIcon(HInstance, StrPCopy(@filestr, Fullname), 0);
  1126.     if h = 0 then FIcon := WindowsIcon
  1127.     else if h = 1 then FIcon := DOSIcon
  1128.     else begin
  1129.       FIcon := TIcon.Create;
  1130.       FIcon.Handle := h;
  1131.       OwnIcon := True;
  1132.     end;
  1133.   end
  1134.  
  1135.   else
  1136.     FIcon := Icons.Get(ext);
  1137. end;
  1138.  
  1139.  
  1140.  
  1141. procedure TFileItem.Open;
  1142. begin
  1143.   DefaultExec(Fullname, '', Dir.Fullname, SW_SHOW);
  1144. end;
  1145.  
  1146.  
  1147. procedure TFile.SetFilename(const AName: TFileBody);
  1148. begin
  1149.   { If the file's extension changes, it might need a different icon }
  1150.  
  1151.   FreeIcon;
  1152.   try
  1153.     inherited SetFilename(AName);
  1154.   finally
  1155.     AssignIcon;
  1156.   end;
  1157. end;
  1158.  
  1159.  
  1160. procedure TFile.AssignRef(ref: TReference);
  1161. begin
  1162.   with Ref do begin
  1163.     BeginUpdate;
  1164.     inherited AssignRef(ref);
  1165.     Kind := rkFile;
  1166.     EndUpdate;
  1167.   end;
  1168. end;
  1169.  
  1170.  
  1171. function TFile.AcceptsDrops : Boolean;
  1172. begin
  1173.   { the user can choose whether programs accept drops }
  1174.   Result := FIsProgram and ProgDrop;
  1175. end;
  1176.  
  1177.  
  1178. procedure TFile.DragDrop(Source : TObject);
  1179. begin
  1180.   FileRef.Target := Fullname;
  1181.   FileRef.DragDrop(Source);
  1182. end;
  1183.  
  1184.  
  1185. function TFile.GetStartInfo : string;
  1186. begin
  1187.   Result := PackStartInfo(Fullname, Dir.Fullname, '', 0, 0);
  1188. end;
  1189.  
  1190.  
  1191. { TFolder }
  1192.  
  1193. constructor TFolder.Create(const details : TSearchRec; ADir : TDirectory);
  1194. begin
  1195.   inherited Create(details, ADir);
  1196.   FIcon := foldericon;
  1197. end;
  1198.  
  1199.  
  1200. procedure TFolder.DrawSmallIcon(Canvas: TCanvas; const Rect: TRect);
  1201. begin
  1202.   Canvas.Draw(Rect.Left+2, Rect.Top, TinyFolder);
  1203. end;
  1204.  
  1205.  
  1206. procedure TFolder.Open;
  1207. begin
  1208.   Desktop.OpenFolderRefresh(Fullname);
  1209. end;
  1210.  
  1211.  
  1212. procedure TFolder.Delete;
  1213. begin
  1214.   Desktop.CloseSubWindows(Fullname);
  1215.   DeleteDirectory(Fullname);
  1216.   if not HDirectoryExists(Fullname) then inherited Delete;
  1217. end;
  1218.  
  1219.  
  1220. procedure TFolder.CheckPath(const p: TFilename);
  1221. var dest: TFilename;
  1222. begin
  1223.   dest := p + Filename;
  1224.  
  1225.   if Fullname = MakeDirname(p) then
  1226.     raise EFileOpError.CreateRes(SCannotPutFolderOnSelf)
  1227.  
  1228.   else if IsAncestorDir(Fullname, Makedirname(p)) then
  1229.     raise EFileOpError.CreateRes(SCannotPutFolderInSelf)
  1230.  
  1231.   else if FFileExists(dest) then
  1232.     raise EFileOpError.CreateResFmt(SCannotPutFolderOverFile, [dest])
  1233. end;
  1234.  
  1235.  
  1236. procedure TFolder.CopyToDirectory(d : TDirectory);
  1237. var
  1238.   rec: TSearchRec;
  1239.   i : Integer;
  1240. begin
  1241.   CheckPath(d.Path);
  1242.   if CopyDirectory(Fullname, d.Path + Filename) then begin
  1243.     inherited CopyToDirectory(d);
  1244.     if not d.Find(Filename, i) and
  1245.       (Findfirst(d.Path + Filename, faDirectory, rec) = 0) then
  1246.       d.AddItem(rec);
  1247.   end;
  1248. end;
  1249.  
  1250.  
  1251. procedure TFolder.CopyToPath(const p : TFilename);
  1252. begin
  1253.   CheckPath(p);
  1254.   if CopyDirectory(Fullname, p + Filename) then
  1255.     inherited CopyToPath(p);
  1256. end;
  1257.  
  1258.  
  1259. procedure TFolder.MoveToDirectory(d : TDirectory);
  1260. var
  1261.   rec: TSearchRec;
  1262.   i : Integer;
  1263. begin
  1264.   { Windows showing this folder or any descendants are closed
  1265.     first to prevent any inconsistencies }
  1266.  
  1267.   CheckPath(d.Path);
  1268.   Desktop.CloseSubWindows(Fullname);
  1269.  
  1270.   if MoveDirectory(Fullname, d.Path + Filename) then begin
  1271.     inherited MoveToDirectory(d);
  1272.     if not d.Find(Filename, i) and
  1273.       (Findfirst(d.Path + Filename, faDirectory, rec) = 0) then
  1274.       d.AddItem(rec);
  1275.     FRelease := frFree;
  1276.   end;
  1277. end;
  1278.  
  1279.  
  1280. procedure TFolder.MoveToPath(const p : TFilename);
  1281. begin
  1282.   CheckPath(p);
  1283.   Desktop.CloseSubWindows(Fullname);
  1284.   if MoveDirectory(Fullname, p + Filename) then
  1285.     inherited MoveToPath(p);
  1286. end;
  1287.  
  1288. procedure TFolder.MoveAndRename(const NewName : TFilename);
  1289. begin
  1290.   Desktop.CloseSubWindows(Fullname);
  1291.   if MoveDirectory(FullName, NewName) then
  1292.     inherited MoveAndRename(NewName);
  1293. end;
  1294.  
  1295.  
  1296.  
  1297. procedure TFolder.SetFileName(const AName: TFileBody);
  1298. var oldname: TFilename;
  1299. begin
  1300.   oldname := Fullname;
  1301.   ExitDirectory(oldname);
  1302.   inherited SetFilename(AName);
  1303.   Desktop.RenameWindows(oldname, Fullname);
  1304. end;
  1305.  
  1306.  
  1307. procedure TFolder.DragDrop(Source : TObject);
  1308. begin
  1309.   FolderRef.Target := Fullname;
  1310.   FolderRef.DragDrop(Source);
  1311. end;
  1312.  
  1313.  
  1314. function TFolder.LessThan(f : TDirItem): Boolean;
  1315. begin
  1316.   Result := (f is TFileItem) or inherited LessThan(f);
  1317. end;
  1318.  
  1319.  
  1320. procedure TFolder.AssignRef(ref: TReference);
  1321. begin
  1322.   with Ref do begin
  1323.     BeginUpdate;
  1324.     inherited AssignRef(ref);
  1325.     Kind := rkFolder;
  1326.     EndUpdate;
  1327.   end;
  1328. end;
  1329.  
  1330.  
  1331. function TFolder.AcceptsDrops: Boolean;
  1332. begin
  1333.   Result := True;
  1334. end;
  1335.  
  1336.  
  1337. function TFolder.GetStartInfo : string;
  1338. begin
  1339.   Result := PackStartInfo('$Folder ' + Fullname, '', '', 0, 0);
  1340. end;
  1341.  
  1342.  
  1343. { TFileList }
  1344.  
  1345. constructor TFileList.Create;
  1346. begin
  1347.   inherited Create;
  1348.   FFileSize := 0;
  1349.   FFileCount := 0;
  1350.   FFolderCount := 0;
  1351. end;
  1352.  
  1353.  
  1354. procedure TFileList.Clear;
  1355. begin
  1356.   inherited Clear;
  1357.   FFileSize := 0;
  1358.   FFileCount := 0;
  1359.   FFolderCount := 0;
  1360.   FItemCount := 0;
  1361. end;
  1362.  
  1363.  
  1364. function TFileList.Add(Item:Pointer): Integer;
  1365. begin
  1366.   Result := inherited Add(Item);
  1367.   if TObject(Item) is TFileItem then begin
  1368.     Inc(FFileCount);
  1369.     Inc(FItemCount);
  1370.     Inc(FFileSize, TFileItem(Item).Size);
  1371.   end
  1372.   else begin
  1373.     Inc(FFolderCount);
  1374.     Inc(FItemCount);
  1375.     if DeepScan then begin
  1376.       ShowHourGlass;
  1377.       with DirInfo(TFolder(Item).Fullname, True) do begin
  1378.         Inc(FFileCount, files);
  1379.         Inc(FFolderCount, dirs);
  1380.         Inc(FItemCount, files + dirs);
  1381.         Inc(FFileSize, size);
  1382.       end;
  1383.     end;
  1384.   end;
  1385. end;
  1386.  
  1387. procedure DoneDirectry; far;
  1388. begin
  1389.   ResizeBitmap.Free;
  1390. end;
  1391.  
  1392. initialization
  1393.   ResizeBitmap := Graphics.TBitmap.Create;
  1394.   ResizeBitmap.Width := 32;
  1395.   ResizeBitmap.Height := 32;
  1396.   AddExitProc(DoneDirectry);
  1397. end.
  1398.