diff options
author | James Cook <james@lindenlab.com> | 2007-01-02 08:33:20 +0000 |
---|---|---|
committer | James Cook <james@lindenlab.com> | 2007-01-02 08:33:20 +0000 |
commit | 420b91db29485df39fd6e724e782c449158811cb (patch) | |
tree | b471a94563af914d3ed3edd3e856d21cb1b69945 /indra/newview/llfilepicker.cpp |
Print done when done.
Diffstat (limited to 'indra/newview/llfilepicker.cpp')
-rw-r--r-- | indra/newview/llfilepicker.cpp | 1339 |
1 files changed, 1339 insertions, 0 deletions
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp new file mode 100644 index 0000000000..776a2e4dc2 --- /dev/null +++ b/indra/newview/llfilepicker.cpp @@ -0,0 +1,1339 @@ +/** + * @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" + +// +// 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 = llwindow_get_hwnd(gViewerWindow->getWindow()); + 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); + 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 = llwindow_get_hwnd(gViewerWindow->getWindow()); + 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 ) + { + mMultiFile = FALSE; + mCurrentFile = mFiles; + LLString tstr = utf16str_to_utf8str(llutf16string(mFilesW)); + memcpy(mFiles, tstr.c_str(), tstr.size()+1); + } + 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); } + else + { + mFilesW[0] = '\0'; + } + mOFN.hwndOwner = llwindow_get_hwnd(gViewerWindow->getWindow()); + + 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); + } + mOFN.lpstrDefExt = L"wav"; + L"WAV Sounds (*.wav)\0*.wav\0" \ + L"\0"; + break; + case FFSAVE_TGA: + if (!filename) + { + wcsncpy( mFilesW,L"untitled.tga", FILENAME_BUFFER_SIZE); + } + 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); + } + 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); + } + 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); + } + 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); + } + 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); + } + + 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); + } + 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); + } + mOFN.lpstrDefExt = L"raw"; + mOFN.lpstrFilter = RAW_FILTER \ + 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); + 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; + 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 ); + S32 len = strlen( mFilename ); + + strcat(mFilename,gDirUtilp->getDirDelimiter().c_str()); + len += strlen(gDirUtilp->getDirDelimiter().c_str()); + +// 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]; + + 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_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]; + char newFileName[SINGLE_FILENAME_BUFFER_SIZE]; + + 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()) + strcpy(mFiles, mFileVector[index].c_str()); +} + +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()))) + strcpy(mFilename, start + 1); + } +} + +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) +{ + gtk_disable_setlocale(); + if (gtk_init_check(NULL, NULL) && + ! 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_ptr = (Window*) gViewerWindow-> + getWindow()->getPlatformWindow(); + if (XWindowID_ptr && None != *XWindowID_ptr) + { + gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin + GdkWindow *gdkwin = gdk_window_foreign_new(*XWindowID_ptr); + gdk_window_set_transient_for(GTK_WIDGET(win)->window, + gdkwin); + } + else + { + llwarns << "Hmm, couldn't get xwid from LLWindow." << 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; + 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 |