Directory Selector

There is no built-in mechanism in DXL to create a dialog box element for capturing a directory name. This utility function provides you with functionality similar to the fileName perm, except that the selector window allows the user to select a directory rather than a file.

directoryName creates an element inside the specified dialog box for capturing a directory name. This consists of a field for the directory name and a Browse button to invoke a directory selector window. This function can be used in place of fileName whenever you want to capture a directory rather than a file.

Usage:

DBE directoryName(DB box, string label, string initial, bool readOnly)

Example:

#include "directoryName.inc"

DB db
DBE dbe

db = create("Demonstrate Directory Selector")

dbeDirectory = directoryName(db, "c:/Temp", "", false)

realize(db)
show(db)

Source code:

//  Directory Browser Facility

/*
    Directory Browser Facility.
    Adapted from Telelogic Kitchen.

    provides directoryName() which may be used in place of fileName()
    when browsing for a directory rather than a file.

    smartDXL.com
*/

DB     dnParentDialog = null

const string S_DRIVE_IS_EMPTY  = "This drive has no folders."

const string POSSIBLE_DRIVES[] = {"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"}

/************************************
	Field and Browse button that are created on the parent dialog box.
************************************/
DBE dbeBrowse         = null
DBE dbeDirectory      = null

/************************************
	Directory browser dialog
************************************/
DB  dbDirectorySelect = null
DBE dbeDirectoryTree  = null
DBE dbeDriveChoice    = null
DBE lblUserPrompt     = null
DBE dbeSelectOK       = null
DBE dbeSelectCancel   = null

string actualDrives[] = {"", "", "", "", "", "", "", "", "", "", "", "", "",
                         "", "", "", "", "", "", "", "", "", "", "", "", ""}
int numDrives = 0

string selectedDirectory = null

/************************************
	convertToBackSlashes

	Converts a directory path into a form suitable for the tree view DBE.
************************************/
string convertToBackSlashes(string s)
{
    string sRetval = null

    if (!isVoid_(s))
    {
        int i

        for (i = 0; i < length(s); i++)
        {
            sRetval = sRetval ((s[i] == '/') ? '\\' : s[i]) ""
        }
    }

    return sRetval
}

/************************************
	convertToForwardSlashes

	Converts a tree view entry into a valid directory path.
************************************/
string convertToForwardSlashes(string s)
{
    string sRetval = null

    if (!isVoid_(s))
    {
        int i

        for (i = 0; i < length(s); i++)
        {
            sRetval = sRetval ((s[i] == '\\') ? '/' : s[i]) ""
        }
    }

    return sRetval
}

/************************************
	getAvailableDrives

	Determines the list of available drives.
************************************/
int getAvailableDrives()
{
    int    cDrive  = 0
    int    i       = 0
    string sDrive  = ""
    string sErrMsg = ""

    // turn off error reporting
    noError

    // go through all possible drives
    for (i = 0; i < sizeof(POSSIBLE_DRIVES); i++)
    {
        sDrive = POSSIBLE_DRIVES[i] ":\\"

        if (sDrive == "A:\\")
        {
            // add to array
            actualDrives[numDrives++] = sDrive
        }
        else
        {
            Stat stat = create sDrive

            if (stat != null)
            {
                // this check is probably redundant
                if (directory stat)
                {
                    // add to array
                    actualDrives[numDrives] = sDrive

                    if (sDrive == "C:\\")
                    {
	                    cDrive = numDrives
                    }

                    numDrives++
                }

                delete stat
            }
        }
    }

    // turn error reporting back on
    sErrMsg = lastError

    return(cDrive)
}

