spfilectrl.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:38k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************************}
  2. {                                                                   }
  3. {       Almediadev Visual Component Library                         }
  4. {       DynamicSkinForm                                             }
  5. {       Version 4.98                                                }
  6. {                                                                   }
  7. {       Copyright (c) 2000-2002 Almediadev                          }
  8. {       ALL RIGHTS RESERVED                                         }
  9. {                                                                   }
  10. {       Home:  http://www.almdev.com                                }
  11. {       Support: support@almdev.com                                 }
  12. {                                                                   }
  13. {*******************************************************************}
  14. unit spfilectrl;
  15. {$R-,T-,H+,X+}
  16. interface
  17. uses Windows, Messages, SysUtils, Classes, Controls, Graphics, Forms,
  18.   Menus, StdCtrls, Buttons, SkinBoxCtrls, SkinCtrls;
  19. type
  20.   TFileAttr = (ftReadOnly, ftHidden, ftSystem, ftVolumeID, ftDirectory,
  21.     ftArchive, ftNormal);
  22.   TFileType = set of TFileAttr;
  23.   TDriveType = (dtUnknown, dtNoDrive, dtFloppy, dtFixed, dtNetwork, dtCDROM,
  24.     dtRAM);
  25.   TspSkinDirectoryListBox = class;
  26.   TspSkinFilterComboBox = class;
  27.   TspSkinDriveComboBox = class;
  28. { TspSkinFileListBox }
  29.   TspSkinFileListBox = class(TspSkinListBox)
  30.   private
  31.     function GetDrive: char;
  32.     function GetFileName: string;
  33.     function IsMaskStored: Boolean;
  34.     procedure SetDrive(Value: char);
  35.     procedure SetFileEdit(Value: TEdit);
  36.     procedure SetDirectory(const NewDirectory: string);
  37.     procedure SetFileType(NewFileType: TFileType);
  38.     procedure SetMask(const NewMask: string);
  39.     procedure SetFileName(const NewFile: string);
  40.   protected
  41.     FDirectory: string;
  42.     FMask: string;
  43.     FFileType: TFileType;
  44.     FFileEdit: TEdit;
  45.     FDirList: TspSkinDirectoryListBox;
  46.     FFilterCombo: TspSkinFilterComboBox;
  47.     FOnChange: TNotifyEvent;
  48.     FLastSel: Integer;
  49.     procedure CreateWnd; override;
  50.     procedure ListBoxClick; override;
  51.     procedure Change; virtual;
  52.     procedure ReadFileNames; virtual;
  53.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  54.     function GetFilePath: string; virtual;
  55.     procedure Loaded; override;
  56.   public
  57.     constructor Create(AOwner: TComponent); override;
  58.     destructor Destroy; override;
  59.     procedure Update; reintroduce;
  60.     procedure ApplyFilePath (const EditText: string); virtual;
  61.     property Drive: char read GetDrive write SetDrive;
  62.     property Directory: string read FDirectory write ApplyFilePath;
  63.     property FileName: string read GetFilePath write ApplyFilePath;
  64.   published
  65.     property Align;
  66.     property Anchors;
  67.     property DragCursor;
  68.     property DragMode;
  69.     property Enabled;
  70.     property FileEdit: TEdit read FFileEdit write SetFileEdit;
  71.     property FileType: TFileType read FFileType write SetFileType default [ftNormal];
  72.     property Font;
  73.     property ImeMode;
  74.     property ImeName;
  75.     property Mask: string read FMask write SetMask stored IsMaskStored;
  76.     property MultiSelect;
  77.     property PopupMenu;
  78.     property ShowHint;
  79.     property TabOrder;
  80.     property TabStop;
  81.     property Visible;
  82.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  83.   end;
  84. { TspDirectoryListBox }
  85.   TspSkinDirectoryListBox = class(TspSkinListBox)
  86.   private
  87.     FFileList: TspSkinFileListBox;
  88.     FDriveCombo: TspSkinDriveComboBox;
  89.     FDirLabel: TspSkinStdLabel;
  90.     FInSetDir: Boolean;
  91.     FPreserveCase: Boolean;
  92.     FCaseSensitive: Boolean;
  93.     function GetDrive: char;
  94.     procedure SetFileListBox(Value: TspSkinFileListBox);
  95.     procedure SetDirLabel(Value: TspSkinStdLabel);
  96.     procedure SetDirLabelCaption;
  97.     procedure SetDrive(Value: char);
  98.     procedure DriveChange(NewDrive: Char);
  99.     procedure SetDir(const NewDirectory: string);
  100.     procedure SetDirectory(const NewDirectory: string); virtual;
  101.   protected
  102.     ClosedBMP, OpenedBMP, CurrentBMP: TBitmap;
  103.     FDirectory: string;
  104.     FOnChange: TNotifyEvent;
  105.     procedure Change; virtual;
  106.     procedure ListBoxDblClick; override;
  107.     procedure ReadBitmaps; virtual;
  108.     procedure CreateWnd; override;
  109.     procedure DrawItem(Cnvs: TCanvas; Index: Integer;
  110.        ItemWidth, ItemHeight: Integer; TextRect: TRect; State: TOwnerDrawState);
  111.     function  ReadDirectoryNames(const ParentDirectory: string;
  112.       DirectoryList: TStringList): Integer;
  113.     procedure BuildList; virtual;
  114.     procedure ListBoxKeyPress(var Key: Char); override;
  115.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  116.     procedure Loaded; override;
  117.     function GetFullItemWidth(Index: Integer; ACnvs: TCanvas): Integer; override;
  118.   public
  119.     constructor Create(AOwner: TComponent); override;
  120.     destructor Destroy; override;
  121.     function  DisplayCase(const S: String): String;
  122.     function  FileCompareText(const A, B: String): Integer;
  123.     function GetItemPath(Index: Integer): string;
  124.     procedure OpenCurrent;
  125.     procedure Update; reintroduce;
  126.     property Drive: Char read GetDrive write SetDrive;
  127.     property Directory: string read FDirectory write SetDirectory;
  128.     property PreserveCase: Boolean read FPreserveCase;
  129.     property CaseSensitive: Boolean read FCaseSensitive;
  130.   published
  131.     property Align;
  132.     property Anchors;
  133.     property Color;
  134.     property Columns;
  135.     property Constraints;
  136.     property Ctl3D;
  137.     property DirLabel: TspSkinStdLabel read FDirLabel write SetDirLabel;
  138.     property DragCursor;
  139.     property DragMode;
  140.     property Enabled;
  141.     property FileList: TspSkinFileListBox read FFileList write SetFileListBox;
  142.     property Font;
  143.     property ImeMode;
  144.     property ImeName;
  145.     property PopupMenu;
  146.     property ShowHint;
  147.     property TabOrder;
  148.     property TabStop;
  149.     property Visible;
  150.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  151.   end;
  152. { TspSkinDriveComboBox }
  153.   TTextCase = (tcLowerCase, tcUpperCase);
  154.   TspSkinDriveComboBox = class(TspSkinComboBox)
  155.   private
  156.     FDirList: TspSkinDirectoryListBox;
  157.     FDrive: Char;
  158.     FTextCase: TTextCase;
  159.     procedure SetDirListBox (Value: TspSkinDirectoryListBox);
  160.     procedure SetDrive(NewDrive: Char);
  161.     procedure SetTextCase(NewTextCase: TTextCase);
  162.     procedure ReadBitmaps;
  163.   protected
  164.     FloppyBMP, FixedBMP, NetworkBMP, CDROMBMP, RAMBMP: TBitmap;
  165.     procedure CreateWnd; override;
  166.     procedure DrawItem(Cnvs: TCanvas; Index: Integer;
  167.        ItemWidth, ItemHeight: Integer; TextRect: TRect; State: TOwnerDrawState);
  168.     procedure NewChange(Sender: TObject);
  169.     procedure BuildList; virtual;
  170.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  171.     procedure Loaded; override;
  172.   public
  173.     constructor Create(AOwner: TComponent); override;
  174.     destructor Destroy; override;
  175.     property Text;
  176.     property Drive: Char read FDrive write SetDrive;
  177.   published
  178.     property Anchors;
  179.     property Color;
  180.     property Constraints;
  181.     property Ctl3D;
  182.     property DirList: TspSkinDirectoryListBox read FDirList write SetDirListBox;
  183.     property DragMode;
  184.     property DragCursor;
  185.     property Enabled;
  186.     property Font;
  187.     property ImeMode;
  188.     property ImeName;
  189.     property ParentColor;
  190.     property ParentCtl3D;
  191.     property ParentFont;
  192.     property ParentShowHint;
  193.     property PopupMenu;
  194.     property ShowHint;
  195.     property TabOrder;
  196.     property TabStop;
  197.     property TextCase: TTextCase read FTextCase write SetTextCase default tcLowerCase;
  198.     property Visible;
  199.     property OnChange;
  200.   end;
  201. { TFilterComboBox }
  202.   TspSkinFilterComboBox = class(TspSkinComboBox)
  203.   private
  204.     FFilter: string;
  205.     FFileList: TspSkinFileListBox;
  206.     MaskList: TStringList;
  207.     function IsFilterStored: Boolean;
  208.     function GetMask: string;
  209.     procedure SetFilter(const NewFilter: string);
  210.     procedure SeTspSkinFileListBox (Value: TspSkinFileListBox);
  211.   protected
  212.     procedure Change; override;
  213.     procedure CreateWnd; override;
  214.     procedure Click; override;
  215.     procedure BuildList;
  216.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  217.   public
  218.     constructor Create(AOwner: TComponent); override;
  219.     destructor Destroy; override;
  220.     property Mask: string read GetMask;
  221.     property Text;
  222.   published
  223.     property Anchors;
  224.     property Color;
  225.     property Constraints;
  226.     property Ctl3D;
  227.     property DragMode;
  228.     property DragCursor;
  229.     property Enabled;
  230.     property FileList: TspSkinFileListBox read FFileList write SeTspSkinFileListBox;
  231.     property Filter: string read FFilter write SetFilter stored IsFilterStored;
  232.     property Font;
  233.     property ImeName;
  234.     property ImeMode;
  235.     property ParentColor;
  236.     property ParentCtl3D;
  237.     property ParentFont;
  238.     property ParentShowHint;
  239.     property PopupMenu;
  240.     property ShowHint;
  241.     property TabOrder;
  242.     property TabStop;
  243.     property Visible;
  244.     property OnChange;
  245.     property OnClick;
  246.   end;
  247. procedure ProcessPath (const EditText: string; var Drive: Char;
  248.   var DirPart: string; var FilePart: string);
  249. function MinimizeName(const Filename: TFileName; Canvas: TCanvas;
  250.   MaxLen: Integer): TFileName;
  251. const
  252.   WNTYPE_DRIVE = 1;
  253. type
  254.   TSelectDirOpt = (sdAllowCreate, sdPerformCreate, sdPrompt);
  255.   TSelectDirOpts = set of TSelectDirOpt;
  256. function DirectoryExists(const Name: string): Boolean;
  257. function ForceDirectories(Dir: string): Boolean;
  258. implementation
  259. uses Consts, Dialogs, spUtils;
  260. {$R spfilectrl}
  261. function DirectoryExists(const Name: string): Boolean;
  262. var
  263.   Code: Integer;
  264. begin
  265.   Code := GetFileAttributes(PChar(Name));
  266.   Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
  267. end;
  268. function ForceDirectories(Dir: string): Boolean;
  269. begin
  270.   Result := True;
  271.   Dir := ExcludeTrailingBackslash(Dir);
  272.   if (Length(Dir) < 3) or DirectoryExists(Dir)
  273.     or (ExtractFilePath(Dir) = Dir) then Exit;
  274.   Result := ForceDirectories(ExtractFilePath(Dir)) and CreateDir(Dir);
  275. end;
  276. function SlashSep(const Path, S: String): String;
  277. begin
  278.   if AnsiLastChar(Path)^ <> '' then
  279.     Result := Path + '' + S
  280.   else
  281.     Result := Path + S;
  282. end;
  283. { TspSkinDriveComboBox }
  284. procedure CutFirstDirectory(var S: TFileName);
  285. var
  286.   Root: Boolean;
  287.   P: Integer;
  288. begin
  289.   if S = '' then
  290.     S := ''
  291.   else
  292.   begin
  293.     if S[1] = '' then
  294.     begin
  295.       Root := True;
  296.       Delete(S, 1, 1);
  297.     end
  298.     else
  299.       Root := False;
  300.     if S[1] = '.' then
  301.       Delete(S, 1, 4);
  302.     P := AnsiPos('',S);
  303.     if P <> 0 then
  304.     begin
  305.       Delete(S, 1, P);
  306.       S := '...' + S;
  307.     end
  308.     else
  309.       S := '';
  310.     if Root then
  311.       S := '' + S;
  312.   end;
  313. end;
  314. function MinimizeName(const Filename: TFileName; Canvas: TCanvas;
  315.   MaxLen: Integer): TFileName;
  316. var
  317.   Drive: TFileName;
  318.   Dir: TFileName;
  319.   Name: TFileName;
  320. begin
  321.   Result := FileName;
  322.   Dir := ExtractFilePath(Result);
  323.   Name := ExtractFileName(Result);
  324.   if (Length(Dir) >= 2) and (Dir[2] = ':') then
  325.   begin
  326.     Drive := Copy(Dir, 1, 2);
  327.     Delete(Dir, 1, 2);
  328.   end
  329.   else
  330.     Drive := '';
  331.   while ((Dir <> '') or (Drive <> '')) and (Canvas.TextWidth(Result) > MaxLen) do
  332.   begin
  333.     if Dir = '...' then
  334.     begin
  335.       Drive := '';
  336.       Dir := '...';
  337.     end
  338.     else if Dir = '' then
  339.       Drive := ''
  340.     else
  341.       CutFirstDirectory(Dir);
  342.     Result := Drive + Dir + Name;
  343.   end;
  344. end;
  345. function VolumeID(DriveChar: Char): string;
  346. var
  347.   OldErrorMode: Integer;
  348.   NotUsed, VolFlags: DWORD;
  349.   Buf: array [0..MAX_PATH] of Char;
  350. begin
  351.   OldErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
  352.   try
  353.     Buf[0] := #$00;
  354.     if GetVolumeInformation(PChar(DriveChar + ':'), Buf, DWORD(sizeof(Buf)),
  355.       nil, NotUsed, VolFlags, nil, 0) then
  356.       SetString(Result, Buf, StrLen(Buf))
  357.     else Result := '';  
  358.     if DriveChar < 'a' then
  359.       Result := AnsiUpperCaseFileName(Result)
  360.     else
  361.       Result := AnsiLowerCaseFileName(Result);
  362.     Result := Format('[%s]',[Result]);
  363.   finally
  364.     SetErrorMode(OldErrorMode);
  365.   end;
  366. end;
  367. function NetworkVolume(DriveChar: Char): string;
  368. var
  369.   Buf: Array [0..MAX_PATH] of Char;
  370.   DriveStr: array [0..3] of Char;
  371.   BufferSize: DWORD;
  372. begin
  373.   BufferSize := sizeof(Buf);
  374.   DriveStr[0] := UpCase(DriveChar);
  375.   DriveStr[1] := ':';
  376.   DriveStr[2] := #0;
  377.   if WNetGetConnection(DriveStr, Buf, BufferSize) = WN_SUCCESS then
  378.   begin
  379.     SetString(Result, Buf, BufferSize);
  380.     if DriveChar < 'a' then
  381.       Result := AnsiUpperCaseFileName(Result)
  382.     else
  383.       Result := AnsiLowerCaseFileName(Result);
  384.   end
  385.   else
  386.     Result := VolumeID(DriveChar);
  387. end;
  388. procedure ProcessPath (const EditText: string; var Drive: Char;
  389.   var DirPart: string; var FilePart: string);
  390. var
  391.   SaveDir, Root: string;
  392. begin
  393.   GetDir(0, SaveDir);
  394.   Drive := SaveDir[1];
  395.   DirPart := EditText;
  396.   if (DirPart[1] = '[') and (AnsiLastChar(DirPart)^ = ']') then
  397.     DirPart := Copy(DirPart, 2, Length(DirPart) - 2)
  398.   else
  399.   begin
  400.     Root := ExtractFileDrive(DirPart);
  401.     if Length(Root) = 0 then
  402.       Root := ExtractFileDrive(SaveDir)
  403.     else
  404.       Delete(DirPart, 1, Length(Root));
  405.     if (Length(Root) >= 2) and (Root[2] = ':') then
  406.       Drive := Root[1]
  407.     else
  408.       Drive := #0;
  409.   end;
  410.   try
  411.     if DirectoryExists(Root) then
  412.       ChDir(Root);
  413.     FilePart := ExtractFileName (DirPart);
  414.     if Length(DirPart) = (Length(FilePart) + 1) then
  415.       DirPart := ''
  416.     else if Length(DirPart) > Length(FilePart) then
  417.       SetLength(DirPart, Length(DirPart) - Length(FilePart) - 1)
  418.     else
  419.     begin
  420.       GetDir(0, DirPart);
  421.       Delete(DirPart, 1, Length(ExtractFileDrive(DirPart)));
  422.       if Length(DirPart) = 0 then
  423.         DirPart := '';
  424.     end;
  425.     if Length(DirPart) > 0 then
  426.       ChDir (DirPart);  {first go to our new directory}
  427.     if (Length(FilePart) > 0) and not
  428.        (((Pos('*', FilePart) > 0) or (Pos('?', FilePart) > 0)) or
  429.        FileExists(FilePart)) then
  430.     begin
  431.       ChDir(FilePart);
  432.       if Length(DirPart) = 1 then
  433.         DirPart := '' + FilePart
  434.       else
  435.         DirPart := DirPart + '' + FilePart;
  436.       FilePart := '';
  437.     end;
  438.     if Drive = #0 then
  439.       DirPart := Root + DirPart;
  440.   finally
  441.     if DirectoryExists(SaveDir) then
  442.       ChDir(SaveDir);  { restore original directory }
  443.   end;
  444. end;
  445. { TspSkinDriveComboBox }
  446. constructor TspSkinDriveComboBox.Create(AOwner: TComponent);
  447. var
  448.   Temp: ShortString;
  449. begin
  450.   inherited Create(AOwner);
  451.   OnChange := NewChange;
  452.   OnListBoxDrawItem := DrawItem;
  453.   OnComboBoxDrawItem := DrawItem;
  454.   ReadBitmaps;
  455.   GetDir(0, Temp);
  456.   FDrive := Temp[1]; { make default drive selected }
  457.   if FDrive = '' then FDrive := #0;
  458. end;
  459. destructor TspSkinDriveComboBox.Destroy;
  460. begin
  461.   FloppyBMP.Free;
  462.   FixedBMP.Free;
  463.   NetworkBMP.Free;
  464.   CDROMBMP.Free;
  465.   RAMBMP.Free;
  466.   inherited Destroy;
  467. end;
  468. procedure TspSkinDriveComboBox.BuildList;
  469. var
  470.   DriveNum: Integer;
  471.   DriveChar: Char;
  472.   DriveType: TDriveType;
  473.   DriveBits: set of 0..25;
  474.   procedure AddDrive(const VolName: string; Obj: TObject);
  475.   begin
  476.     Items.AddObject(Format('%s: %s',[DriveChar, VolName]), Obj);
  477.   end;
  478. begin
  479.   { fill list }
  480.   Items.Clear;
  481.   Integer(DriveBits) := GetLogicalDrives;
  482.   for DriveNum := 0 to 25 do
  483.   begin
  484.     if not (DriveNum in DriveBits) then Continue;
  485.     DriveChar := Char(DriveNum + Ord('a'));
  486.     DriveType := TDriveType(GetDriveType(PChar(DriveChar + ':')));
  487.     if TextCase = tcUpperCase then
  488.       DriveChar := Upcase(DriveChar);
  489.     case DriveType of
  490.       dtFloppy:   Items.AddObject(DriveChar + ':', FloppyBMP);
  491.       dtFixed:    AddDrive(VolumeID(DriveChar), FixedBMP);
  492.       dtNetwork:  AddDrive(NetworkVolume(DriveChar), NetworkBMP);
  493.       dtCDROM:    AddDrive(VolumeID(DriveChar), CDROMBMP);
  494.       dtRAM:      AddDrive(VolumeID(DriveChar), RAMBMP);
  495.     end;
  496.   end;
  497. end;
  498. procedure TspSkinDriveComboBox.SetDrive(NewDrive: Char);
  499. var
  500.   Item: Integer;
  501.   drv: string;
  502. begin
  503.   if (ItemIndex < 0) or (UpCase(NewDrive) <> UpCase(FDrive)) then
  504.   begin
  505.     if NewDrive = #0 then
  506.     begin
  507.       FDrive := NewDrive;
  508.       ItemIndex := -1;
  509.     end
  510.     else
  511.     begin
  512.       if TextCase = tcUpperCase then
  513.         FDrive := UpCase(NewDrive)
  514.       else
  515.         FDrive := Chr(ord(UpCase(NewDrive)) + 32);
  516.       { change selected item }
  517.       for Item := 0 to Items.Count - 1 do
  518.       begin
  519.         drv := Items[Item];
  520.         if (UpCase(drv[1]) = UpCase(FDrive)) and (drv[2] = ':') then
  521.         begin
  522.           ItemIndex := Item;
  523.           break;
  524.         end;
  525.       end;
  526.     end;
  527.     if FDirList <> nil then FDirList.DriveChange(Drive);
  528.     Change;
  529.   end;
  530. end;
  531. procedure TspSkinDriveComboBox.SetTextCase(NewTextCase: TTextCase);
  532. var
  533.   OldDrive: Char;
  534. begin
  535.   FTextCase := NewTextCase;
  536.   OldDrive := FDrive;
  537.   BuildList;
  538.   SetDrive (OldDrive);
  539. end;
  540. procedure TspSkinDriveComboBox.SetDirListBox (Value: TspSkinDirectoryListBox);
  541. begin
  542.   if FDirList <> nil then FDirList.FDriveCombo := nil;
  543.   FDirList := Value;
  544.   if FDirList <> nil then
  545.   begin
  546.     FDirList.FDriveCombo := Self;
  547.     FDirList.FreeNotification(Self);
  548.   end;
  549. end;
  550. procedure TspSkinDriveComboBox.Loaded;
  551. var
  552.   Temp: String;
  553. begin
  554.   inherited;
  555.   if (csDesigning in ComponentState)
  556.   then
  557.     begin
  558.       GetDir(0, Temp);
  559.       FDrive := Temp[1]; { make default drive selected }
  560.       if FDrive = '' then FDrive := #0;
  561.       BuildList;
  562.       SetDrive (FDrive);
  563.     end;  
  564. end;
  565. procedure TspSkinDriveComboBox.CreateWnd;
  566. begin
  567.   inherited CreateWnd;
  568.   BuildList;
  569.   SetDrive (FDrive);
  570. end;
  571. procedure TspSkinDriveComboBox.DrawItem;
  572. var
  573.   Bitmap: TBitmap;
  574.   bmpWidth: Integer;
  575. begin
  576.   Bitmap := TBitmap(Items.Objects[Index]);
  577.   if Bitmap <> nil then
  578.   begin
  579.     bmpWidth := Bitmap.Width;
  580.     Cnvs.BrushCopy(Bounds(TextRect.Left,
  581.                (TextRect.Top + TextRect.Bottom - Bitmap.Height) div 2,
  582.                 Bitmap.Width, Bitmap.Height),
  583.                 Bitmap, Bounds(0, 0, Bitmap.Width, Bitmap.Height),
  584.                 Bitmap.Canvas.Pixels[0, Bitmap.Height - 1]);
  585.   end
  586.   else
  587.     bmpWidth := 0;
  588.   Cnvs.TextOut(TextRect.Left + bmpWidth + 6,
  589.                TextRect.Top + RectHeight(TextRect) div 2 - Cnvs.TextHeight('Wg') div 2,
  590.                Items[Index]);
  591. end;
  592. procedure TspSkinDriveComboBox.NewChange(Sender: TObject);
  593. begin
  594.   if ItemIndex >= 0 then
  595.     Drive := Items[ItemIndex][1];
  596. end;
  597. procedure TspSkinDriveComboBox.ReadBitmaps;
  598. begin
  599.   { assign bitmap glyphs }
  600.   FloppyBMP := TBitmap.Create;
  601.   FloppyBMP.Handle := LoadBitmap(HInstance, 'SP_FLOPPY');
  602.   FixedBMP := TBitmap.Create;
  603.   FixedBMP.Handle := LoadBitmap(HInstance, 'SP_HARD');
  604.   NetworkBMP := TBitmap.Create;
  605.   NetworkBMP.Handle := LoadBitmap(HInstance, 'SP_NETWORK');
  606.   CDROMBMP := TBitmap.Create;
  607.   CDROMBMP.Handle := LoadBitmap(HInstance, 'SP_CDROM');
  608.   RAMBMP := TBitmap.Create;
  609.   RAMBMP.Handle := LoadBitmap(HInstance, 'SP_RAM');
  610. end;
  611. procedure TspSkinDriveComboBox.Notification(AComponent: TComponent;
  612.   Operation: TOperation);
  613. begin
  614.   inherited Notification(AComponent, Operation);
  615.   if (Operation = opRemove) and (AComponent = FDirList) then
  616.     FDirList := nil;
  617. end;
  618. { TspSkinDirectoryListBox }
  619. function DirLevel(const PathName: string): Integer;  { counts '' in path }
  620. var
  621.   P: PChar;
  622. begin
  623.   Result := 0;
  624.   P := AnsiStrScan(PChar(PathName), '');
  625.   while P <> nil do
  626.   begin
  627.     Inc(Result);
  628.     Inc(P);
  629.     P := AnsiStrScan(P, '');
  630.   end;
  631. end;
  632. constructor TspSkinDirectoryListBox.Create(AOwner: TComponent);
  633. begin
  634.   inherited Create(AOwner);
  635.   OnDrawItem := DrawItem;
  636.   Width := 145;
  637.   Sorted := False;
  638.   ReadBitmaps;
  639.   GetDir(0, FDirectory);
  640. end;
  641. destructor TspSkinDirectoryListBox.Destroy;
  642. begin
  643.   ClosedBMP.Free;
  644.   OpenedBMP.Free;
  645.   CurrentBMP.Free;
  646.   inherited Destroy;
  647. end;
  648. procedure TspSkinDirectoryListBox.DriveChange(NewDrive: Char);
  649. begin
  650.   if (UpCase(NewDrive) <> UpCase(Drive)) then
  651.   begin
  652.     if NewDrive <> #0 then
  653.     begin
  654.       {$I-}
  655.       ChDir(NewDrive + ':');
  656.       {$I+}
  657.       if IOResult = 0 then GetDir(0, FDirectory);
  658.     end;
  659.     if (not FInSetDir) and (IOResult = 0) then
  660.     begin
  661.       BuildList;
  662.       Change;
  663.     end;
  664.   end;
  665. end;
  666. procedure TspSkinDirectoryListBox.SetFileListBox (Value: TspSkinFileListBox);
  667. begin
  668.   if FFileList <> nil then FFileList.FDirList := nil;
  669.   FFileList := Value;
  670.   if FFileList <> nil then
  671.   begin
  672.     FFileList.FDirList := Self;
  673.     FFileList.FreeNotification(Self);
  674.   end;
  675. end;
  676. procedure TspSkinDirectoryListBox.SetDirLabel;
  677. begin
  678.   FDirLabel := Value;
  679.   if Value <> nil then Value.FreeNotification(Self);
  680.   SetDirLabelCaption;
  681. end;
  682. procedure TspSkinDirectoryListBox.SetDir(const NewDirectory: string);
  683. begin
  684.      { go to old directory first, in case of incomplete pathname
  685.        and curdir changed - probably not necessary }
  686.   if DirectoryExists(FDirectory) then
  687.     ChDir(FDirectory);
  688.   ChDir(NewDirectory);     { exception raised if invalid dir }
  689.   GetDir(0, FDirectory);   { store correct directory name }
  690.   BuildList;
  691.   Change;
  692. end;
  693. procedure TspSkinDirectoryListBox.OpenCurrent;
  694. begin
  695.   Directory := GetItemPath(ItemIndex);
  696. end;
  697. procedure TspSkinDirectoryListBox.Update;
  698. begin
  699.   BuildList;
  700.   Change;
  701. end;
  702. function TspSkinDirectoryListBox.DisplayCase(const S: String): String;
  703. begin
  704.   if FPreserveCase or FCaseSensitive then
  705.     Result := S
  706.   else
  707.     Result := AnsiLowerCase(S);
  708. end;
  709. function TspSkinDirectoryListBox.FileCompareText(const A,B: String): Integer;
  710. begin
  711.   if FCaseSensitive then
  712.     Result := AnsiCompareStr(A,B)
  713.   else
  714.     Result := AnsiCompareFileName(A,B);
  715. end;
  716.   {
  717.     Reads all directories in ParentDirectory, adds their paths to
  718.     DirectoryList,and returns the number added
  719.   }
  720. function TspSkinDirectoryListBox.ReadDirectoryNames(const ParentDirectory: string;
  721.   DirectoryList: TStringList): Integer;
  722. var
  723.   Status: Integer;
  724.   SearchRec: TSearchRec;
  725. begin
  726.   Result := 0;
  727.   Status := FindFirst(SlashSep(ParentDirectory, '*.*'), faDirectory, SearchRec);
  728.   try
  729.     while Status = 0 do
  730.     begin
  731.       if (SearchRec.Attr and faDirectory = faDirectory) then
  732.       begin
  733.         if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then
  734.         begin
  735.           DirectoryList.Add(SearchRec.Name);
  736.           Inc(Result);
  737.         end;
  738.       end;
  739.       Status := FindNext(SearchRec);
  740.     end;
  741.   finally
  742.     FindClose(SearchRec);
  743.   end;
  744. end;
  745. procedure TspSkinDirectoryListBox.BuildList;
  746. var
  747.   TempPath: string;
  748.   DirName: string;
  749.   IndentLevel, BackSlashPos: Integer;
  750.   VolFlags: DWORD;
  751.   I: Integer;
  752.   Siblings: TStringList;
  753.   NewSelect: Integer;
  754.   Root: string;
  755. begin
  756.   FStopUpDateHScrollBar := True;
  757.   try
  758.     Items.BeginUpdate;
  759.     Items.Clear;
  760.     IndentLevel := 0;
  761.     Root := ExtractFileDrive(Directory)+'';
  762.     GetVolumeInformation(PChar(Root), nil, 0, nil, DWORD(i), VolFlags, nil, 0);
  763.     FPreserveCase := VolFlags and (FS_CASE_IS_PRESERVED or FS_CASE_SENSITIVE) <> 0;
  764.     FCaseSensitive := (VolFlags and FS_CASE_SENSITIVE) <> 0;
  765.     if (Length(Root) >= 2) and (Root[2] = '') then
  766.     begin
  767.       ListBox.Items.AddObject(Root, OpenedBMP);
  768.       Inc(IndentLevel);
  769.       TempPath := Copy(Directory, Length(Root)+1, Length(Directory));
  770.     end
  771.     else
  772.       TempPath := Directory;
  773.     if (Length(TempPath) > 0) then
  774.     begin
  775.       if AnsiLastChar(TempPath)^ <> '' then
  776.       begin
  777.         BackSlashPos := AnsiPos('', TempPath);
  778.         while BackSlashPos <> 0 do
  779.         begin
  780.           DirName := Copy(TempPath, 1, BackSlashPos - 1);
  781.           if IndentLevel = 0 then DirName := DirName + '';
  782.           Delete(TempPath, 1, BackSlashPos);
  783.           ListBox.Items.AddObject(DirName, OpenedBMP);
  784.           Inc(IndentLevel);
  785.           BackSlashPos := AnsiPos('', TempPath);
  786.         end;
  787.       end;
  788.       Items.AddObject(TempPath, CurrentBMP);
  789.     end;
  790.     NewSelect := Items.Count - 1;
  791.     Siblings := TStringList.Create;
  792.     try
  793.       Siblings.Sorted := True;
  794.         { read all the dir names into Siblings }
  795.       ReadDirectoryNames(Directory, Siblings);
  796.       for i := 0 to Siblings.Count - 1 do
  797.         ListBox.Items.AddObject(Siblings[i], ClosedBMP);
  798.     finally
  799.       Siblings.Free;
  800.     end;
  801.   finally
  802.     Items.EndUpdate;
  803.   end;
  804.   FStopUpDateHScrollBar := False;
  805.   if HandleAllocated then
  806.   begin
  807.     ItemIndex := NewSelect;
  808.     UpDateScrollbar;
  809.   end;
  810. end;
  811. procedure TspSkinDirectoryListBox.ReadBitmaps;
  812. begin
  813.   OpenedBMP := TBitmap.Create;
  814.   OpenedBMP.LoadFromResourceName(HInstance, 'SP_OPENFOLDER');
  815.   ClosedBMP := TBitmap.Create;
  816.   ClosedBMP.LoadFromResourceName(HInstance, 'SP_CLOSEDFOLDER');
  817.   CurrentBMP := TBitmap.Create;
  818.   CurrentBMP.LoadFromResourceName(HInstance, 'SP_CURRENTFOLDER');
  819. end;
  820. procedure TspSkinDirectoryListBox.ListBoxDblClick;
  821. begin
  822.   inherited;
  823.   OpenCurrent;
  824. end;
  825. procedure TspSkinDirectoryListBox.Change;
  826. begin
  827.   if FFileList <> nil then FFileList.SetDirectory(Directory);
  828.   SetDirLabelCaption;
  829.   if Assigned(FOnChange) then FOnChange(Self);
  830. end;
  831. function TspSkinDirectoryListBox.GetFullItemWidth(Index: Integer; ACnvs: TCanvas): Integer;
  832. var
  833.   bmpWidth, dirOffset: Integer;
  834.   BitMap: TBitMap;
  835. begin
  836.   Result := inherited GetFullItemWidth(Index, ACnvs);
  837.   bmpWidth  := 16;
  838.   dirOffset := Index * 4 + 2;
  839.   Bitmap := TBitmap(ListBox.Items.Objects[Index]);
  840.   if Bitmap <> nil
  841.   then
  842.     begin
  843.       if Bitmap = ClosedBMP then
  844.          dirOffset := (DirLevel (Directory) + 1) * 4 + 2;
  845.       bmpWidth := Bitmap.Width;   
  846.     end;
  847.   Result := Result + DirOffset + bmpWidth + 4;
  848. end;
  849. procedure TspSkinDirectoryListBox.DrawItem(Cnvs: TCanvas; Index: Integer;
  850.        ItemWidth, ItemHeight: Integer; TextRect: TRect; State: TOwnerDrawState);
  851. var
  852.   Bitmap: TBitmap;
  853.   bmpWidth: Integer;
  854.   dirOffset: Integer;
  855.   R: TRect;
  856. begin
  857.   bmpWidth  := 16;
  858.   dirOffset := Index * 4 + 2;
  859.   Bitmap := TBitmap(ListBox.Items.Objects[Index]);
  860.   if Bitmap <> nil then
  861.   begin
  862.     if Bitmap = ClosedBMP then
  863.        dirOffset := (DirLevel (Directory) + 1) * 4 + 2;
  864.     bmpWidth := Bitmap.Width;
  865.     Cnvs.BrushCopy(Bounds(TextRect.Left + dirOffset - ListBox.HorizontalExtentValue,
  866.                (TextRect.Top + TextRect.Bottom - Bitmap.Height) div 2,
  867.                 Bitmap.Width, Bitmap.Height),
  868.                 Bitmap, Bounds(0, 0, Bitmap.Width, Bitmap.Height),
  869.                 Bitmap.Canvas.Pixels[0, Bitmap.Height - 1]);
  870.   end;
  871.   R := TextRect;
  872.   Cnvs.Brush.Style := bsClear;
  873.   SPDrawText3(Cnvs, Items[Index], R, bmpWidth + dirOffset + 4 - ListBox.HorizontalExtentValue);
  874. end;
  875. function TspSkinDirectoryListBox.GetItemPath (Index: Integer): string;
  876. var
  877.   CurDir: string;
  878.   i, j: Integer;
  879.   Bitmap: TBitmap;
  880. begin
  881.   Result := '';
  882.   if Index < Items.Count then
  883.   begin
  884.     CurDir := Directory;
  885.     Bitmap := TBitmap(Items.Objects[Index]);
  886.     if Index = 0 then
  887.       Result := ExtractFileDrive(CurDir)+''
  888.     else if Bitmap = ClosedBMP then
  889.       Result := SlashSep(CurDir,Items[Index])
  890.     else if Bitmap = CurrentBMP then
  891.       Result := CurDir
  892.     else
  893.     begin
  894.       i   := 0;
  895.       j   := 0;
  896.       Delete(CurDir, 1, Length(ExtractFileDrive(CurDir)));
  897.       while j <> (Index + 1) do
  898.       begin
  899.         Inc(i);
  900.         if i > Length (CurDir) then
  901.           break;
  902.         if CurDir[i] in LeadBytes then
  903.           Inc(i)
  904.         else if CurDir[i] = '' then
  905.           Inc(j);
  906.       end;
  907.       Result := ExtractFileDrive(Directory) + Copy(CurDir, 1, i - 1);
  908.     end;
  909.   end;
  910. end;
  911. procedure TspSkinDirectoryListBox.Loaded;
  912. begin
  913.   inherited;
  914.   if (csDesigning in ComponentState)
  915.   then
  916.     begin
  917.       GetDir(0, FDirectory);
  918.       BuildList;
  919.     end;  
  920. end;
  921. procedure TspSkinDirectoryListBox.CreateWnd;
  922. begin
  923.   inherited;
  924.   BuildList;
  925.   ItemIndex := DirLevel (Directory);
  926. end;
  927. function TspSkinDirectoryListBox.GetDrive: char;
  928. begin
  929.   Result := FDirectory[1];
  930. end;
  931. procedure TspSkinDirectoryListBox.SetDrive(Value: char);
  932. begin
  933.   if (UpCase(Value) <> UpCase(Drive)) then
  934.     SetDirectory (Format ('%s:', [Value]));
  935. end;
  936. procedure TspSkinDirectoryListBox.SetDirectory(const NewDirectory: string);
  937. var
  938.   DirPart: string;
  939.   FilePart: string;
  940.   NewDrive: Char;
  941. begin
  942.   if Length (NewDirectory) = 0 then Exit;
  943.   if (FileCompareText(NewDirectory, Directory) = 0) then Exit;
  944.   ProcessPath (NewDirectory, NewDrive, DirPart, FilePart);
  945.   try
  946.     if Drive <> NewDrive then
  947.     begin
  948.       FInSetDir := True;
  949.       if (FDriveCombo <> nil) then
  950.         FDriveCombo.Drive := NewDrive
  951.       else
  952.         DriveChange(NewDrive);
  953.     end;
  954.   finally
  955.     FInSetDir := False;
  956.   end;
  957.   SetDir(DirPart);
  958. end;
  959. procedure TspSkinDirectoryListBox.ListBoxKeyPress;
  960. begin
  961.   inherited;
  962.   if (Word(Key) = VK_RETURN) then
  963.     OpenCurrent;
  964. end;
  965. procedure TspSkinDirectoryListBox.Notification(AComponent: TComponent;
  966.   Operation: TOperation);
  967. begin
  968.   inherited Notification(AComponent, Operation);
  969.   if (Operation = opRemove) then
  970.   begin
  971.     if (AComponent = FFileList) then FFileList := nil
  972.     else if (AComponent = FDriveCombo) then FDriveCombo := nil
  973.     else if (AComponent = FDirLabel) then FDirLabel := nil;
  974.   end;
  975. end;
  976. procedure TspSkinDirectoryListBox.SetDirLabelCaption;
  977. var
  978.   DirWidth: Integer;
  979. begin
  980.   if FDirLabel <> nil then
  981.   begin
  982.     DirWidth := Width;
  983.     if not FDirLabel.AutoSize then DirWidth := FDirLabel.Width;
  984.     FDirLabel.Caption := MinimizeName(Directory, FDirLabel.Canvas, DirWidth);
  985.   end;
  986. end;
  987. { TspSkinFileListBox }
  988. const
  989.   DefaultMask = '*.*';
  990. constructor TspSkinFileListBox.Create(AOwner: TComponent);
  991. begin
  992.   inherited Create(AOwner);
  993.   Width := 145;
  994.   FFileType := [ftNormal]; { show only normal files by default }
  995.   GetDir(0, FDirectory); { initially use current dir on default drive }
  996.   FMask := DefaultMask;  { default file mask is all }
  997.   MultiSelect := False;    { default is not multi-select }
  998.   FLastSel := -1;
  999.   Sorted := True;
  1000. end;
  1001. destructor TspSkinFileListBox.Destroy;
  1002. begin
  1003.   inherited Destroy;
  1004. end;
  1005. procedure TspSkinFileListBox.Update;
  1006. begin
  1007.   ReadFileNames;
  1008. end;
  1009. procedure TspSkinFileListBox.CreateWnd;
  1010. begin
  1011.   inherited;
  1012.   ReadFileNames;
  1013. end;
  1014. procedure TspSkinFileListBox.Loaded;
  1015. begin
  1016.   inherited;
  1017.   if (csDesigning in ComponentState)
  1018.   then
  1019.     begin
  1020.       GetDir(0, FDirectory);
  1021.       ReadFileNames;
  1022.     end;  
  1023. end;
  1024. function TspSkinFileListBox.IsMaskStored: Boolean;
  1025. begin
  1026.   Result := DefaultMask <> FMask;
  1027. end;
  1028. function TspSkinFileListBox.GetDrive: char;
  1029. begin
  1030.   Result := FDirectory[1];
  1031. end;
  1032. procedure TspSkinFileListBox.ReadFileNames;
  1033. var
  1034.   AttrIndex: TFileAttr;
  1035.   I: Integer;
  1036.   FileExt: string;
  1037.   MaskPtr: PChar;
  1038.   Ptr: PChar;
  1039.   AttrWord: Word;
  1040.   FileInfo: TSearchRec;
  1041.   SaveCursor: TCursor;
  1042. const
  1043.    Attributes: array[TFileAttr] of Word = (faReadOnly, faHidden, faSysFile,
  1044.      faVolumeID, faDirectory, faArchive, 0);
  1045. begin
  1046.       { if no handle allocated yet, this call will force
  1047.         one to be allocated incorrectly (i.e. at the wrong time.
  1048.         In due time, one will be allocated appropriately.  }
  1049.   AttrWord := DDL_READWRITE;
  1050.   if HandleAllocated then
  1051.   begin
  1052.     { Set attribute flags based on values in FileType }
  1053.     for AttrIndex := ftReadOnly to ftArchive do
  1054.       if AttrIndex in FileType then
  1055.         AttrWord := AttrWord or Attributes[AttrIndex];
  1056.     ChDir(FDirectory); { go to the directory we want }
  1057.     Clear; { clear the list }
  1058.     I := 0;
  1059.     SaveCursor := Screen.Cursor;
  1060.     try
  1061.       MaskPtr := PChar(FMask);
  1062.       while MaskPtr <> nil do
  1063.       begin
  1064.         Ptr := StrScan (MaskPtr, ';');
  1065.         if Ptr <> nil then
  1066.           Ptr^ := #0;
  1067.         if FindFirst(MaskPtr, AttrWord, FileInfo) = 0 then
  1068.         begin
  1069.           repeat            { exclude normal files if ftNormal not set }
  1070.             if (ftNormal in FileType) or (FileInfo.Attr and AttrWord <> 0) then
  1071.               if FileInfo.Attr and faDirectory <> 0 then
  1072.               begin
  1073.                 I := Items.Add(Format('[%s]',[FileInfo.Name]));
  1074.               end
  1075.               else
  1076.               begin
  1077.                 FileExt := AnsiLowerCase(ExtractFileExt(FileInfo.Name));
  1078.                 I := Items.AddObject(FileInfo.Name, nil);
  1079.               end;
  1080.             if I = 100 then
  1081.               Screen.Cursor := crHourGlass;
  1082.           until FindNext(FileInfo) <> 0;
  1083.           FindClose(FileInfo);
  1084.         end;
  1085.         if Ptr <> nil then
  1086.         begin
  1087.           Ptr^ := ';';
  1088.           Inc (Ptr);
  1089.         end;
  1090.         MaskPtr := Ptr;
  1091.       end;
  1092.     finally
  1093.       Screen.Cursor := SaveCursor;
  1094.     end;
  1095.     Change;
  1096.   end;
  1097. end;
  1098. procedure TspSkinFileListBox.ListBoxClick;
  1099. begin
  1100.   inherited;
  1101.   if FLastSel <> ItemIndex then
  1102.      Change;
  1103. end;
  1104. procedure TspSkinFileListBox.Change;
  1105. begin
  1106.   FLastSel := ItemIndex;
  1107.   if FFileEdit <> nil then
  1108.   begin
  1109.     if Length(GetFileName) = 0 then
  1110.       FileEdit.Text := Mask
  1111.     else
  1112.       FileEdit.Text := GetFileName;
  1113.     FileEdit.SelectAll;
  1114.   end;
  1115.   if Assigned(FOnChange) then FOnChange(Self);
  1116. end;
  1117. function TspSkinFileListBox.GetFileName: string;
  1118. var
  1119.   idx: Integer;
  1120. begin
  1121.   idx  := ItemIndex;
  1122.   if (idx < 0)  or  (Items.Count = 0)  or  (Selected[idx] = FALSE)  then
  1123.     Result  := ''
  1124.   else
  1125.     Result  := Items[idx];
  1126. end;
  1127. procedure TspSkinFileListBox.SetFileName(const NewFile: string);
  1128. begin
  1129.   if AnsiCompareFileName(NewFile, GetFileName) <> 0 then
  1130.   begin
  1131.     ItemIndex := SendMessage(Handle, LB_FindStringExact, 0,
  1132.       Longint(PChar(NewFile)));
  1133.     Change;
  1134.   end;
  1135. end;
  1136. procedure TspSkinFileListBox.SetFileEdit(Value: TEdit);
  1137. begin
  1138.   FFileEdit := Value;
  1139.   if FFileEdit <> nil then
  1140.   begin
  1141.     FFileEdit.FreeNotification(Self);
  1142.     if GetFileName <> '' then
  1143.       FFileEdit.Text := GetFileName
  1144.     else
  1145.       FFileEdit.Text := Mask;
  1146.   end;
  1147. end;
  1148. procedure TspSkinFileListBox.SetDrive(Value: char);
  1149. begin
  1150.   if (UpCase(Value) <> UpCase(FDirectory[1])) then
  1151.     ApplyFilePath (Format ('%s:', [Value]));
  1152. end;
  1153. procedure TspSkinFileListBox.SetDirectory(const NewDirectory: string);
  1154. begin
  1155.   if AnsiCompareFileName(NewDirectory, FDirectory) <> 0 then
  1156.   begin
  1157.        { go to old directory first, in case not complete pathname
  1158.          and curdir changed - probably not necessary }
  1159.     if DirectoryExists(FDirectory) then
  1160.       ChDir(FDirectory);
  1161.     ChDir(NewDirectory);     { exception raised if invalid dir }
  1162.     GetDir(0, FDirectory);   { store correct directory name }
  1163.     ReadFileNames;
  1164.   end;
  1165. end;
  1166. procedure TspSkinFileListBox.SetFileType(NewFileType: TFileType);
  1167. begin
  1168.   if NewFileType <> FFileType then
  1169.   begin
  1170.     FFileType := NewFileType;
  1171.     ReadFileNames;
  1172.   end;
  1173. end;
  1174. procedure TspSkinFileListBox.SetMask(const NewMask: string);
  1175. begin
  1176.   if FMask <> NewMask then
  1177.   begin
  1178.     FMask := NewMask;
  1179.     ReadFileNames;
  1180.   end;
  1181. end;
  1182. procedure TspSkinFileListBox.ApplyFilePath(const EditText: string);
  1183. var
  1184.   DirPart: string;
  1185.   FilePart: string;
  1186.   NewDrive: Char;
  1187. begin
  1188.   if AnsiCompareFileName(FileName, EditText) = 0 then Exit;
  1189.   if Length (EditText) = 0 then Exit;
  1190.   ProcessPath (EditText, NewDrive, DirPart, FilePart);
  1191.   if FDirList <> nil then
  1192.     FDirList.Directory := EditText
  1193.   else
  1194.     if NewDrive <> #0 then
  1195.       SetDirectory(Format('%s:%s', [NewDrive, DirPart]))
  1196.     else
  1197.       SetDirectory(DirPart);
  1198.   if (Pos('*', FilePart) > 0) or (Pos('?', FilePart) > 0) then
  1199.     SetMask (FilePart)
  1200.   else if Length(FilePart) > 0 then
  1201.   begin
  1202.     SetFileName (FilePart);
  1203.     if FileExists (FilePart) then
  1204.     begin
  1205.       if GetFileName = '' then
  1206.       begin
  1207.         SetMask(FilePart);
  1208.         SetFileName (FilePart);
  1209.       end;
  1210.     end;
  1211.   end;
  1212. end;
  1213. function TspSkinFileListBox.GetFilePath: string;
  1214. begin
  1215.   Result := '';
  1216.   if GetFileName <> '' then
  1217.     Result := SlashSep(FDirectory, GetFileName);
  1218. end;
  1219. procedure TspSkinFileListBox.Notification(AComponent: TComponent;
  1220.   Operation: TOperation);
  1221. begin
  1222.   inherited Notification(AComponent, Operation);
  1223.   if (Operation = opRemove) then
  1224.   begin
  1225.     if (AComponent = FFileEdit) then FFileEdit := nil
  1226.     else if (AComponent = FDirList) then FDirList := nil
  1227.     else if (AComponent = FFilterCombo) then FFilterCombo := nil;
  1228.   end;
  1229. end;
  1230. { TspSkinFilterComboBox }
  1231. constructor TspSkinFilterComboBox.Create(AOwner: TComponent);
  1232. begin
  1233.   inherited Create(AOwner);
  1234.   FFilter := SDefaultFilter;
  1235.   MaskList := TStringList.Create;
  1236. end;
  1237. destructor TspSkinFilterComboBox.Destroy;
  1238. begin
  1239.   MaskList.Free;
  1240.   inherited Destroy;
  1241. end;
  1242. procedure TspSkinFilterComboBox.CreateWnd;
  1243. begin
  1244.   inherited CreateWnd;
  1245.   BuildList;
  1246. end;
  1247. function TspSkinFilterComboBox.IsFilterStored: Boolean;
  1248. begin
  1249.   Result := SDefaultFilter <> FFilter;
  1250. end;
  1251. procedure TspSkinFilterComboBox.SetFilter(const NewFilter: string);
  1252. begin
  1253.   if AnsiCompareFileName(NewFilter, FFilter) <> 0 then
  1254.   begin
  1255.     FFilter := NewFilter;
  1256.     if HandleAllocated then BuildList;
  1257.     Change;
  1258.   end;
  1259. end;
  1260. procedure TspSkinFilterComboBox.SeTspSkinFileListBox (Value: TspSkinFileListBox);
  1261. begin
  1262.   if FFileList <> nil then FFileList.FFilterCombo := nil;
  1263.   FFileList := Value;
  1264.   if FFileList <> nil then
  1265.   begin
  1266.     FFileList.FreeNotification(Self);
  1267.     FFileList.FFilterCombo := Self;
  1268.   end;
  1269. end;
  1270. procedure TspSkinFilterComboBox.Click;
  1271. begin
  1272.   inherited Click;
  1273.   Change;
  1274. end;
  1275. function TspSkinFilterComboBox.GetMask: string;
  1276. begin
  1277.   if ItemIndex < 0 then
  1278.     ItemIndex := Items.Count - 1;
  1279.   if ItemIndex >= 0 then
  1280.   begin
  1281.      Result := MaskList[ItemIndex];
  1282.   end
  1283.   else
  1284.      Result := '*.*';
  1285. end;
  1286. procedure TspSkinFilterComboBox.BuildList;
  1287. var
  1288.   AFilter, MaskName, Mask: string;
  1289.   BarPos: Integer;
  1290. begin
  1291.   Items.Clear;
  1292.   MaskList.Clear;
  1293.   AFilter := Filter;
  1294.   BarPos := AnsiPos('|', AFilter);
  1295.   while BarPos <> 0 do
  1296.   begin
  1297.     MaskName := Copy(AFilter, 1, BarPos - 1);
  1298.     Delete(AFilter, 1, BarPos);
  1299.     BarPos := AnsiPos('|', AFilter);
  1300.     if BarPos > 0 then
  1301.     begin
  1302.       Mask := Copy(AFilter, 1, BarPos - 1);
  1303.       Delete(AFilter, 1, BarPos);
  1304.     end
  1305.     else
  1306.     begin
  1307.       Mask := AFilter;
  1308.       AFilter := '';
  1309.     end;
  1310.     Items.Add(MaskName);
  1311.     MaskList.Add(Mask);
  1312.     BarPos := AnsiPos('|', AFilter);
  1313.   end;
  1314.   ItemIndex := 0;
  1315. end;
  1316. procedure TspSkinFilterComboBox.Notification(AComponent: TComponent;
  1317.   Operation: TOperation);
  1318. begin
  1319.   inherited Notification(AComponent, Operation);
  1320.   if (Operation = opRemove) and (AComponent = FFileList) then
  1321.     FFileList := nil;
  1322. end;
  1323. procedure TspSkinFilterComboBox.Change;
  1324. begin
  1325.   if FFileList <> nil then FFileList.Mask := Mask;
  1326.   inherited Change;
  1327. end;
  1328. end.