phoenix-firestorm/indra/newview/llfilepicker.cpp

1370 lines
30 KiB
C++

/**
* @file llfilepicker.cpp
* @brief OS-specific file picker
*
* Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
* $License$
*/
#include "llviewerprecompiledheaders.h"
#include "llfilepicker.h"
//#include "viewer.h"
//#include "llviewermessage.h"
#include "llworld.h"
#include "llviewerwindow.h"
#include "llkeyboard.h"
#include "lldir.h"
#include "llframetimer.h"
#if LL_SDL
#include "llwindowsdl.h" // for some X/GTK utils to help with filepickers
#endif // LL_SDL
//
// Globals
//
LLFilePicker LLFilePicker::sInstance;
#if LL_WINDOWS
#define SOUND_FILTER L"Sounds (*.wav)\0*.wav\0"
#define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg)\0*.tga;*.bmp;*.jpg;*.jpeg\0"
#define ANIM_FILTER L"Animations (*.bvh)\0*.bvh\0"
#ifdef _CORY_TESTING
#define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0"
#endif
#define XML_FILTER L"XML files (*.xml)\0*.xml\0"
#define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0"
#define RAW_FILTER L"RAW files (*.raw)\0*.raw\0"
#endif
//
// Implementation
//
#if LL_WINDOWS
LLFilePicker::LLFilePicker()
{
reset();
mOFN.lStructSize = sizeof(OPENFILENAMEW);
mOFN.hwndOwner = NULL; // Set later
mOFN.hInstance = NULL;
mOFN.lpstrCustomFilter = NULL;
mOFN.nMaxCustFilter = 0;
mOFN.lpstrFile = NULL; // set in open and close
mOFN.nMaxFile = LL_MAX_PATH;
mOFN.lpstrFileTitle = NULL;
mOFN.nMaxFileTitle = 0;
mOFN.lpstrInitialDir = NULL;
mOFN.lpstrTitle = NULL;
mOFN.Flags = 0; // set in open and close
mOFN.nFileOffset = 0;
mOFN.nFileExtension = 0;
mOFN.lpstrDefExt = NULL;
mOFN.lCustData = 0L;
mOFN.lpfnHook = NULL;
mOFN.lpTemplateName = NULL;
}
LLFilePicker::~LLFilePicker()
{
// nothing
}
BOOL LLFilePicker::setupFilter(ELoadFilter filter)
{
BOOL res = TRUE;
switch (filter)
{
case FFLOAD_ALL:
mOFN.lpstrFilter = L"All Files (*.*)\0*.*\0" \
SOUND_FILTER \
IMAGE_FILTER \
ANIM_FILTER \
L"\0";
break;
case FFLOAD_WAV:
mOFN.lpstrFilter = SOUND_FILTER \
L"\0";
break;
case FFLOAD_IMAGE:
mOFN.lpstrFilter = IMAGE_FILTER \
L"\0";
break;
case FFLOAD_ANIM:
mOFN.lpstrFilter = ANIM_FILTER \
L"\0";
break;
#ifdef _CORY_TESTING
case FFLOAD_GEOMETRY:
mOFN.lpstrFilter = GEOMETRY_FILTER \
L"\0";
break;
#endif
case FFLOAD_XML:
mOFN.lpstrFilter = XML_FILTER \
L"\0";
break;
case FFLOAD_SLOBJECT:
mOFN.lpstrFilter = SLOBJECT_FILTER \
L"\0";
break;
case FFLOAD_RAW:
mOFN.lpstrFilter = RAW_FILTER \
L"\0";
break;
default:
res = FALSE;
break;
}
return res;
}
BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
{
if( mLocked )
{
return FALSE;
}
BOOL success = FALSE;
mMultiFile = FALSE;
// don't provide default file selection
mFilesW[0] = '\0';
mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow();
mOFN.lpstrFile = mFilesW;
mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE;
mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR ;
mOFN.nFilterIndex = 1;
setupFilter(filter);
// Modal, so pause agent
send_agent_pause();
// NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!!
success = GetOpenFileName(&mOFN);
if (success)
{
LLString tstr = utf16str_to_utf8str(llutf16string(mFilesW));
memcpy(mFiles, tstr.c_str(), tstr.size()+1); /*Flawfinder: ignore*/
mCurrentFile = mFiles;
}
send_agent_resume();
// Account for the fact that the app has been stalled.
LLFrameTimer::updateFrameTime();
return success;
}
BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter)
{
if( mLocked )
{
return FALSE;
}
BOOL success = FALSE;
mMultiFile = FALSE;
// don't provide default file selection
mFilesW[0] = '\0';
mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow();
mOFN.lpstrFile = mFilesW;
mOFN.nFilterIndex = 1;
mOFN.nMaxFile = FILENAME_BUFFER_SIZE;
mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR |
OFN_EXPLORER | OFN_ALLOWMULTISELECT;
setupFilter(filter);
// Modal, so pause agent
send_agent_pause();
// NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!!
success = GetOpenFileName(&mOFN); // pauses until ok or cancel.
if( success )
{
// The getopenfilename api doesn't tell us if we got more than
// one file, so we have to test manually by checking string
// lengths.
if( wcslen(mOFN.lpstrFile) > mOFN.nFileOffset ) /*Flawfinder: ignore*/
{
mMultiFile = FALSE;
mCurrentFile = mFiles;
LLString tstr = utf16str_to_utf8str(llutf16string(mFilesW));
memcpy(mFiles, tstr.c_str(), tstr.size()+1); /*Flawfinder: ignore*/
}
else
{
mMultiFile = TRUE;
mCurrentFile = 0;
mLocked = TRUE;
WCHAR* tptrw = mFilesW;
char* tptr = mFiles;
memset( mFiles, 0, FILENAME_BUFFER_SIZE );
while(1)
{
if (*tptrw == 0 && *(tptrw+1) == 0) // double '\0'
break;
if (*tptrw == 0 && !mCurrentFile)
mCurrentFile = tptr+1;
S32 tlen16,tlen8;
tlen16 = utf16chars_to_utf8chars(tptrw, tptr, &tlen8);
tptrw += tlen16;
tptr += tlen8;
}
}
}
send_agent_resume();
// Account for the fact that the app has been stalled.
LLFrameTimer::updateFrameTime();
return success;
}
BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const char* filename)
{
if( mLocked )
{
return FALSE;
}
BOOL success = FALSE;
mMultiFile = FALSE;
mOFN.lpstrFile = mFilesW;
if (filename)
{
llutf16string tstring = utf8str_to_utf16str(filename);
wcsncpy(mFilesW, tstring.c_str(), FILENAME_BUFFER_SIZE); } /*Flawfinder: ignore*/
else
{
mFilesW[0] = '\0';
}
mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow();
switch( filter )
{
case FFSAVE_ALL:
mOFN.lpstrDefExt = NULL;
mOFN.lpstrFilter =
L"All Files (*.*)\0*.*\0" \
L"WAV Sounds (*.wav)\0*.wav\0" \
L"Targa, Bitmap Images (*.tga; *.bmp)\0*.tga;*.bmp\0" \
L"\0";
break;
case FFSAVE_WAV:
if (!filename)
{
wcsncpy( mFilesW,L"untitled.wav", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
}
mOFN.lpstrDefExt = L"wav";
mOFN.lpstrFilter =
L"WAV Sounds (*.wav)\0*.wav\0" \
L"\0";
break;
case FFSAVE_TGA:
if (!filename)
{
wcsncpy( mFilesW,L"untitled.tga", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
}
mOFN.lpstrDefExt = L"tga";
mOFN.lpstrFilter =
L"Targa Images (*.tga)\0*.tga\0" \
L"\0";
break;
case FFSAVE_BMP:
if (!filename)
{
wcsncpy( mFilesW,L"untitled.bmp", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
}
mOFN.lpstrDefExt = L"bmp";
mOFN.lpstrFilter =
L"Bitmap Images (*.bmp)\0*.bmp\0" \
L"\0";
break;
case FFSAVE_AVI:
if (!filename)
{
wcsncpy( mFilesW,L"untitled.avi", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
}
mOFN.lpstrDefExt = L"avi";
mOFN.lpstrFilter =
L"AVI Movie File (*.avi)\0*.avi\0" \
L"\0";
break;
case FFSAVE_ANIM:
if (!filename)
{
wcsncpy( mFilesW,L"untitled.xaf", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
}
mOFN.lpstrDefExt = L"xaf";
mOFN.lpstrFilter =
L"XAF Anim File (*.xaf)\0*.xaf\0" \
L"\0";
break;
#ifdef _CORY_TESTING
case FFSAVE_GEOMETRY:
if (!filename)
{
wcsncpy( mFilesW,L"untitled.slg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
}
mOFN.lpstrDefExt = L"slg";
mOFN.lpstrFilter =
L"SLG SL Geometry File (*.slg)\0*.slg\0" \
L"\0";
break;
#endif
case FFSAVE_XML:
if (!filename)
{
wcsncpy( mFilesW,L"untitled.xml", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
}
mOFN.lpstrDefExt = L"xml";
mOFN.lpstrFilter =
L"XML File (*.xml)\0*.xml\0" \
L"\0";
break;
case FFSAVE_COLLADA:
if (!filename)
{
wcsncpy( mFilesW,L"untitled.collada", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
}
mOFN.lpstrDefExt = L"collada";
mOFN.lpstrFilter =
L"COLLADA File (*.collada)\0*.collada\0" \
L"\0";
break;
case FFSAVE_RAW:
if (!filename)
{
wcsncpy( mFilesW,L"untitled.raw", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
}
mOFN.lpstrDefExt = L"raw";
mOFN.lpstrFilter = RAW_FILTER \
L"\0";
break;
case FFSAVE_J2C:
if (!filename)
{
wcsncpy( mFilesW,L"untitled.j2c", FILENAME_BUFFER_SIZE);
}
mOFN.lpstrDefExt = L"j2c";
mOFN.lpstrFilter =
L"Compressed Images (*.j2c)\0*.j2c\0" \
L"\0";
break;
default:
return FALSE;
}
mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE;
mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
// Modal, so pause agent
send_agent_pause();
{
// NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!!
success = GetSaveFileName(&mOFN);
if (success)
{
LLString tstr = utf16str_to_utf8str(llutf16string(mFilesW));
memcpy(mFiles, tstr.c_str(), tstr.size()+1); /*Flawfinder: ignore*/
mCurrentFile = mFiles;
}
gKeyboard->resetKeys();
}
send_agent_resume();
// Account for the fact that the app has been stalled.
LLFrameTimer::updateFrameTime();
return success;
}
const char* LLFilePicker::getFirstFile()
{
if(mMultiFile)
{
buildFilename();
return mFilename;
}
return mFiles;
}
const char* LLFilePicker::getNextFile()
{
if(mMultiFile)
{
mCurrentFile += strlen(mCurrentFile) + 1; /*Flawfinder: ignore*/
if( '\0' != mCurrentFile[0] )
{
buildFilename();
return mFilename;
}
else
{
mLocked = FALSE;
}
}
return NULL;
}
const char* LLFilePicker::getDirname()
{
if( '\0' != mCurrentFile[0] )
{
return mCurrentFile;
}
return NULL;
}
void LLFilePicker::reset()
{
mLocked = FALSE;
memset( mFiles, 0, FILENAME_BUFFER_SIZE );
memset( mFilename, 0, LL_MAX_PATH );
mCurrentFile = mFiles;
}
void LLFilePicker::buildFilename( void )
{
strncpy( mFilename, mFiles, LL_MAX_PATH );
mFilename[LL_MAX_PATH-1] = '\0'; // stupid strncpy
S32 len = strlen( mFilename );
strncat(mFilename,gDirUtilp->getDirDelimiter().c_str(), sizeof(mFilename)-len+1); /*Flawfinder: ignore*/
len += strlen(gDirUtilp->getDirDelimiter().c_str()); /*Flawfinder: ignore*/
// mFilename[len++] = '\\';
LLString::copy( mFilename + len, mCurrentFile, LL_MAX_PATH - len );
}
#elif LL_DARWIN
LLFilePicker::LLFilePicker()
{
reset();
memset(&mNavOptions, 0, sizeof(mNavOptions));
OSStatus error = NavGetDefaultDialogCreationOptions(&mNavOptions);
if (error == noErr)
{
mNavOptions.modality = kWindowModalityAppModal;
}
mFileIndex = 0;
}
LLFilePicker::~LLFilePicker()
{
// nothing
}
Boolean LLFilePicker::navOpenFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode)
{
Boolean result = true;
ELoadFilter filter = *((ELoadFilter*) callBackUD);
OSStatus error = noErr;
if (filterMode == kNavFilteringBrowserList && filter != FFLOAD_ALL && (theItem->descriptorType == typeFSRef || theItem->descriptorType == typeFSS))
{
// navInfo is only valid for typeFSRef and typeFSS
NavFileOrFolderInfo *navInfo = (NavFileOrFolderInfo*) info;
if (!navInfo->isFolder)
{
AEDesc desc;
error = AECoerceDesc(theItem, typeFSRef, &desc);
if (error == noErr)
{
FSRef fileRef;
error = AEGetDescData(&desc, &fileRef, sizeof(fileRef));
if (error == noErr)
{
LSItemInfoRecord fileInfo;
error = LSCopyItemInfoForRef(&fileRef, kLSRequestExtension | kLSRequestTypeCreator, &fileInfo);
if (error == noErr)
{
if (filter == FFLOAD_IMAGE)
{
if (fileInfo.filetype != 'JPEG' && fileInfo.filetype != 'JPG ' &&
fileInfo.filetype != 'BMP ' && fileInfo.filetype != 'TGA ' &&
fileInfo.filetype != 'BMPf' && fileInfo.filetype != 'TPIC' &&
(fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("jpeg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
CFStringCompare(fileInfo.extension, CFSTR("jpg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
CFStringCompare(fileInfo.extension, CFSTR("bmp"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
CFStringCompare(fileInfo.extension, CFSTR("tga"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
)
{
result = false;
}
}
else if (filter == FFLOAD_WAV)
{
if (fileInfo.filetype != 'WAVE' && fileInfo.filetype != 'WAV ' &&
(fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("wave"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
CFStringCompare(fileInfo.extension, CFSTR("wav"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
)
{
result = false;
}
}
else if (filter == FFLOAD_ANIM)
{
if (fileInfo.filetype != 'BVH ' &&
(fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("bvh"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
)
{
result = false;
}
}
#ifdef _CORY_TESTING
else if (filter == FFLOAD_GEOMETRY)
{
if (fileInfo.filetype != 'SLG ' &&
(fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("slg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
)
{
result = false;
}
}
#endif
else if (filter == FFLOAD_SLOBJECT)
{
llwarns << "*** navOpenFilterProc: FFLOAD_SLOBJECT NOT IMPLEMENTED ***" << llendl;
}
else if (filter == FFLOAD_RAW)
{
if (fileInfo.filetype != '\?\?\?\?' &&
(fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("raw"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
)
{
result = false;
}
}
if (fileInfo.extension)
{
CFRelease(fileInfo.extension);
}
}
}
AEDisposeDesc(&desc);
}
}
}
return result;
}
OSStatus LLFilePicker::doNavChooseDialog(ELoadFilter filter)
{
OSStatus error = noErr;
NavDialogRef navRef = NULL;
NavReplyRecord navReply;
memset(&navReply, 0, sizeof(navReply));
mFiles[0] = '\0';
mFileVector.clear();
// NOTE: we are passing the address of a local variable here.
// This is fine, because the object this call creates will exist for less than the lifetime of this function.
// (It is destroyed by NavDialogDispose() below.)
error = NavCreateChooseFileDialog(&mNavOptions, NULL, NULL, NULL, navOpenFilterProc, (void*)(&filter), &navRef);
gViewerWindow->mWindow->beforeDialog();
if (error == noErr)
error = NavDialogRun(navRef);
gViewerWindow->mWindow->afterDialog();
if (error == noErr)
error = NavDialogGetReply(navRef, &navReply);
if (navRef)
NavDialogDispose(navRef);
if (error == noErr && navReply.validRecord)
{
SInt32 count = 0;
SInt32 index;
// AE indexes are 1 based...
error = AECountItems(&navReply.selection, &count);
for (index = 1; index <= count; index++)
{
FSRef fsRef;
AEKeyword theAEKeyword;
DescType typeCode;
Size actualSize = 0;
char path[MAX_PATH]; /*Flawfinder: ignore*/
memset(&fsRef, 0, sizeof(fsRef));
error = AEGetNthPtr(&navReply.selection, index, typeFSRef, &theAEKeyword, &typeCode, &fsRef, sizeof(fsRef), &actualSize);
if (error == noErr)
error = FSRefMakePath(&fsRef, (UInt8*) path, sizeof(path));
if (error == noErr)
mFileVector.push_back(LLString(path));
}
}
return error;
}
OSStatus LLFilePicker::doNavSaveDialog(ESaveFilter filter, const char* filename)
{
OSStatus error = noErr;
NavDialogRef navRef = NULL;
NavReplyRecord navReply;
memset(&navReply, 0, sizeof(navReply));
mFiles[0] = '\0';
mFileVector.clear();
// Setup the type, creator, and extension
OSType type, creator;
CFStringRef extension = NULL;
switch (filter)
{
case FFSAVE_WAV:
type = 'WAVE';
creator = 'TVOD';
extension = CFSTR(".wav");
break;
case FFSAVE_TGA:
type = 'TPIC';
creator = 'prvw';
extension = CFSTR(".tga");
break;
case FFSAVE_BMP:
type = 'BMPf';
creator = 'prvw';
extension = CFSTR(".bmp");
break;
case FFSAVE_AVI:
type = '\?\?\?\?';
creator = '\?\?\?\?';
extension = CFSTR(".mov");
break;
case FFSAVE_ANIM:
type = '\?\?\?\?';
creator = '\?\?\?\?';
extension = CFSTR(".xaf");
break;
#ifdef _CORY_TESTING
case FFSAVE_GEOMETRY:
type = '\?\?\?\?';
creator = '\?\?\?\?';
extension = CFSTR(".slg");
break;
#endif
case FFSAVE_RAW:
type = '\?\?\?\?';
creator = '\?\?\?\?';
extension = CFSTR(".raw");
break;
case FFSAVE_J2C:
type = '\?\?\?\?';
creator = 'prvw';
extension = CFSTR(".j2c");
break;
case FFSAVE_ALL:
default:
type = '\?\?\?\?';
creator = '\?\?\?\?';
extension = CFSTR("");
break;
}
// Create the dialog
error = NavCreatePutFileDialog(&mNavOptions, type, creator, NULL, NULL, &navRef);
if (error == noErr)
{
CFStringRef nameString = NULL;
bool hasExtension = true;
// Create a CFString of the initial file name
if (filename)
nameString = CFStringCreateWithCString(NULL, filename, kCFStringEncodingUTF8);
else
nameString = CFSTR("Untitled");
// Add the extension if one was not provided
if (nameString && !CFStringHasSuffix(nameString, extension))
{
CFStringRef tempString = nameString;
hasExtension = false;
nameString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), tempString, extension);
CFRelease(tempString);
}
// Set the name in the dialog
if (nameString)
{
error = NavDialogSetSaveFileName(navRef, nameString);
CFRelease(nameString);
}
else
{
error = paramErr;
}
}
gViewerWindow->mWindow->beforeDialog();
// Run the dialog
if (error == noErr)
error = NavDialogRun(navRef);
gViewerWindow->mWindow->afterDialog();
if (error == noErr)
error = NavDialogGetReply(navRef, &navReply);
if (navRef)
NavDialogDispose(navRef);
if (error == noErr && navReply.validRecord)
{
SInt32 count = 0;
// AE indexes are 1 based...
error = AECountItems(&navReply.selection, &count);
if (count > 0)
{
// Get the FSRef to the containing folder
FSRef fsRef;
AEKeyword theAEKeyword;
DescType typeCode;
Size actualSize = 0;
memset(&fsRef, 0, sizeof(fsRef));
error = AEGetNthPtr(&navReply.selection, 1, typeFSRef, &theAEKeyword, &typeCode, &fsRef, sizeof(fsRef), &actualSize);
if (error == noErr)
{
char path[PATH_MAX]; /*Flawfinder: ignore*/
char newFileName[SINGLE_FILENAME_BUFFER_SIZE]; /*Flawfinder: ignore*/
error = FSRefMakePath(&fsRef, (UInt8*)path, PATH_MAX);
if (error == noErr)
{
if (CFStringGetCString(navReply.saveFileName, newFileName, sizeof(newFileName), kCFStringEncodingUTF8))
{
mFileVector.push_back(LLString(path) + LLString("/") + LLString(newFileName));
}
else
{
error = paramErr;
}
}
else
{
error = paramErr;
}
}
}
}
return error;
}
BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
{
if( mLocked ) return FALSE;
mMultiFile = FALSE;
BOOL success = FALSE;
OSStatus error = noErr;
mFileVector.clear();
mNavOptions.optionFlags &= ~kNavAllowMultipleFiles;
// Modal, so pause agent
send_agent_pause();
{
error = doNavChooseDialog(filter);
}
send_agent_resume();
if (error == noErr)
{
if (mFileVector.size())
success = true;
}
// Account for the fact that the app has been stalled.
LLFrameTimer::updateFrameTime();
return success;
}
BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter)
{
if( mLocked ) return FALSE;
mMultiFile = TRUE;
BOOL success = FALSE;
OSStatus error = noErr;
mFileVector.clear();
mNavOptions.optionFlags |= kNavAllowMultipleFiles;
// Modal, so pause agent
send_agent_pause();
{
error = doNavChooseDialog(filter);
}
send_agent_resume();
if (error == noErr)
{
if (mFileVector.size())
success = true;
if (mFileVector.size() > 1)
mLocked = TRUE;
}
// Account for the fact that the app has been stalled.
LLFrameTimer::updateFrameTime();
return success;
}
void LLFilePicker::getFilePath(SInt32 index)
{
mFiles[0] = 0;
if (mFileVector.size())
{
strncpy(mFiles, mFileVector[index].c_str(), sizeof(mFiles));
mFiles[sizeof(mFiles)-1] = '\0'; // stupid strncpy
}
}
void LLFilePicker::getFileName(SInt32 index)
{
mFilename[0] = 0;
if (mFileVector.size())
{
char *start = strrchr(mFileVector[index].c_str(), '/');
if (start && ((start + 1 - mFileVector[index].c_str()) < (mFileVector[index].size())))
{
strncpy(mFilename, start + 1, sizeof(mFilename));
mFilename[sizeof(mFilename)-1] = '\0';// stupid strncpy
}
}
}
BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const char* filename)
{
if( mLocked ) return FALSE;
BOOL success = FALSE;
OSStatus error = noErr;
mFileVector.clear();
mMultiFile = FALSE;
mNavOptions.optionFlags &= ~kNavAllowMultipleFiles;
// Modal, so pause agent
send_agent_pause();
{
error = doNavSaveDialog(filter, filename);
}
send_agent_resume();
if (error == noErr)
{
if (mFileVector.size())
success = true;
}
// Account for the fact that the app has been stalled.
LLFrameTimer::updateFrameTime();
return success;
}
const char* LLFilePicker::getFirstFile()
{
mFileIndex = 0;
getFilePath(mFileIndex);
return mFiles;
}
const char* LLFilePicker::getNextFile()
{
if(mMultiFile)
{
mFileIndex++;
if (mFileIndex < mFileVector.size())
{
getFilePath(mFileIndex);
return mFiles;
}
else
{
mLocked = FALSE;
}
}
return NULL;
}
const char* LLFilePicker::getDirname()
{
if (mFileIndex < mFileVector.size())
{
getFileName(mFileIndex);
return mFilename;
}
return NULL;
}
void LLFilePicker::reset()
{
mLocked = FALSE;
memset( mFiles, 0, FILENAME_BUFFER_SIZE );
memset( mFilename, 0, LL_MAX_PATH );
mCurrentFile = mFiles;
mFileIndex = 0;
mFileVector.clear();
}
#elif LL_LINUX
# if LL_GTK
LLFilePicker::LLFilePicker()
{
reset();
}
LLFilePicker::~LLFilePicker()
{
}
static void store_filenames(GtkWidget *widget, gpointer user_data) {
StoreFilenamesStruct *sfs = (StoreFilenamesStruct*) user_data;
GtkWidget *win = sfs->win;
llinfos <<"store_filesnames: marker A" << llendl;
// get NULL-terminated list of strings allocated for us by GTK
gchar** string_list =
gtk_file_selection_get_selections(GTK_FILE_SELECTION(win));
llinfos <<"store_filesnames: marker B" << llendl;
int idx = 0;
while (string_list[idx])
{
// platform-string to utf8
gchar* filename_utf8 = g_filename_from_utf8(string_list[idx],
-1, NULL,
NULL,
NULL);
sfs->fileVector.push_back(LLString(filename_utf8));
++idx;
}
llinfos <<"store_filesnames: marker C" << llendl;
g_strfreev(string_list);
llinfos <<"store_filesnames: marker D" << llendl;
llinfos << sfs->fileVector.size() << " filename(s) selected:" << llendl;
U32 x;
for (x=0; x<sfs->fileVector.size(); ++x)
llinfos << x << ":" << sfs->fileVector[x] << llendl;
}
GtkWindow* LLFilePicker::buildFilePicker(void)
{
if (ll_try_gtk_init() &&
! gViewerWindow->getWindow()->getFullscreen())
{
GtkWidget *win = NULL;
win = gtk_file_selection_new(NULL);
mStoreFilenames.win = win;
# if LL_X11
// Make GTK tell the window manager to associate this
// dialog with our non-GTK raw X11 window, which should try
// to keep it on top etc.
Window XWindowID = get_SDL_XWindowID();
if (None != XWindowID)
{
gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin
GdkWindow *gdkwin = gdk_window_foreign_new(XWindowID);
gdk_window_set_transient_for(GTK_WIDGET(win)->window,
gdkwin);
}
else
{
llwarns << "Hmm, couldn't get xwid to use for transient." << llendl;
}
# endif //LL_X11
g_signal_connect (G_OBJECT(win), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
// on 'ok', grab the file selection list
g_signal_connect (GTK_FILE_SELECTION(win)->ok_button,
"clicked",
G_CALLBACK(store_filenames),
&mStoreFilenames);
// both 'ok' and 'cancel' will end the dialog
g_signal_connect_swapped (G_OBJECT(GTK_FILE_SELECTION(win)->
ok_button),
"clicked",
G_CALLBACK(gtk_widget_destroy),
G_OBJECT(win));
g_signal_connect_swapped (G_OBJECT(GTK_FILE_SELECTION(win)->
cancel_button),
"clicked",
G_CALLBACK(gtk_widget_destroy),
G_OBJECT(win));
gtk_file_selection_show_fileop_buttons(GTK_FILE_SELECTION(win));
gtk_file_selection_set_select_multiple(GTK_FILE_SELECTION(win),
FALSE);
gtk_window_set_modal(GTK_WINDOW(win), TRUE);
return GTK_WINDOW(win);
}
else
{
return NULL;
}
}
BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const char* filename )
{
BOOL rtn = FALSE;
gViewerWindow->mWindow->beforeDialog();
reset();
GtkWindow* picker = buildFilePicker();
if (picker)
{
std::string suggest_name = "untitled";
std::string suggest_ext = "";
std::string caption = "Save ";
switch (filter)
{
case FFSAVE_WAV:
caption += "Sounds (*.wav)";
suggest_ext += ".wav";
break;
case FFSAVE_TGA:
caption += "Targa Images (*.tga)";
suggest_ext += ".tga";
break;
case FFSAVE_BMP:
caption += "Bitmap Images (*.bmp)";
suggest_ext += ".bmp";
break;
case FFSAVE_AVI:
caption += "AVI Movie File (*.avi)";
suggest_ext += ".avi";
break;
case FFSAVE_ANIM:
caption += "XAF Anim File (*.xaf)";
suggest_ext += ".xaf";
break;
case FFSAVE_XML:
caption += "XML File (*.xml)";
suggest_ext += ".xml";
break;
case FFSAVE_RAW:
caption += "RAW File (*.raw)";
suggest_ext += ".raw";
break;
case FFSAVE_J2C:
caption += "Compressed Images (*.j2c)";
suggest_ext += ".j2c";
break;
default:;
break;
}
gtk_window_set_title(GTK_WINDOW(picker), caption.c_str());
if (!filename)
{
suggest_name += suggest_ext;
gtk_file_selection_set_filename
(GTK_FILE_SELECTION(picker),
g_filename_from_utf8(suggest_name.c_str(),
-1, NULL,
NULL,
NULL));
gtk_editable_select_region(GTK_EDITABLE(GTK_FILE_SELECTION(picker)->selection_entry), 0, suggest_name.length() - suggest_ext.length() );
}
else
{
gtk_file_selection_set_filename
(GTK_FILE_SELECTION(picker),
g_filename_from_utf8(filename,
-1, NULL,
NULL,
NULL));
gtk_editable_select_region(GTK_EDITABLE(GTK_FILE_SELECTION(picker)->selection_entry), 0, -1 );
}
gtk_widget_show_all(GTK_WIDGET(picker));
gtk_main();
rtn = (mStoreFilenames.fileVector.size() == 1);
}
gViewerWindow->mWindow->afterDialog();
return rtn;
}
BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
{
BOOL rtn = FALSE;
gViewerWindow->mWindow->beforeDialog();
reset();
GtkWindow* picker = buildFilePicker();
if (picker)
{
std::string caption = "Load ";
switch (filter)
{
case FFLOAD_WAV:
caption += "Sounds (*.wav)"; break;
case FFLOAD_ANIM:
caption += "Animations (*.bvh)"; break;
case FFLOAD_IMAGE:
caption += "Images (*.tga; *.bmp; *.jpg; *.jpeg)"; break;
default:;
break;
}
gtk_window_set_title(GTK_WINDOW(picker), caption.c_str());
gtk_widget_show_all(GTK_WIDGET(picker));
gtk_main();
rtn = (mStoreFilenames.fileVector.size() == 1);
}
gViewerWindow->mWindow->afterDialog();
return rtn;
}
BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
{
BOOL rtn = FALSE;
gViewerWindow->mWindow->beforeDialog();
reset();
GtkWindow* picker = buildFilePicker();
if (picker)
{
gtk_file_selection_set_select_multiple(GTK_FILE_SELECTION(picker),
TRUE);
gtk_window_set_title(GTK_WINDOW(picker), "Load Files");
gtk_widget_show_all(GTK_WIDGET(picker));
gtk_main();
rtn = !mStoreFilenames.fileVector.empty();
}
gViewerWindow->mWindow->afterDialog();
return rtn;
}
const char* LLFilePicker::getFirstFile()
{
mNextFileIndex = 0;
return getNextFile();
}
const char* LLFilePicker::getNextFile()
{
if (mStoreFilenames.fileVector.size() > mNextFileIndex)
return mStoreFilenames.fileVector[mNextFileIndex++].c_str();
else
return NULL;
}
const char* LLFilePicker::getDirname()
{
// getDirname is badly named... it really means getBasename.
S32 index = mNextFileIndex - 1; // want index before the 'next' cursor
if (index >= 0 && index < (S32)mStoreFilenames.fileVector.size())
{
// we do this using C strings so we don't have to
// convert a LLString/std::string character offset into a
// byte-offset for the return (which is a C string anyway).
const char* dirsep = gDirUtilp->getDirDelimiter().c_str();
const char* fullpath = mStoreFilenames.fileVector[index].c_str();
const char* finalpart = NULL;
const char* thispart = fullpath;
// walk through the string looking for the final dirsep, i.e. /
do
{
thispart = strstr(thispart, dirsep);
if (NULL != thispart)
finalpart = thispart = &thispart[1];
}
while (NULL != thispart);
return finalpart;
}
else
return NULL;
}
void LLFilePicker::reset()
{
llinfos << "GTK LLFilePicker::reset()" << llendl;
mNextFileIndex = 0;
mStoreFilenames.win = NULL;
mStoreFilenames.fileVector.clear();
}
# else // LL_GTK
// Hacky stubs designed to facilitate fake getSaveFile and getOpenFile with
// static results, when we don't have a real filepicker.
static LLString hackyfilename;
LLFilePicker::LLFilePicker()
{
reset();
}
LLFilePicker::~LLFilePicker()
{
}
BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const char* filename )
{
llinfos << "getSaveFile suggested filename is [" << filename
<< "]" << llendl;
if (filename && filename[0])
{
hackyfilename.assign(gDirUtilp->getLindenUserDir());
hackyfilename += gDirUtilp->getDirDelimiter();
hackyfilename += filename;
return TRUE;
}
hackyfilename.clear();
return FALSE;
}
BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
{
// HACK: Static filenames for 'open' until we implement filepicker
hackyfilename.assign(gDirUtilp->getLindenUserDir());
hackyfilename += gDirUtilp->getDirDelimiter();
hackyfilename += "upload";
switch (filter)
{
case FFLOAD_WAV: hackyfilename += ".wav"; break;
case FFLOAD_IMAGE: hackyfilename += ".tga"; break;
case FFLOAD_ANIM: hackyfilename += ".bvh"; break;
default: break;
}
llinfos << "getOpenFile: Will try to open file: " << hackyfilename
<< llendl;
return TRUE;
}
BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
{
hackyfilename.clear();
return FALSE;
}
const char* LLFilePicker::getFirstFile()
{
if (!hackyfilename.empty())
{
return hackyfilename.c_str();
}
return NULL;
}
const char* LLFilePicker::getNextFile()
{
hackyfilename.clear();
return NULL;
}
const char* LLFilePicker::getDirname()
{
return NULL;
}
void LLFilePicker::reset()
{
}
#endif // LL_GTK
#else // not implemented
LLFilePicker::LLFilePicker()
{
reset();
}
LLFilePicker::~LLFilePicker()
{
}
BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const char* filename )
{
return FALSE;
}
BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
{
return FALSE;
}
BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
{
return FALSE;
}
const char* LLFilePicker::getFirstFile()
{
return NULL;
}
const char* LLFilePicker::getNextFile()
{
return NULL;
}
const char* LLFilePicker::getDirname()
{
return NULL;
}
void LLFilePicker::reset()
{
}
#endif