/indra/newview/llfilepicker.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 1503 lines · 1202 code · 196 blank · 105 comment · 230 complexity · 842e598c8edd91b1a733252295ad36c4 MD5 · raw file

  1. /**
  2. * @file llfilepicker.cpp
  3. * @brief OS-specific file picker
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llfilepicker.h"
  28. #include "llworld.h"
  29. #include "llviewerwindow.h"
  30. #include "llkeyboard.h"
  31. #include "lldir.h"
  32. #include "llframetimer.h"
  33. #include "lltrans.h"
  34. #include "llviewercontrol.h"
  35. #include "llwindow.h" // beforeDialog()
  36. #if LL_SDL
  37. #include "llwindowsdl.h" // for some X/GTK utils to help with filepickers
  38. #endif // LL_SDL
  39. //
  40. // Globals
  41. //
  42. LLFilePicker LLFilePicker::sInstance;
  43. #if LL_WINDOWS
  44. #define SOUND_FILTER L"Sounds (*.wav)\0*.wav\0"
  45. #define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0"
  46. #define ANIM_FILTER L"Animations (*.bvh)\0*.bvh\0"
  47. #define COLLADA_FILTER L"Scene (*.dae)\0*.dae\0"
  48. #ifdef _CORY_TESTING
  49. #define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0"
  50. #endif
  51. #define XML_FILTER L"XML files (*.xml)\0*.xml\0"
  52. #define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0"
  53. #define RAW_FILTER L"RAW files (*.raw)\0*.raw\0"
  54. #define MODEL_FILTER L"Model files (*.dae)\0*.dae\0"
  55. #define SCRIPT_FILTER L"Script files (*.lsl)\0*.lsl\0"
  56. #endif
  57. //
  58. // Implementation
  59. //
  60. LLFilePicker::LLFilePicker()
  61. : mCurrentFile(0),
  62. mLocked(false)
  63. {
  64. reset();
  65. #if LL_WINDOWS
  66. mOFN.lStructSize = sizeof(OPENFILENAMEW);
  67. mOFN.hwndOwner = NULL; // Set later
  68. mOFN.hInstance = NULL;
  69. mOFN.lpstrCustomFilter = NULL;
  70. mOFN.nMaxCustFilter = 0;
  71. mOFN.lpstrFile = NULL; // set in open and close
  72. mOFN.nMaxFile = LL_MAX_PATH;
  73. mOFN.lpstrFileTitle = NULL;
  74. mOFN.nMaxFileTitle = 0;
  75. mOFN.lpstrInitialDir = NULL;
  76. mOFN.lpstrTitle = NULL;
  77. mOFN.Flags = 0; // set in open and close
  78. mOFN.nFileOffset = 0;
  79. mOFN.nFileExtension = 0;
  80. mOFN.lpstrDefExt = NULL;
  81. mOFN.lCustData = 0L;
  82. mOFN.lpfnHook = NULL;
  83. mOFN.lpTemplateName = NULL;
  84. mFilesW[0] = '\0';
  85. #endif
  86. #if LL_DARWIN
  87. memset(&mNavOptions, 0, sizeof(mNavOptions));
  88. OSStatus error = NavGetDefaultDialogCreationOptions(&mNavOptions);
  89. if (error == noErr)
  90. {
  91. mNavOptions.modality = kWindowModalityAppModal;
  92. }
  93. #endif
  94. }
  95. LLFilePicker::~LLFilePicker()
  96. {
  97. // nothing
  98. }
  99. // utility function to check if access to local file system via file browser
  100. // is enabled and if not, tidy up and indicate we're not allowed to do this.
  101. bool LLFilePicker::check_local_file_access_enabled()
  102. {
  103. // if local file browsing is turned off, return without opening dialog
  104. bool local_file_system_browsing_enabled = gSavedSettings.getBOOL("LocalFileSystemBrowsingEnabled");
  105. if ( ! local_file_system_browsing_enabled )
  106. {
  107. mFiles.clear();
  108. return false;
  109. }
  110. return true;
  111. }
  112. const std::string LLFilePicker::getFirstFile()
  113. {
  114. mCurrentFile = 0;
  115. return getNextFile();
  116. }
  117. const std::string LLFilePicker::getNextFile()
  118. {
  119. if (mCurrentFile >= getFileCount())
  120. {
  121. mLocked = false;
  122. return std::string();
  123. }
  124. else
  125. {
  126. return mFiles[mCurrentFile++];
  127. }
  128. }
  129. const std::string LLFilePicker::getCurFile()
  130. {
  131. if (mCurrentFile >= getFileCount())
  132. {
  133. mLocked = false;
  134. return std::string();
  135. }
  136. else
  137. {
  138. return mFiles[mCurrentFile];
  139. }
  140. }
  141. void LLFilePicker::reset()
  142. {
  143. mLocked = false;
  144. mFiles.clear();
  145. mCurrentFile = 0;
  146. }
  147. #if LL_WINDOWS
  148. BOOL LLFilePicker::setupFilter(ELoadFilter filter)
  149. {
  150. BOOL res = TRUE;
  151. switch (filter)
  152. {
  153. case FFLOAD_ALL:
  154. mOFN.lpstrFilter = L"All Files (*.*)\0*.*\0" \
  155. SOUND_FILTER \
  156. IMAGE_FILTER \
  157. ANIM_FILTER \
  158. L"\0";
  159. break;
  160. case FFLOAD_WAV:
  161. mOFN.lpstrFilter = SOUND_FILTER \
  162. L"\0";
  163. break;
  164. case FFLOAD_IMAGE:
  165. mOFN.lpstrFilter = IMAGE_FILTER \
  166. L"\0";
  167. break;
  168. case FFLOAD_ANIM:
  169. mOFN.lpstrFilter = ANIM_FILTER \
  170. L"\0";
  171. break;
  172. case FFLOAD_COLLADA:
  173. mOFN.lpstrFilter = COLLADA_FILTER \
  174. L"\0";
  175. break;
  176. #ifdef _CORY_TESTING
  177. case FFLOAD_GEOMETRY:
  178. mOFN.lpstrFilter = GEOMETRY_FILTER \
  179. L"\0";
  180. break;
  181. #endif
  182. case FFLOAD_XML:
  183. mOFN.lpstrFilter = XML_FILTER \
  184. L"\0";
  185. break;
  186. case FFLOAD_SLOBJECT:
  187. mOFN.lpstrFilter = SLOBJECT_FILTER \
  188. L"\0";
  189. break;
  190. case FFLOAD_RAW:
  191. mOFN.lpstrFilter = RAW_FILTER \
  192. L"\0";
  193. break;
  194. case FFLOAD_MODEL:
  195. mOFN.lpstrFilter = MODEL_FILTER \
  196. L"\0";
  197. break;
  198. case FFLOAD_SCRIPT:
  199. mOFN.lpstrFilter = SCRIPT_FILTER \
  200. L"\0";
  201. break;
  202. default:
  203. res = FALSE;
  204. break;
  205. }
  206. return res;
  207. }
  208. BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking)
  209. {
  210. if( mLocked )
  211. {
  212. return FALSE;
  213. }
  214. BOOL success = FALSE;
  215. // if local file browsing is turned off, return without opening dialog
  216. if ( check_local_file_access_enabled() == false )
  217. {
  218. return FALSE;
  219. }
  220. // don't provide default file selection
  221. mFilesW[0] = '\0';
  222. mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow();
  223. mOFN.lpstrFile = mFilesW;
  224. mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE;
  225. mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR ;
  226. mOFN.nFilterIndex = 1;
  227. setupFilter(filter);
  228. if (blocking)
  229. {
  230. // Modal, so pause agent
  231. send_agent_pause();
  232. }
  233. reset();
  234. // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!!
  235. success = GetOpenFileName(&mOFN);
  236. if (success)
  237. {
  238. std::string filename = utf16str_to_utf8str(llutf16string(mFilesW));
  239. mFiles.push_back(filename);
  240. }
  241. if (blocking)
  242. {
  243. send_agent_resume();
  244. // Account for the fact that the app has been stalled.
  245. LLFrameTimer::updateFrameTime();
  246. }
  247. return success;
  248. }
  249. BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter)
  250. {
  251. if( mLocked )
  252. {
  253. return FALSE;
  254. }
  255. BOOL success = FALSE;
  256. // if local file browsing is turned off, return without opening dialog
  257. if ( check_local_file_access_enabled() == false )
  258. {
  259. return FALSE;
  260. }
  261. // don't provide default file selection
  262. mFilesW[0] = '\0';
  263. mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow();
  264. mOFN.lpstrFile = mFilesW;
  265. mOFN.nFilterIndex = 1;
  266. mOFN.nMaxFile = FILENAME_BUFFER_SIZE;
  267. mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR |
  268. OFN_EXPLORER | OFN_ALLOWMULTISELECT;
  269. setupFilter(filter);
  270. reset();
  271. // Modal, so pause agent
  272. send_agent_pause();
  273. // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!!
  274. success = GetOpenFileName(&mOFN); // pauses until ok or cancel.
  275. if( success )
  276. {
  277. // The getopenfilename api doesn't tell us if we got more than
  278. // one file, so we have to test manually by checking string
  279. // lengths.
  280. if( wcslen(mOFN.lpstrFile) > mOFN.nFileOffset ) /*Flawfinder: ignore*/
  281. {
  282. std::string filename = utf16str_to_utf8str(llutf16string(mFilesW));
  283. mFiles.push_back(filename);
  284. }
  285. else
  286. {
  287. mLocked = true;
  288. WCHAR* tptrw = mFilesW;
  289. std::string dirname;
  290. while(1)
  291. {
  292. if (*tptrw == 0 && *(tptrw+1) == 0) // double '\0'
  293. break;
  294. if (*tptrw == 0)
  295. tptrw++; // shouldn't happen?
  296. std::string filename = utf16str_to_utf8str(llutf16string(tptrw));
  297. if (dirname.empty())
  298. dirname = filename + "\\";
  299. else
  300. mFiles.push_back(dirname + filename);
  301. tptrw += filename.size();
  302. }
  303. }
  304. }
  305. send_agent_resume();
  306. // Account for the fact that the app has been stalled.
  307. LLFrameTimer::updateFrameTime();
  308. return success;
  309. }
  310. BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename)
  311. {
  312. if( mLocked )
  313. {
  314. return FALSE;
  315. }
  316. BOOL success = FALSE;
  317. // if local file browsing is turned off, return without opening dialog
  318. if ( check_local_file_access_enabled() == false )
  319. {
  320. return FALSE;
  321. }
  322. mOFN.lpstrFile = mFilesW;
  323. if (!filename.empty())
  324. {
  325. llutf16string tstring = utf8str_to_utf16str(filename);
  326. wcsncpy(mFilesW, tstring.c_str(), FILENAME_BUFFER_SIZE); } /*Flawfinder: ignore*/
  327. else
  328. {
  329. mFilesW[0] = '\0';
  330. }
  331. mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow();
  332. switch( filter )
  333. {
  334. case FFSAVE_ALL:
  335. mOFN.lpstrDefExt = NULL;
  336. mOFN.lpstrFilter =
  337. L"All Files (*.*)\0*.*\0" \
  338. L"WAV Sounds (*.wav)\0*.wav\0" \
  339. L"Targa, Bitmap Images (*.tga; *.bmp)\0*.tga;*.bmp\0" \
  340. L"\0";
  341. break;
  342. case FFSAVE_WAV:
  343. if (filename.empty())
  344. {
  345. wcsncpy( mFilesW,L"untitled.wav", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
  346. }
  347. mOFN.lpstrDefExt = L"wav";
  348. mOFN.lpstrFilter =
  349. L"WAV Sounds (*.wav)\0*.wav\0" \
  350. L"\0";
  351. break;
  352. case FFSAVE_TGA:
  353. if (filename.empty())
  354. {
  355. wcsncpy( mFilesW,L"untitled.tga", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
  356. }
  357. mOFN.lpstrDefExt = L"tga";
  358. mOFN.lpstrFilter =
  359. L"Targa Images (*.tga)\0*.tga\0" \
  360. L"\0";
  361. break;
  362. case FFSAVE_BMP:
  363. if (filename.empty())
  364. {
  365. wcsncpy( mFilesW,L"untitled.bmp", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
  366. }
  367. mOFN.lpstrDefExt = L"bmp";
  368. mOFN.lpstrFilter =
  369. L"Bitmap Images (*.bmp)\0*.bmp\0" \
  370. L"\0";
  371. break;
  372. case FFSAVE_PNG:
  373. if (filename.empty())
  374. {
  375. wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
  376. }
  377. mOFN.lpstrDefExt = L"png";
  378. mOFN.lpstrFilter =
  379. L"PNG Images (*.png)\0*.png\0" \
  380. L"\0";
  381. break;
  382. case FFSAVE_JPEG:
  383. if (filename.empty())
  384. {
  385. wcsncpy( mFilesW,L"untitled.jpeg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
  386. }
  387. mOFN.lpstrDefExt = L"jpg";
  388. mOFN.lpstrFilter =
  389. L"JPEG Images (*.jpg *.jpeg)\0*.jpg;*.jpeg\0" \
  390. L"\0";
  391. break;
  392. case FFSAVE_AVI:
  393. if (filename.empty())
  394. {
  395. wcsncpy( mFilesW,L"untitled.avi", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
  396. }
  397. mOFN.lpstrDefExt = L"avi";
  398. mOFN.lpstrFilter =
  399. L"AVI Movie File (*.avi)\0*.avi\0" \
  400. L"\0";
  401. break;
  402. case FFSAVE_ANIM:
  403. if (filename.empty())
  404. {
  405. wcsncpy( mFilesW,L"untitled.xaf", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
  406. }
  407. mOFN.lpstrDefExt = L"xaf";
  408. mOFN.lpstrFilter =
  409. L"XAF Anim File (*.xaf)\0*.xaf\0" \
  410. L"\0";
  411. break;
  412. #ifdef _CORY_TESTING
  413. case FFSAVE_GEOMETRY:
  414. if (filename.empty())
  415. {
  416. wcsncpy( mFilesW,L"untitled.slg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
  417. }
  418. mOFN.lpstrDefExt = L"slg";
  419. mOFN.lpstrFilter =
  420. L"SLG SL Geometry File (*.slg)\0*.slg\0" \
  421. L"\0";
  422. break;
  423. #endif
  424. case FFSAVE_XML:
  425. if (filename.empty())
  426. {
  427. wcsncpy( mFilesW,L"untitled.xml", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
  428. }
  429. mOFN.lpstrDefExt = L"xml";
  430. mOFN.lpstrFilter =
  431. L"XML File (*.xml)\0*.xml\0" \
  432. L"\0";
  433. break;
  434. case FFSAVE_COLLADA:
  435. if (filename.empty())
  436. {
  437. wcsncpy( mFilesW,L"untitled.collada", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
  438. }
  439. mOFN.lpstrDefExt = L"collada";
  440. mOFN.lpstrFilter =
  441. L"COLLADA File (*.collada)\0*.collada\0" \
  442. L"\0";
  443. break;
  444. case FFSAVE_RAW:
  445. if (filename.empty())
  446. {
  447. wcsncpy( mFilesW,L"untitled.raw", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
  448. }
  449. mOFN.lpstrDefExt = L"raw";
  450. mOFN.lpstrFilter = RAW_FILTER \
  451. L"\0";
  452. break;
  453. case FFSAVE_J2C:
  454. if (filename.empty())
  455. {
  456. wcsncpy( mFilesW,L"untitled.j2c", FILENAME_BUFFER_SIZE);
  457. }
  458. mOFN.lpstrDefExt = L"j2c";
  459. mOFN.lpstrFilter =
  460. L"Compressed Images (*.j2c)\0*.j2c\0" \
  461. L"\0";
  462. break;
  463. case FFSAVE_SCRIPT:
  464. if (filename.empty())
  465. {
  466. wcsncpy( mFilesW,L"untitled.lsl", FILENAME_BUFFER_SIZE);
  467. }
  468. mOFN.lpstrDefExt = L"txt";
  469. mOFN.lpstrFilter = L"LSL Files (*.lsl)\0*.lsl\0" L"\0";
  470. break;
  471. default:
  472. return FALSE;
  473. }
  474. mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE;
  475. mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
  476. reset();
  477. // Modal, so pause agent
  478. send_agent_pause();
  479. {
  480. // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!!
  481. success = GetSaveFileName(&mOFN);
  482. if (success)
  483. {
  484. std::string filename = utf16str_to_utf8str(llutf16string(mFilesW));
  485. mFiles.push_back(filename);
  486. }
  487. gKeyboard->resetKeys();
  488. }
  489. send_agent_resume();
  490. // Account for the fact that the app has been stalled.
  491. LLFrameTimer::updateFrameTime();
  492. return success;
  493. }
  494. #elif LL_DARWIN
  495. Boolean LLFilePicker::navOpenFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode)
  496. {
  497. Boolean result = true;
  498. ELoadFilter filter = *((ELoadFilter*) callBackUD);
  499. OSStatus error = noErr;
  500. if (filterMode == kNavFilteringBrowserList && filter != FFLOAD_ALL && (theItem->descriptorType == typeFSRef || theItem->descriptorType == typeFSS))
  501. {
  502. // navInfo is only valid for typeFSRef and typeFSS
  503. NavFileOrFolderInfo *navInfo = (NavFileOrFolderInfo*) info;
  504. if (!navInfo->isFolder)
  505. {
  506. AEDesc desc;
  507. error = AECoerceDesc(theItem, typeFSRef, &desc);
  508. if (error == noErr)
  509. {
  510. FSRef fileRef;
  511. error = AEGetDescData(&desc, &fileRef, sizeof(fileRef));
  512. if (error == noErr)
  513. {
  514. LSItemInfoRecord fileInfo;
  515. error = LSCopyItemInfoForRef(&fileRef, kLSRequestExtension | kLSRequestTypeCreator, &fileInfo);
  516. if (error == noErr)
  517. {
  518. if (filter == FFLOAD_IMAGE)
  519. {
  520. if (fileInfo.filetype != 'JPEG' && fileInfo.filetype != 'JPG ' &&
  521. fileInfo.filetype != 'BMP ' && fileInfo.filetype != 'TGA ' &&
  522. fileInfo.filetype != 'BMPf' && fileInfo.filetype != 'TPIC' &&
  523. fileInfo.filetype != 'PNG ' &&
  524. (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("jpeg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
  525. CFStringCompare(fileInfo.extension, CFSTR("jpg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
  526. CFStringCompare(fileInfo.extension, CFSTR("bmp"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
  527. CFStringCompare(fileInfo.extension, CFSTR("tga"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
  528. CFStringCompare(fileInfo.extension, CFSTR("png"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
  529. )
  530. {
  531. result = false;
  532. }
  533. }
  534. else if (filter == FFLOAD_WAV)
  535. {
  536. if (fileInfo.filetype != 'WAVE' && fileInfo.filetype != 'WAV ' &&
  537. (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("wave"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
  538. CFStringCompare(fileInfo.extension, CFSTR("wav"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
  539. )
  540. {
  541. result = false;
  542. }
  543. }
  544. else if (filter == FFLOAD_ANIM)
  545. {
  546. if (fileInfo.filetype != 'BVH ' &&
  547. (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("bvh"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
  548. )
  549. {
  550. result = false;
  551. }
  552. }
  553. else if (filter == FFLOAD_COLLADA)
  554. {
  555. if (fileInfo.filetype != 'DAE ' &&
  556. (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("dae"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
  557. )
  558. {
  559. result = false;
  560. }
  561. }
  562. #ifdef _CORY_TESTING
  563. else if (filter == FFLOAD_GEOMETRY)
  564. {
  565. if (fileInfo.filetype != 'SLG ' &&
  566. (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("slg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
  567. )
  568. {
  569. result = false;
  570. }
  571. }
  572. #endif
  573. else if (filter == FFLOAD_SLOBJECT)
  574. {
  575. llwarns << "*** navOpenFilterProc: FFLOAD_SLOBJECT NOT IMPLEMENTED ***" << llendl;
  576. }
  577. else if (filter == FFLOAD_RAW)
  578. {
  579. if (fileInfo.filetype != '\?\?\?\?' &&
  580. (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("raw"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
  581. )
  582. {
  583. result = false;
  584. }
  585. }
  586. else if (filter == FFLOAD_SCRIPT)
  587. {
  588. if (fileInfo.filetype != 'LSL ' &&
  589. (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("lsl"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) )
  590. {
  591. result = false;
  592. }
  593. }
  594. if (fileInfo.extension)
  595. {
  596. CFRelease(fileInfo.extension);
  597. }
  598. }
  599. }
  600. AEDisposeDesc(&desc);
  601. }
  602. }
  603. }
  604. return result;
  605. }
  606. OSStatus LLFilePicker::doNavChooseDialog(ELoadFilter filter)
  607. {
  608. OSStatus error = noErr;
  609. NavDialogRef navRef = NULL;
  610. NavReplyRecord navReply;
  611. // if local file browsing is turned off, return without opening dialog
  612. if ( check_local_file_access_enabled() == false )
  613. {
  614. return FALSE;
  615. }
  616. memset(&navReply, 0, sizeof(navReply));
  617. // NOTE: we are passing the address of a local variable here.
  618. // This is fine, because the object this call creates will exist for less than the lifetime of this function.
  619. // (It is destroyed by NavDialogDispose() below.)
  620. error = NavCreateChooseFileDialog(&mNavOptions, NULL, NULL, NULL, navOpenFilterProc, (void*)(&filter), &navRef);
  621. gViewerWindow->getWindow()->beforeDialog();
  622. if (error == noErr)
  623. error = NavDialogRun(navRef);
  624. gViewerWindow->getWindow()->afterDialog();
  625. if (error == noErr)
  626. error = NavDialogGetReply(navRef, &navReply);
  627. if (navRef)
  628. NavDialogDispose(navRef);
  629. if (error == noErr && navReply.validRecord)
  630. {
  631. SInt32 count = 0;
  632. SInt32 index;
  633. // AE indexes are 1 based...
  634. error = AECountItems(&navReply.selection, &count);
  635. for (index = 1; index <= count; index++)
  636. {
  637. FSRef fsRef;
  638. AEKeyword theAEKeyword;
  639. DescType typeCode;
  640. Size actualSize = 0;
  641. char path[MAX_PATH]; /*Flawfinder: ignore*/
  642. memset(&fsRef, 0, sizeof(fsRef));
  643. error = AEGetNthPtr(&navReply.selection, index, typeFSRef, &theAEKeyword, &typeCode, &fsRef, sizeof(fsRef), &actualSize);
  644. if (error == noErr)
  645. error = FSRefMakePath(&fsRef, (UInt8*) path, sizeof(path));
  646. if (error == noErr)
  647. mFiles.push_back(std::string(path));
  648. }
  649. }
  650. return error;
  651. }
  652. OSStatus LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filename)
  653. {
  654. OSStatus error = noErr;
  655. NavDialogRef navRef = NULL;
  656. NavReplyRecord navReply;
  657. memset(&navReply, 0, sizeof(navReply));
  658. // Setup the type, creator, and extension
  659. OSType type, creator;
  660. CFStringRef extension = NULL;
  661. switch (filter)
  662. {
  663. case FFSAVE_WAV:
  664. type = 'WAVE';
  665. creator = 'TVOD';
  666. extension = CFSTR(".wav");
  667. break;
  668. case FFSAVE_TGA:
  669. type = 'TPIC';
  670. creator = 'prvw';
  671. extension = CFSTR(".tga");
  672. break;
  673. case FFSAVE_BMP:
  674. type = 'BMPf';
  675. creator = 'prvw';
  676. extension = CFSTR(".bmp");
  677. break;
  678. case FFSAVE_JPEG:
  679. type = 'JPEG';
  680. creator = 'prvw';
  681. extension = CFSTR(".jpeg");
  682. break;
  683. case FFSAVE_PNG:
  684. type = 'PNG ';
  685. creator = 'prvw';
  686. extension = CFSTR(".png");
  687. break;
  688. case FFSAVE_AVI:
  689. type = '\?\?\?\?';
  690. creator = '\?\?\?\?';
  691. extension = CFSTR(".mov");
  692. break;
  693. case FFSAVE_ANIM:
  694. type = '\?\?\?\?';
  695. creator = '\?\?\?\?';
  696. extension = CFSTR(".xaf");
  697. break;
  698. #ifdef _CORY_TESTING
  699. case FFSAVE_GEOMETRY:
  700. type = '\?\?\?\?';
  701. creator = '\?\?\?\?';
  702. extension = CFSTR(".slg");
  703. break;
  704. #endif
  705. case FFSAVE_RAW:
  706. type = '\?\?\?\?';
  707. creator = '\?\?\?\?';
  708. extension = CFSTR(".raw");
  709. break;
  710. case FFSAVE_J2C:
  711. type = '\?\?\?\?';
  712. creator = 'prvw';
  713. extension = CFSTR(".j2c");
  714. break;
  715. case FFSAVE_SCRIPT:
  716. type = 'LSL ';
  717. creator = '\?\?\?\?';
  718. extension = CFSTR(".lsl");
  719. break;
  720. case FFSAVE_ALL:
  721. default:
  722. type = '\?\?\?\?';
  723. creator = '\?\?\?\?';
  724. extension = CFSTR("");
  725. break;
  726. }
  727. // Create the dialog
  728. error = NavCreatePutFileDialog(&mNavOptions, type, creator, NULL, NULL, &navRef);
  729. if (error == noErr)
  730. {
  731. CFStringRef nameString = NULL;
  732. bool hasExtension = true;
  733. // Create a CFString of the initial file name
  734. if (!filename.empty())
  735. nameString = CFStringCreateWithCString(NULL, filename.c_str(), kCFStringEncodingUTF8);
  736. else
  737. nameString = CFSTR("Untitled");
  738. // Add the extension if one was not provided
  739. if (nameString && !CFStringHasSuffix(nameString, extension))
  740. {
  741. CFStringRef tempString = nameString;
  742. hasExtension = false;
  743. nameString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), tempString, extension);
  744. CFRelease(tempString);
  745. }
  746. // Set the name in the dialog
  747. if (nameString)
  748. {
  749. error = NavDialogSetSaveFileName(navRef, nameString);
  750. CFRelease(nameString);
  751. }
  752. else
  753. {
  754. error = paramErr;
  755. }
  756. }
  757. gViewerWindow->getWindow()->beforeDialog();
  758. // Run the dialog
  759. if (error == noErr)
  760. error = NavDialogRun(navRef);
  761. gViewerWindow->getWindow()->afterDialog();
  762. if (error == noErr)
  763. error = NavDialogGetReply(navRef, &navReply);
  764. if (navRef)
  765. NavDialogDispose(navRef);
  766. if (error == noErr && navReply.validRecord)
  767. {
  768. SInt32 count = 0;
  769. // AE indexes are 1 based...
  770. error = AECountItems(&navReply.selection, &count);
  771. if (count > 0)
  772. {
  773. // Get the FSRef to the containing folder
  774. FSRef fsRef;
  775. AEKeyword theAEKeyword;
  776. DescType typeCode;
  777. Size actualSize = 0;
  778. memset(&fsRef, 0, sizeof(fsRef));
  779. error = AEGetNthPtr(&navReply.selection, 1, typeFSRef, &theAEKeyword, &typeCode, &fsRef, sizeof(fsRef), &actualSize);
  780. if (error == noErr)
  781. {
  782. char path[PATH_MAX]; /*Flawfinder: ignore*/
  783. char newFileName[SINGLE_FILENAME_BUFFER_SIZE]; /*Flawfinder: ignore*/
  784. error = FSRefMakePath(&fsRef, (UInt8*)path, PATH_MAX);
  785. if (error == noErr)
  786. {
  787. if (CFStringGetCString(navReply.saveFileName, newFileName, sizeof(newFileName), kCFStringEncodingUTF8))
  788. {
  789. mFiles.push_back(std::string(path) + "/" + std::string(newFileName));
  790. }
  791. else
  792. {
  793. error = paramErr;
  794. }
  795. }
  796. else
  797. {
  798. error = paramErr;
  799. }
  800. }
  801. }
  802. }
  803. return error;
  804. }
  805. BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking)
  806. {
  807. if( mLocked )
  808. return FALSE;
  809. BOOL success = FALSE;
  810. // if local file browsing is turned off, return without opening dialog
  811. if ( check_local_file_access_enabled() == false )
  812. {
  813. return FALSE;
  814. }
  815. OSStatus error = noErr;
  816. reset();
  817. mNavOptions.optionFlags &= ~kNavAllowMultipleFiles;
  818. if(filter == FFLOAD_ALL) // allow application bundles etc. to be traversed; important for DEV-16869, but generally useful
  819. {
  820. // mNavOptions.optionFlags |= kNavAllowOpenPackages;
  821. mNavOptions.optionFlags |= kNavSupportPackages;
  822. }
  823. if (blocking)
  824. {
  825. // Modal, so pause agent
  826. send_agent_pause();
  827. }
  828. {
  829. error = doNavChooseDialog(filter);
  830. }
  831. if (error == noErr)
  832. {
  833. if (getFileCount())
  834. success = true;
  835. }
  836. if (blocking)
  837. {
  838. send_agent_resume();
  839. // Account for the fact that the app has been stalled.
  840. LLFrameTimer::updateFrameTime();
  841. }
  842. return success;
  843. }
  844. BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter)
  845. {
  846. if( mLocked )
  847. return FALSE;
  848. BOOL success = FALSE;
  849. // if local file browsing is turned off, return without opening dialog
  850. if ( check_local_file_access_enabled() == false )
  851. {
  852. return FALSE;
  853. }
  854. OSStatus error = noErr;
  855. reset();
  856. mNavOptions.optionFlags |= kNavAllowMultipleFiles;
  857. // Modal, so pause agent
  858. send_agent_pause();
  859. {
  860. error = doNavChooseDialog(filter);
  861. }
  862. send_agent_resume();
  863. if (error == noErr)
  864. {
  865. if (getFileCount())
  866. success = true;
  867. if (getFileCount() > 1)
  868. mLocked = true;
  869. }
  870. // Account for the fact that the app has been stalled.
  871. LLFrameTimer::updateFrameTime();
  872. return success;
  873. }
  874. BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename)
  875. {
  876. if( mLocked )
  877. return FALSE;
  878. BOOL success = FALSE;
  879. OSStatus error = noErr;
  880. // if local file browsing is turned off, return without opening dialog
  881. if ( check_local_file_access_enabled() == false )
  882. {
  883. return FALSE;
  884. }
  885. reset();
  886. mNavOptions.optionFlags &= ~kNavAllowMultipleFiles;
  887. // Modal, so pause agent
  888. send_agent_pause();
  889. {
  890. error = doNavSaveDialog(filter, filename);
  891. }
  892. send_agent_resume();
  893. if (error == noErr)
  894. {
  895. if (getFileCount())
  896. success = true;
  897. }
  898. // Account for the fact that the app has been stalled.
  899. LLFrameTimer::updateFrameTime();
  900. return success;
  901. }
  902. #elif LL_LINUX || LL_SOLARIS
  903. # if LL_GTK
  904. // static
  905. void LLFilePicker::add_to_selectedfiles(gpointer data, gpointer user_data)
  906. {
  907. // We need to run g_filename_to_utf8 in the user's locale
  908. std::string saved_locale(setlocale(LC_ALL, NULL));
  909. setlocale(LC_ALL, "");
  910. LLFilePicker* picker = (LLFilePicker*) user_data;
  911. GError *error = NULL;
  912. gchar* filename_utf8 = g_filename_to_utf8((gchar*)data,
  913. -1, NULL, NULL, &error);
  914. if (error)
  915. {
  916. // *FIXME.
  917. // This condition should really be notified to the user, e.g.
  918. // through a message box. Just logging it is inappropriate.
  919. // g_filename_display_name is ideal, but >= glib 2.6, so:
  920. // a hand-rolled hacky makeASCII which disallows control chars
  921. std::string display_name;
  922. for (const gchar *str = (const gchar *)data; *str; str++)
  923. {
  924. display_name += (char)((*str >= 0x20 && *str <= 0x7E) ? *str : '?');
  925. }
  926. llwarns << "g_filename_to_utf8 failed on \"" << display_name << "\": " << error->message << llendl;
  927. }
  928. if (filename_utf8)
  929. {
  930. picker->mFiles.push_back(std::string(filename_utf8));
  931. lldebugs << "ADDED FILE " << filename_utf8 << llendl;
  932. g_free(filename_utf8);
  933. }
  934. setlocale(LC_ALL, saved_locale.c_str());
  935. }
  936. // static
  937. void LLFilePicker::chooser_responder(GtkWidget *widget, gint response, gpointer user_data)
  938. {
  939. LLFilePicker* picker = (LLFilePicker*)user_data;
  940. lldebugs << "GTK DIALOG RESPONSE " << response << llendl;
  941. if (response == GTK_RESPONSE_ACCEPT)
  942. {
  943. GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
  944. g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, user_data);
  945. g_slist_foreach(file_list, (GFunc)g_free, NULL);
  946. g_slist_free (file_list);
  947. }
  948. // set the default path for this usage context.
  949. picker->mContextToPathMap[picker->mCurContextName] =
  950. gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget));
  951. gtk_widget_destroy(widget);
  952. gtk_main_quit();
  953. }
  954. GtkWindow* LLFilePicker::buildFilePicker(bool is_save, bool is_folder, std::string context)
  955. {
  956. if (LLWindowSDL::ll_try_gtk_init())
  957. {
  958. GtkWidget *win = NULL;
  959. GtkFileChooserAction pickertype =
  960. is_save?
  961. (is_folder?
  962. GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER :
  963. GTK_FILE_CHOOSER_ACTION_SAVE) :
  964. (is_folder?
  965. GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER :
  966. GTK_FILE_CHOOSER_ACTION_OPEN);
  967. win = gtk_file_chooser_dialog_new(NULL, NULL,
  968. pickertype,
  969. GTK_STOCK_CANCEL,
  970. GTK_RESPONSE_CANCEL,
  971. is_folder ?
  972. GTK_STOCK_APPLY :
  973. (is_save ?
  974. GTK_STOCK_SAVE :
  975. GTK_STOCK_OPEN),
  976. GTK_RESPONSE_ACCEPT,
  977. (gchar *)NULL);
  978. mCurContextName = context;
  979. // get the default path for this usage context if it's been
  980. // seen before.
  981. std::map<std::string,std::string>::iterator
  982. this_path = mContextToPathMap.find(context);
  983. if (this_path != mContextToPathMap.end())
  984. {
  985. gtk_file_chooser_set_current_folder
  986. (GTK_FILE_CHOOSER(win),
  987. this_path->second.c_str());
  988. }
  989. # if LL_X11
  990. // Make GTK tell the window manager to associate this
  991. // dialog with our non-GTK raw X11 window, which should try
  992. // to keep it on top etc.
  993. Window XWindowID = LLWindowSDL::get_SDL_XWindowID();
  994. if (None != XWindowID)
  995. {
  996. gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin
  997. GdkWindow *gdkwin = gdk_window_foreign_new(XWindowID);
  998. gdk_window_set_transient_for(GTK_WIDGET(win)->window,
  999. gdkwin);
  1000. }
  1001. else
  1002. {
  1003. llwarns << "Hmm, couldn't get xwid to use for transient." << llendl;
  1004. }
  1005. # endif //LL_X11
  1006. g_signal_connect (GTK_FILE_CHOOSER(win),
  1007. "response",
  1008. G_CALLBACK(LLFilePicker::chooser_responder),
  1009. this);
  1010. gtk_window_set_modal(GTK_WINDOW(win), TRUE);
  1011. /* GTK 2.6: if (is_folder)
  1012. gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win),
  1013. TRUE); */
  1014. return GTK_WINDOW(win);
  1015. }
  1016. else
  1017. {
  1018. return NULL;
  1019. }
  1020. }
  1021. static void add_common_filters_to_gtkchooser(GtkFileFilter *gfilter,
  1022. GtkWindow *picker,
  1023. std::string filtername)
  1024. {
  1025. gtk_file_filter_set_name(gfilter, filtername.c_str());
  1026. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker),
  1027. gfilter);
  1028. GtkFileFilter *allfilter = gtk_file_filter_new();
  1029. gtk_file_filter_add_pattern(allfilter, "*");
  1030. gtk_file_filter_set_name(allfilter, LLTrans::getString("all_files").c_str());
  1031. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter);
  1032. gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter);
  1033. }
  1034. static std::string add_simple_pattern_filter_to_gtkchooser(GtkWindow *picker,
  1035. std::string pattern,
  1036. std::string filtername)
  1037. {
  1038. GtkFileFilter *gfilter = gtk_file_filter_new();
  1039. gtk_file_filter_add_pattern(gfilter, pattern.c_str());
  1040. add_common_filters_to_gtkchooser(gfilter, picker, filtername);
  1041. return filtername;
  1042. }
  1043. static std::string add_simple_mime_filter_to_gtkchooser(GtkWindow *picker,
  1044. std::string mime,
  1045. std::string filtername)
  1046. {
  1047. GtkFileFilter *gfilter = gtk_file_filter_new();
  1048. gtk_file_filter_add_mime_type(gfilter, mime.c_str());
  1049. add_common_filters_to_gtkchooser(gfilter, picker, filtername);
  1050. return filtername;
  1051. }
  1052. static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker)
  1053. {
  1054. return add_simple_mime_filter_to_gtkchooser(picker, "audio/x-wav",
  1055. LLTrans::getString("sound_files") + " (*.wav)");
  1056. }
  1057. static std::string add_bvh_filter_to_gtkchooser(GtkWindow *picker)
  1058. {
  1059. return add_simple_pattern_filter_to_gtkchooser(picker, "*.bvh",
  1060. LLTrans::getString("animation_files") + " (*.bvh)");
  1061. }
  1062. static std::string add_collada_filter_to_gtkchooser(GtkWindow *picker)
  1063. {
  1064. return add_simple_pattern_filter_to_gtkchooser(picker, "*.dae",
  1065. LLTrans::getString("scene_files") + " (*.dae)");
  1066. }
  1067. static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker)
  1068. {
  1069. GtkFileFilter *gfilter = gtk_file_filter_new();
  1070. gtk_file_filter_add_pattern(gfilter, "*.tga");
  1071. gtk_file_filter_add_mime_type(gfilter, "image/jpeg");
  1072. gtk_file_filter_add_mime_type(gfilter, "image/png");
  1073. gtk_file_filter_add_mime_type(gfilter, "image/bmp");
  1074. std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)";
  1075. add_common_filters_to_gtkchooser(gfilter, picker, filtername);
  1076. return filtername;
  1077. }
  1078. static std::string add_script_filter_to_gtkchooser(GtkWindow *picker)
  1079. {
  1080. return add_simple_mime_filter_to_gtkchooser(picker, "text/plain",
  1081. LLTrans::getString("script_files") + " (*.lsl)");
  1082. }
  1083. BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename )
  1084. {
  1085. BOOL rtn = FALSE;
  1086. // if local file browsing is turned off, return without opening dialog
  1087. if ( check_local_file_access_enabled() == false )
  1088. {
  1089. return FALSE;
  1090. }
  1091. gViewerWindow->getWindow()->beforeDialog();
  1092. reset();
  1093. GtkWindow* picker = buildFilePicker(true, false, "savefile");
  1094. if (picker)
  1095. {
  1096. std::string suggest_name = "untitled";
  1097. std::string suggest_ext = "";
  1098. std::string caption = LLTrans::getString("save_file_verb") + " ";
  1099. switch (filter)
  1100. {
  1101. case FFSAVE_WAV:
  1102. caption += add_wav_filter_to_gtkchooser(picker);
  1103. suggest_ext = ".wav";
  1104. break;
  1105. case FFSAVE_TGA:
  1106. caption += add_simple_pattern_filter_to_gtkchooser
  1107. (picker, "*.tga", LLTrans::getString("targa_image_files") + " (*.tga)");
  1108. suggest_ext = ".tga";
  1109. break;
  1110. case FFSAVE_BMP:
  1111. caption += add_simple_mime_filter_to_gtkchooser
  1112. (picker, "image/bmp", LLTrans::getString("bitmap_image_files") + " (*.bmp)");
  1113. suggest_ext = ".bmp";
  1114. break;
  1115. case FFSAVE_AVI:
  1116. caption += add_simple_mime_filter_to_gtkchooser
  1117. (picker, "video/x-msvideo",
  1118. LLTrans::getString("avi_movie_file") + " (*.avi)");
  1119. suggest_ext = ".avi";
  1120. break;
  1121. case FFSAVE_ANIM:
  1122. caption += add_simple_pattern_filter_to_gtkchooser
  1123. (picker, "*.xaf", LLTrans::getString("xaf_animation_file") + " (*.xaf)");
  1124. suggest_ext = ".xaf";
  1125. break;
  1126. case FFSAVE_XML:
  1127. caption += add_simple_pattern_filter_to_gtkchooser
  1128. (picker, "*.xml", LLTrans::getString("xml_file") + " (*.xml)");
  1129. suggest_ext = ".xml";
  1130. break;
  1131. case FFSAVE_RAW:
  1132. caption += add_simple_pattern_filter_to_gtkchooser
  1133. (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)");
  1134. suggest_ext = ".raw";
  1135. break;
  1136. case FFSAVE_J2C:
  1137. caption += add_simple_mime_filter_to_gtkchooser
  1138. (picker, "images/jp2",
  1139. LLTrans::getString("compressed_image_files") + " (*.j2c)");
  1140. suggest_ext = ".j2c";
  1141. break;
  1142. case FFSAVE_SCRIPT:
  1143. caption += add_script_filter_to_gtkchooser(picker);
  1144. suggest_ext = ".lsl";
  1145. break;
  1146. default:;
  1147. break;
  1148. }
  1149. gtk_window_set_title(GTK_WINDOW(picker), caption.c_str());
  1150. if (filename.empty())
  1151. {
  1152. suggest_name += suggest_ext;
  1153. gtk_file_chooser_set_current_name
  1154. (GTK_FILE_CHOOSER(picker),
  1155. suggest_name.c_str());
  1156. }
  1157. else
  1158. {
  1159. gtk_file_chooser_set_current_name
  1160. (GTK_FILE_CHOOSER(picker), filename.c_str());
  1161. }
  1162. gtk_widget_show_all(GTK_WIDGET(picker));
  1163. gtk_main();
  1164. rtn = (getFileCount() == 1);
  1165. }
  1166. gViewerWindow->getWindow()->afterDialog();
  1167. return rtn;
  1168. }
  1169. BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking )
  1170. {
  1171. BOOL rtn = FALSE;
  1172. // if local file browsing is turned off, return without opening dialog
  1173. if ( check_local_file_access_enabled() == false )
  1174. {
  1175. return FALSE;
  1176. }
  1177. gViewerWindow->getWindow()->beforeDialog();
  1178. reset();
  1179. GtkWindow* picker = buildFilePicker(false, false, "openfile");
  1180. if (picker)
  1181. {
  1182. std::string caption = LLTrans::getString("load_file_verb") + " ";
  1183. std::string filtername = "";
  1184. switch (filter)
  1185. {
  1186. case FFLOAD_WAV:
  1187. filtername = add_wav_filter_to_gtkchooser(picker);
  1188. break;
  1189. case FFLOAD_ANIM:
  1190. filtername = add_bvh_filter_to_gtkchooser(picker);
  1191. break;
  1192. case FFLOAD_COLLADA:
  1193. filtername = add_collada_filter_to_gtkchooser(picker);
  1194. break;
  1195. case FFLOAD_IMAGE:
  1196. filtername = add_imageload_filter_to_gtkchooser(picker);
  1197. break;
  1198. case FFLOAD_SCRIPT:
  1199. filtername = add_script_filter_to_gtkchooser(picker);
  1200. break;
  1201. default:;
  1202. break;
  1203. }
  1204. caption += filtername;
  1205. gtk_window_set_title(GTK_WINDOW(picker), caption.c_str());
  1206. gtk_widget_show_all(GTK_WIDGET(picker));
  1207. gtk_main();
  1208. rtn = (getFileCount() == 1);
  1209. }
  1210. gViewerWindow->getWindow()->afterDialog();
  1211. return rtn;
  1212. }
  1213. BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
  1214. {
  1215. BOOL rtn = FALSE;
  1216. // if local file browsing is turned off, return without opening dialog
  1217. if ( check_local_file_access_enabled() == false )
  1218. {
  1219. return FALSE;
  1220. }
  1221. gViewerWindow->getWindow()->beforeDialog();
  1222. reset();
  1223. GtkWindow* picker = buildFilePicker(false, false, "openfile");
  1224. if (picker)
  1225. {
  1226. gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker),
  1227. TRUE);
  1228. gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str());
  1229. gtk_widget_show_all(GTK_WIDGET(picker));
  1230. gtk_main();
  1231. rtn = !mFiles.empty();
  1232. }
  1233. gViewerWindow->getWindow()->afterDialog();
  1234. return rtn;
  1235. }
  1236. # else // LL_GTK
  1237. // Hacky stubs designed to facilitate fake getSaveFile and getOpenFile with
  1238. // static results, when we don't have a real filepicker.
  1239. BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename )
  1240. {
  1241. // if local file browsing is turned off, return without opening dialog
  1242. // (Even though this is a stub, I think we still should not return anything at all)
  1243. if ( check_local_file_access_enabled() == false )
  1244. {
  1245. return FALSE;
  1246. }
  1247. reset();
  1248. llinfos << "getSaveFile suggested filename is [" << filename
  1249. << "]" << llendl;
  1250. if (!filename.empty())
  1251. {
  1252. mFiles.push_back(gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + filename);
  1253. return TRUE;
  1254. }
  1255. return FALSE;
  1256. }
  1257. BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
  1258. {
  1259. // if local file browsing is turned off, return without opening dialog
  1260. // (Even though this is a stub, I think we still should not return anything at all)
  1261. if ( check_local_file_access_enabled() == false )
  1262. {
  1263. return FALSE;
  1264. }
  1265. reset();
  1266. // HACK: Static filenames for 'open' until we implement filepicker
  1267. std::string filename = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + "upload";
  1268. switch (filter)
  1269. {
  1270. case FFLOAD_WAV: filename += ".wav"; break;
  1271. case FFLOAD_IMAGE: filename += ".tga"; break;
  1272. case FFLOAD_ANIM: filename += ".bvh"; break;
  1273. default: break;
  1274. }
  1275. mFiles.push_back(filename);
  1276. llinfos << "getOpenFile: Will try to open file: " << hackyfilename << llendl;
  1277. return TRUE;
  1278. }
  1279. BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
  1280. {
  1281. // if local file browsing is turned off, return without opening dialog
  1282. // (Even though this is a stub, I think we still should not return anything at all)
  1283. if ( check_local_file_access_enabled() == false )
  1284. {
  1285. return FALSE;
  1286. }
  1287. reset();
  1288. return FALSE;
  1289. }
  1290. #endif // LL_GTK
  1291. #else // not implemented
  1292. BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename )
  1293. {
  1294. reset();
  1295. return FALSE;
  1296. }
  1297. BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
  1298. {
  1299. reset();
  1300. return FALSE;
  1301. }
  1302. BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
  1303. {
  1304. reset();
  1305. return FALSE;
  1306. }
  1307. #endif