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