/************************************
	doExpandDirectory
************************************/
bool doExpandDirectory(DBE db, string sTreeEntry)
{
	int    numSubDirs      = 0
    string s               = ""
    string sDummyEntry     = ""
    string sDirectory      = ""
    string f               = ""
	string sNewTreeEntry   = ""
	string sNewDummyEntry  = ""
	string sDriveIsEmpty   = ""
	string sErrMsg         = ""
	string sFullPath       = ""
	Stat   fStat           = null

    // convert backslashes
    sDirectory = convertToBackSlashes(sTreeEntry)

    sDummyEntry = sTreeEntry "/" dummyItem

    // turn off error reporting
    noError

    // process contents of directory
    for s in directory sDirectory do
    {
        // exclude
        if ( s == "." || s == ".." || isVoid_(s) )
        {
            continue
        }

        // get absolute location
        sFullPath = sDirectory FileSep_ s

        // it is possible to exceed max windows path if you use drive maps
        if (platform == "WIN32" && length(sFullPath) > 255)
        {
            continue
        }

        Stat stat = create sFullPath

        if (stat != null)
        {
            // only relevant for directories
            if (directory stat)
            {
                // count subdirectorys
                numSubDirs = 0

                for f in directory sFullPath do
                {
                    fStat = create sFullPath FileSep_ f

                    if (null fStat || !directory(fStat) || f == "." || f == "..")
                    {
	                    continue
                    }

                    numSubDirs++
                }

                sNewTreeEntry  = sTreeEntry "/" s
                sNewDummyEntry = sNewTreeEntry "/" dummyItem

                // check for dummy entry
                if (exists(db, sDummyEntry))
                {
                    //This entry was only added so that a '+' was displayed against a new directory (i.e. pre-expansion).
                    delete(db, sDummyEntry)
                }

                sDriveIsEmpty = sTreeEntry "/" S_DRIVE_IS_EMPTY

                // check for dummy entry
                if (exists(db, sDriveIsEmpty))
                {
                    delete(db, sDriveIsEmpty)
                }

                // only relevant if entry does not already exist
                if (!exists(db, sNewTreeEntry))
                {
                    // add to tree view
                    insert(db, sNewTreeEntry,  iconFolder, iconFolderOpen)

                    if (numSubDirs > 0)
                    {
	                    insert(db, sNewDummyEntry, iconFolder, iconFolderOpen)
                    }
                }
            }

            delete(stat)
        }
    }

    // turn error reporting back on
    sErrMsg = lastError

    return(true)
}

/************************************
	doSelectDrive
************************************/
void doSelectDrive(DBE db)
{
    string sDrive = get db

    // remove trailing slash
    if (sDrive[length(sDrive) - 1] == '\\')
    {
        sDrive = sDrive[0 : length(sDrive) - 2]
    }

    // clear existing structure
    empty(dbeDirectoryTree)

    // add drive and dummy entry
    insert(dbeDirectoryTree, sDrive, iconFolder, iconFolderOpen)
    insert(dbeDirectoryTree, (sDrive "/" S_DRIVE_IS_EMPTY), iconNone, iconNone)
}

/************************************
	doSelectOK

	Callback for dbeSelectOk
************************************/
void doSelectOK(DB db)
{
    selectedDirectory = convertToBackSlashes(get dbeDirectoryTree)

    // only relevant for root directories
    if (length(selectedDirectory) == 2)
    {
        // add trailing slash
        selectedDirectory = selectedDirectory "\\"
    }

    // update directory field on parent dialog
    set(dbeDirectory, selectedDirectory)	

    release dbDirectorySelect

}

/************************************
	doSelectCancel
************************************/
void doSelectCancel(DB db)
{
    selectedDirectory = null

    release dbDirectorySelect
}

/************************************
	doBrowse
************************************/
void doBrowse(DBE dbe)
{
	int cDriveIdx = 0

	// initialise available drives array and return index to C: drive
    cDriveIdx = getAvailableDrives()

    // Create Directory Browser dialog
    dbDirectorySelect = create(dnParentDialog, "Directory Selector", styleSubWindow)

  	// drop-down of available drives - set to drive C:\ by default
	dbeDriveChoice = choice(dbDirectorySelect, "Drive: ", actualDrives, numDrives, cDriveIdx)

    // directory tree
    dbeDirectoryTree = treeView(dbDirectorySelect, treeViewOptionSorted, 400, 15)

    close(dbDirectorySelect, true, doSelectCancel)
	apply(dbDirectorySelect, "OK", doSelectOK)

    realize dbDirectorySelect

    set(dbeDirectoryTree, doExpandDirectory)
    set(dbeDriveChoice, doSelectDrive)

    // initialise directory tree according to default drive setting
    doSelectDrive(dbeDriveChoice)

	// show the directory browser dialog
	block dbDirectorySelect
	hide dbDirectorySelect
	destroy dbDirectorySelect
}

/************************************
	directoryName
************************************/
DBE directoryName(DB     dbParent,
                  string sLabel,
                  string initDirectory,
                  bool   readOnly)
{
    // use default if parameter is null
    if (dbParent == null)
    {
        dnParentDialog = dbExplorer
    }
    else
    {
	    dnParentDialog = dbParent
	}

	// Create Field and Browse button on parent dialog
    dbeDirectory = field(dbParent, sLabel, initDirectory, 40, readOnly)
    beside(dbParent)
   	dbeBrowse = button(dbParent, "Browse...", doBrowse)
   	left(dbParent)

    // return handle on directory field dbe
    return(dbeDirectory)
}