/** * @file llfilepicker.cpp * @brief OS-specific file picker * * $LicenseInfo:firstyear=2001&license=viewergpl$ * * Copyright (c) 2001-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ #include "linden_common.h" #include "llfilepicker.h" #include "llerror.h" #include "basic_plugin_base.h" // For PLS_INFOS etc. // // Globals // LLFilePicker LLFilePicker::sInstance; #if LL_WINDOWS // #define SOUND_FILTER L"Sounds (*.wav; *.ogg)\0*.wav;*.ogg\0" #define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png; *.jp2; *.j2k; *.j2c)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png;*.jp2;*.j2k;*.j2c\0" #define INVGZ_FILTER L"Inv cache (*.inv; *.inv.gz)\0*.inv;*.inv.gz\0" #define AO_FILTER L"Animation Override (*.ao)\0*.ao\0" #define BLACKLIST_FILTER L"Asset Blacklist (*.blacklist)\0*.blacklist\0" // #define ANIM_FILTER L"Animations (*.bvh; *.anim)\0*.bvh;*.anim\0" #define COLLADA_FILTER L"Scene (*.dae)\0*.dae\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" #define MODEL_FILTER L"Model files (*.dae)\0*.dae\0" #define SCRIPT_FILTER L"Script files (*.lsl)\0*.lsl\0" #define DICTIONARY_FILTER L"Dictionary files (*.dic; *.xcu)\0*.dic;*.xcu\0" #endif // // Implementation // LLFilePickerBase::LLFilePickerBase() : mCurrentFile(0), mLocked(FALSE) { reset(); #if LL_WINDOWS mOFN.lStructSize = sizeof(OPENFILENAMEW); mOFN.hwndOwner = NULL; // Set later with setWindowID 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; #endif #if LL_DARWIN memset(&mNavOptions, 0, sizeof(mNavOptions)); OSStatus error = NavGetDefaultDialogCreationOptions(&mNavOptions); if (error == noErr) { mNavOptions.modality = kWindowModalityAppModal; } #endif } const std::string LLFilePickerBase::getFirstFile() { mCurrentFile = 0; return getNextFile(); } const std::string LLFilePickerBase::getNextFile() { if (mCurrentFile >= getFileCount()) { mLocked = FALSE; return std::string(); } else { return mFiles[mCurrentFile++]; } } const std::string LLFilePickerBase::getCurFile() { if (mCurrentFile >= getFileCount()) { mLocked = FALSE; return std::string(); } else { return mFiles[mCurrentFile]; } } void LLFilePickerBase::reset() { mLocked = FALSE; mFiles.clear(); mCurrentFile = 0; } #if LL_WINDOWS bool LLFilePickerBase::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; case FFLOAD_COLLADA: mOFN.lpstrFilter = COLLADA_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; case FFLOAD_MODEL: mOFN.lpstrFilter = MODEL_FILTER \ L"\0"; break; case FFLOAD_SCRIPT: mOFN.lpstrFilter = SCRIPT_FILTER \ L"\0"; break; case FFLOAD_DICTIONARY: mOFN.lpstrFilter = DICTIONARY_FILTER \ L"\0"; break; // case FFLOAD_INVGZ: mOFN.lpstrFilter = INVGZ_FILTER \ L"\0"; break; case FFLOAD_AO: mOFN.lpstrFilter = AO_FILTER \ L"\0"; break; case FFLOAD_BLACKLIST: mOFN.lpstrFilter = BLACKLIST_FILTER \ L"\0"; break; // default: res = FALSE; break; } return res; } bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) { if( mLocked ) { return FALSE; } bool success = FALSE; llutf16string tstring = utf8str_to_utf16str(folder); mOFN.lpstrInitialDir = (LPCTSTR)tstring.data(); mFilesW[0] = '\0'; mOFN.lpstrFile = mFilesW; mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR ; mOFN.nFilterIndex = 1; setupFilter(filter); reset(); // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! success = GetOpenFileName(&mOFN); if (success) { std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); mFiles.push_back(filename); } return success; } bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string const& folder) { if( mLocked ) { return FALSE; } bool success = FALSE; llutf16string tstring = utf8str_to_utf16str(folder); mOFN.lpstrInitialDir = (LPCTSTR)tstring.data(); mFilesW[0] = '\0'; 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); reset(); // 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*/ { std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); mFiles.push_back(filename); } else { mLocked = TRUE; WCHAR* tptrw = mFilesW; std::string dirname; while(1) { if (*tptrw == 0 && *(tptrw+1) == 0) // double '\0' break; if (*tptrw == 0) tptrw++; // shouldn't happen? std::string filename = utf16str_to_utf8str(llutf16string(tptrw)); if (dirname.empty()) dirname = filename + "\\"; else mFiles.push_back(dirname + filename); tptrw += filename.size(); } } } return success; } bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filename, std::string const& folder) { if( mLocked ) { return FALSE; } bool success = FALSE; llutf16string tstring = utf8str_to_utf16str(folder); mOFN.lpstrInitialDir = (LPCTSTR)tstring.data(); mOFN.lpstrFile = mFilesW; if (!filename.empty()) { llutf16string tstring = utf8str_to_utf16str(filename); wcsncpy(mFilesW, tstring.data(), FILENAME_BUFFER_SIZE); } /*Flawfinder: ignore*/ else { mFilesW[0] = '\0'; } 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.empty()) { 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.empty()) { 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.empty()) { 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_PNG: if (filename.empty()) { wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ } mOFN.lpstrDefExt = L"png"; mOFN.lpstrFilter = L"PNG Images (*.png)\0*.png\0" \ L"\0"; break; case FFSAVE_JPEG: if (filename.empty()) { wcsncpy( mFilesW,L"untitled.jpg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ } mOFN.lpstrDefExt = L"jpg"; mOFN.lpstrFilter = L"JPEG Images (*.jpg *.jpeg)\0*.jpg;*.jpeg\0" \ L"\0"; break; case FFSAVE_AVI: if (filename.empty()) { 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.empty()) { 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.empty()) { 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.empty()) { 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.empty()) { 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.empty()) { 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.empty()) { wcsncpy( mFilesW,L"untitled.j2c", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"j2c"; mOFN.lpstrFilter = L"Compressed Images (*.j2c)\0*.j2c\0" \ L"\0"; break; // case FFSAVE_ANIMATN: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.animatn", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"animatn"; mOFN.lpstrFilter = L"SL Animations (*.animatn)\0*.animatn\0" \ L"\0"; break; case FFSAVE_OGG: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.ogg", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"ogg"; mOFN.lpstrFilter = L"Ogg (*.ogg)\0*.ogg\0" \ L"\0"; break; case FFSAVE_NOTECARD: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.notecard", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"notecard"; mOFN.lpstrFilter = L"Notecards (*.notecard)\0*.notecard\0" \ L"\0"; break; case FFSAVE_GESTURE: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.gesture", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"gesture"; mOFN.lpstrFilter = L"Gestures (*.gesture)\0*.gesture\0" \ L"\0"; break; case FFSAVE_SCRIPT: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.lsl", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"lsl"; mOFN.lpstrFilter = L"LSL Files (*.lsl)\0*.lsl\0" L"\0"; break; case FFSAVE_SHAPE: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.shape", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"shape"; mOFN.lpstrFilter = L"Shapes (*.shape)\0*.shape\0" \ L"\0"; break; case FFSAVE_SKIN: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.skin", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"skin"; mOFN.lpstrFilter = L"Skins (*.skin)\0*.skin\0" \ L"\0"; break; case FFSAVE_HAIR: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.hair", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"hair"; mOFN.lpstrFilter = L"Hair (*.hair)\0*.hair\0" \ L"\0"; break; case FFSAVE_EYES: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.eyes", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"eyes"; mOFN.lpstrFilter = L"Eyes (*.eyes)\0*.eyes\0" \ L"\0"; break; case FFSAVE_SHIRT: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.shirt", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"shirt"; mOFN.lpstrFilter = L"Shirts (*.shirt)\0*.shirt\0" \ L"\0"; break; case FFSAVE_PANTS: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.pants", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"pants"; mOFN.lpstrFilter = L"Pants (*.pants)\0*.pants\0" \ L"\0"; break; case FFSAVE_SHOES: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.shoes", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"shoes"; mOFN.lpstrFilter = L"Shoes (*.shoes)\0*.shoes\0" \ L"\0"; break; case FFSAVE_SOCKS: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.socks", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"socks"; mOFN.lpstrFilter = L"Socks (*.socks)\0*.socks\0" \ L"\0"; break; case FFSAVE_JACKET: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.jacket", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"jacket"; mOFN.lpstrFilter = L"Jackets (*.jacket)\0*.jacket\0" \ L"\0"; break; case FFSAVE_GLOVES: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.gloves", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"gloves"; mOFN.lpstrFilter = L"Gloves (*.gloves)\0*.gloves\0" \ L"\0"; break; case FFSAVE_UNDERSHIRT: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.undershirt", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"undershirt"; mOFN.lpstrFilter = L"Undershirts (*.undershirt)\0*.undershirt\0" \ L"\0"; break; case FFSAVE_UNDERPANTS: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.underpants", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"underpants"; mOFN.lpstrFilter = L"Underpants (*.underpants)\0*.underpants\0" \ L"\0"; break; case FFSAVE_SKIRT: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.skirt", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"skirt"; mOFN.lpstrFilter = L"Skirts (*.skirt)\0*.skirt\0" \ L"\0"; break; case FFSAVE_LANDMARK: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.landmark", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"landmark"; mOFN.lpstrFilter = L"Landmarks (*.landmark)\0*.landmark\0" \ L"\0"; break; case FFSAVE_AO: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.ao", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"ao"; mOFN.lpstrFilter = L"Animation overrides (*.ao)\0*.ao\0" \ L"\0"; break; case FFSAVE_INVGZ: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.inv", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L".inv"; mOFN.lpstrFilter = L"InvCache (*.inv)\0*.inv\0" \ L"\0"; break; case FFSAVE_BLACKLIST: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.blacklist", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L".blacklist"; mOFN.lpstrFilter = L"Asset Blacklists (*.blacklist)\0*.blacklist\0" \ L"\0"; break; case FFSAVE_PHYSICS: if(filename.empty()) { wcsncpy( mFilesW,L"untitled.phy", FILENAME_BUFFER_SIZE); } mOFN.lpstrDefExt = L"phy"; mOFN.lpstrFilter = L"Landmarks (*.phy)\0*.phy\0" \ L"\0"; break; case FFSAVE_IMAGE: mOFN.lpstrDefExt = NULL; mOFN.lpstrFilter = L"Image (*.bmp *.dxt *.jpg *.jpeg *.j2c *.mip *.png *.tga)\0*.bmp;*.dxt;*.jpg;*.jpeg;*.j2c;*.mip;*.png;*.tga\0" \ L"PNG Image (*.png)\0*.png\0" \ L"Targa Image (*.tga)\0*.tga\0" \ L"Bitmap Image (*.bmp)\0*.bmp\0" \ L"JPEG Image (*.jpg *.jpeg)\0*.jpg;*.jpeg\0" \ L"Compressed Image (*.j2c)\0*.j2c\0" \ L"DXT Image (*.dxt *.mip)\0*.dxt;*.mip\0" \ L"\0"; break; // default: return FALSE; } mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; reset(); { // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! success = GetSaveFileName(&mOFN); if (success) { std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); mFiles.push_back(filename); } } return success; } #elif LL_DARWIN Boolean LLFilePickerBase::navOpenFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode) { LLFilePickerBase* picker = (LLFilePickerBase*)callBackUD; Boolean result = true; ELoadFilter filter = picker->getLoadFilter(); 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.filetype != 'PNG ' && fileInfo.filetype != 'JP2 ' && (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 && CFStringCompare(fileInfo.extension, CFSTR("png"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && CFStringCompare(fileInfo.extension, CFSTR("jp2"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && CFStringCompare(fileInfo.extension, CFSTR("j2k"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && CFStringCompare(fileInfo.extension, CFSTR("j2c"), 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.filetype != 'ANIM' && (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("bvh"), kCFCompareCaseInsensitive) != kCFCompareEqualTo) && CFStringCompare(fileInfo.extension, CFSTR("anim"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) { result = false; } } else if (filter == FFLOAD_COLLADA) { if (fileInfo.filetype != 'DAE ' && (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("dae"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) ) { result = false; } } else if (filter == FFLOAD_XML) { if (fileInfo.filetype != 'XML ' && (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("xml"), 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) { PLS_WARNS << "*** navOpenFilterProc: FFLOAD_SLOBJECT NOT IMPLEMENTED ***" << PLS_ENDL; } else if (filter == FFLOAD_RAW) { if (fileInfo.filetype != '\?\?\?\?' && (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("raw"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) ) { result = false; } } else if (filter == FFLOAD_SCRIPT) { if (fileInfo.filetype != 'LSL ' && (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("lsl"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) ) { result = false; } } else if (filter == FFLOAD_DICTIONARY) { if (fileInfo.filetype != 'DIC ' && fileInfo.filetype != 'XCU ' && (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("dic"), kCFCompareCaseInsensitive) != kCFCompareEqualTo) && fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("xcu"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))) { result = false; } } if (fileInfo.extension) { CFRelease(fileInfo.extension); } } } AEDisposeDesc(&desc); } } } return result; } //static pascal void LLFilePickerBase::doNavCallbackEvent(NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, void* callBackUD) { switch(callBackSelector) { case kNavCBStart: { LLFilePickerBase* picker = reinterpret_cast(callBackUD); if (picker->getFolder().empty()) break; OSStatus error = noErr; AEDesc theLocation = {typeNull, NULL}; FSSpec outFSSpec; //Convert string to a FSSpec FSRef myFSRef; const char* folder = picker->getFolder().c_str(); error = FSPathMakeRef ((UInt8*)folder, &myFSRef, NULL); if (error != noErr) break; error = FSGetCatalogInfo (&myFSRef, kFSCatInfoNone, NULL, NULL, &outFSSpec, NULL); if (error != noErr) break; error = AECreateDesc(typeFSS, &outFSSpec, sizeof(FSSpec), &theLocation); if (error != noErr) break; error = NavCustomControl(callBackParms->context, kNavCtlSetLocation, (void*)&theLocation); } } } OSStatus LLFilePickerBase::doNavChooseDialog(ELoadFilter filter, std::string const& folder) { OSStatus error = noErr; NavDialogRef navRef = NULL; NavReplyRecord navReply; memset(&navReply, 0, sizeof(navReply)); mLoadFilter = filter; mFolder = folder; NavEventUPP eventProc = NewNavEventUPP(doNavCallbackEvent); // 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, eventProc, NULL, navOpenFilterProc, (void*)this, &navRef); //gViewerWindow->getWindow()->beforeDialog(); if (error == noErr) { PLS_FLUSH; error = NavDialogRun(navRef); } //gViewerWindow->getWindow()->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) mFiles.push_back(std::string(path)); } } if (eventProc) DisposeNavEventUPP(eventProc); return error; } OSStatus LLFilePickerBase::doNavSaveDialog(ESaveFilter filter, std::string const& filename, std::string const& folder) { OSStatus error = noErr; NavDialogRef navRef = NULL; NavReplyRecord navReply; memset(&navReply, 0, sizeof(navReply)); // 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_JPEG: type = 'JPEG'; creator = 'prvw'; extension = CFSTR(".jpeg"); break; case FFSAVE_PNG: type = 'PNG '; creator = 'prvw'; extension = CFSTR(".png"); 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 = L'\?\?\?\?'; creator = L'\?\?\?\?'; 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_SCRIPT: type = 'LSL '; creator = '\?\?\?\?'; extension = CFSTR(".lsl"); break; case FFSAVE_ALL: default: type = '\?\?\?\?'; creator = '\?\?\?\?'; extension = CFSTR(""); break; } NavEventUPP eventUPP = NewNavEventUPP(NULL); //TODO: test filepicker mFolder = folder; // Create the dialog error = NavCreatePutFileDialog(&mNavOptions, type, creator, eventUPP, (void*)this, &navRef); if (error == noErr) { CFStringRef nameString = NULL; bool hasExtension = true; // Create a CFString of the initial file name if (!filename.empty()) nameString = CFStringCreateWithCString(NULL, filename.c_str(), 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->getWindow()->beforeDialog(); // Run the dialog if (error == noErr) { PLS_FLUSH; error = NavDialogRun(navRef); } //gViewerWindow->getWindow()->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)) { mFiles.push_back(std::string(path) + "/" + std::string(newFileName)); } else { error = paramErr; } } else { error = paramErr; } } } } if (eventUPP) DisposeNavEventUPP(eventUPP); return error; } bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) { if( mLocked ) return FALSE; bool success = FALSE; OSStatus error = noErr; reset(); mNavOptions.optionFlags &= ~kNavAllowMultipleFiles; { error = doNavChooseDialog(filter, folder); } if (error == noErr) { if (getFileCount()) success = true; } return success; } bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string const& folder) { if( mLocked ) return FALSE; bool success = FALSE; OSStatus error = noErr; reset(); mNavOptions.optionFlags |= kNavAllowMultipleFiles; { error = doNavChooseDialog(filter, folder); } if (error == noErr) { if (getFileCount()) success = true; if (getFileCount() > 1) mLocked = TRUE; } return success; } bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filename, std::string const& folder) { if( mLocked ) return FALSE; bool success = FALSE; OSStatus error = noErr; reset(); mNavOptions.optionFlags &= ~kNavAllowMultipleFiles; { error = doNavSaveDialog(filter, filename, folder); } if (error == noErr) { if (getFileCount()) success = true; } return success; } #elif LL_LINUX || LL_SOLARIS # if LL_GTK // static void LLFilePickerBase::add_to_selectedfiles(gpointer data, gpointer user_data) { // We need to run g_filename_to_utf8 in the user's locale std::string saved_locale(setlocale(LC_ALL, NULL)); setlocale(LC_ALL, ""); LLFilePickerBase* picker = (LLFilePickerBase*) user_data; GError *error = NULL; // gchar* filename_utf8 = g_filename_to_utf8((gchar*)data, // -1, NULL, NULL, &error); gchar* filename_utf8 = g_filename_display_name ((gchar*) data); if (error) { // *FIXME. // This condition should really be notified to the user, e.g. // through a message box. Just logging it is inappropriate. // Ghhhh. g_filename_display_name is new to glib 2.6, and it // is too new for SL! (Note that the latest glib as of this // writing is 2.22. *sigh*) LL supplied *makeASCII family are // also unsuitable since they allow control characters... // muhahaha ... Imprudence can ! PLS_WARNS << "g_filename_display_name failed on" << filename_utf8 << ": "<< error->message << PLS_ENDL; } if (filename_utf8) { picker->mFiles.push_back(std::string(filename_utf8)); PLS_DEBUGS << "ADDED FILE " << filename_utf8 << PLS_ENDL; g_free(filename_utf8); } setlocale(LC_ALL, saved_locale.c_str()); } // static void LLFilePickerBase::chooser_responder(GtkWidget *widget, gint response, gpointer user_data) { LLFilePicker* picker = (LLFilePicker*)user_data; PLS_DEBUGS << "GTK DIALOG RESPONSE " << response << PLS_ENDL; if (response == GTK_RESPONSE_ACCEPT) { GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget)); g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, picker); g_slist_foreach(file_list, (GFunc)g_free, NULL); g_slist_free (file_list); } gtk_widget_destroy(widget); gtk_main_quit(); } GtkWindow* LLFilePickerBase::buildFilePicker(bool is_save, bool is_folder, std::string const& folder) { if (LLWindowSDL::ll_try_gtk_init()) { GtkWidget *win = NULL; GtkFileChooserAction pickertype = is_save? (is_folder? GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER : GTK_FILE_CHOOSER_ACTION_SAVE) : (is_folder? GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : GTK_FILE_CHOOSER_ACTION_OPEN); win = gtk_file_chooser_dialog_new(NULL, NULL, pickertype, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, is_folder ? GTK_STOCK_APPLY : (is_save ? GTK_STOCK_SAVE : GTK_STOCK_OPEN), GTK_RESPONSE_ACCEPT, (gchar *)NULL); if (!folder.empty()) { PLS_DEBUGS << "Calling gtk_file_chooser_set_current_folder(\"" << folder << "\")." << PLS_ENDL; gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(win), folder.c_str()); } # 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. if (mX11WindowID != None) { gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin GdkWindow *gdkwin = gdk_window_foreign_new(mX11WindowID); gdk_window_set_transient_for(GTK_WIDGET(win)->window, gdkwin); } # endif //LL_X11 g_signal_connect (GTK_FILE_CHOOSER(win), "response", G_CALLBACK(LLFilePickerBase::chooser_responder), this); PLS_FLUSH; gtk_window_set_modal(GTK_WINDOW(win), TRUE); /* GTK 2.6: if (is_folder) gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win), TRUE); */ return GTK_WINDOW(win); } else { return NULL; } } static void add_common_filters_to_gtkchooser(GtkFileFilter *gfilter, GtkWindow *picker, std::string filtername) { gtk_file_filter_set_name(gfilter, filtername.c_str()); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), gfilter); GtkFileFilter *allfilter = gtk_file_filter_new(); gtk_file_filter_add_pattern(allfilter, "*"); gtk_file_filter_set_name(allfilter, LLTrans::getString("all_files").c_str()); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter); gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter); } static std::string add_simple_pattern_filter_to_gtkchooser(GtkWindow *picker, std::string pattern, std::string filtername) { GtkFileFilter *gfilter = gtk_file_filter_new(); gtk_file_filter_add_pattern(gfilter, pattern.c_str()); add_common_filters_to_gtkchooser(gfilter, picker, filtername); return filtername; } static std::string add_simple_mime_filter_to_gtkchooser(GtkWindow *picker, std::string mime, std::string filtername) { GtkFileFilter *gfilter = gtk_file_filter_new(); gtk_file_filter_add_mime_type(gfilter, mime.c_str()); add_common_filters_to_gtkchooser(gfilter, picker, filtername); return filtername; } static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker) { return add_simple_mime_filter_to_gtkchooser(picker, "audio/x-wav", LLTrans::getString("sound_files") + " (*.wav)"); } static std::string add_anim_filter_to_gtkchooser(GtkWindow *picker) { GtkFileFilter *gfilter = gtk_file_filter_new(); gtk_file_filter_add_pattern(gfilter, "*.bvh"); gtk_file_filter_add_pattern(gfilter, "*.anim"); std::string filtername = LLTrans::getString("animation_files") + " (*.bvh; *.anim)"; add_common_filters_to_gtkchooser(gfilter, picker, filtername); return filtername; } static std::string add_xml_filter_to_gtkchooser(GtkWindow *picker) { return add_simple_mime_filter_to_gtkchooser(picker, "text/xml", LLTrans::getString("xml_file") + " (*.xml)"); } static std::string add_collada_filter_to_gtkchooser(GtkWindow *picker) { return add_simple_pattern_filter_to_gtkchooser(picker, "*.dae", LLTrans::getString("scene_files") + " (*.dae)"); } static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) { GtkFileFilter *gfilter = gtk_file_filter_new(); gtk_file_filter_add_pattern(gfilter, "*.tga"); gtk_file_filter_add_mime_type(gfilter, "image/jpeg"); gtk_file_filter_add_mime_type(gfilter, "image/png"); gtk_file_filter_add_mime_type(gfilter, "image/bmp"); gtk_file_filter_add_mime_type(gfilter, "image/jp2"); std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png; *.jp2; *.j2k; *.j2c)"; add_common_filters_to_gtkchooser(gfilter, picker, filtername); return filtername; } static std::string add_imagesave_filter_to_gtkchooser(GtkWindow *picker) { GtkFileFilter *gfilter = gtk_file_filter_new(); gtk_file_filter_add_mime_type(gfilter, "image/bmp"); gtk_file_filter_add_pattern(gfilter, "*.dxt"); gtk_file_filter_add_mime_type(gfilter, "image/jpeg"); gtk_file_filter_add_pattern(gfilter, "*.j2c"); gtk_file_filter_add_pattern(gfilter, "*.mip"); gtk_file_filter_add_mime_type(gfilter, "image/png"); gtk_file_filter_add_pattern(gfilter, "*.tga"); std::string filtername = LLTrans::getString("image_files") + "(*.bmp; *.dxt; *.jpg; *.jpeg; *.j2c; *.mip; *.png; *.tga)"; add_common_filters_to_gtkchooser(gfilter, picker, filtername); return filtername; } static std::string add_script_filter_to_gtkchooser(GtkWindow *picker) { return add_simple_mime_filter_to_gtkchooser(picker, "text/plain", LLTrans::getString("script_files") + " (*.lsl)"); } static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker) { return add_simple_mime_filter_to_gtkchooser(picker, "text/plain", LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)"); } bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filename, std::string const& folder) { bool rtn = FALSE; //gViewerWindow->getWindow()->beforeDialog(); reset(); GtkWindow* picker = buildFilePicker(true, false, folder); if (picker) { std::string suggest_name = "untitled"; std::string suggest_ext = ""; std::string caption = LLTrans::getString("save_file_verb") + " "; switch (filter) { case FFSAVE_WAV: caption += add_wav_filter_to_gtkchooser(picker); suggest_ext = ".wav"; break; case FFSAVE_TGA: caption += add_simple_pattern_filter_to_gtkchooser (picker, "*.tga", LLTrans::getString("targa_image_files") + " (*.tga)"); suggest_ext = ".tga"; break; case FFSAVE_BMP: caption += add_simple_mime_filter_to_gtkchooser (picker, "image/bmp", LLTrans::getString("bitmap_image_files") + " (*.bmp)"); suggest_ext = ".bmp"; break; case FFSAVE_AVI: caption += add_simple_mime_filter_to_gtkchooser (picker, "video/x-msvideo", LLTrans::getString("avi_movie_file") + " (*.avi)"); suggest_ext = ".avi"; break; case FFSAVE_ANIM: caption += add_simple_pattern_filter_to_gtkchooser (picker, "*.xaf", LLTrans::getString("xaf_animation_file") + " (*.xaf)"); suggest_ext = ".xaf"; break; case FFSAVE_XML: caption += add_simple_pattern_filter_to_gtkchooser (picker, "*.xml", LLTrans::getString("xml_file") + " (*.xml)"); suggest_ext = ".xml"; break; case FFSAVE_RAW: caption += add_simple_pattern_filter_to_gtkchooser (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)"); suggest_ext = ".raw"; break; case FFSAVE_J2C: caption += add_simple_mime_filter_to_gtkchooser (picker, "images/jp2", LLTrans::getString("compressed_image_files") + " (*.j2c)"); suggest_ext = ".j2c"; break; case FFSAVE_SCRIPT: caption += add_script_filter_to_gtkchooser(picker); suggest_ext = ".lsl"; break; case FFSAVE_IMAGE: caption += add_imagesave_filter_to_gtkchooser(picker); suggest_ext = ".png"; break; default:; break; } gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); if (filename.empty()) { suggest_name += suggest_ext; gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(picker), suggest_name.c_str()); } else { gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(picker), filename.c_str()); } gtk_widget_show_all(GTK_WIDGET(picker)); PLS_FLUSH; gtk_main(); rtn = (getFileCount() == 1); } //gViewerWindow->getWindow()->afterDialog(); return rtn; } bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) { bool rtn = FALSE; //gViewerWindow->getWindow()->beforeDialog(); reset(); GtkWindow* picker = buildFilePicker(false, false, folder); if (picker) { std::string caption = LLTrans::getString("load_file_verb") + " "; std::string filtername = ""; switch (filter) { case FFLOAD_WAV: filtername = add_wav_filter_to_gtkchooser(picker); break; case FFLOAD_ANIM: filtername = add_anim_filter_to_gtkchooser(picker); break; case FFLOAD_COLLADA: filtername = add_collada_filter_to_gtkchooser(picker); break; case FFLOAD_IMAGE: filtername = add_imageload_filter_to_gtkchooser(picker); break; case FFLOAD_SCRIPT: filtername = add_script_filter_to_gtkchooser(picker); break; case FFLOAD_DICTIONARY: filtername = add_dictionary_filter_to_gtkchooser(picker); break; case FFLOAD_XML: filtername = add_xml_filter_to_gtkchooser(picker); break; default:; break; } caption += filtername; gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); gtk_widget_show_all(GTK_WIDGET(picker)); PLS_FLUSH; gtk_main(); rtn = (getFileCount() == 1); } //gViewerWindow->getWindow()->afterDialog(); return rtn; } bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string const& folder) { bool rtn = FALSE; //gViewerWindow->getWindow()->beforeDialog(); reset(); GtkWindow* picker = buildFilePicker(false, false, folder); if (picker) { gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker), TRUE); gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str()); gtk_widget_show_all(GTK_WIDGET(picker)); PLS_FLUSH; gtk_main(); rtn = !mFiles.empty(); } //gViewerWindow->getWindow()->afterDialog(); return rtn; } # else // LL_GTK // Hacky stubs designed to facilitate fake getSaveFile and getLoadFile with // static results, when we don't have a real filepicker. bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filename, std::string const& folder) { reset(); PLS_INFOS << "getSaveFile suggested filename is [" << filename << "]" << PLS_ENDL; if (!filename.empty()) { mFiles.push_back(gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + filename); return TRUE; } return FALSE; } bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) { reset(); // HACK: Static filenames for 'open' until we implement filepicker std::string filename = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + "upload"; switch (filter) { case FFLOAD_WAV: filename += ".wav"; break; case FFLOAD_IMAGE: filename += ".tga"; break; case FFLOAD_ANIM: filename += ".bvh"; break; case FFLOAD_XML: filename += ".xml"; break; default: break; } mFiles.push_back(filename); PLS_INFOS << "getLoadFile: Will try to open file: " << hackyfilename << PLS_ENDL; return TRUE; } bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string const& folder) { reset(); return FALSE; } #endif // LL_GTK #else // not implemented bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filename, std::string const& folder) { reset(); return FALSE; } bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) { reset(); return FALSE; } bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string const& folder) { reset(); return FALSE; } #endif