home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1997 May
/
Pcwk0597.iso
/
borland
/
cb
/
setup
/
cbuilder
/
data.z
/
DIROUTLN.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1997-02-28
|
12KB
|
396 lines
//---------------------------------------------------------------------------
// Borland C++Builder
// Copyright (c) 1987, 1997 Borland International Inc. All Rights Reserved.
//---------------------------------------------------------------------------
#pragma hdrstop //This header has some initialized data so we can't use
//pre compiled headers.
#if !defined (REGISTER_ALL_CONTROLS)
#include "diroutln.h"
#else
#include "source\diroutln.h"
#endif
#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();
}
//---------------------------------------------------------------------------
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[1] != '.') {
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[1];
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[1], Drive))
Drive = Path[1];
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[1];
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 + 1] == '\\') ? 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);
}
}
//---------------------------------------------------------------------------