home *** CD-ROM | disk | FTP | other *** search
- //---------------------------------------------------------------------------
- // Borland C++Builder
- // Copyright (c) 1987, 1997 Borland International Inc. All Rights Reserved.
- //---------------------------------------------------------------------------
- #pragma hdrstop //This header has some initialized data so we can use
- #include "diroutln.h" //pre compiled headers.
-
- #include <ctype.h>
- #include <dir.h>
-
- //#pragma resource "*.res" //IDE links .res automatically for components
-
- //
- // definitions of static data members
- // ----------------------------------
- //
- const TDirectoryOutline::InvalidIndex;
- const TDirectoryOutline::RootIndex;
- void *TDirectoryOutline::APointer; // = &TDirectoryOutline::APointer;
-
- //
- // inline helpers
- // --------------
- //
-
- inline bool SameLetter(char a, char b)
- {
- return toupper(a) == toupper(b);
- }
-
- inline int GetPos(const AnsiString& s, const AnsiString& p)
- {
- #ifndef _MBCS
- return s.Pos(p);
- #else
- return s.AnsiPos(p);
- #endif
- }
-
-
- //---------------------------------------------------------------------------
- static inline TDirectoryOutline *ValidCtrCheck()
- {
- return new TDirectoryOutline(NULL);
- }
- //---------------------------------------------------------------------------
- __fastcall TDirectoryOutline::TDirectoryOutline(TComponent* Owner)
- : TCustomOutline(Owner),
- PictureLeaf(PictureClosed),
- FTextCase(tcLowerCase)
- {
- OutlineStyle = osTreePictureText;
- Options = TOutlineOptions() << ooStretchBitmaps << ooDrawFocusRect;
- PictureLeaf = PictureClosed;
- AssignCaseProc();
-
- if (!APointer)
- APointer = &APointer;
- }
- //---------------------------------------------------------------------------
- inline int __fastcall TDirectoryOutline::DriveToInt(char d)
- {
- // this assumes that A..Z are contiguous and packed
- return toupper(d) - 'A';
- }
- //---------------------------------------------------------------------------
- inline char __fastcall TDirectoryOutline::IntToDrive(int i)
- {
- // this assumes that A..Z are contiguous and packed
- return static_cast<char>(i + 'A');
- }
- //---------------------------------------------------------------------------
- void __fastcall TDirectoryOutline::AssignCaseProc()
- {
- switch (TextCase) {
- #ifndef _MBCS
- case tcLowerCase:
- FCaseFunction = AnsiLowerCase;
- break;
-
- case tcUpperCase:
- FCaseFunction = AnsiUpperCase;
- break;
- #else
- case tcLowerCase:
- FCaseFunction = AnsiLowerCaseFileName;
- break;
-
- case tcUpperCase:
- FCaseFunction = AnsiUpperCaseFileName;
- break;
- #endif
- default:
- FCaseFunction = NULL;
- break;
- }
- }
- //---------------------------------------------------------------------------
-
- // helper class for exception safety that wraps FindFirst/FindNext/FindClose
- namespace {
- class FileFind {
- private:
- TSearchRec FSRec;
- int FError;
- bool IsOk() { return FError == 0; }
-
- public:
- FileFind(const AnsiString &Path, int Attr)
- {
- FError = FindFirst(Path, Attr, FSRec);
- }
-
- ~FileFind() { FindClose(FSRec); }
-
- __property bool Ok = { read = IsOk };
- __property int Error = { read = FError };
- __property TSearchRec SRec = { read = GetSRec };
-
- TSearchRec &GetSRec() { return FSRec; }
- operator bool() { return Ok; }
-
- bool Next()
- {
- FError = FindNext(FSRec);
- return Ok;
- }
- };
- };
- //---------------------------------------------------------------------------
-
- void __fastcall TDirectoryOutline::BuildOneLevel(long RootItem)
- {
- TOutlineNode *RootNode = Items[RootItem];
- AnsiString RootName = RootNode->FullPath;
-
- #ifndef _MBCS
- if (RootName[RootName.Length()] != '\\')
- #else
- if (!RootName.IsPathDelimiter(RootName.Length()))
- #endif
- RootName += "\\";
- RootName += "*.*";
-
- for (FileFind Find(RootName, faDirectory); Find.Ok; Find.Next()) {
- TSearchRec &SRec = Find.GetSRec();
-
- // only store directories, ignoring "." and ".."
- if ((SRec.Attr & faDirectory) && SRec.Name[0] != '.') {
- AnsiString Name = ForceCase(SRec.Name);
-
- if (RootNode->HasItems) { // insert in sorted order
- long Child = RootNode->getFirstChild();
- while (Child != InvalidIndex &&
- Items[Child]->Text.AnsiCompareIC(Name) < 0)
- Child = RootNode->GetNextChild(Child);
-
- if (Child != InvalidIndex)
- Insert(Child, Name);
- else
- Add(RootNode->GetLastChild(), Name);
- }
- else
- AddChild(RootItem, Name);
- }
- }
- // mark this node with an arbitrary address so we can tell we've
- // already been here
- Items[RootItem]->Data = APointer;
- }
- //---------------------------------------------------------------------------
- void __fastcall TDirectoryOutline::BuildTree()
- {
- Clear();
- AddChild(0, ForceCase(AnsiString(Drive) + ":"));
- WalkTree(FDirectory);
- Change();
- }
- //---------------------------------------------------------------------------
- void __fastcall TDirectoryOutline::BuildSubTree(long RootItem)
- {
- BuildOneLevel(RootItem);
- TOutlineNode *RootNode = Items[RootItem];
-
- for (long TempRoot = RootNode->getFirstChild();
- TempRoot != InvalidIndex;
- TempRoot = RootNode->GetNextChild(TempRoot))
- BuildSubTree(TempRoot);
- }
- //---------------------------------------------------------------------------
- void __fastcall TDirectoryOutline::Change()
- {
- if (FOnChange)
- FOnChange(this);
- }
- //---------------------------------------------------------------------------
- void __fastcall TDirectoryOutline::Click()
- {
- TCustomOutline::Click();
- Directory = Items[SelectedItem]->FullPath;
- }
- //---------------------------------------------------------------------------
- void __fastcall TDirectoryOutline::CreateWnd()
- {
- AnsiString CurrentPath;
-
- TCustomOutline::CreateWnd();
-
- if (FDrive == 0) {
- AnsiString CurrentPath = ForceCase(CurDir());
- if (CurrentPath.Length() != 0) {
- FDrive = CurrentPath[0];
- FDirectory = CurrentPath;
- }
- }
-
- if (!ComponentState.Contains(csLoading))
- BuildTree();
- }
- //---------------------------------------------------------------------------
- void __fastcall TDirectoryOutline::Expand(long Index)
- {
- // check to see if we've already built this
- if (!Items[Index]->Data)
- BuildOneLevel(Index);
-
- // call the event handler
- TCustomOutline::Expand(Index);
- }
- //---------------------------------------------------------------------------
- void __fastcall TDirectoryOutline::Loaded()
- {
- TCustomOutline::Loaded();
- AssignCaseProc();
- BuildTree();
- }
-
- //---------------------------------------------------------------------------
- AnsiString __fastcall TDirectoryOutline::ForceCase(const AnsiString &s)
- {
- return FCaseFunction ? (*FCaseFunction)(s) : s;
- }
- //---------------------------------------------------------------------------
-
- void __fastcall TDirectoryOutline::SetDirectory(const TFileName NewDir)
- {
- if (NewDir.Length() > 0) {
- TFileName Path = ForceCase(ExpandFileName(NewDir));
- int n = Path.Length();
-
- #ifndef _MBCS
- if (n > 3 && Path[n] == '\\')
- #else
- if (n > 3 && Path.IsPathDelimiter(n))
- #endif
- Path.SetLength(n - 1);
-
- if (Path != FDirectory) {
- FDirectory = Path;
- chdir(FDirectory.c_str());
-
- if (!SameLetter(Path[0], Drive))
- Drive = Path[0];
- else {
- WalkTree(Path);
- Change();
- }
- }
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TDirectoryOutline::SetDrive(char NewDrive)
- {
- // the original sample did not throw an exception here.
- // should we do so now?
- NewDrive = static_cast<char>(toupper(NewDrive));
- if ((NewDrive >= 'A' && NewDrive <= 'Z')) {
- if (!SameLetter(NewDrive, FDrive)) {
- FDrive = NewDrive;
- setdisk(DriveToInt(FDrive));
- FDirectory = ForceCase(CurDir());
- if (!ComponentState.Contains(csLoading))
- BuildTree();
- }
- }
- }
-
- //---------------------------------------------------------------------------
- void __fastcall TDirectoryOutline::SetTextCase(TTextCase NewCase)
- {
- if (NewCase != FTextCase) {
- FTextCase = NewCase;
- AssignCaseProc();
-
- if (NewCase == tcAsIs) {
- AnsiString CurrentPath = CurDir();
- FDrive = CurrentPath[0];
- FDirectory = CurrentPath;
- }
-
- if (!ComponentState.Contains(csLoading))
- BuildTree();
- }
- }
- //---------------------------------------------------------------------------
- AnsiString TDirectoryOutline::CurDir()
- {
- const initbuf = 256;
- size_t buflen = initbuf;
- char *buf = reinterpret_cast<char *>(malloc(buflen));
-
- if (buf) {
- buflen = GetCurrentDirectory(buflen, buf);
- if (buflen > initbuf) {
- char *p = reinterpret_cast<char *>(realloc(buf, buflen));
- if (p) {
- buf = p;
- buflen = GetCurrentDirectory(buflen, buf);
- }
- }
- }
-
- try {
- AnsiString Result((buflen && buf) ? buf : "");
- free(buf);
- return Result;
- } catch (...) {
- free(buf);
- throw;
- }
- }
- //---------------------------------------------------------------------------
- long __fastcall TDirectoryOutline::GetChildNamed(const AnsiString& Name,
- long Item)
- {
-
- TOutlineNode* Node = Items[Item];
-
- Node->Expanded = true;
- long rc = Node->getFirstChild();
-
- while (rc != InvalidIndex && Items[rc]->Text != Name)
- rc = Node->GetNextChild(rc);
-
- return rc;
- }
-
- //---------------------------------------------------------------------------
-
- void __fastcall TDirectoryOutline::WalkTree(const AnsiString& Dest)
- {
- AnsiString Path = ForceCase(Dest);
- long Item = RootIndex; // start at root
-
-
- // remove drive component of Path
-
- int Colon = Path.Pos(":"); // do we care about MBCS here?
- if (Colon > 0) {
- int Offset = (Path[Colon] == '\\') ? 2 : 1;
- Path = Path.SubString(Colon + Offset, Path.Length());
- }
-
- // do the walk
- for (int SlashPos = GetPos(Path, "\\"); Path.Length() > 0;
- SlashPos = GetPos(Path, "\\")) {
- AnsiString Dir = Path;
-
- if (SlashPos > 0) {
- // splice out the first directory
- Dir = Path.SubString(1, SlashPos - 1);
- Path = Path.SubString(SlashPos + 1, Path.Length());
- }
- else {
- Dir = Path;
- Path = "";
- }
-
- Item = GetChildNamed(Dir, Item);
- }
-
- SelectedItem = Item;
- }
-
- //---------------------------------------------------------------------------
- namespace Diroutln
- {
- void __fastcall Register()
- {
- TComponentClass classes[1] = {__classid(TDirectoryOutline)};
- RegisterComponents("Samples", classes, 0);
- }
- }
- //---------------------------------------------------------------------------
-