00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llfilepicker.h"
00035 #include "llworld.h"
00036 #include "llviewerwindow.h"
00037 #include "llkeyboard.h"
00038 #include "lldir.h"
00039 #include "llframetimer.h"
00040
00041 #if LL_SDL
00042 #include "llwindowsdl.h"
00043 #endif // LL_SDL
00044
00045
00046
00047
00048
00049 LLFilePicker LLFilePicker::sInstance;
00050
00051 #if LL_WINDOWS
00052 #define SOUND_FILTER L"Sounds (*.wav)\0*.wav\0"
00053 #define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0"
00054 #define ANIM_FILTER L"Animations (*.bvh)\0*.bvh\0"
00055 #ifdef _CORY_TESTING
00056 #define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0"
00057 #endif
00058 #define XML_FILTER L"XML files (*.xml)\0*.xml\0"
00059 #define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0"
00060 #define RAW_FILTER L"RAW files (*.raw)\0*.raw\0"
00061 #endif
00062
00063
00064
00065
00066 #if LL_WINDOWS
00067
00068 LLFilePicker::LLFilePicker()
00069 {
00070 reset();
00071
00072 mOFN.lStructSize = sizeof(OPENFILENAMEW);
00073 mOFN.hwndOwner = NULL;
00074 mOFN.hInstance = NULL;
00075 mOFN.lpstrCustomFilter = NULL;
00076 mOFN.nMaxCustFilter = 0;
00077 mOFN.lpstrFile = NULL;
00078 mOFN.nMaxFile = LL_MAX_PATH;
00079 mOFN.lpstrFileTitle = NULL;
00080 mOFN.nMaxFileTitle = 0;
00081 mOFN.lpstrInitialDir = NULL;
00082 mOFN.lpstrTitle = NULL;
00083 mOFN.Flags = 0;
00084 mOFN.nFileOffset = 0;
00085 mOFN.nFileExtension = 0;
00086 mOFN.lpstrDefExt = NULL;
00087 mOFN.lCustData = 0L;
00088 mOFN.lpfnHook = NULL;
00089 mOFN.lpTemplateName = NULL;
00090 }
00091
00092 LLFilePicker::~LLFilePicker()
00093 {
00094
00095 }
00096
00097 BOOL LLFilePicker::setupFilter(ELoadFilter filter)
00098 {
00099 BOOL res = TRUE;
00100 switch (filter)
00101 {
00102 case FFLOAD_ALL:
00103 mOFN.lpstrFilter = L"All Files (*.*)\0*.*\0" \
00104 SOUND_FILTER \
00105 IMAGE_FILTER \
00106 ANIM_FILTER \
00107 L"\0";
00108 break;
00109 case FFLOAD_WAV:
00110 mOFN.lpstrFilter = SOUND_FILTER \
00111 L"\0";
00112 break;
00113 case FFLOAD_IMAGE:
00114 mOFN.lpstrFilter = IMAGE_FILTER \
00115 L"\0";
00116 break;
00117 case FFLOAD_ANIM:
00118 mOFN.lpstrFilter = ANIM_FILTER \
00119 L"\0";
00120 break;
00121 #ifdef _CORY_TESTING
00122 case FFLOAD_GEOMETRY:
00123 mOFN.lpstrFilter = GEOMETRY_FILTER \
00124 L"\0";
00125 break;
00126 #endif
00127 case FFLOAD_XML:
00128 mOFN.lpstrFilter = XML_FILTER \
00129 L"\0";
00130 break;
00131 case FFLOAD_SLOBJECT:
00132 mOFN.lpstrFilter = SLOBJECT_FILTER \
00133 L"\0";
00134 break;
00135 case FFLOAD_RAW:
00136 mOFN.lpstrFilter = RAW_FILTER \
00137 L"\0";
00138 break;
00139 default:
00140 res = FALSE;
00141 break;
00142 }
00143 return res;
00144 }
00145
00146 BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
00147 {
00148 if( mLocked )
00149 {
00150 return FALSE;
00151 }
00152 BOOL success = FALSE;
00153 mMultiFile = FALSE;
00154
00155
00156 mFilesW[0] = '\0';
00157
00158 mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow();
00159 mOFN.lpstrFile = mFilesW;
00160 mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE;
00161 mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR ;
00162 mOFN.nFilterIndex = 1;
00163
00164 setupFilter(filter);
00165
00166
00167 send_agent_pause();
00168
00169 success = GetOpenFileName(&mOFN);
00170 if (success)
00171 {
00172 LLString tstr = utf16str_to_utf8str(llutf16string(mFilesW));
00173 memcpy(mFiles, tstr.c_str(), tstr.size()+1);
00174 mCurrentFile = mFiles;
00175 }
00176 send_agent_resume();
00177
00178
00179 LLFrameTimer::updateFrameTime();
00180 return success;
00181 }
00182
00183 BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter)
00184 {
00185 if( mLocked )
00186 {
00187 return FALSE;
00188 }
00189 BOOL success = FALSE;
00190 mMultiFile = FALSE;
00191
00192
00193 mFilesW[0] = '\0';
00194
00195 mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow();
00196 mOFN.lpstrFile = mFilesW;
00197 mOFN.nFilterIndex = 1;
00198 mOFN.nMaxFile = FILENAME_BUFFER_SIZE;
00199 mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR |
00200 OFN_EXPLORER | OFN_ALLOWMULTISELECT;
00201
00202 setupFilter(filter);
00203
00204
00205 send_agent_pause();
00206
00207 success = GetOpenFileName(&mOFN);
00208 if( success )
00209 {
00210
00211
00212
00213 if( wcslen(mOFN.lpstrFile) > mOFN.nFileOffset )
00214 {
00215 mMultiFile = FALSE;
00216 mCurrentFile = mFiles;
00217 LLString tstr = utf16str_to_utf8str(llutf16string(mFilesW));
00218 memcpy(mFiles, tstr.c_str(), tstr.size()+1);
00219
00220 mCurrentFile = &mFiles[mOFN.nFileOffset];
00221 }
00222 else
00223 {
00224 mMultiFile = TRUE;
00225 mCurrentFile = 0;
00226 mLocked = TRUE;
00227 WCHAR* tptrw = mFilesW;
00228 char* tptr = mFiles;
00229 memset( mFiles, 0, FILENAME_BUFFER_SIZE );
00230 while(1)
00231 {
00232 if (*tptrw == 0 && *(tptrw+1) == 0)
00233 break;
00234 if (*tptrw == 0 && !mCurrentFile)
00235 mCurrentFile = tptr+1;
00236 S32 tlen16,tlen8;
00237 tlen16 = utf16chars_to_utf8chars(tptrw, tptr, &tlen8);
00238 tptrw += tlen16;
00239 tptr += tlen8;
00240 }
00241 }
00242 }
00243 send_agent_resume();
00244
00245
00246 LLFrameTimer::updateFrameTime();
00247 return success;
00248 }
00249
00250 BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const char* filename)
00251 {
00252 if( mLocked )
00253 {
00254 return FALSE;
00255 }
00256 BOOL success = FALSE;
00257 mMultiFile = FALSE;
00258
00259 mOFN.lpstrFile = mFilesW;
00260 if (filename)
00261 {
00262 llutf16string tstring = utf8str_to_utf16str(filename);
00263 wcsncpy(mFilesW, tstring.c_str(), FILENAME_BUFFER_SIZE); }
00264 else
00265 {
00266 mFilesW[0] = '\0';
00267 }
00268 mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow();
00269
00270 switch( filter )
00271 {
00272 case FFSAVE_ALL:
00273 mOFN.lpstrDefExt = NULL;
00274 mOFN.lpstrFilter =
00275 L"All Files (*.*)\0*.*\0" \
00276 L"WAV Sounds (*.wav)\0*.wav\0" \
00277 L"Targa, Bitmap Images (*.tga; *.bmp)\0*.tga;*.bmp\0" \
00278 L"\0";
00279 break;
00280 case FFSAVE_WAV:
00281 if (!filename)
00282 {
00283 wcsncpy( mFilesW,L"untitled.wav", FILENAME_BUFFER_SIZE);
00284 }
00285 mOFN.lpstrDefExt = L"wav";
00286 mOFN.lpstrFilter =
00287 L"WAV Sounds (*.wav)\0*.wav\0" \
00288 L"\0";
00289 break;
00290 case FFSAVE_TGA:
00291 if (!filename)
00292 {
00293 wcsncpy( mFilesW,L"untitled.tga", FILENAME_BUFFER_SIZE);
00294 }
00295 mOFN.lpstrDefExt = L"tga";
00296 mOFN.lpstrFilter =
00297 L"Targa Images (*.tga)\0*.tga\0" \
00298 L"\0";
00299 break;
00300 case FFSAVE_BMP:
00301 if (!filename)
00302 {
00303 wcsncpy( mFilesW,L"untitled.bmp", FILENAME_BUFFER_SIZE);
00304 }
00305 mOFN.lpstrDefExt = L"bmp";
00306 mOFN.lpstrFilter =
00307 L"Bitmap Images (*.bmp)\0*.bmp\0" \
00308 L"\0";
00309 break;
00310 case FFSAVE_AVI:
00311 if (!filename)
00312 {
00313 wcsncpy( mFilesW,L"untitled.avi", FILENAME_BUFFER_SIZE);
00314 }
00315 mOFN.lpstrDefExt = L"avi";
00316 mOFN.lpstrFilter =
00317 L"AVI Movie File (*.avi)\0*.avi\0" \
00318 L"\0";
00319 break;
00320 case FFSAVE_ANIM:
00321 if (!filename)
00322 {
00323 wcsncpy( mFilesW,L"untitled.xaf", FILENAME_BUFFER_SIZE);
00324 }
00325 mOFN.lpstrDefExt = L"xaf";
00326 mOFN.lpstrFilter =
00327 L"XAF Anim File (*.xaf)\0*.xaf\0" \
00328 L"\0";
00329 break;
00330 #ifdef _CORY_TESTING
00331 case FFSAVE_GEOMETRY:
00332 if (!filename)
00333 {
00334 wcsncpy( mFilesW,L"untitled.slg", FILENAME_BUFFER_SIZE);
00335 }
00336 mOFN.lpstrDefExt = L"slg";
00337 mOFN.lpstrFilter =
00338 L"SLG SL Geometry File (*.slg)\0*.slg\0" \
00339 L"\0";
00340 break;
00341 #endif
00342 case FFSAVE_XML:
00343 if (!filename)
00344 {
00345 wcsncpy( mFilesW,L"untitled.xml", FILENAME_BUFFER_SIZE);
00346 }
00347
00348 mOFN.lpstrDefExt = L"xml";
00349 mOFN.lpstrFilter =
00350 L"XML File (*.xml)\0*.xml\0" \
00351 L"\0";
00352 break;
00353 case FFSAVE_COLLADA:
00354 if (!filename)
00355 {
00356 wcsncpy( mFilesW,L"untitled.collada", FILENAME_BUFFER_SIZE);
00357 }
00358 mOFN.lpstrDefExt = L"collada";
00359 mOFN.lpstrFilter =
00360 L"COLLADA File (*.collada)\0*.collada\0" \
00361 L"\0";
00362 break;
00363 case FFSAVE_RAW:
00364 if (!filename)
00365 {
00366 wcsncpy( mFilesW,L"untitled.raw", FILENAME_BUFFER_SIZE);
00367 }
00368 mOFN.lpstrDefExt = L"raw";
00369 mOFN.lpstrFilter = RAW_FILTER \
00370 L"\0";
00371 break;
00372 case FFSAVE_J2C:
00373 if (!filename)
00374 {
00375 wcsncpy( mFilesW,L"untitled.j2c", FILENAME_BUFFER_SIZE);
00376 }
00377 mOFN.lpstrDefExt = L"j2c";
00378 mOFN.lpstrFilter =
00379 L"Compressed Images (*.j2c)\0*.j2c\0" \
00380 L"\0";
00381 break;
00382 default:
00383 return FALSE;
00384 }
00385
00386
00387 mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE;
00388 mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
00389
00390
00391 send_agent_pause();
00392 {
00393
00394 success = GetSaveFileName(&mOFN);
00395 if (success)
00396 {
00397 LLString tstr = utf16str_to_utf8str(llutf16string(mFilesW));
00398 memcpy(mFiles, tstr.c_str(), tstr.size()+1);
00399 mCurrentFile = mFiles;
00400 }
00401 gKeyboard->resetKeys();
00402 }
00403 send_agent_resume();
00404
00405
00406 LLFrameTimer::updateFrameTime();
00407 return success;
00408 }
00409
00410 const char* LLFilePicker::getFirstFile()
00411 {
00412 if(mMultiFile)
00413 {
00414 buildFilename();
00415 return mFilename;
00416 }
00417 return mFiles;
00418 }
00419
00420 const char* LLFilePicker::getNextFile()
00421 {
00422 if(mMultiFile)
00423 {
00424 mCurrentFile += strlen(mCurrentFile) + 1;
00425 if( '\0' != mCurrentFile[0] )
00426 {
00427 buildFilename();
00428 return mFilename;
00429 }
00430 else
00431 {
00432 mLocked = FALSE;
00433 }
00434 }
00435 return NULL;
00436 }
00437
00438 const char* LLFilePicker::getDirname()
00439 {
00440 if( '\0' != mCurrentFile[0] )
00441 {
00442 return mCurrentFile;
00443 }
00444 return NULL;
00445 }
00446
00447 void LLFilePicker::reset()
00448 {
00449 mLocked = FALSE;
00450 memset( mFiles, 0, FILENAME_BUFFER_SIZE );
00451 memset( mFilename, 0, LL_MAX_PATH );
00452 mCurrentFile = mFiles;
00453 }
00454
00455 void LLFilePicker::buildFilename( void )
00456 {
00457 strncpy( mFilename, mFiles, LL_MAX_PATH );
00458 mFilename[LL_MAX_PATH-1] = '\0';
00459 S32 len = strlen( mFilename );
00460
00461 strncat(mFilename,gDirUtilp->getDirDelimiter().c_str(), sizeof(mFilename)-len+1);
00462 len += strlen(gDirUtilp->getDirDelimiter().c_str());
00463
00464
00465 LLString::copy( mFilename + len, mCurrentFile, LL_MAX_PATH - len );
00466 }
00467
00468 #elif LL_DARWIN
00469
00470 LLFilePicker::LLFilePicker()
00471 {
00472 reset();
00473
00474 memset(&mNavOptions, 0, sizeof(mNavOptions));
00475 OSStatus error = NavGetDefaultDialogCreationOptions(&mNavOptions);
00476 if (error == noErr)
00477 {
00478 mNavOptions.modality = kWindowModalityAppModal;
00479 }
00480 mFileIndex = 0;
00481 }
00482
00483 LLFilePicker::~LLFilePicker()
00484 {
00485
00486 }
00487
00488 Boolean LLFilePicker::navOpenFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode)
00489 {
00490 Boolean result = true;
00491 ELoadFilter filter = *((ELoadFilter*) callBackUD);
00492 OSStatus error = noErr;
00493
00494 if (filterMode == kNavFilteringBrowserList && filter != FFLOAD_ALL && (theItem->descriptorType == typeFSRef || theItem->descriptorType == typeFSS))
00495 {
00496
00497 NavFileOrFolderInfo *navInfo = (NavFileOrFolderInfo*) info;
00498 if (!navInfo->isFolder)
00499 {
00500 AEDesc desc;
00501 error = AECoerceDesc(theItem, typeFSRef, &desc);
00502 if (error == noErr)
00503 {
00504 FSRef fileRef;
00505 error = AEGetDescData(&desc, &fileRef, sizeof(fileRef));
00506 if (error == noErr)
00507 {
00508 LSItemInfoRecord fileInfo;
00509 error = LSCopyItemInfoForRef(&fileRef, kLSRequestExtension | kLSRequestTypeCreator, &fileInfo);
00510 if (error == noErr)
00511 {
00512 if (filter == FFLOAD_IMAGE)
00513 {
00514 if (fileInfo.filetype != 'JPEG' && fileInfo.filetype != 'JPG ' &&
00515 fileInfo.filetype != 'BMP ' && fileInfo.filetype != 'TGA ' &&
00516 fileInfo.filetype != 'BMPf' && fileInfo.filetype != 'TPIC' &&
00517 fileInfo.filetype != 'PNG ' &&
00518 (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("jpeg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
00519 CFStringCompare(fileInfo.extension, CFSTR("jpg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
00520 CFStringCompare(fileInfo.extension, CFSTR("bmp"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
00521 CFStringCompare(fileInfo.extension, CFSTR("tga"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
00522 CFStringCompare(fileInfo.extension, CFSTR("png"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
00523 )
00524 {
00525 result = false;
00526 }
00527 }
00528 else if (filter == FFLOAD_WAV)
00529 {
00530 if (fileInfo.filetype != 'WAVE' && fileInfo.filetype != 'WAV ' &&
00531 (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("wave"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
00532 CFStringCompare(fileInfo.extension, CFSTR("wav"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
00533 )
00534 {
00535 result = false;
00536 }
00537 }
00538 else if (filter == FFLOAD_ANIM)
00539 {
00540 if (fileInfo.filetype != 'BVH ' &&
00541 (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("bvh"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
00542 )
00543 {
00544 result = false;
00545 }
00546 }
00547 #ifdef _CORY_TESTING
00548 else if (filter == FFLOAD_GEOMETRY)
00549 {
00550 if (fileInfo.filetype != 'SLG ' &&
00551 (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("slg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
00552 )
00553 {
00554 result = false;
00555 }
00556 }
00557 #endif
00558 else if (filter == FFLOAD_SLOBJECT)
00559 {
00560 llwarns << "*** navOpenFilterProc: FFLOAD_SLOBJECT NOT IMPLEMENTED ***" << llendl;
00561 }
00562 else if (filter == FFLOAD_RAW)
00563 {
00564 if (fileInfo.filetype != '\?\?\?\?' &&
00565 (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("raw"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
00566 )
00567 {
00568 result = false;
00569 }
00570 }
00571
00572 if (fileInfo.extension)
00573 {
00574 CFRelease(fileInfo.extension);
00575 }
00576 }
00577 }
00578 AEDisposeDesc(&desc);
00579 }
00580 }
00581 }
00582 return result;
00583 }
00584
00585 OSStatus LLFilePicker::doNavChooseDialog(ELoadFilter filter)
00586 {
00587 OSStatus error = noErr;
00588 NavDialogRef navRef = NULL;
00589 NavReplyRecord navReply;
00590
00591 memset(&navReply, 0, sizeof(navReply));
00592 mFiles[0] = '\0';
00593 mFileVector.clear();
00594
00595
00596
00597
00598 error = NavCreateChooseFileDialog(&mNavOptions, NULL, NULL, NULL, navOpenFilterProc, (void*)(&filter), &navRef);
00599
00600 gViewerWindow->mWindow->beforeDialog();
00601
00602 if (error == noErr)
00603 error = NavDialogRun(navRef);
00604
00605 gViewerWindow->mWindow->afterDialog();
00606
00607 if (error == noErr)
00608 error = NavDialogGetReply(navRef, &navReply);
00609
00610 if (navRef)
00611 NavDialogDispose(navRef);
00612
00613 if (error == noErr && navReply.validRecord)
00614 {
00615 SInt32 count = 0;
00616 SInt32 index;
00617
00618
00619 error = AECountItems(&navReply.selection, &count);
00620 for (index = 1; index <= count; index++)
00621 {
00622 FSRef fsRef;
00623 AEKeyword theAEKeyword;
00624 DescType typeCode;
00625 Size actualSize = 0;
00626 char path[MAX_PATH];
00627
00628 memset(&fsRef, 0, sizeof(fsRef));
00629 error = AEGetNthPtr(&navReply.selection, index, typeFSRef, &theAEKeyword, &typeCode, &fsRef, sizeof(fsRef), &actualSize);
00630
00631 if (error == noErr)
00632 error = FSRefMakePath(&fsRef, (UInt8*) path, sizeof(path));
00633
00634 if (error == noErr)
00635 mFileVector.push_back(LLString(path));
00636 }
00637 }
00638
00639 return error;
00640 }
00641
00642 OSStatus LLFilePicker::doNavSaveDialog(ESaveFilter filter, const char* filename)
00643 {
00644 OSStatus error = noErr;
00645 NavDialogRef navRef = NULL;
00646 NavReplyRecord navReply;
00647
00648 memset(&navReply, 0, sizeof(navReply));
00649 mFiles[0] = '\0';
00650 mFileVector.clear();
00651
00652
00653 OSType type, creator;
00654 CFStringRef extension = NULL;
00655 switch (filter)
00656 {
00657 case FFSAVE_WAV:
00658 type = 'WAVE';
00659 creator = 'TVOD';
00660 extension = CFSTR(".wav");
00661 break;
00662
00663 case FFSAVE_TGA:
00664 type = 'TPIC';
00665 creator = 'prvw';
00666 extension = CFSTR(".tga");
00667 break;
00668
00669 case FFSAVE_BMP:
00670 type = 'BMPf';
00671 creator = 'prvw';
00672 extension = CFSTR(".bmp");
00673 break;
00674
00675 case FFSAVE_AVI:
00676 type = '\?\?\?\?';
00677 creator = '\?\?\?\?';
00678 extension = CFSTR(".mov");
00679 break;
00680
00681 case FFSAVE_ANIM:
00682 type = '\?\?\?\?';
00683 creator = '\?\?\?\?';
00684 extension = CFSTR(".xaf");
00685 break;
00686
00687 #ifdef _CORY_TESTING
00688 case FFSAVE_GEOMETRY:
00689 type = '\?\?\?\?';
00690 creator = '\?\?\?\?';
00691 extension = CFSTR(".slg");
00692 break;
00693 #endif
00694 case FFSAVE_RAW:
00695 type = '\?\?\?\?';
00696 creator = '\?\?\?\?';
00697 extension = CFSTR(".raw");
00698 break;
00699
00700 case FFSAVE_J2C:
00701 type = '\?\?\?\?';
00702 creator = 'prvw';
00703 extension = CFSTR(".j2c");
00704 break;
00705
00706 case FFSAVE_ALL:
00707 default:
00708 type = '\?\?\?\?';
00709 creator = '\?\?\?\?';
00710 extension = CFSTR("");
00711 break;
00712 }
00713
00714
00715 error = NavCreatePutFileDialog(&mNavOptions, type, creator, NULL, NULL, &navRef);
00716 if (error == noErr)
00717 {
00718 CFStringRef nameString = NULL;
00719 bool hasExtension = true;
00720
00721
00722 if (filename)
00723 nameString = CFStringCreateWithCString(NULL, filename, kCFStringEncodingUTF8);
00724 else
00725 nameString = CFSTR("Untitled");
00726
00727
00728 if (nameString && !CFStringHasSuffix(nameString, extension))
00729 {
00730 CFStringRef tempString = nameString;
00731 hasExtension = false;
00732 nameString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), tempString, extension);
00733 CFRelease(tempString);
00734 }
00735
00736
00737 if (nameString)
00738 {
00739 error = NavDialogSetSaveFileName(navRef, nameString);
00740 CFRelease(nameString);
00741 }
00742 else
00743 {
00744 error = paramErr;
00745 }
00746 }
00747
00748 gViewerWindow->mWindow->beforeDialog();
00749
00750
00751 if (error == noErr)
00752 error = NavDialogRun(navRef);
00753
00754 gViewerWindow->mWindow->afterDialog();
00755
00756 if (error == noErr)
00757 error = NavDialogGetReply(navRef, &navReply);
00758
00759 if (navRef)
00760 NavDialogDispose(navRef);
00761
00762 if (error == noErr && navReply.validRecord)
00763 {
00764 SInt32 count = 0;
00765
00766
00767 error = AECountItems(&navReply.selection, &count);
00768 if (count > 0)
00769 {
00770
00771 FSRef fsRef;
00772 AEKeyword theAEKeyword;
00773 DescType typeCode;
00774 Size actualSize = 0;
00775
00776 memset(&fsRef, 0, sizeof(fsRef));
00777 error = AEGetNthPtr(&navReply.selection, 1, typeFSRef, &theAEKeyword, &typeCode, &fsRef, sizeof(fsRef), &actualSize);
00778
00779 if (error == noErr)
00780 {
00781 char path[PATH_MAX];
00782 char newFileName[SINGLE_FILENAME_BUFFER_SIZE];
00783
00784 error = FSRefMakePath(&fsRef, (UInt8*)path, PATH_MAX);
00785 if (error == noErr)
00786 {
00787 if (CFStringGetCString(navReply.saveFileName, newFileName, sizeof(newFileName), kCFStringEncodingUTF8))
00788 {
00789 mFileVector.push_back(LLString(path) + LLString("/") + LLString(newFileName));
00790 }
00791 else
00792 {
00793 error = paramErr;
00794 }
00795 }
00796 else
00797 {
00798 error = paramErr;
00799 }
00800 }
00801 }
00802 }
00803
00804 return error;
00805 }
00806
00807 BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
00808 {
00809 if( mLocked ) return FALSE;
00810 mMultiFile = FALSE;
00811 BOOL success = FALSE;
00812
00813 OSStatus error = noErr;
00814
00815 mFileVector.clear();
00816 mNavOptions.optionFlags &= ~kNavAllowMultipleFiles;
00817
00818 send_agent_pause();
00819 {
00820 error = doNavChooseDialog(filter);
00821 }
00822 send_agent_resume();
00823 if (error == noErr)
00824 {
00825 if (mFileVector.size())
00826 success = true;
00827 }
00828
00829
00830 LLFrameTimer::updateFrameTime();
00831 return success;
00832 }
00833
00834 BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter)
00835 {
00836 if( mLocked ) return FALSE;
00837 mMultiFile = TRUE;
00838 BOOL success = FALSE;
00839
00840 OSStatus error = noErr;
00841
00842 mFileVector.clear();
00843 mNavOptions.optionFlags |= kNavAllowMultipleFiles;
00844
00845 send_agent_pause();
00846 {
00847 error = doNavChooseDialog(filter);
00848 }
00849 send_agent_resume();
00850 if (error == noErr)
00851 {
00852 if (mFileVector.size())
00853 success = true;
00854 if (mFileVector.size() > 1)
00855 mLocked = TRUE;
00856 }
00857
00858
00859 LLFrameTimer::updateFrameTime();
00860 return success;
00861 }
00862
00863 void LLFilePicker::getFilePath(SInt32 index)
00864 {
00865 mFiles[0] = 0;
00866 if (mFileVector.size())
00867 {
00868 strncpy(mFiles, mFileVector[index].c_str(), sizeof(mFiles));
00869 mFiles[sizeof(mFiles)-1] = '\0';
00870 }
00871 }
00872
00873 void LLFilePicker::getFileName(SInt32 index)
00874 {
00875 mFilename[0] = 0;
00876 if (mFileVector.size())
00877 {
00878 char *start = strrchr(mFileVector[index].c_str(), '/');
00879 if (start && ((start + 1 - mFileVector[index].c_str()) < (mFileVector[index].size())))
00880 {
00881 strncpy(mFilename, start + 1, sizeof(mFilename));
00882 mFilename[sizeof(mFilename)-1] = '\0';
00883 }
00884 }
00885 }
00886
00887 BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const char* filename)
00888 {
00889 if( mLocked ) return FALSE;
00890 BOOL success = FALSE;
00891 OSStatus error = noErr;
00892
00893 mFileVector.clear();
00894 mMultiFile = FALSE;
00895 mNavOptions.optionFlags &= ~kNavAllowMultipleFiles;
00896
00897
00898 send_agent_pause();
00899 {
00900 error = doNavSaveDialog(filter, filename);
00901 }
00902 send_agent_resume();
00903 if (error == noErr)
00904 {
00905 if (mFileVector.size())
00906 success = true;
00907 }
00908
00909
00910 LLFrameTimer::updateFrameTime();
00911 return success;
00912 }
00913
00914 const char* LLFilePicker::getFirstFile()
00915 {
00916 mFileIndex = 0;
00917 getFilePath(mFileIndex);
00918 return mFiles;
00919 }
00920
00921 const char* LLFilePicker::getNextFile()
00922 {
00923 if(mMultiFile)
00924 {
00925 mFileIndex++;
00926 if (mFileIndex < mFileVector.size())
00927 {
00928 getFilePath(mFileIndex);
00929 return mFiles;
00930 }
00931 else
00932 {
00933 mLocked = FALSE;
00934 }
00935 }
00936 return NULL;
00937 }
00938
00939 const char* LLFilePicker::getDirname()
00940 {
00941 if (mFileIndex < mFileVector.size())
00942 {
00943 getFileName(mFileIndex);
00944 return mFilename;
00945 }
00946 return NULL;
00947 }
00948
00949 void LLFilePicker::reset()
00950 {
00951 mLocked = FALSE;
00952 memset( mFiles, 0, FILENAME_BUFFER_SIZE );
00953 memset( mFilename, 0, LL_MAX_PATH );
00954 mCurrentFile = mFiles;
00955
00956 mFileIndex = 0;
00957 mFileVector.clear();
00958 }
00959
00960 #elif LL_LINUX
00961
00962 # if LL_GTK
00963
00964
00965 std::map <std::string, std::string> LLFilePicker::sContextToPathMap;
00966
00967 LLFilePicker::LLFilePicker()
00968 {
00969 reset();
00970 }
00971
00972 LLFilePicker::~LLFilePicker()
00973 {
00974 }
00975
00976
00977 static void add_to_sfs(gpointer data, gpointer user_data)
00978 {
00979 StoreFilenamesStruct *sfs = (StoreFilenamesStruct*) user_data;
00980 gchar* filename_utf8 = g_filename_to_utf8((gchar*)data,
00981 -1, NULL,
00982 NULL,
00983 NULL);
00984 sfs->fileVector.push_back(LLString(filename_utf8));
00985 g_free(filename_utf8);
00986 }
00987
00988
00989 void chooser_responder(GtkWidget *widget,
00990 gint response,
00991 gpointer user_data) {
00992 StoreFilenamesStruct *sfs = (StoreFilenamesStruct*) user_data;
00993
00994 lldebugs << "GTK DIALOG RESPONSE " << response << llendl;
00995
00996 if (response == GTK_RESPONSE_ACCEPT)
00997 {
00998 GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
00999 g_slist_foreach(file_list, (GFunc)add_to_sfs, sfs);
01000 g_slist_foreach(file_list, (GFunc)g_free, NULL);
01001 g_slist_free (file_list);
01002 }
01003
01004
01005 LLFilePicker::sContextToPathMap[sfs->contextName] =
01006 gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget));
01007
01008 gtk_widget_destroy(widget);
01009 gtk_main_quit();
01010 }
01011
01012
01013 GtkWindow* LLFilePicker::buildFilePicker(bool is_save, bool is_folder,
01014 std::string context)
01015 {
01016 if (ll_try_gtk_init() &&
01017 ! gViewerWindow->getWindow()->getFullscreen())
01018 {
01019 GtkWidget *win = NULL;
01020 GtkFileChooserAction pickertype =
01021 is_save?
01022 (is_folder?
01023 GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER :
01024 GTK_FILE_CHOOSER_ACTION_SAVE) :
01025 (is_folder?
01026 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER :
01027 GTK_FILE_CHOOSER_ACTION_OPEN);
01028
01029 win = gtk_file_chooser_dialog_new(NULL, NULL,
01030 pickertype,
01031 GTK_STOCK_CANCEL,
01032 GTK_RESPONSE_CANCEL,
01033 is_folder ?
01034 GTK_STOCK_APPLY :
01035 (is_save ?
01036 GTK_STOCK_SAVE :
01037 GTK_STOCK_OPEN),
01038 GTK_RESPONSE_ACCEPT,
01039 (gchar *)NULL);
01040 mStoreFilenames.win = win;
01041 mStoreFilenames.contextName = context;
01042
01043
01044
01045 std::map<std::string,std::string>::iterator
01046 this_path = sContextToPathMap.find(context);
01047 if (this_path != sContextToPathMap.end())
01048 {
01049 gtk_file_chooser_set_current_folder
01050 (GTK_FILE_CHOOSER(win),
01051 this_path->second.c_str());
01052 }
01053
01054 # if LL_X11
01055
01056
01057
01058 Window XWindowID = get_SDL_XWindowID();
01059 if (None != XWindowID)
01060 {
01061 gtk_widget_realize(GTK_WIDGET(win));
01062 GdkWindow *gdkwin = gdk_window_foreign_new(XWindowID);
01063 gdk_window_set_transient_for(GTK_WIDGET(win)->window,
01064 gdkwin);
01065 }
01066 else
01067 {
01068 llwarns << "Hmm, couldn't get xwid to use for transient." << llendl;
01069 }
01070 # endif //LL_X11
01071
01072 g_signal_connect (GTK_FILE_CHOOSER(win),
01073 "response",
01074 G_CALLBACK(chooser_responder),
01075 &mStoreFilenames);
01076
01077 gtk_window_set_modal(GTK_WINDOW(win), TRUE);
01078
01079
01080
01081
01082
01083 return GTK_WINDOW(win);
01084 }
01085 else
01086 {
01087 return NULL;
01088 }
01089 }
01090
01091 static void add_common_filters_to_gtkchooser(GtkFileFilter *gfilter,
01092 GtkWindow *picker,
01093 std::string filtername)
01094 {
01095 gtk_file_filter_set_name(gfilter, filtername.c_str());
01096 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker),
01097 gfilter);
01098 GtkFileFilter *allfilter = gtk_file_filter_new();
01099 gtk_file_filter_add_pattern(allfilter, "*");
01100 gtk_file_filter_set_name(allfilter, "All Files");
01101 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter);
01102 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter);
01103 }
01104
01105 static std::string add_simple_pattern_filter_to_gtkchooser(GtkWindow *picker,
01106 std::string pattern,
01107 std::string filtername)
01108 {
01109 GtkFileFilter *gfilter = gtk_file_filter_new();
01110 gtk_file_filter_add_pattern(gfilter, pattern.c_str());
01111 add_common_filters_to_gtkchooser(gfilter, picker, filtername);
01112 return filtername;
01113 }
01114
01115 static std::string add_simple_mime_filter_to_gtkchooser(GtkWindow *picker,
01116 std::string mime,
01117 std::string filtername)
01118 {
01119 GtkFileFilter *gfilter = gtk_file_filter_new();
01120 gtk_file_filter_add_mime_type(gfilter, mime.c_str());
01121 add_common_filters_to_gtkchooser(gfilter, picker, filtername);
01122 return filtername;
01123 }
01124
01125 static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker)
01126 {
01127 return add_simple_mime_filter_to_gtkchooser(picker, "audio/x-wav",
01128 "Sounds (*.wav)");
01129 }
01130
01131 static std::string add_bvh_filter_to_gtkchooser(GtkWindow *picker)
01132 {
01133 return add_simple_pattern_filter_to_gtkchooser(picker, "*.bvh",
01134 "Animations (*.bvh)");
01135 }
01136
01137 static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker)
01138 {
01139 GtkFileFilter *gfilter = gtk_file_filter_new();
01140 gtk_file_filter_add_pattern(gfilter, "*.tga");
01141 gtk_file_filter_add_mime_type(gfilter, "image/jpeg");
01142 gtk_file_filter_add_mime_type(gfilter, "image/png");
01143 gtk_file_filter_add_mime_type(gfilter, "image/bmp");
01144 std::string filtername = "Images (*.tga; *.bmp; *.jpg; *.png)";
01145 add_common_filters_to_gtkchooser(gfilter, picker, filtername);
01146 return filtername;
01147 }
01148
01149
01150 BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const char* filename )
01151 {
01152 BOOL rtn = FALSE;
01153
01154 gViewerWindow->mWindow->beforeDialog();
01155
01156 reset();
01157 GtkWindow* picker = buildFilePicker(true, false, "savefile");
01158
01159 if (picker)
01160 {
01161 std::string suggest_name = "untitled";
01162 std::string suggest_ext = "";
01163 std::string caption = "Save ";
01164 switch (filter)
01165 {
01166 case FFSAVE_WAV:
01167 caption += add_wav_filter_to_gtkchooser(picker);
01168 suggest_ext = ".wav";
01169 break;
01170 case FFSAVE_TGA:
01171 caption += add_simple_pattern_filter_to_gtkchooser
01172 (picker, "*.tga", "Targa Images (*.tga)");
01173 suggest_ext = ".tga";
01174 break;
01175 case FFSAVE_BMP:
01176 caption += add_simple_mime_filter_to_gtkchooser
01177 (picker, "image/bmp", "Bitmap Images (*.bmp)");
01178 suggest_ext = ".bmp";
01179 break;
01180 case FFSAVE_AVI:
01181 caption += add_simple_mime_filter_to_gtkchooser
01182 (picker, "video/x-msvideo",
01183 "AVI Movie File (*.avi)");
01184 suggest_ext = ".avi";
01185 break;
01186 case FFSAVE_ANIM:
01187 caption += add_simple_pattern_filter_to_gtkchooser
01188 (picker, "*.xaf", "XAF Anim File (*.xaf)");
01189 suggest_ext = ".xaf";
01190 break;
01191 case FFSAVE_XML:
01192 caption += add_simple_pattern_filter_to_gtkchooser
01193 (picker, "*.xml", "XML File (*.xml)");
01194 suggest_ext = ".xml";
01195 break;
01196 case FFSAVE_RAW:
01197 caption += add_simple_pattern_filter_to_gtkchooser
01198 (picker, "*.raw", "RAW File (*.raw)");
01199 suggest_ext = ".raw";
01200 break;
01201 case FFSAVE_J2C:
01202 caption += add_simple_mime_filter_to_gtkchooser
01203 (picker, "images/jp2",
01204 "Compressed Images (*.j2c)");
01205 suggest_ext = ".j2c";
01206 break;
01207 default:;
01208 break;
01209 }
01210
01211 gtk_window_set_title(GTK_WINDOW(picker), caption.c_str());
01212
01213 if (!filename)
01214 {
01215 suggest_name += suggest_ext;
01216
01217 gtk_file_chooser_set_current_name
01218 (GTK_FILE_CHOOSER(picker),
01219 suggest_name.c_str());
01220 }
01221 else
01222 {
01223 gtk_file_chooser_set_current_name
01224 (GTK_FILE_CHOOSER(picker), filename);
01225 }
01226
01227 gtk_widget_show_all(GTK_WIDGET(picker));
01228 gtk_main();
01229
01230 rtn = (mStoreFilenames.fileVector.size() == 1);
01231 }
01232
01233 gViewerWindow->mWindow->afterDialog();
01234
01235 return rtn;
01236 }
01237
01238 BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
01239 {
01240 BOOL rtn = FALSE;
01241
01242 gViewerWindow->mWindow->beforeDialog();
01243
01244 reset();
01245 GtkWindow* picker = buildFilePicker(false, false, "openfile");
01246
01247 if (picker)
01248 {
01249 std::string caption = "Load ";
01250 std::string filtername = "";
01251 switch (filter)
01252 {
01253 case FFLOAD_WAV:
01254 filtername = add_wav_filter_to_gtkchooser(picker);
01255 break;
01256 case FFLOAD_ANIM:
01257 filtername = add_bvh_filter_to_gtkchooser(picker);
01258 break;
01259 case FFLOAD_IMAGE:
01260 filtername = add_imageload_filter_to_gtkchooser(picker);
01261 break;
01262 default:;
01263 break;
01264 }
01265
01266 caption += filtername;
01267
01268 gtk_window_set_title(GTK_WINDOW(picker), caption.c_str());
01269
01270 gtk_widget_show_all(GTK_WIDGET(picker));
01271 gtk_main();
01272
01273 rtn = (mStoreFilenames.fileVector.size() == 1);
01274 }
01275
01276 gViewerWindow->mWindow->afterDialog();
01277
01278 return rtn;
01279 }
01280
01281 BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
01282 {
01283 BOOL rtn = FALSE;
01284
01285 gViewerWindow->mWindow->beforeDialog();
01286
01287 reset();
01288 GtkWindow* picker = buildFilePicker(false, false, "openfile");
01289
01290 if (picker)
01291 {
01292 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker),
01293 TRUE);
01294
01295 gtk_window_set_title(GTK_WINDOW(picker), "Load Files");
01296
01297 gtk_widget_show_all(GTK_WIDGET(picker));
01298 gtk_main();
01299 rtn = !mStoreFilenames.fileVector.empty();
01300 }
01301
01302 gViewerWindow->mWindow->afterDialog();
01303
01304 return rtn;
01305 }
01306
01307 const char* LLFilePicker::getFirstFile()
01308 {
01309 mNextFileIndex = 0;
01310 return getNextFile();
01311 }
01312
01313 const char* LLFilePicker::getNextFile()
01314 {
01315 if (mStoreFilenames.fileVector.size() > mNextFileIndex)
01316 return mStoreFilenames.fileVector[mNextFileIndex++].c_str();
01317 else
01318 return NULL;
01319 }
01320
01321 const char* LLFilePicker::getDirname()
01322 {
01323
01324 S32 index = mNextFileIndex - 1;
01325 if (index >= 0 && index < (S32)mStoreFilenames.fileVector.size())
01326 {
01327
01328
01329
01330 const char* dirsep = gDirUtilp->getDirDelimiter().c_str();
01331 const char* fullpath = mStoreFilenames.fileVector[index].c_str();
01332 const char* finalpart = NULL;
01333 const char* thispart = fullpath;
01334
01335
01336 do
01337 {
01338 thispart = strstr(thispart, dirsep);
01339 if (NULL != thispart)
01340 finalpart = thispart = &thispart[1];
01341 }
01342 while (NULL != thispart);
01343 return finalpart;
01344 }
01345 else
01346 return NULL;
01347 }
01348
01349 void LLFilePicker::reset()
01350 {
01351 mNextFileIndex = 0;
01352 mStoreFilenames.win = NULL;
01353 mStoreFilenames.fileVector.clear();
01354 }
01355
01356 # else // LL_GTK
01357
01358
01359
01360
01361 static LLString hackyfilename;
01362
01363 LLFilePicker::LLFilePicker()
01364 {
01365 reset();
01366 }
01367
01368 LLFilePicker::~LLFilePicker()
01369 {
01370 }
01371
01372 BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const char* filename )
01373 {
01374 llinfos << "getSaveFile suggested filename is [" << filename
01375 << "]" << llendl;
01376 if (filename && filename[0])
01377 {
01378 hackyfilename.assign(gDirUtilp->getLindenUserDir());
01379 hackyfilename += gDirUtilp->getDirDelimiter();
01380 hackyfilename += filename;
01381 return TRUE;
01382 }
01383 hackyfilename.clear();
01384 return FALSE;
01385 }
01386
01387 BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
01388 {
01389
01390 hackyfilename.assign(gDirUtilp->getLindenUserDir());
01391 hackyfilename += gDirUtilp->getDirDelimiter();
01392 hackyfilename += "upload";
01393 switch (filter)
01394 {
01395 case FFLOAD_WAV: hackyfilename += ".wav"; break;
01396 case FFLOAD_IMAGE: hackyfilename += ".tga"; break;
01397 case FFLOAD_ANIM: hackyfilename += ".bvh"; break;
01398 default: break;
01399 }
01400 llinfos << "getOpenFile: Will try to open file: " << hackyfilename
01401 << llendl;
01402 return TRUE;
01403 }
01404
01405 BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
01406 {
01407 hackyfilename.clear();
01408 return FALSE;
01409 }
01410
01411 const char* LLFilePicker::getFirstFile()
01412 {
01413 if (!hackyfilename.empty())
01414 {
01415 return hackyfilename.c_str();
01416 }
01417 return NULL;
01418 }
01419
01420 const char* LLFilePicker::getNextFile()
01421 {
01422 hackyfilename.clear();
01423 return NULL;
01424 }
01425
01426 const char* LLFilePicker::getDirname()
01427 {
01428 return NULL;
01429 }
01430
01431 void LLFilePicker::reset()
01432 {
01433 }
01434 #endif // LL_GTK
01435
01436 #else // not implemented
01437
01438 LLFilePicker::LLFilePicker()
01439 {
01440 reset();
01441 }
01442
01443 LLFilePicker::~LLFilePicker()
01444 {
01445 }
01446
01447 BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const char* filename )
01448 {
01449 return FALSE;
01450 }
01451
01452 BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
01453 {
01454 return FALSE;
01455 }
01456
01457 BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
01458 {
01459 return FALSE;
01460 }
01461
01462 const char* LLFilePicker::getFirstFile()
01463 {
01464 return NULL;
01465 }
01466
01467 const char* LLFilePicker::getNextFile()
01468 {
01469 return NULL;
01470 }
01471
01472 const char* LLFilePicker::getDirname()
01473 {
01474 return NULL;
01475 }
01476
01477 void LLFilePicker::reset()
01478 {
01479 }
01480
01481 #endif