tge/engine/gui/controls/guiDirectoryTreeCtrl.cc
2017-04-17 06:17:10 -06:00

382 lines
11 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "gui/controls/guiDirectoryTreeCtrl.h"
IMPLEMENT_CONOBJECT(GuiDirectoryTreeCtrl);
GuiDirectoryTreeCtrl::GuiDirectoryTreeCtrl(): GuiTreeViewCtrl()
{
// Parent configuration
mBounds.set( 0,0,200,100 );
mDestroyOnSleep = false;
mSupportMouseDragging = false;
mMultipleSelections = false;
mSelPath = StringTable->insert("");
}
bool GuiDirectoryTreeCtrl::onAdd()
{
if( !Parent::onAdd() )
return false;
// Specify our icons
buildIconTable( NULL );
return true;
}
bool GuiDirectoryTreeCtrl::onWake()
{
if( !Parent::onWake() )
return false;
// Kill off any existing items
destroyTree();
// Here we're going to grab our system volumes from the platform layer and create them as roots
//
// Note : that we're passing a 1 as the last parameter to Platform::dumpDirectories, which tells it
// how deep to dump in recursion. This is an optimization to keep from dumping the whole file system
// to the tree. The tree will dump more paths as necessary when the virtual parents are expanded,
// much as windows does.
ResourceManager->initExcludedDirectories();
StringTableEntry RootPath = ResourceManager->getModPaths();
//getUnit(argv[1], dAtoi(argv[2]), " \t\n");
S32 modCount = getUnitCount( RootPath, ";" );
for( S32 i = 0; i < modCount; i++ )
{
// Compose full mod path location, and dump the path to our vector
StringTableEntry currentMod = getUnit( RootPath, i, ";" );
char fullModPath [512];
dMemset( fullModPath, 0, 512 );
dSprintf( fullModPath, 512, "%s/%s/", Platform::getWorkingDirectory(), currentMod );
Vector<StringTableEntry> pathVec;
Platform::dumpDirectories( fullModPath, pathVec, 0, true);
if( ! pathVec.empty() )
{
// Iterate through the returned paths and add them to the tree
Vector<StringTableEntry>::iterator j = pathVec.begin();
for( ; j != pathVec.end(); j++ )
{
char fullModPathSub [512];
dMemset( fullModPathSub, 0, 512 );
dSprintf( fullModPathSub, 512, "%s/%s", currentMod, (*j) );
addPathToTree( fullModPathSub );
}
}
else
addPathToTree( fullModPath );
}
// Success!
return true;
}
bool GuiDirectoryTreeCtrl::onVirtualParentExpand(Item *item)
{
if( !item || !item->isExpanded() )
return true;
StringTableEntry pathToExpand = item->getValue();
if( !pathToExpand )
{
Con::errorf("GuiDirectoryTreeCtrl::onVirtualParentExpand - Unable to retrieve item value!");
return false;
}
Vector<StringTableEntry> pathVec;
Platform::dumpDirectories( pathToExpand, pathVec, 0, true );
if( ! pathVec.empty() )
{
// Iterate through the returned paths and add them to the tree
Vector<StringTableEntry>::iterator i = pathVec.begin();
for( ; i != pathVec.end(); i++ )
recurseInsert(item, (*i) );
item->setExpanded( true );
}
item->setVirtualParent( false );
// Update our tree view
buildVisibleTree();
return true;
}
bool GuiDirectoryTreeCtrl::buildIconTable(const char * icons)
{
// Icons should be designated by the bitmap/png file names (minus the file extensions)
// and separated by colons (:).
if (!icons)
icons = StringTable->insert("common/ui/folder:common/ui/folder:common/ui/folder_closed");
return Parent::buildIconTable( icons );
}
void GuiDirectoryTreeCtrl::addPathToTree( StringTableEntry path )
{
if( !path )
{
Con::errorf("GuiDirectoryTreeCtrl::addPathToTree - Invalid Path!");
return;
}
// Identify which root (volume) this path belongs to (if any)
S32 root = getFirstRootItem();
StringTableEntry ourPath = &path[ dStrcspn( path, "//" ) + 1];
StringTableEntry ourRoot = getUnit( path, 0, "//" );
// There are no current roots, we can safely create one
if( root == 0 )
{
recurseInsert( NULL, path );
}
else
{
while( root != 0 )
{
if( dStrcmp( getItemValue( root ), ourRoot ) == 0 )
{
recurseInsert( getItem( root ), ourPath );
break;
}
root = this->getNextSiblingItem( root );
}
// We found none so we'll create one
if ( root == 0 )
{
recurseInsert( NULL, path );
}
}
}
void GuiDirectoryTreeCtrl::onItemSelected( Item *item )
{
Con::executef( this, 2, "onSelectPath", avar("%s",item->getValue()) );
mSelPath = StringTable->insert( item->getValue() );
if( Platform::hasSubDirectory( item->getValue() ) )
item->setVirtualParent( true );
}
void GuiDirectoryTreeCtrl::recurseInsert( Item* parent, StringTableEntry path )
{
if( !path )
return;
char szPathCopy [ 1024 ];
dMemset( szPathCopy, 0, 1024 );
dStrcpy( szPathCopy, path );
// Jump over the first character if it's a root /
char *curPos = szPathCopy;
if( *curPos == '/' )
curPos++;
char *delim = dStrchr( curPos, '/' );
if ( delim )
{
// terminate our / and then move our pointer to the next character (rest of the path)
*delim = 0x00;
delim++;
}
S32 itemIndex = 0;
// only insert blindly if we have no root
if( !parent )
{
itemIndex = insertItem( 0, curPos, curPos );
getItem( itemIndex )->setNormalImage( Icon_FolderClosed );
getItem( itemIndex )->setExpandedImage( Icon_Folder );
}
else
{
Item *item = parent;
char *szValue = new char[ 1024 ];
dMemset( szValue, 0, 1024 );
dSprintf( szValue, 1024, "%s/%s", parent->getValue(), curPos );
Item *exists = item->findChildByValue( szValue );
if( !exists && dStrcmp( curPos, "" ) != 0 )
{
// Since we're adding a child this parent can't be a virtual parent, so clear that flag
item->setVirtualParent( false );
itemIndex = insertItem( item->getID(), curPos);
getItem( itemIndex )->setValue( szValue );
getItem( itemIndex )->setNormalImage( Icon_FolderClosed );
getItem( itemIndex )->setExpandedImage( Icon_Folder );
}
else
{
delete []szValue;
itemIndex = ( item != NULL ) ? ( ( exists != NULL ) ? exists->getID() : -1 ) : -1;
}
}
// since we're only dealing with volumes and directories, all end nodes will be virtual parents
// so if we are at the bottom of the rabbit hole, set the item to be a virtual parent
Item* item = getItem( itemIndex );
if( delim )
{
if( ( dStrcmp( delim, "" ) == 0 ) && item )
{
item->setExpanded( false );
if( parent && Platform::hasSubDirectory( item->getValue() ) )
item->setVirtualParent( true );
}
}
else
{
if( item )
{
item->setExpanded( false );
if( parent && Platform::hasSubDirectory( item->getValue() ) )
item->setVirtualParent( true );
}
}
// Down the rabbit hole we go
recurseInsert( getItem( itemIndex ), delim );
}
StringTableEntry GuiDirectoryTreeCtrl::getUnit(const char *string, U32 index, const char *set)
{
U32 sz;
while(index--)
{
if(!*string)
return "";
sz = dStrcspn(string, set);
if (string[sz] == 0)
return "";
string += (sz + 1);
}
sz = dStrcspn(string, set);
if (sz == 0)
return "";
char *ret = Con::getReturnBuffer(sz+1);
dStrncpy(ret, string, sz);
ret[sz] = '\0';
return ret;
}
StringTableEntry GuiDirectoryTreeCtrl::getUnits(const char *string, S32 startIndex, S32 endIndex, const char *set)
{
S32 sz;
S32 index = startIndex;
while(index--)
{
if(!*string)
return "";
sz = dStrcspn(string, set);
if (string[sz] == 0)
return "";
string += (sz + 1);
}
const char *startString = string;
while(startIndex <= endIndex--)
{
sz = dStrcspn(string, set);
string += sz;
if (*string == 0)
break;
string++;
}
if(!*string)
string++;
U32 totalSize = (U32(string - startString));
char *ret = Con::getReturnBuffer(totalSize);
dStrncpy(ret, startString, totalSize - 1);
ret[totalSize-1] = '\0';
return ret;
}
U32 GuiDirectoryTreeCtrl::getUnitCount(const char *string, const char *set)
{
U32 count = 0;
U8 last = 0;
while(*string)
{
last = *string++;
for(U32 i =0; set[i]; i++)
{
if(last == set[i])
{
count++;
last = 0;
break;
}
}
}
if(last)
count++;
return count;
}
ConsoleMethod( GuiDirectoryTreeCtrl, getSelectedPath, const char*, 2,2, "getSelectedPath() - returns the currently selected path in the tree")
{
return object->getSelectedPath();
}
StringTableEntry GuiDirectoryTreeCtrl::getSelectedPath()
{
return mSelPath;
}
ConsoleMethod( GuiDirectoryTreeCtrl, setSelectedPath, bool, 3, 3, "setSelectedPath(path) - expands the tree to the specified path")
{
return object->setSelectedPath( argv[2] );
}
bool GuiDirectoryTreeCtrl::setSelectedPath( StringTableEntry path )
{
if( !path )
return false;
// Since we only list one deep on paths, we need to add the path to the tree just incase it isn't already indexed in the tree
// or else we wouldn't be able to select a path we hadn't previously browsed to. :)
if( Platform::isDirectory( path ) )
addPathToTree( path );
// see if we have a child that matches what we want
for(U32 i = 0; i < mItems.size(); i++)
{
if( dStricmp( mItems[i]->getValue(), path ) == 0 )
{
Item* item = mItems[i];
AssertFatal(item,"GuiDirectoryTreeCtrl::setSelectedPath - Item Index Bad, Fatal Mistake!!!");
item->setExpanded( true );
clearSelection();
setItemSelected( item->getID(), true );
// make sure all of it's parents are expanded
S32 parent = getParentItem( item->getID() );
while( parent != 0 )
{
setItemExpanded( parent, true );
parent = getParentItem( parent );
}
// Rebuild our tree just incase we've oops'd
buildVisibleTree();
scrollVisible( item );
}
}
return false;
}