//  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)
}

sitemap