17. Sprßvce soubor∙ I
  1. V tΘto kapitole se budeme zab²vat postupn²m v²vojem aplikace jednoduchΘho sprßvce soubor∙. V²voj naÜi aplikace budeme provßd∞t v t∞chto krocφch: Navrhneme formulß° sprßvce soubor∙, propojφme ovladaΦe (aplikace pou₧φvß t°i r∙znΘ ovladaΦe k zobrazenφ p°φpustn²ch diskov²ch jednotek, adresß°∙ a soubor∙), vytvo°φme vlastnφ zobrazovacφ ovladaΦ, zajistφme prßci se soubory a vytvo°φme alternativnφ zp∙sob prßce se soubory pomocφ myÜi. Nejprve provedeme nßvrh formulß°e aplikace sprßvce soubor∙. ZaΦneme vytvo°enφm novΘho projektu. Pou₧itφm Inspektora objekt∙ nastavφme nßsledujφcφ vlastnosti pro hlavnφ formulß° projektu: Caption nastavφme na Sprßvce soubor∙, Name na FMForm a Position na poDefault. Nynφ p°idßme na formulß° ovladaΦe. Proto₧e umφst∞nφ ka₧dΘho z nich zßvisφ na umφst∞nφ ostatnφch je nutno jejich umφst∞nφ a nastavenφ jejich vlastnostφ zadßvat v po°adφ uvedenΘm v nßsledujφcφ tabulce. Komponenty DirectoryPanel a FilePanel jsou umφst∞ny na StatusBar:

  2.  
    Komponenta Vlastnost  Hodnota
    Panel  Align alBottom
    Caption nechßme prßzdn²
    Name StatusBar
    BevelOuter bvNone
    Panel Align alLeft
    Caption nechßme prßzdn²
    Name DirectoryPanel
    BevelInner bvLowered
    BevelWidth 2
    Panel Align alClient
    Caption nechßme prßzdn²
    Name FilePanel
    BevelInner bvLowered
    BevelWidth 2
    TabSet Align alBottom
    Name DriveTabSet
    CDirectoryOutline Name DirectoryOutline
    Align alLeft
    FileListBox Align alClient
    Name FileList
    ShowGlyphs  true

    Kdy₧ mßme p°idßny vÜechny komponenty a nastaveny jejich vlastnosti, je vhodnΘ projekt ulo₧it. Unit1 ulo₧φme pod jmΘnem FMXWin a Project1 pod FilManEx. K projektu dßle p°idßme nßsledujφcφ programovou jednotku (nazveme ji FMXUtils). Obsahuje r∙znΘ pomocnΘ funkce pro prßci se soubory (prostudujte si je a zjist∞te co a jak d∞lajφ). Jsou zde takΘ pou₧ity deklarace t°φd v²jimek. Nejprve je uveden hlaviΦkov² soubor a nßsleduje jeho programovß jednotka:
    #ifndef FmxUtilsHPP
    #define FmxUtilsHPP
    #include <consts.hpp>
    #include <Classes.hpp>
    #include <Windows.hpp>
    #include <SysUtils.hpp>
    #include <System.hpp>
    class __declspec(delphiclass) EInvalidDest;
    class __declspec(pascalimplementation) EInvalidDest:public EStreamError
    {
     typedef EStreamError inherited;
    public:
      __fastcall EInvalidDest(const AnsiString Msg) : EStreamError(Msg) { }
      __fastcall EInvalidDest(const AnsiString Msg, const TVarRec *Args,
          const int Args_Size) : EStreamError(Msg, Args, Args_Size) { }
      __fastcall EInvalidDest(int Ident) : EStreamError(Ident) { }
      __fastcall EInvalidDest(int Ident, const TVarRec *Args,
          const int Args_Size) : EStreamError(Ident, Args, Args_Size) { }
      __fastcall EInvalidDest(const AnsiString Msg, int AHelpContext) :
          EStreamError(Msg, AHelpContext) { }
      __fastcall EInvalidDest(const AnsiString Msg, const TVarRec *Args,
          const int Args_Size, int AHelpContext) : EStreamError(Msg, Args,
          Args_Size, AHelpContext) { }
      __fastcall EInvalidDest(int Ident, int AHelpContext) :
          EStreamError(Ident, AHelpContext) { }
      __fastcall EInvalidDest(int Ident, const TVarRec *Args,
          const int Args_Size, int AHelpContext) : EStreamError(Ident,
          Args, Args_Size, AHelpContext) { }
    public:
      __fastcall virtual ~EInvalidDest(void) { }
    };
    class EFCantMove : public EStreamError
    {
      typedef EStreamError inherited;
    public:
      __fastcall EFCantMove(const AnsiString Msg) : EStreamError(Msg) { }
      __fastcall EFCantMove(const AnsiString Msg, const TVarRec *Args,
          const int Args_Size) : EStreamError(Msg, Args, Args_Size) { }
      __fastcall EFCantMove(int Ident) : EStreamError(Ident) { }
      __fastcall EFCantMove(int Ident, const TVarRec *Args,
          const int Args_Size) : EStreamError(Ident, Args, Args_Size) { }
      __fastcall EFCantMove(const AnsiString Msg, int AHelpContext) :
          EStreamError(Msg, AHelpContext) { }
      __fastcall EFCantMove(const AnsiString Msg, const TVarRec *Args,
          const int Args_Size, int AHelpContext) : EStreamError(Msg, Args,
          Args_Size, AHelpContext) { }
      __fastcall EFCantMove(int Ident, int AHelpContext) :
          EStreamError(Ident, AHelpContext) { }
      __fastcall EFCantMove(int Ident, const TVarRec *Args,
          const int Args_Size, int AHelpContext) : EStreamError(Ident,
          Args, Args_Size, AHelpContext) { }
    public:
      __fastcall virtual ~EFCantMove(void) { }
    };
    extern void __fastcall CopyFile(const AnsiString FileName,
      const AnsiString DestName);
    extern void __fastcall MoveFile(const AnsiString FileName,
      const AnsiString DestName);
    extern long __fastcall GetFileSize(const AnsiString FileName);
    extern TDateTime __fastcall FileDateTime(const AnsiString FileName);
    extern bool __fastcall HasAttr(const AnsiString FileName,
      unsigned short Attr);
    extern int __fastcall ExecuteFile(const AnsiString FileName,
      const AnsiString Params, const AnsiString DefaultDir, int ShowCmd);
    #endif

    #include <vcl.h>
    #pragma hdrstop
    #include <shellapi.h>
    #include <stdio.h>
    #include "FmxUtils.h"
    TDateTime __fastcall FileDateTime(const AnsiString FileName)
    {
      return (FileDateToDateTime(FileAge(FileName)));
    }
    long __fastcall GetFileSize(const AnsiString FileName)
    {
      TSearchRec SearchRec;
      if(FindFirst(ExpandFileName(FileName), faAnyFile, SearchRec)==0)
        return SearchRec.Size;
      else
        return -1;
    }
    void __fastcall MoveFile(const AnsiString FileName,
      const AnsiString DestName)
    {
      AnsiString Destination;
      char FName[255];
      bool ckmove;
      Destination=ExpandFileName(DestName);
      GetFileTitle(FileName.c_str(),FName,255);
      if(HasAttr(FileName, faReadOnly)) {
        char buffer[255];
        sprintf(buffer, "Error: Can not move the file '%s'.",
          FileName.c_str());
        throw EFCantMove(buffer);
      }
      if (HasAttr(Destination,faDirectory))
        Destination=Destination+AnsiString(FName);
      ckmove= MoveFile(FileName.c_str(), Destination.c_str());
      if(!ckmove)
        ShowMessage("Please give the destination filename");
    }
    void __fastcall CopyFile(AnsiString FileName,AnsiString DestName)
    {
      bool   ckcopy;
      AnsiString Destination;
      char   FName[255];
      GetFileTitle(FileName.c_str(),FName,255);
      Destination = ExpandFileName(DestName);
      if(HasAttr(Destination,faDirectory))
        Destination=Destination+FName;
      ckcopy= CopyFile(FileName.c_str(),Destination.c_str(),false);
      if(!ckcopy)
        ShowMessage("Please give the destination filename");
    }
    bool __fastcall HasAttr(const AnsiString FileName,
      const unsigned short Attr)
    {
      int attribtest;
      attribtest=FileGetAttr(FileName);
      if(attribtest & Attr)
        return true;
      else
        return false;
    }
    int __fastcall ExecuteFile(const AnsiString FileName,
      const AnsiString Params, const AnsiString DefaultDir, int ShowCmd)
    {
      char zFileName[79], zParams[79], zDir[79];
      return (int) ShellExecute(Application->MainForm->Handle, NULL,
        strcpy(zFileName, FileName.c_str()),
        strcpy(zParams, Params.c_str()),
        strcpy(zDir, DefaultDir.c_str()), ShowCmd);
    }
    K naÜemu formulß°i p°idßme i nabφdku. Na formulß° p°idßme komponentu MainMenu a pomocφ Nßvrhß°e nabφdky vytvo°φme nabφdku podle nßsledujφcφ tabulky (jsou zde uvedeny i zkracovacφ klßvesy):
    &File
    &Open
    &Move...        F7
    &Copy...        F8
    &Delete...      Del
    &Rename...
    &Properties...
    ------------
    &Exit
    Nynφ ji₧ m∙₧eme vytvo°it obsluhu udßlosti OnClick pro volbu File | Exit, kterß uzavφrß hlavnφ formulß° aplikace. Vytvo°te ji sami.

  3. Po p°idßnφ komponenty TabSet na formulß°, se m∙₧eme zab²vat zprovozn∞nφm tohoto ovladaΦe. Tato komponenta vytvß°φ zßlo₧ky pro ka₧d² prvek v jeho seznamu zßlo₧ek v zßvislosti na vlastnosti Tabs. Implicitn∞ tento seznam je prßzdn². Seznam sice m∙₧eme editovat b∞hem nßvrhu, ale budeme jej vytvß°et a₧ p°i b∞hu aplikace. Po zprovozn∞nφ tohoto ovladaΦe jej musφme propojit s ovladaΦem DirectoryOutline a nßsledn∞ s FileList.

  4. API Windows poskytuje funkci GetDriveType, kterß vracφ informaci o typu specifikovanΘ jednotky. K urΦenφ zda jednotka je p°φpustnß, p°edßme nulou ukonΦen² °et∞zec obsahujφcφ ko°enov² adresß° jednotky, funkci GetDriveType. Vrßcenß hodnota indikuje typ jednotky: hodnota v∞tÜφ ne₧ 1 indikuje p°φpustnou jednotku; jinß hodnota indikuje nep°φpustnou jednotku. Nßsledujφcφ k≤d tvo°φ obsluhu udßlosti OnCreate formulß°e a slou₧φ k vytvo°enφ seznamu zßlo₧ek p°i vytvo°enφ formulß°e. Seznam zßlo₧ek obsahuje p°φpustnΘ jednotky v systΘmu.
    static char * Drive_Letter[]={"a:\\","b:\\","c:\\","d:\\","e:\\","f:\\",
     "g:\\","h:\\","i:\\","j:\\","k:\\","l:\\","m:\\","n:\\","o:\\","p:\\",
     "q:\\","r:\\","s:\\","t:\\","u:\\","v:\\","w:\\","x:\\","y:\\","z:\\"};
    int AddedIndex;
    for(int x =0; x <= 25; x++ ) {
      if(GetDriveType(Drive_Letter[x]) > 1) {
        AddedIndex=DriveTabSet->Tabs->Add(String(Drive_Letter[x]));
        if (toupper(*Drive_Letter[x]) == FileList->Drive)
          DriveTabSet->TabIndex = AddedIndex;
      }
    }
    Tato obsluha vlo₧φ pφsmena p°φpustn²ch jednotek na zßlo₧ky. Pozd∞ji se jeÜt∞ budeme zab²vat zobrazenφm typu jednotky. Nynφ, kdy₧ mßme ovladaΦe reprezentujφcφ diskovΘ jednotky, adresß°e a soubory, je nutno je propojit. Kdy₧ zvolφme jinou diskovou jednotku, chceme zobrazit jejφ adresß°ovou strukturu a seznam soubor∙ vybranΘho adresß°e. K propojenφ ovladaΦ∙, musφme vytvo°it obsluhy udßlostφ reagujφcφ na v²b∞r zßlo₧ky a zm∞nu adresß°e. Kdy₧ u₧ivatel kliknutφm (nebo pomocφ klßvesnice) vybere zßlo₧ku komponenty TabSet, komponenta generuje udßlost OnClick. V naÜem p°φpad∞ TabSet obsahuje zßlo₧ky pro p°φpustnΘ diskovΘ jednotky a kliknutφ na n∞kterΘ zßlo₧ce znamenß zm∞nu jednotky. Vytvo°φme tedy nßsledujφcφ obsluhu udßlosti OnClick pro komponentu nazvanou DriveTabSet, kterß nastavφ vlastnost Drive v ovladaΦi DirectoryOutline na prvnφ pφsmeno pou₧itΘ zßlo₧ky:
    DirectoryOutline->Drive= *((DriveTabSet->Tabs->Strings
                             [DriveTabSet->TabIndex]).c_str());
    Jestli₧e nynφ vybereme zßlo₧ku diskovΘ jednotky, pak DirectoryOutline zobrazφ adresß°ovou strukturu specifikovanΘ jednotky. Kdy₧ u₧ivatel vybere prvek v komponent∞ DirectoryOutline (kliknutφm nebo pomocφ kurzorov²ch klßves), pak komponenta generuje udßlost OnClick. Mnohem praktiΦt∞jÜφ je ale vyu₧φvat udßlost OnChange, kterß indikuje, ₧e n∞co v komponent∞ DirectoryOutline bylo zm∞n∞no. Reakci na tuto udßlost m∙₧eme vyu₧φt k aktualizaci seznamu soubor∙. Nßsledujφcφ k≤d aktualizuje jak seznam soubor∙ tak i stavov² °ßdek a to v₧dy p°i zm∞n∞ adresß°e:
    FileList->Directory = DirectoryOutline->Directory;
    DirectoryPanel->Caption=DirectoryOutline->Directory;
    JakΘkoli zm∞ny v adresß°ovΘm stromu se projevφ jednak zobrazenφm seznamu soubor∙ vybranΘho adresß°e a v²pisem adresß°ovΘ cesty k aktußlnφmu adresß°i na panelu stavovΘho °ßdku. Kdy₧ u₧ivatel klikne na prvek v seznamu soubor∙, pak okno seznamu generuje udßlost OnChange. V naÜem p°φpad∞ vyu₧ijeme tuto udßlost k zobrazenφ informacφ o vybranΘm souboru (na druhΘm panelu stavovΘho °ßdku). Vytvo°φme tedy tuto obsluhu udßlosti:
    AnsiString TheFileName;
    if(FileList->ItemIndex>=0){
      char buffer[255];
      TheFileName =FileList->Items->Strings[FileList->ItemIndex];
      sprintf(buffer,"%s  %d bytes",TheFileName,GetFileSize(TheFileName));
      FilePanel->Caption = buffer;
      if (GetFileAttributes(TheFileName.c_str()) & FILE_ATTRIBUTE_DIRECTORY)
        FileSelected = false;
      else
        FileSelected = true;
    }
    else {
      FilePanel->Caption="";
      FileSelected = false;
    }
    Funkce GetFileSize je deklarovßna v programovΘ jednotce FMXUnit. Do soukromΘ Φßsti deklarace formulß°e umφstφme:
    bool FileSelected;
    Zm∞na vybranΘho souboru v seznamu soubor∙ zp∙sobφ v²pis jmΘna a velikosti vybranΘho souboru na stavovΘm °ßdku.
  5. Ka₧d² ovladaΦ, kter² mß vlastnφ variantu zobrazovßnφ mß vlastnost nazvanou Style. V naÜi aplikaci nastavφme vlastnost Style komponenty TabSet na tsOwnerDraw. Ka₧d² seznam °et∞zc∙ C++ Builderu m∙₧e obsahovat seznam objekt∙. Do sprßvce soubor∙ p°idßme bitovΘ mapy indikujφcφ typ diskovΘ jednotky. Po₧adovanΘ obrßzky bitov²ch map musφme p°idat k aplikaci, a potom tyto obrßzky lze umφs¥ovat do seznamu °et∞zc∙. OvladaΦ Image je ovladaΦ obsahujφcφ grafick² obrßzek, nap°. bitovou mapu. Komponentu Image lze pou₧φt k zobrazenφ grafickΘho obrßzku na formulß°i, ale m∙₧eme ji takΘ pou₧φt pro dr₧enφ skryt²ch obrßzk∙, kterΘ pak v aplikaci budeme pou₧φvat. Lze je nap°. pou₧φt k ulo₧enφ bitov²ch map pro vlastnφ zobrazovacφ ovladaΦ. V naÜi aplikaci p°idßme na hlavnφ formulß° t°i komponenty Image, nastavφme jejich jmΘna na Floppy, Fixed a Network, vlastnosti Visible u vÜech t°φ komponent nastavφme na false a vlastnosti Picture p°i°adφme odpovφdajφcφ bitovΘ mapy (m∙₧eme je stßhnout). Kdy₧ ji₧ mßme grafickΘ obrßzky v aplikaci, m∙₧eme je p°i°adit k °et∞zc∙m v seznamu °et∞zc∙. V naÜi aplikaci zjistφme existujφcφ diskovß za°φzenφ a pro ka₧dΘ existujφcφ za°φzenφ do seznamu p°idßme °et∞zec souΦasn∞ s obrßzkem reprezentujφcφm typ za°φzenφ. Zm∞nφme tedy ji₧ existujφcφ obsluhu udßlosti OnCreate pro formulß° a to takto:

  6. static char * Drive_Letter[]={"a:\\","b:\\","c:\\","d:\\","e:\\","f:\\",
     "g:\\","h:\\","i:\\","j:\\","k:\\","l:\\","m:\\","n:\\","o:\\","p:\\",
     "q:\\","r:\\","s:\\","t:\\","u:\\","v:\\","w:\\","x:\\","y:\\","z:\\"};
    int AddedIndex;
    for(int x =0; x <= 25; x++ ) {
      switch(GetDriveType(Drive_Letter[x])) {
        case DRIVE_REMOVABLE:
          AddedIndex=DriveTabSet->Tabs->AddObject(String(Drive_Letter[x]),
            Floppy->Picture->Graphic);
          break;
        case DRIVE_FIXED:
          AddedIndex=DriveTabSet->Tabs->AddObject(String(Drive_Letter[x]),
            Fixed->Picture->Graphic);
          break;
        case DRIVE_REMOTE:
          AddedIndex=DriveTabSet->Tabs->AddObject(String(Drive_Letter[x]),
            Network->Picture->Graphic);
          break;
        case DRIVE_CDROM:
          AddedIndex=DriveTabSet->Tabs->AddObject(Drive_Letter[x],
            Floppy->Picture->Graphic);
          break;
        case DRIVE_RAMDISK:
          AddedIndex=DriveTabSet->Tabs->AddObject(Drive_Letter[x],
            Floppy->Picture->Graphic);
          break;
      }
      if (toupper(*Drive_Letter[x]) == FileList->Drive)
        DriveTabSet->TabIndex = AddedIndex;
    }
    Kdy₧ nastavφme styl ovladaΦe na vlastnφ kreslenφ, Windows ji₧ dßle nezobrazuje ovladaΦ na obrazovku. Mφsto toho generuje udßlosti pro ka₧d² viditeln² prvek v ovladaΦi. NaÜe aplikace tyto udßlosti zpracuje pro nakreslenφ prvk∙. P°ed vlastnφm zobrazenφm prvk∙ v prom∞nnΘm vlastnφm kreslφcφm ovladaΦi, Windows generuje udßlost OnMeasureItem. Windows urΦujφ, jakß plocha bude pot°ebnß k zobrazenφ prvku (obecn∞ plocha, na kterΘ bude zobrazen text prvku aktußlnφm pφsmem). NaÜe aplikace m∙₧e zpracovat tuto udßlost a zm∞nit navr₧enou plochu. K zm∞n∞ velikosti prvku pro vlastnφ kreslenφ, vytvo°φme obsluhu udßlosti OnMeasureItem. Tato udßlost mß dva d∙le₧itΘ parametry: index prvku a velikost tohoto prvku. Velikost je parametr volan² odkazem a aplikace m∙₧e jeho hodnotu zmenÜovat nebo zv∞tÜovat. Pozice nßsledujφcφho prvku zßvisφ na velikosti p°edchozφho prvku. Zm∞nu velikosti prvku lze vyu₧φvat v komponentßch seznamu, kombinovanΘho okna a TabSet (zde se pou₧φvß udßlost OnMeasureTab). V naÜφ aplikaci vytvo°φme obsluhu udßlosti OnMeasureTab pro komponentu TabSet, kterß zv∞tÜφ p∙vodnφ Üφ°ku zßlo₧ky o Üφ°ku bitovΘ mapy + 2:
    int BitmapWidth;
    BitmapWidth = ((Graphics::TBitmap *)
                  (DriveTabSet->Tabs->Objects[Index]))->Width;
    TabWidth=TabWidth+2+BitmapWidth;
    Prvek z vlastnostφ Objects v seznamu °et∞zc∙ musφme p°etypovat. Objects je vlastnost typu TObject a m∙₧e tak obsahovat libovolnΘho potomka TObject. Kdy₧ zφskßvßme objekty z pole, je pot°eba je p°evΘst zp∞t na aktußlnφ typ prvk∙. Jestli₧e aplikace po₧aduje kreslenφ nebo p°ekreslenφ ovladaΦe pomocφ vlastnφho kreslenφ, Windows generuje kreslφcφ udßlost pro ka₧d² viditeln² prvek v ovladaΦi. JmΘna t∞chto udßlostφ zaΦφnajφ v₧dy OnDraw, nap°. OnDrawItem, OnDrawTab nebo OnDrawCell. Tato udßlost obsahuje parametry indikujφcφ index kreslenΘho prvku, obdΘlnφk, ve kterΘm bude zobrazen a obvykle n∞kterΘ informace o stavu prvku. Pro naÜi aplikaci tedy vytvo°φme obsluhu udßlosti OnDrawTab pro komponentu TabSet:
    Graphics::TBitmap *Bitmap;
    Bitmap = (Graphics::TBitmap *) (DriveTabSet->Tabs->Objects[Index]);
    TabCanvas->Draw(R.Left, R.Top + 4, Bitmap);
    TabCanvas->TextOut(R.Left + 2 + Bitmap->Width, R.Top + 2,
      DriveTabSet->Tabs->Strings[Index].SubString(1,1));
    V∞tÜina kreslφcφch udßlostφ nep°edßvß jako parametr plßtno objektu; b∞₧n∞ se p°i kreslenφ pou₧φvß plßtno ovladaΦe. Proto₧e TabSet mß mezi prvky vlo₧en odd∞lovaΦ zßlo₧ek, je p°edßno pro kreslen² prvek specißlnφ plßtno jako parametr.
  7. V knihovn∞ b∞hu programu Builderu je zabudovßno n∞kolik souborov²ch operacφ. Funkce pro prßci se soubory vy₧adujφ zadßnφ jmΘna souboru, se kter²m chceme pracovat. Mimo t∞chto knihovnφch funkcφ budeme v naÜφ aplikaci pou₧φvat n∞kterΘ dalÜφ; jsou uvedeny v programovΘ jednotce FMXUtils. Prßci se soubory budeme provßd∞t jako reakci na volbu v nabφdce. N∞kterΘ prvky nabφdky, je vhodnΘ zp°φstupnit pouze v p°φpad∞ vybranΘho souboru. Pro povolovßnφ a zakazovßnφ prvk∙ v nabφdce vytvo°φme obsluhu udßlosti OnClick pro nabφdku File:

  8. Open1->Enabled = FileSelected;
    Delete1->Enabled = FileSelected;
    Copy1->Enabled = FileSelected;
    Move1->Enabled = FileSelected;
    Rename1->Enabled = FileSelected;
    Properties1->Enabled = FileSelected;
    Nynφ, kdy₧ u₧ivatel otev°e nabφdku File, aplikace povoluje nebo zakazuje vÜechny prvky tΘto nabφdky (mimo Exit) v zßvislosti na tom, zda mßme v seznamu soubor∙ vybran² soubor.
    ZruÜenφ souboru odstranφ soubor z disku a zruÜφ p°φsluÜnou polo₧ku v seznamu soubor∙. Pro zruÜenφ souboru, p°edßme jmΘno souboru funkci DeleteFile. DeleteFile vracφ true, jestli₧e soubor byl zruÜen, nebo false, pokud jej nelze zruÜit (jednß se nap°. o soubor urΦen² pouze pro Φtenφ). Nßsledujφcφ k≤d zpracovßvß volbu File | Delete:
    if(MessageDlg("Delete" + FileList->FileName + "?", mtConfirmation,
                  TMsgDlgButtons() << mbYes << mbNo, 0) == mrYes){
      if(DeleteFile(FileList->FileName.c_str()))
        FileList->Items->Delete(FileList->ItemIndex);
    }
    Ka₧d² soubor mß n∞kolik atribut∙ ulo₧en²ch operaΦnφm systΘmem jako bitovΘ p°φznaky. Zm∞na atributu souboru se provßdφ v t∞chto krocφch: p°eΦteme atributy souboru, zm∞nφme po₧adovan² atribut a ulo₧φme atributy souboru. Pro p°eΦtenφ atribut∙ souboru, p°edßme jmΘno souboru funkci FileGetAttr. Vrßcenß hodnota typu unsigned short popisuje nastavenΘ atributy. V naÜem p°φklad∞ volbou File | Properties otev°eme dialogovΘ okno, ve kterΘm u₧ivatel zjistφ informace o souboru a kde takΘ m∙₧e atributy souboru m∞nit. P°idßme tedy k projektu nov² formulß°, p°i°azenou programovou jednotku ulo₧φme pod jmΘnem FAttrDlg a vlastnosti novΘho formulß°e nastavφme podle nßsledujφcφ tabulky:
     
    Vlastnost Hodnota
    Name FileAttrDlg
    Caption File Attributes
    Position poScreenCenter
    BorderIcons [biSystemMenu]
    BorderStyle bsDialog

    Podle nßsledujφcφho obrßzku na formulß° p°idßme dalÜφ ovladaΦe (jmΘna t°φ komponent Label jsou uvedena na obrßzku a znaΦky nazveme ReadOnly, Archive, System a Hidden):

    Pro nastavenφ souborov²ch atribut∙, p°edßme jmΘno souboru a atributy funkci FileSetAttr. Nßsledujφcφ k≤d Φte souborovΘ atributy do prom∞nnΘ, nastavφ znaΦky v dialogovΘm okn∞ na souΦasnΘ hodnoty atribut∙ a dialogovΘ okno provede. Jestli₧e u₧ivatel n∞kter² z atribut∙ zm∞nφ, pak v p°φpad∞ uzav°enφ dialogovΘho okna pomocφ tlaΦφtka OK, jsou jejich hodnoty p°edßny souboru (nßsledujφcφ p°φkazy tvo°φ obsluhu volby File | Properties):
    unsigned short  Attributes,  NewAttributes;
    FileAttrDlg->FileDirName->Caption =
      FileList->Items->Strings[FileList->ItemIndex];
    FileAttrDlg->FilePathName->Caption = FileList->Directory;
    FileAttrDlg->ChangeDate->Caption =
      DateTimeToStr(FileDateTime(FileList->FileName));
    Attributes = FileGetAttr(FileList->Items->Strings[FileList->ItemIndex]);
    FileAttrDlg->ReadOnly->Checked = Attributes & faReadOnly;
    FileAttrDlg->Archive->Checked = Attributes & faArchive;
    FileAttrDlg->System->Checked = Attributes & faSysFile;
    FileAttrDlg->Hidden->Checked = Attributes & faHidden;
    if (FileAttrDlg->ShowModal()!= mrCancel){
      NewAttributes = Attributes;
      if (FileAttrDlg->ReadOnly->Checked)
        NewAttributes = NewAttributes | faReadOnly;
      else NewAttributes = NewAttributes & ~faReadOnly;
      if(FileAttrDlg->Archive->Checked)
        NewAttributes=NewAttributes|faArchive;
      else NewAttributes = NewAttributes & ~faArchive;
      if(FileAttrDlg->System->Checked)NewAttributes=NewAttributes|faSysFile;
      else NewAttributes = NewAttributes & ~faSysFile;
      if(FileAttrDlg->Hidden->Checked)NewAttributes=NewAttributes|faHidden;
      else NewAttributes = NewAttributes  & ~faHidden;
      if (NewAttributes != Attributes)
        FileSetAttr(FileAttrDlg->FileDirName->Caption, NewAttributes);
    }
    P°esun, kopφrovßnφ a p°ejmenovßnφ soubor∙ jsou podobnΘ operace, vÜechny vytvß°ejφ soubor z jinΘho souboru. LiÜφ se pouze tφm, co zbude z p∙vodnφho souboru. Knihovna b∞hu programu poskytuje funkci RenameFile, kterß provßdφ p°ejmenovßnφ. Programovß jednotka FMXUtils poskytuje podobnΘ funkce nazvanΘ MoveFile a CopyFile pro dalÜφ operace. VÜechny tyto funkce p°ebφrajφ dva °et∞zce jako svΘ parametry: jmΘno p∙vodnφho souboru a jmΘno cφlovΘho souboru. Nßsledujφcφ k≤d zobrazuje soukromou metodu nazvanou ConfirmChange, kterß zobrazφ potvrzovacφ dialogovΘ okno:
    void __fastcall TFMForm::ConfirmChange(const AnsiString ACaption,
                    AnsiString FromFile, AnsiString ToFile)
    {
      char buffer[700];
      sprintf(buffer,"%s %s to %s?",ACaption, FromFile, ToFile);
      if(MessageDlg(buffer, mtConfirmation,
         TMsgDlgButtons() << mbYes << mbNo, 0) == mrYes){
        if (ACaption == "Move") MoveFile(FromFile, ToFile);
        else if (ACaption == "Copy") CopyFile(FromFile, ToFile);
        else if (ACaption =="Rename") RenameFile(FromFile, ToFile);
       FileList->Update();
      }
    }
    Proto₧e vÜechny t°i operace jsou si podobnΘ, m∙₧e aplikace sprßvce soubor∙ sdφlet v∞tÜinu pou₧itΘho k≤du. Vytvo°φme dialogovΘ okno, ve kterΘm u₧ivatel zadß p∙vodnφ jmΘno a cφlovΘ jmΘno a pou₧ijeme jej v t∞chto operacφch. Na obrßzku je toto okno zobrazeno (hornφ editaΦnφ ovladaΦ nazveme FromFileName a spodnφ ToFileName).

    Formulß° dialogovΘho okna nazveme ChangeDlg a jeho jednotku ulo₧φme do souboru FChngDlg.CPP. Po vytvo°enφ dialogovΘho okna jej m∙₧eme otevφrat z obsluhy udßlosti sdφlenΘ prvky nabφdky Move, Copy a Rename (nazveme ji FileChange). Tato obsluha je tvo°ena p°φkazy (funkce _c_exit je definovßna v hlaviΦkovΘm souboru Process.h):
    if (dynamic_cast<TMenuItem *>(Sender) == Move1 )
      ChangeDlg->Caption = "Move" ;
    else if (dynamic_cast<TMenuItem *>(Sender) == Copy1)
      ChangeDlg->Caption = "Copy";
    else if (dynamic_cast<TMenuItem *>(Sender) == Rename1)
      ChangeDlg->Caption = "Rename";
    else _c_exit();
    ChangeDlg->CurrentDir->Caption = DirectoryOutline->Directory;
    ChangeDlg->FromFileName->Text = FileList->FileName;
    ChangeDlg->ToFileName->Text = "";
    if((ChangeDlg->ShowModal()!=mrCancel)&&(ChangeDlg->ToFileName->Text!=""))
      ConfirmChange(ChangeDlg->Caption, ChangeDlg->FromFileName->Text,
                    ChangeDlg->ToFileName->Text);
    Aplikace nynφ zobrazuje dialogovΘ okno se sprßvn²m titulkem a provßdφ po₧adovanou operaci. Aplikace n∞kdy pot°ebuje provΘst jinou aplikaci. API Windows poskytuje funkci ShellExecute, kterß provßdφ aplikaci, ale tato funkce vy₧aduje n∞kolik parametr∙. Programovß jednotka FMXUtils obsahuje jejφ snadn∞ji pou₧itelnou alternativu, nazvanou ExecuteFile. ExecuteFile pracuje dv∞ma zp∙soby. Je-li ji p°edßno jmΘno proveditelnΘho souboru, ExecuteFile spustφ tuto aplikaci. Je-li ji p°edßno jmΘno dokumentu p°i°azenΘho aplikaci, ExecuteFile spustφ aplikaci a automaticky otev°e tento dokument. ExecuteFile p°ebφrß t°i parametry typu AnsiString a Φtvrt² parametr indikujφcφ zp∙sob zobrazenφ okna aplikace. T°i °et∞zce reprezentujφ jmΘno souboru, parametry p°edanΘ aplikaci a adresß° pou₧it² jako pracovnφ adresß° aplikace. Poslednφ parametr m∙₧e b²t jedna z konstant pou₧φvanß API funkcφ ShowWindow. Nap°. SW_SHOW zobrazφ okno normßln∞, SW_SHOWMINIMIZED zobrazφ okno minimalizovanΘ apod. Okno seznamu soubor∙ obsahuje vÜechny informace pot°ebnΘ k provedenφ souboru. StejnΘ p°φkazy m∙₧eme p°ipojit k udßlosti OnDblClk okna seznamu soubor∙, co₧ umo₧nφ spouÜt∞t programy dvojit²m kliknutφm na jejich jmΘnu v seznamu. Jestli₧e ale vybran² prvek je adresß°, potom pravd∞podobn∞ chceme tento adresß° otev°φt (p°ejφt na tento adresß°). Obsluha udßlosti volby File | Open bude vypadat takto:
    if (HasAttr(FileList->FileName, faDirectory))
      DirectoryOutline->Directory = FileList->FileName;
    else ExecuteFile(FileList->FileName," ", DirectoryOutline->Directory, SW_SHOW);
    a obsluha dvojitΘho kliknutφ na seznamu soubor∙ je tvo°ena p°φkazem:
    Open1Click(Sender);
    HasAttr je funkce typu bool z FMXUtils, kterß vracφ true, kdy₧ soubor uveden² jako jejφ prvnφ parametr mß atribut urΦen² druh²m parametrem; jinak vracφ false. Nastavenφ vlastnosti Directory seznamu adresß°∙, zp∙sobφ zm∞nu adresß°e. Dvojit²m kliknutφm na adresß°i v seznamu soubor∙ lze nynφ m∞nit adresß°. V²voj aplikace dokonΦφme v nßsledujφcφ kapitole.

17. Sprßvce soubor∙ I