home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 May / Chip_2002-05_cd1.bin / chplus / cpp / 5 / Komponety.exe / cdiroutl.cpp < prev    next >
C/C++ Source or Header  |  1998-02-09  |  12KB  |  378 lines

  1. //---------------------------------------------------------------------------
  2. // Borland C++Builder
  3. // Copyright (c) 1987, 1998 Borland International Inc.  All Rights Reserved.
  4. //---------------------------------------------------------------------------
  5. #pragma hdrstop          //This header has some initialized data so we can't use
  6. #include  "cdiroutl.h"
  7. #include <ctype.h>
  8. #include <dir.h>
  9. #include "samp.h"
  10.  
  11. #pragma resource "*.res"    
  12. #pragma package(smart_init);
  13.  
  14. //
  15. // definitions of static data members
  16. // ----------------------------------
  17. //
  18. const TCDirectoryOutline::InvalidIndex;
  19. const TCDirectoryOutline::RootIndex;
  20. void *TCDirectoryOutline::APointer = &TCDirectoryOutline::APointer;
  21.  
  22. //
  23. // inline helpers
  24. // --------------
  25. //
  26.  
  27. inline bool SameLetter(char a, char b)
  28. {
  29.     return toupper(a) == toupper(b);
  30. }
  31.  
  32. inline int GetPos(const AnsiString& s, const AnsiString& p)
  33. {
  34.     return s.AnsiPos(p);
  35. }
  36.  
  37. //---------------------------------------------------------------------------
  38. static inline TCDirectoryOutline *ValidCtrCheck()
  39. {
  40.     return new TCDirectoryOutline((TComponent *)NULL);
  41. }
  42. //---------------------------------------------------------------------------
  43. __fastcall TCDirectoryOutline::TCDirectoryOutline(TComponent* Owner)
  44.     : TCustomOutline(Owner),
  45.       PictureLeaf(PictureClosed),
  46.       FTextCase(tcLowerCase)
  47. {
  48.     OutlineStyle = osTreePictureText;
  49.     Options = TOutlineOptions() << ooStretchBitmaps << ooDrawFocusRect;
  50.     PictureLeaf = PictureClosed;
  51.     AssignCaseProc();
  52. }
  53. //---------------------------------------------------------------------------
  54. inline int __fastcall TCDirectoryOutline::DriveToInt(char d)
  55. {
  56.     // this assumes that A..Z are contiguous and packed
  57.     return toupper(d) - 'A';
  58. }
  59. //---------------------------------------------------------------------------
  60. inline char __fastcall TCDirectoryOutline::IntToDrive(int i)
  61. {
  62.     // this assumes that A..Z are contiguous and packed
  63.     return static_cast<char>(i + 'A');
  64. }
  65. //---------------------------------------------------------------------------
  66. void __fastcall TCDirectoryOutline::AssignCaseProc()
  67. {
  68.     switch (TextCase) {
  69.         case tcLowerCase:
  70.             FCaseFunction = AnsiLowerCaseFileName;
  71.             break;
  72.             
  73.         case tcUpperCase:
  74.             FCaseFunction = AnsiUpperCaseFileName;
  75.             break;
  76.         default:
  77.             FCaseFunction = NULL;
  78.             break;
  79.     }
  80. }
  81. //---------------------------------------------------------------------------
  82.  
  83. // helper class for exception safety that wraps FindFirst/FindNext/FindClose
  84. namespace {
  85.     class FileFind {
  86.         private:
  87.             TSearchRec FSRec;
  88.             int FError;
  89.             bool IsOk()                      { return FError == 0; }
  90.  
  91.         public:
  92.             FileFind(const AnsiString &Path, int Attr)
  93.             {
  94.                 FError = FindFirst(Path, Attr, FSRec);
  95.             }
  96.  
  97.             ~FileFind()                      { FindClose(FSRec); }
  98.  
  99.             __property bool Ok             = { read = IsOk };
  100.             __property int Error           = { read = FError };
  101.             __property TSearchRec SRec     = { read = GetSRec };
  102.  
  103.             TSearchRec &GetSRec()            { return FSRec; }
  104.             operator bool()                  { return Ok; }
  105.  
  106.             bool Next()
  107.             {
  108.                 FError = FindNext(FSRec);
  109.                 return Ok;
  110.             }
  111.     };
  112. };
  113. //---------------------------------------------------------------------------
  114.  
  115. void __fastcall TCDirectoryOutline::BuildOneLevel(long RootItem)
  116. {
  117.     TOutlineNode *RootNode = Items[RootItem];
  118.     AnsiString RootName = RootNode->FullPath;
  119.  
  120.     if (!RootName.IsPathDelimiter(RootName.Length()))
  121.         RootName += "\\";
  122.     RootName += "*.*";
  123.  
  124.     for (FileFind Find(RootName, faDirectory); Find.Ok; Find.Next()) {
  125.         TSearchRec &SRec = Find.GetSRec();
  126.  
  127.         // only store directories, ignoring "." and ".."
  128.         if ((SRec.Attr & faDirectory) && SRec.Name[1] != '.') {
  129.             AnsiString Name = ForceCase(SRec.Name);
  130.  
  131.             if (RootNode->HasItems) { // insert in sorted order
  132.                 long Child = RootNode->getFirstChild();
  133.                 while (Child != InvalidIndex &&
  134.                         Items[Child]->Text.AnsiCompareIC(Name) < 0)
  135.                     Child = RootNode->GetNextChild(Child);
  136.  
  137.                 if (Child != InvalidIndex)
  138.                     Insert(Child, Name);
  139.                 else
  140.                     Add(RootNode->GetLastChild(), Name);
  141.             }
  142.             else
  143.                 AddChild(RootItem, Name);
  144.         }
  145.     }
  146.     // mark this node with an arbitrary address so we can tell we've
  147.     // already been here
  148.     Items[RootItem]->Data = APointer;
  149. }
  150. //---------------------------------------------------------------------------
  151. void __fastcall TCDirectoryOutline::BuildTree()
  152. {
  153.     Clear();
  154.     AddChild(0, ForceCase(AnsiString(Drive) + ":")); // was ":\\"
  155.     WalkTree(FDirectory);
  156.     Change();
  157. }
  158. //---------------------------------------------------------------------------
  159. void __fastcall TCDirectoryOutline::BuildSubTree(long RootItem)
  160. {
  161.     BuildOneLevel(RootItem);
  162.     TOutlineNode *RootNode = Items[RootItem];
  163.  
  164.     for (long TempRoot = RootNode->getFirstChild();
  165.             TempRoot != InvalidIndex; 
  166.             TempRoot = RootNode->GetNextChild(TempRoot))
  167.         BuildSubTree(TempRoot);
  168. }
  169. //---------------------------------------------------------------------------
  170. void __fastcall TCDirectoryOutline::Change()
  171. {
  172.     if (FOnChange)
  173.         FOnChange(this);
  174. }
  175. //---------------------------------------------------------------------------
  176. void __fastcall TCDirectoryOutline::Click()
  177. {
  178.     TCustomOutline::Click();
  179.     Directory = Items[SelectedItem]->FullPath;
  180. }
  181. //---------------------------------------------------------------------------
  182. void __fastcall TCDirectoryOutline::CreateWnd()
  183. {
  184.     AnsiString CurrentPath;
  185.     
  186.     TCustomOutline::CreateWnd();
  187.     
  188.     if (FDrive == 0) {
  189.         AnsiString CurrentPath = ForceCase(CurDir());
  190.         if (CurrentPath.Length() != 0) {
  191.             FDrive = CurrentPath[1];
  192.             FDirectory = CurrentPath;
  193.         }
  194.     }
  195.     
  196.     if (!Loading)
  197.         BuildTree();
  198. }
  199. //---------------------------------------------------------------------------
  200. void __fastcall TCDirectoryOutline::Expand(int Index)
  201. {
  202.     // check to see if we've already built this
  203.     if (!Items[Index]->Data)
  204.         BuildOneLevel(Index);
  205.     
  206.     // call the event handler
  207.     TCustomOutline::Expand(Index);
  208. }
  209. //---------------------------------------------------------------------------
  210. void __fastcall TCDirectoryOutline::Loaded()
  211. {
  212.     Loading = true;
  213.     TCustomOutline::Loaded();
  214.     AssignCaseProc();
  215.     BuildTree();
  216.     Loading = false;
  217. }
  218.  
  219. //---------------------------------------------------------------------------
  220. AnsiString __fastcall TCDirectoryOutline::ForceCase(const AnsiString &s)
  221. {
  222.     return FCaseFunction ? (*FCaseFunction)(s) : s;
  223. }
  224. //---------------------------------------------------------------------------
  225.  
  226. void __fastcall TCDirectoryOutline::SetDirectory(const TFileName NewDir)
  227. {
  228.     if (NewDir.Length() > 0) {
  229.         TFileName Path = ForceCase(ExpandFileName(NewDir));
  230.         int n = Path.Length();
  231.  
  232.         if (n > 3 && Path.IsPathDelimiter(n))
  233.             Path.SetLength(n - 1);
  234.  
  235.         if (Path != FDirectory) {
  236.             FDirectory = Path;
  237.             chdir(FDirectory.c_str());
  238.  
  239.             if (!SameLetter(Path[1], Drive))
  240.                 Drive = Path[1];
  241.             else {
  242.                 WalkTree(Path);
  243.                 Change();
  244.             }
  245.         }
  246.     }
  247. }
  248. //---------------------------------------------------------------------------
  249. void __fastcall TCDirectoryOutline::SetDrive(char NewDrive)
  250. {
  251.     // the original sample did not throw an exception here.
  252.     // should we do so now?
  253.     NewDrive = static_cast<char>(toupper(NewDrive));
  254.     if ((NewDrive >= 'A' && NewDrive <= 'Z')) {
  255.         if (!SameLetter(NewDrive, FDrive)) {
  256.             FDrive = NewDrive;
  257.             setdisk(DriveToInt(FDrive));
  258.             FDirectory = ForceCase(CurDir());
  259.             if (!ComponentState.Contains(csLoading)) 
  260.                 BuildTree();
  261.         }
  262.     }
  263. }
  264.  
  265. //---------------------------------------------------------------------------
  266. void __fastcall TCDirectoryOutline::SetTextCase(TTextCase NewCase)
  267. {
  268.     if (NewCase != FTextCase) {
  269.         FTextCase = NewCase;
  270.         AssignCaseProc();
  271.         
  272.         if (NewCase == tcAsIs) {
  273.             AnsiString CurrentPath = CurDir();
  274.             FDrive = CurrentPath[1];
  275.             FDirectory = CurrentPath;
  276.         }
  277.         
  278.         if (!ComponentState.Contains(csLoading))
  279.             BuildTree();
  280.     }
  281. }
  282. //---------------------------------------------------------------------------
  283. AnsiString TCDirectoryOutline::CurDir()
  284. {
  285.     const initbuf = 256;
  286.     size_t buflen = initbuf;
  287.     char *buf = reinterpret_cast<char *>(malloc(buflen));
  288.     
  289.     if (buf) {
  290.         buflen = GetCurrentDirectory(buflen, buf);
  291.         if (buflen > initbuf) {
  292.             char *p = reinterpret_cast<char *>(realloc(buf, buflen));
  293.             if (p) {
  294.                 buf = p;
  295.                 buflen = GetCurrentDirectory(buflen, buf);
  296.             }
  297.         }
  298.     }
  299.     
  300.     try {
  301.         AnsiString Result((buflen && buf) ? buf : "");
  302.         free(buf);
  303.         return Result;
  304.     } catch (...) {
  305.         free(buf);
  306.         throw;
  307.     }
  308. }
  309. //---------------------------------------------------------------------------
  310. long __fastcall TCDirectoryOutline::GetChildNamed(const AnsiString& Name,
  311.         long Item)
  312. {
  313.     String AText, AName;
  314.  
  315.     TOutlineNode* Node = Items[Item];
  316.  
  317.     Node->Expanded = true;
  318.     long rc = Node->getFirstChild();
  319.  
  320.     AName = AnsiUpperCase(Name);
  321.     AText = AnsiUpperCase(Items[rc]->Text); 
  322.     while (rc != InvalidIndex && AText != AName)
  323.       {
  324.         rc = Node->GetNextChild(rc);
  325.         if (rc != InvalidIndex)
  326.             AText = AnsiUpperCase(Items[rc]->Text);
  327.       }
  328.     return rc;
  329. }
  330.  
  331. //---------------------------------------------------------------------------
  332.  
  333. void __fastcall TCDirectoryOutline::WalkTree(const AnsiString& Dest)
  334. {
  335.     AnsiString Path = ForceCase(Dest);
  336.     long Item = RootIndex;  // start at root
  337.  
  338.  
  339.     // remove drive component of Path
  340.  
  341.     int Colon = Path.Pos(":");
  342.     if (Colon > 0) {
  343.         int Offset = (Path[Colon + 1] == '\\') ? 2 : 1;
  344.         Path = Path.SubString(Colon + Offset, Path.Length());
  345.     }
  346.  
  347.     // do the walk
  348.     for (int SlashPos = GetPos(Path, "\\"); Path.Length() > 0;
  349.             SlashPos = GetPos(Path, "\\")) {
  350.         AnsiString Dir = Path;
  351.  
  352.         if (SlashPos > 0) {
  353.             // splice out the first directory
  354.             Dir = Path.SubString(1, SlashPos - 1);
  355.             Path = Path.SubString(SlashPos + 1, Path.Length());
  356.         }
  357.         else {
  358.             Dir = Path;
  359.             Path = "";
  360.         }
  361.  
  362.         Item = GetChildNamed(Dir, Item);
  363.     }
  364.  
  365.     SelectedItem = Item;
  366. }
  367.             
  368. //---------------------------------------------------------------------------
  369. namespace Cdiroutl
  370. {
  371.     void __fastcall PACKAGE Register()
  372.     {
  373.         TComponentClass classes[1] = {__classid(TCDirectoryOutline)};
  374.         RegisterComponents(LoadStr(Tab_101), classes, 0);
  375.     }
  376. }
  377. //---------------------------------------------------------------------------
  378.