aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llfilepicker.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llfilepicker.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llfilepicker.cpp')
-rw-r--r--linden/indra/newview/llfilepicker.cpp1358
1 files changed, 1358 insertions, 0 deletions
diff --git a/linden/indra/newview/llfilepicker.cpp b/linden/indra/newview/llfilepicker.cpp
new file mode 100644
index 0000000..6b56df6
--- /dev/null
+++ b/linden/indra/newview/llfilepicker.cpp
@@ -0,0 +1,1358 @@
1/**
2 * @file llfilepicker.cpp
3 * @brief OS-specific file picker
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include "llfilepicker.h"
31//#include "viewer.h"
32//#include "llviewermessage.h"
33#include "llworld.h"
34#include "llviewerwindow.h"
35#include "llkeyboard.h"
36#include "lldir.h"
37#include "llframetimer.h"
38
39//
40// Globals
41//
42
43LLFilePicker LLFilePicker::sInstance;
44
45#if LL_WINDOWS
46#define SOUND_FILTER L"Sounds (*.wav)\0*.wav\0"
47#define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg)\0*.tga;*.bmp;*.jpg;*.jpeg\0"
48#define ANIM_FILTER L"Animations (*.bvh)\0*.bvh\0"
49#ifdef _CORY_TESTING
50#define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0"
51#endif
52#define XML_FILTER L"XML files (*.xml)\0*.xml\0"
53#define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0"
54#define RAW_FILTER L"RAW files (*.raw)\0*.raw\0"
55#endif
56
57//
58// Implementation
59//
60#if LL_WINDOWS
61
62LLFilePicker::LLFilePicker()
63{
64 reset();
65
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}
85
86LLFilePicker::~LLFilePicker()
87{
88 // nothing
89}
90
91BOOL LLFilePicker::setupFilter(ELoadFilter filter)
92{
93 BOOL res = TRUE;
94 switch (filter)
95 {
96 case FFLOAD_ALL:
97 mOFN.lpstrFilter = L"All Files (*.*)\0*.*\0" \
98 SOUND_FILTER \
99 IMAGE_FILTER \
100 ANIM_FILTER \
101 L"\0";
102 break;
103 case FFLOAD_WAV:
104 mOFN.lpstrFilter = SOUND_FILTER \
105 L"\0";
106 break;
107 case FFLOAD_IMAGE:
108 mOFN.lpstrFilter = IMAGE_FILTER \
109 L"\0";
110 break;
111 case FFLOAD_ANIM:
112 mOFN.lpstrFilter = ANIM_FILTER \
113 L"\0";
114 break;
115#ifdef _CORY_TESTING
116 case FFLOAD_GEOMETRY:
117 mOFN.lpstrFilter = GEOMETRY_FILTER \
118 L"\0";
119 break;
120#endif
121 case FFLOAD_XML:
122 mOFN.lpstrFilter = XML_FILTER \
123 L"\0";
124 break;
125 case FFLOAD_SLOBJECT:
126 mOFN.lpstrFilter = SLOBJECT_FILTER \
127 L"\0";
128 break;
129 case FFLOAD_RAW:
130 mOFN.lpstrFilter = RAW_FILTER \
131 L"\0";
132 break;
133 default:
134 res = FALSE;
135 break;
136 }
137 return res;
138}
139
140BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
141{
142 if( mLocked )
143 {
144 return FALSE;
145 }
146 BOOL success = FALSE;
147 mMultiFile = FALSE;
148
149 // don't provide default file selection
150 mFilesW[0] = '\0';
151
152 mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow();
153 mOFN.lpstrFile = mFilesW;
154 mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE;
155 mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR ;
156 mOFN.nFilterIndex = 1;
157
158 setupFilter(filter);
159
160 // Modal, so pause agent
161 send_agent_pause();
162 // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!!
163 success = GetOpenFileName(&mOFN);
164 if (success)
165 {
166 LLString tstr = utf16str_to_utf8str(llutf16string(mFilesW));
167 memcpy(mFiles, tstr.c_str(), tstr.size()+1);
168 mCurrentFile = mFiles;
169 }
170 send_agent_resume();
171
172 // Account for the fact that the app has been stalled.
173 LLFrameTimer::updateFrameTime();
174 return success;
175}
176
177BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter)
178{
179 if( mLocked )
180 {
181 return FALSE;
182 }
183 BOOL success = FALSE;
184 mMultiFile = FALSE;
185
186 // don't provide default file selection
187 mFilesW[0] = '\0';
188
189 mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow();
190 mOFN.lpstrFile = mFilesW;
191 mOFN.nFilterIndex = 1;
192 mOFN.nMaxFile = FILENAME_BUFFER_SIZE;
193 mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR |
194 OFN_EXPLORER | OFN_ALLOWMULTISELECT;
195
196 setupFilter(filter);
197
198 // Modal, so pause agent
199 send_agent_pause();
200 // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!!
201 success = GetOpenFileName(&mOFN); // pauses until ok or cancel.
202 if( success )
203 {
204 // The getopenfilename api doesn't tell us if we got more than
205 // one file, so we have to test manually by checking string
206 // lengths.
207 if( wcslen(mOFN.lpstrFile) > mOFN.nFileOffset )
208 {
209 mMultiFile = FALSE;
210 mCurrentFile = mFiles;
211 LLString tstr = utf16str_to_utf8str(llutf16string(mFilesW));
212 memcpy(mFiles, tstr.c_str(), tstr.size()+1);
213 }
214 else
215 {
216 mMultiFile = TRUE;
217 mCurrentFile = 0;
218 mLocked = TRUE;
219 WCHAR* tptrw = mFilesW;
220 char* tptr = mFiles;
221 memset( mFiles, 0, FILENAME_BUFFER_SIZE );
222 while(1)
223 {
224 if (*tptrw == 0 && *(tptrw+1) == 0) // double '\0'
225 break;
226 if (*tptrw == 0 && !mCurrentFile)
227 mCurrentFile = tptr+1;
228 S32 tlen16,tlen8;
229 tlen16 = utf16chars_to_utf8chars(tptrw, tptr, &tlen8);
230 tptrw += tlen16;
231 tptr += tlen8;
232 }
233 }
234 }
235 send_agent_resume();
236
237 // Account for the fact that the app has been stalled.
238 LLFrameTimer::updateFrameTime();
239 return success;
240}
241
242BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const char* filename)
243{
244 if( mLocked )
245 {
246 return FALSE;
247 }
248 BOOL success = FALSE;
249 mMultiFile = FALSE;
250
251 mOFN.lpstrFile = mFilesW;
252 if (filename)
253 {
254 llutf16string tstring = utf8str_to_utf16str(filename);
255 wcsncpy(mFilesW, tstring.c_str(), FILENAME_BUFFER_SIZE); }
256 else
257 {
258 mFilesW[0] = '\0';
259 }
260 mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow();
261
262 switch( filter )
263 {
264 case FFSAVE_ALL:
265 mOFN.lpstrDefExt = NULL;
266 mOFN.lpstrFilter =
267 L"All Files (*.*)\0*.*\0" \
268 L"WAV Sounds (*.wav)\0*.wav\0" \
269 L"Targa, Bitmap Images (*.tga; *.bmp)\0*.tga;*.bmp\0" \
270 L"\0";
271 break;
272 case FFSAVE_WAV:
273 if (!filename)
274 {
275 wcsncpy( mFilesW,L"untitled.wav", FILENAME_BUFFER_SIZE);
276 }
277 mOFN.lpstrDefExt = L"wav";
278 L"WAV Sounds (*.wav)\0*.wav\0" \
279 L"\0";
280 break;
281 case FFSAVE_TGA:
282 if (!filename)
283 {
284 wcsncpy( mFilesW,L"untitled.tga", FILENAME_BUFFER_SIZE);
285 }
286 mOFN.lpstrDefExt = L"tga";
287 mOFN.lpstrFilter =
288 L"Targa Images (*.tga)\0*.tga\0" \
289 L"\0";
290 break;
291 case FFSAVE_BMP:
292 if (!filename)
293 {
294 wcsncpy( mFilesW,L"untitled.bmp", FILENAME_BUFFER_SIZE);
295 }
296 mOFN.lpstrDefExt = L"bmp";
297 mOFN.lpstrFilter =
298 L"Bitmap Images (*.bmp)\0*.bmp\0" \
299 L"\0";
300 break;
301 case FFSAVE_AVI:
302 if (!filename)
303 {
304 wcsncpy( mFilesW,L"untitled.avi", FILENAME_BUFFER_SIZE);
305 }
306 mOFN.lpstrDefExt = L"avi";
307 mOFN.lpstrFilter =
308 L"AVI Movie File (*.avi)\0*.avi\0" \
309 L"\0";
310 break;
311 case FFSAVE_ANIM:
312 if (!filename)
313 {
314 wcsncpy( mFilesW,L"untitled.xaf", FILENAME_BUFFER_SIZE);
315 }
316 mOFN.lpstrDefExt = L"xaf";
317 mOFN.lpstrFilter =
318 L"XAF Anim File (*.xaf)\0*.xaf\0" \
319 L"\0";
320 break;
321#ifdef _CORY_TESTING
322 case FFSAVE_GEOMETRY:
323 if (!filename)
324 {
325 wcsncpy( mFilesW,L"untitled.slg", FILENAME_BUFFER_SIZE);
326 }
327 mOFN.lpstrDefExt = L"slg";
328 mOFN.lpstrFilter =
329 L"SLG SL Geometry File (*.slg)\0*.slg\0" \
330 L"\0";
331 break;
332#endif
333 case FFSAVE_XML:
334 if (!filename)
335 {
336 wcsncpy( mFilesW,L"untitled.xml", FILENAME_BUFFER_SIZE);
337 }
338
339 mOFN.lpstrDefExt = L"xml";
340 mOFN.lpstrFilter =
341 L"XML File (*.xml)\0*.xml\0" \
342 L"\0";
343 break;
344 case FFSAVE_COLLADA:
345 if (!filename)
346 {
347 wcsncpy( mFilesW,L"untitled.collada", FILENAME_BUFFER_SIZE);
348 }
349 mOFN.lpstrDefExt = L"collada";
350 mOFN.lpstrFilter =
351 L"COLLADA File (*.collada)\0*.collada\0" \
352 L"\0";
353 break;
354 case FFSAVE_RAW:
355 if (!filename)
356 {
357 wcsncpy( mFilesW,L"untitled.raw", FILENAME_BUFFER_SIZE);
358 }
359 mOFN.lpstrDefExt = L"raw";
360 mOFN.lpstrFilter = RAW_FILTER \
361 L"\0";
362 break;
363 default:
364 return FALSE;
365 }
366
367
368 mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE;
369 mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
370
371 // Modal, so pause agent
372 send_agent_pause();
373 {
374 // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!!
375 success = GetSaveFileName(&mOFN);
376 if (success)
377 {
378 LLString tstr = utf16str_to_utf8str(llutf16string(mFilesW));
379 memcpy(mFiles, tstr.c_str(), tstr.size()+1);
380 mCurrentFile = mFiles;
381 }
382 gKeyboard->resetKeys();
383 }
384 send_agent_resume();
385
386 // Account for the fact that the app has been stalled.
387 LLFrameTimer::updateFrameTime();
388 return success;
389}
390
391const char* LLFilePicker::getFirstFile()
392{
393 if(mMultiFile)
394 {
395 buildFilename();
396 return mFilename;
397 }
398 return mFiles;
399}
400
401const char* LLFilePicker::getNextFile()
402{
403 if(mMultiFile)
404 {
405 mCurrentFile += strlen(mCurrentFile) + 1;
406 if( '\0' != mCurrentFile[0] )
407 {
408 buildFilename();
409 return mFilename;
410 }
411 else
412 {
413 mLocked = FALSE;
414 }
415 }
416 return NULL;
417}
418
419const char* LLFilePicker::getDirname()
420{
421 if( '\0' != mCurrentFile[0] )
422 {
423 return mCurrentFile;
424 }
425 return NULL;
426}
427
428void LLFilePicker::reset()
429{
430 mLocked = FALSE;
431 memset( mFiles, 0, FILENAME_BUFFER_SIZE );
432 memset( mFilename, 0, LL_MAX_PATH );
433 mCurrentFile = mFiles;
434}
435
436void LLFilePicker::buildFilename( void )
437{
438 strncpy( mFilename, mFiles, LL_MAX_PATH );
439 S32 len = strlen( mFilename );
440
441 strcat(mFilename,gDirUtilp->getDirDelimiter().c_str());
442 len += strlen(gDirUtilp->getDirDelimiter().c_str());
443
444// mFilename[len++] = '\\';
445 LLString::copy( mFilename + len, mCurrentFile, LL_MAX_PATH - len );
446}
447
448#elif LL_DARWIN
449
450LLFilePicker::LLFilePicker()
451{
452 reset();
453
454 memset(&mNavOptions, 0, sizeof(mNavOptions));
455 OSStatus error = NavGetDefaultDialogCreationOptions(&mNavOptions);
456 if (error == noErr)
457 {
458 mNavOptions.modality = kWindowModalityAppModal;
459 }
460 mFileIndex = 0;
461}
462
463LLFilePicker::~LLFilePicker()
464{
465 // nothing
466}
467
468Boolean LLFilePicker::navOpenFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode)
469{
470 Boolean result = true;
471 ELoadFilter filter = *((ELoadFilter*) callBackUD);
472 OSStatus error = noErr;
473
474 if (filterMode == kNavFilteringBrowserList && filter != FFLOAD_ALL && (theItem->descriptorType == typeFSRef || theItem->descriptorType == typeFSS))
475 {
476 // navInfo is only valid for typeFSRef and typeFSS
477 NavFileOrFolderInfo *navInfo = (NavFileOrFolderInfo*) info;
478 if (!navInfo->isFolder)
479 {
480 AEDesc desc;
481 error = AECoerceDesc(theItem, typeFSRef, &desc);
482 if (error == noErr)
483 {
484 FSRef fileRef;
485 error = AEGetDescData(&desc, &fileRef, sizeof(fileRef));
486 if (error == noErr)
487 {
488 LSItemInfoRecord fileInfo;
489 error = LSCopyItemInfoForRef(&fileRef, kLSRequestExtension | kLSRequestTypeCreator, &fileInfo);
490 if (error == noErr)
491 {
492 if (filter == FFLOAD_IMAGE)
493 {
494 if (fileInfo.filetype != 'JPEG' && fileInfo.filetype != 'JPG ' &&
495 fileInfo.filetype != 'BMP ' && fileInfo.filetype != 'TGA ' &&
496 fileInfo.filetype != 'BMPf' && fileInfo.filetype != 'TPIC' &&
497 (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("jpeg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
498 CFStringCompare(fileInfo.extension, CFSTR("jpg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
499 CFStringCompare(fileInfo.extension, CFSTR("bmp"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
500 CFStringCompare(fileInfo.extension, CFSTR("tga"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
501 )
502 {
503 result = false;
504 }
505 }
506 else if (filter == FFLOAD_WAV)
507 {
508 if (fileInfo.filetype != 'WAVE' && fileInfo.filetype != 'WAV ' &&
509 (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("wave"), kCFCompareCaseInsensitive) != kCFCompareEqualTo &&
510 CFStringCompare(fileInfo.extension, CFSTR("wav"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
511 )
512 {
513 result = false;
514 }
515 }
516 else if (filter == FFLOAD_ANIM)
517 {
518 if (fileInfo.filetype != 'BVH ' &&
519 (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("bvh"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
520 )
521 {
522 result = false;
523 }
524 }
525#ifdef _CORY_TESTING
526 else if (filter == FFLOAD_GEOMETRY)
527 {
528 if (fileInfo.filetype != 'SLG ' &&
529 (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("slg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
530 )
531 {
532 result = false;
533 }
534 }
535#endif
536 else if (filter == FFLOAD_SLOBJECT)
537 {
538 llwarns << "*** navOpenFilterProc: FFLOAD_SLOBJECT NOT IMPLEMENTED ***" << llendl;
539 }
540 else if (filter == FFLOAD_RAW)
541 {
542 if (fileInfo.filetype != '\?\?\?\?' &&
543 (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("raw"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
544 )
545 {
546 result = false;
547 }
548 }
549
550 if (fileInfo.extension)
551 {
552 CFRelease(fileInfo.extension);
553 }
554 }
555 }
556 AEDisposeDesc(&desc);
557 }
558 }
559 }
560 return result;
561}
562
563OSStatus LLFilePicker::doNavChooseDialog(ELoadFilter filter)
564{
565 OSStatus error = noErr;
566 NavDialogRef navRef = NULL;
567 NavReplyRecord navReply;
568
569 memset(&navReply, 0, sizeof(navReply));
570 mFiles[0] = '\0';
571 mFileVector.clear();
572
573 // NOTE: we are passing the address of a local variable here.
574 // This is fine, because the object this call creates will exist for less than the lifetime of this function.
575 // (It is destroyed by NavDialogDispose() below.)
576 error = NavCreateChooseFileDialog(&mNavOptions, NULL, NULL, NULL, navOpenFilterProc, (void*)(&filter), &navRef);
577
578 gViewerWindow->mWindow->beforeDialog();
579
580 if (error == noErr)
581 error = NavDialogRun(navRef);
582
583 gViewerWindow->mWindow->afterDialog();
584
585 if (error == noErr)
586 error = NavDialogGetReply(navRef, &navReply);
587
588 if (navRef)
589 NavDialogDispose(navRef);
590
591 if (error == noErr && navReply.validRecord)
592 {
593 SInt32 count = 0;
594 SInt32 index;
595
596 // AE indexes are 1 based...
597 error = AECountItems(&navReply.selection, &count);
598 for (index = 1; index <= count; index++)
599 {
600 FSRef fsRef;
601 AEKeyword theAEKeyword;
602 DescType typeCode;
603 Size actualSize = 0;
604 char path[MAX_PATH];
605
606 memset(&fsRef, 0, sizeof(fsRef));
607 error = AEGetNthPtr(&navReply.selection, index, typeFSRef, &theAEKeyword, &typeCode, &fsRef, sizeof(fsRef), &actualSize);
608
609 if (error == noErr)
610 error = FSRefMakePath(&fsRef, (UInt8*) path, sizeof(path));
611
612 if (error == noErr)
613 mFileVector.push_back(LLString(path));
614 }
615 }
616
617 return error;
618}
619
620OSStatus LLFilePicker::doNavSaveDialog(ESaveFilter filter, const char* filename)
621{
622 OSStatus error = noErr;
623 NavDialogRef navRef = NULL;
624 NavReplyRecord navReply;
625
626 memset(&navReply, 0, sizeof(navReply));
627 mFiles[0] = '\0';
628 mFileVector.clear();
629
630 // Setup the type, creator, and extension
631 OSType type, creator;
632 CFStringRef extension = NULL;
633 switch (filter)
634 {
635 case FFSAVE_WAV:
636 type = 'WAVE';
637 creator = 'TVOD';
638 extension = CFSTR(".wav");
639 break;
640
641 case FFSAVE_TGA:
642 type = 'TPIC';
643 creator = 'prvw';
644 extension = CFSTR(".tga");
645 break;
646
647 case FFSAVE_BMP:
648 type = 'BMPf';
649 creator = 'prvw';
650 extension = CFSTR(".bmp");
651 break;
652
653 case FFSAVE_AVI:
654 type = '\?\?\?\?';
655 creator = '\?\?\?\?';
656 extension = CFSTR(".mov");
657 break;
658
659 case FFSAVE_ANIM:
660 type = '\?\?\?\?';
661 creator = '\?\?\?\?';
662 extension = CFSTR(".xaf");
663 break;
664
665#ifdef _CORY_TESTING
666 case FFSAVE_GEOMETRY:
667 type = '\?\?\?\?';
668 creator = '\?\?\?\?';
669 extension = CFSTR(".slg");
670 break;
671#endif
672 case FFSAVE_RAW:
673 type = '\?\?\?\?';
674 creator = '\?\?\?\?';
675 extension = CFSTR(".raw");
676 break;
677
678 case FFSAVE_ALL:
679 default:
680 type = '\?\?\?\?';
681 creator = '\?\?\?\?';
682 extension = CFSTR("");
683 break;
684 }
685
686 // Create the dialog
687 error = NavCreatePutFileDialog(&mNavOptions, type, creator, NULL, NULL, &navRef);
688 if (error == noErr)
689 {
690 CFStringRef nameString = NULL;
691 bool hasExtension = true;
692
693 // Create a CFString of the initial file name
694 if (filename)
695 nameString = CFStringCreateWithCString(NULL, filename, kCFStringEncodingUTF8);
696 else
697 nameString = CFSTR("Untitled");
698
699 // Add the extension if one was not provided
700 if (nameString && !CFStringHasSuffix(nameString, extension))
701 {
702 CFStringRef tempString = nameString;
703 hasExtension = false;
704 nameString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), tempString, extension);
705 CFRelease(tempString);
706 }
707
708 // Set the name in the dialog
709 if (nameString)
710 {
711 error = NavDialogSetSaveFileName(navRef, nameString);
712 CFRelease(nameString);
713 }
714 else
715 {
716 error = paramErr;
717 }
718 }
719
720 gViewerWindow->mWindow->beforeDialog();
721
722 // Run the dialog
723 if (error == noErr)
724 error = NavDialogRun(navRef);
725
726 gViewerWindow->mWindow->afterDialog();
727
728 if (error == noErr)
729 error = NavDialogGetReply(navRef, &navReply);
730
731 if (navRef)
732 NavDialogDispose(navRef);
733
734 if (error == noErr && navReply.validRecord)
735 {
736 SInt32 count = 0;
737
738 // AE indexes are 1 based...
739 error = AECountItems(&navReply.selection, &count);
740 if (count > 0)
741 {
742 // Get the FSRef to the containing folder
743 FSRef fsRef;
744 AEKeyword theAEKeyword;
745 DescType typeCode;
746 Size actualSize = 0;
747
748 memset(&fsRef, 0, sizeof(fsRef));
749 error = AEGetNthPtr(&navReply.selection, 1, typeFSRef, &theAEKeyword, &typeCode, &fsRef, sizeof(fsRef), &actualSize);
750
751 if (error == noErr)
752 {
753 char path[PATH_MAX];
754 char newFileName[SINGLE_FILENAME_BUFFER_SIZE];
755
756 error = FSRefMakePath(&fsRef, (UInt8*)path, PATH_MAX);
757 if (error == noErr)
758 {
759 if (CFStringGetCString(navReply.saveFileName, newFileName, sizeof(newFileName), kCFStringEncodingUTF8))
760 {
761 mFileVector.push_back(LLString(path) + LLString("/") + LLString(newFileName));
762 }
763 else
764 {
765 error = paramErr;
766 }
767 }
768 else
769 {
770 error = paramErr;
771 }
772 }
773 }
774 }
775
776 return error;
777}
778
779BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
780{
781 if( mLocked ) return FALSE;
782 mMultiFile = FALSE;
783 BOOL success = FALSE;
784
785 OSStatus error = noErr;
786
787 mFileVector.clear();
788 mNavOptions.optionFlags &= ~kNavAllowMultipleFiles;
789 // Modal, so pause agent
790 send_agent_pause();
791 {
792 error = doNavChooseDialog(filter);
793 }
794 send_agent_resume();
795 if (error == noErr)
796 {
797 if (mFileVector.size())
798 success = true;
799 }
800
801 // Account for the fact that the app has been stalled.
802 LLFrameTimer::updateFrameTime();
803 return success;
804}
805
806BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter)
807{
808 if( mLocked ) return FALSE;
809 mMultiFile = TRUE;
810 BOOL success = FALSE;
811
812 OSStatus error = noErr;
813
814 mFileVector.clear();
815 mNavOptions.optionFlags |= kNavAllowMultipleFiles;
816 // Modal, so pause agent
817 send_agent_pause();
818 {
819 error = doNavChooseDialog(filter);
820 }
821 send_agent_resume();
822 if (error == noErr)
823 {
824 if (mFileVector.size())
825 success = true;
826 if (mFileVector.size() > 1)
827 mLocked = TRUE;
828 }
829
830 // Account for the fact that the app has been stalled.
831 LLFrameTimer::updateFrameTime();
832 return success;
833}
834
835void LLFilePicker::getFilePath(SInt32 index)
836{
837 mFiles[0] = 0;
838 if (mFileVector.size())
839 strcpy(mFiles, mFileVector[index].c_str());
840}
841
842void LLFilePicker::getFileName(SInt32 index)
843{
844 mFilename[0] = 0;
845 if (mFileVector.size())
846 {
847 char *start = strrchr(mFileVector[index].c_str(), '/');
848 if (start && ((start + 1 - mFileVector[index].c_str()) < (mFileVector[index].size())))
849 strcpy(mFilename, start + 1);
850 }
851}
852
853BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const char* filename)
854{
855 if( mLocked ) return FALSE;
856 BOOL success = FALSE;
857 OSStatus error = noErr;
858
859 mFileVector.clear();
860 mMultiFile = FALSE;
861 mNavOptions.optionFlags &= ~kNavAllowMultipleFiles;
862
863 // Modal, so pause agent
864 send_agent_pause();
865 {
866 error = doNavSaveDialog(filter, filename);
867 }
868 send_agent_resume();
869 if (error == noErr)
870 {
871 if (mFileVector.size())
872 success = true;
873 }
874
875 // Account for the fact that the app has been stalled.
876 LLFrameTimer::updateFrameTime();
877 return success;
878}
879
880const char* LLFilePicker::getFirstFile()
881{
882 mFileIndex = 0;
883 getFilePath(mFileIndex);
884 return mFiles;
885}
886
887const char* LLFilePicker::getNextFile()
888{
889 if(mMultiFile)
890 {
891 mFileIndex++;
892 if (mFileIndex < mFileVector.size())
893 {
894 getFilePath(mFileIndex);
895 return mFiles;
896 }
897 else
898 {
899 mLocked = FALSE;
900 }
901 }
902 return NULL;
903}
904
905const char* LLFilePicker::getDirname()
906{
907 if (mFileIndex < mFileVector.size())
908 {
909 getFileName(mFileIndex);
910 return mFilename;
911 }
912 return NULL;
913}
914
915void LLFilePicker::reset()
916{
917 mLocked = FALSE;
918 memset( mFiles, 0, FILENAME_BUFFER_SIZE );
919 memset( mFilename, 0, LL_MAX_PATH );
920 mCurrentFile = mFiles;
921
922 mFileIndex = 0;
923 mFileVector.clear();
924}
925
926#elif LL_LINUX
927
928# if LL_GTK
929LLFilePicker::LLFilePicker()
930{
931 reset();
932}
933
934LLFilePicker::~LLFilePicker()
935{
936}
937
938static void store_filenames(GtkWidget *widget, gpointer user_data) {
939 StoreFilenamesStruct *sfs = (StoreFilenamesStruct*) user_data;
940 GtkWidget *win = sfs->win;
941
942 llinfos <<"store_filesnames: marker A" << llendl;
943
944 // get NULL-terminated list of strings allocated for us by GTK
945 gchar** string_list =
946 gtk_file_selection_get_selections(GTK_FILE_SELECTION(win));
947
948 llinfos <<"store_filesnames: marker B" << llendl;
949
950 int idx = 0;
951 while (string_list[idx])
952 {
953 // platform-string to utf8
954 gchar* filename_utf8 = g_filename_from_utf8(string_list[idx],
955 -1, NULL,
956 NULL,
957 NULL);
958 sfs->fileVector.push_back(LLString(filename_utf8));
959 ++idx;
960 }
961
962 llinfos <<"store_filesnames: marker C" << llendl;
963
964 g_strfreev(string_list);
965
966 llinfos <<"store_filesnames: marker D" << llendl;
967
968 llinfos << sfs->fileVector.size() << " filename(s) selected:" << llendl;
969 U32 x;
970 for (x=0; x<sfs->fileVector.size(); ++x)
971 llinfos << x << ":" << sfs->fileVector[x] << llendl;
972}
973
974GtkWindow* LLFilePicker::buildFilePicker(void)
975{
976 gtk_disable_setlocale();
977 if (gtk_init_check(NULL, NULL) &&
978 ! gViewerWindow->getWindow()->getFullscreen())
979 {
980 GtkWidget *win = NULL;
981
982 win = gtk_file_selection_new(NULL);
983 mStoreFilenames.win = win;
984
985# if LL_X11
986 // Make GTK tell the window manager to associate this
987 // dialog with our non-GTK raw X11 window, which should try
988 // to keep it on top etc.
989 Window *XWindowID_ptr = (Window*) gViewerWindow->
990 getWindow()->getPlatformWindow();
991 if (XWindowID_ptr && None != *XWindowID_ptr)
992 {
993 gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin
994 GdkWindow *gdkwin = gdk_window_foreign_new(*XWindowID_ptr);
995 gdk_window_set_transient_for(GTK_WIDGET(win)->window,
996 gdkwin);
997 }
998 else
999 {
1000 llwarns << "Hmm, couldn't get xwid from LLWindow." << llendl;
1001 }
1002# endif //LL_X11
1003
1004 g_signal_connect (G_OBJECT(win), "destroy",
1005 G_CALLBACK(gtk_main_quit), NULL);
1006
1007 // on 'ok', grab the file selection list
1008 g_signal_connect (GTK_FILE_SELECTION(win)->ok_button,
1009 "clicked",
1010 G_CALLBACK(store_filenames),
1011 &mStoreFilenames);
1012
1013 // both 'ok' and 'cancel' will end the dialog
1014 g_signal_connect_swapped (G_OBJECT(GTK_FILE_SELECTION(win)->
1015 ok_button),
1016 "clicked",
1017 G_CALLBACK(gtk_widget_destroy),
1018 G_OBJECT(win));
1019 g_signal_connect_swapped (G_OBJECT(GTK_FILE_SELECTION(win)->
1020 cancel_button),
1021 "clicked",
1022 G_CALLBACK(gtk_widget_destroy),
1023 G_OBJECT(win));
1024
1025 gtk_file_selection_show_fileop_buttons(GTK_FILE_SELECTION(win));
1026 gtk_file_selection_set_select_multiple(GTK_FILE_SELECTION(win),
1027 FALSE);
1028
1029 gtk_window_set_modal(GTK_WINDOW(win), TRUE);
1030
1031 return GTK_WINDOW(win);
1032 }
1033 else
1034 {
1035 return NULL;
1036 }
1037}
1038
1039BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const char* filename )
1040{
1041 BOOL rtn = FALSE;
1042
1043 gViewerWindow->mWindow->beforeDialog();
1044
1045 reset();
1046 GtkWindow* picker = buildFilePicker();
1047
1048 if (picker)
1049 {
1050 std::string suggest_name = "untitled";
1051 std::string suggest_ext = "";
1052 std::string caption = "Save ";
1053 switch (filter)
1054 {
1055 case FFSAVE_WAV:
1056 caption += "Sounds (*.wav)";
1057 suggest_ext += ".wav";
1058 break;
1059 case FFSAVE_TGA:
1060 caption += "Targa Images (*.tga)";
1061 suggest_ext += ".tga";
1062 break;
1063 case FFSAVE_BMP:
1064 caption += "Bitmap Images (*.bmp)";
1065 suggest_ext += ".bmp";
1066 break;
1067 case FFSAVE_AVI:
1068 caption += "AVI Movie File (*.avi)";
1069 suggest_ext += ".avi";
1070 break;
1071 case FFSAVE_ANIM:
1072 caption += "XAF Anim File (*.xaf)";
1073 suggest_ext += ".xaf";
1074 break;
1075 case FFSAVE_XML:
1076 caption += "XML File (*.xml)";
1077 suggest_ext += ".xml";
1078 break;
1079 case FFSAVE_RAW:
1080 caption += "RAW File (*.raw)";
1081 suggest_ext += ".raw";
1082 break;
1083 default:;
1084 break;
1085 }
1086
1087 gtk_window_set_title(GTK_WINDOW(picker), caption.c_str());
1088
1089 if (!filename)
1090 {
1091 suggest_name += suggest_ext;
1092
1093 gtk_file_selection_set_filename
1094 (GTK_FILE_SELECTION(picker),
1095 g_filename_from_utf8(suggest_name.c_str(),
1096 -1, NULL,
1097 NULL,
1098 NULL));
1099 gtk_editable_select_region(GTK_EDITABLE(GTK_FILE_SELECTION(picker)->selection_entry), 0, suggest_name.length() - suggest_ext.length() );
1100 }
1101 else
1102 {
1103 gtk_file_selection_set_filename
1104 (GTK_FILE_SELECTION(picker),
1105 g_filename_from_utf8(filename,
1106 -1, NULL,
1107 NULL,
1108 NULL));
1109 gtk_editable_select_region(GTK_EDITABLE(GTK_FILE_SELECTION(picker)->selection_entry), 0, -1 );
1110 }
1111
1112 gtk_widget_show_all(GTK_WIDGET(picker));
1113 gtk_main();
1114 rtn = (mStoreFilenames.fileVector.size() == 1);
1115 }
1116
1117 gViewerWindow->mWindow->afterDialog();
1118
1119 return rtn;
1120}
1121
1122BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
1123{
1124 BOOL rtn = FALSE;
1125
1126 gViewerWindow->mWindow->beforeDialog();
1127
1128 reset();
1129 GtkWindow* picker = buildFilePicker();
1130
1131 if (picker)
1132 {
1133 std::string caption = "Load ";
1134 switch (filter)
1135 {
1136 case FFLOAD_WAV:
1137 caption += "Sounds (*.wav)"; break;
1138 case FFLOAD_ANIM:
1139 caption += "Animations (*.bvh)"; break;
1140 case FFLOAD_IMAGE:
1141 caption += "Images (*.tga; *.bmp; *.jpg; *.jpeg)"; break;
1142 default:;
1143 break;
1144 }
1145
1146 gtk_window_set_title(GTK_WINDOW(picker), caption.c_str());
1147
1148 gtk_widget_show_all(GTK_WIDGET(picker));
1149 gtk_main();
1150 rtn = (mStoreFilenames.fileVector.size() == 1);
1151 }
1152
1153 gViewerWindow->mWindow->afterDialog();
1154
1155 return rtn;
1156}
1157
1158BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
1159{
1160 BOOL rtn = FALSE;
1161
1162 gViewerWindow->mWindow->beforeDialog();
1163
1164 reset();
1165 GtkWindow* picker = buildFilePicker();
1166
1167 if (picker)
1168 {
1169 gtk_file_selection_set_select_multiple(GTK_FILE_SELECTION(picker),
1170 TRUE);
1171
1172 gtk_window_set_title(GTK_WINDOW(picker), "Load Files");
1173
1174 gtk_widget_show_all(GTK_WIDGET(picker));
1175 gtk_main();
1176 rtn = !mStoreFilenames.fileVector.empty();
1177 }
1178
1179 gViewerWindow->mWindow->afterDialog();
1180
1181 return rtn;
1182}
1183
1184const char* LLFilePicker::getFirstFile()
1185{
1186 mNextFileIndex = 0;
1187 return getNextFile();
1188}
1189
1190const char* LLFilePicker::getNextFile()
1191{
1192 if (mStoreFilenames.fileVector.size() > mNextFileIndex)
1193 return mStoreFilenames.fileVector[mNextFileIndex++].c_str();
1194 else
1195 return NULL;
1196}
1197
1198const char* LLFilePicker::getDirname()
1199{
1200 // getDirname is badly named... it really means getBasename.
1201 S32 index = mNextFileIndex - 1; // want index before the 'next' cursor
1202 if (index >= 0 && index < (S32)mStoreFilenames.fileVector.size())
1203 {
1204 // we do this using C strings so we don't have to
1205 // convert a LLString/std::string character offset into a
1206 // byte-offset for the return (which is a C string anyway).
1207 const char* dirsep = gDirUtilp->getDirDelimiter().c_str();
1208 const char* fullpath = mStoreFilenames.fileVector[index].c_str();
1209 const char* finalpart = NULL;
1210 const char* thispart = fullpath;
1211 // walk through the string looking for the final dirsep, i.e. /
1212 do
1213 {
1214 thispart = strstr(thispart, dirsep);
1215 if (NULL != thispart)
1216 finalpart = thispart = &thispart[1];
1217 }
1218 while (NULL != thispart);
1219 return finalpart;
1220 }
1221 else
1222 return NULL;
1223}
1224
1225void LLFilePicker::reset()
1226{
1227 llinfos << "GTK LLFilePicker::reset()" << llendl;
1228 mNextFileIndex = 0;
1229 mStoreFilenames.win = NULL;
1230 mStoreFilenames.fileVector.clear();
1231}
1232
1233# else // LL_GTK
1234
1235// Hacky stubs designed to facilitate fake getSaveFile and getOpenFile with
1236// static results, when we don't have a real filepicker.
1237
1238static LLString hackyfilename;
1239
1240LLFilePicker::LLFilePicker()
1241{
1242 reset();
1243}
1244
1245LLFilePicker::~LLFilePicker()
1246{
1247}
1248
1249BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const char* filename )
1250{
1251 llinfos << "getSaveFile suggested filename is [" << filename
1252 << "]" << llendl;
1253 if (filename && filename[0])
1254 {
1255 hackyfilename.assign(gDirUtilp->getLindenUserDir());
1256 hackyfilename += gDirUtilp->getDirDelimiter();
1257 hackyfilename += filename;
1258 return TRUE;
1259 }
1260 hackyfilename.clear();
1261 return FALSE;
1262}
1263
1264BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
1265{
1266 // HACK: Static filenames for 'open' until we implement filepicker
1267 hackyfilename.assign(gDirUtilp->getLindenUserDir());
1268 hackyfilename += gDirUtilp->getDirDelimiter();
1269 hackyfilename += "upload";
1270 switch (filter)
1271 {
1272 case FFLOAD_WAV: hackyfilename += ".wav"; break;
1273 case FFLOAD_IMAGE: hackyfilename += ".tga"; break;
1274 case FFLOAD_ANIM: hackyfilename += ".bvh"; break;
1275 default: break;
1276 }
1277 llinfos << "getOpenFile: Will try to open file: " << hackyfilename
1278 << llendl;
1279 return TRUE;
1280}
1281
1282BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
1283{
1284 hackyfilename.clear();
1285 return FALSE;
1286}
1287
1288const char* LLFilePicker::getFirstFile()
1289{
1290 if (!hackyfilename.empty())
1291 {
1292 return hackyfilename.c_str();
1293 }
1294 return NULL;
1295}
1296
1297const char* LLFilePicker::getNextFile()
1298{
1299 hackyfilename.clear();
1300 return NULL;
1301}
1302
1303const char* LLFilePicker::getDirname()
1304{
1305 return NULL;
1306}
1307
1308void LLFilePicker::reset()
1309{
1310}
1311#endif // LL_GTK
1312
1313#else // not implemented
1314
1315LLFilePicker::LLFilePicker()
1316{
1317 reset();
1318}
1319
1320LLFilePicker::~LLFilePicker()
1321{
1322}
1323
1324BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const char* filename )
1325{
1326 return FALSE;
1327}
1328
1329BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
1330{
1331 return FALSE;
1332}
1333
1334BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
1335{
1336 return FALSE;
1337}
1338
1339const char* LLFilePicker::getFirstFile()
1340{
1341 return NULL;
1342}
1343
1344const char* LLFilePicker::getNextFile()
1345{
1346 return NULL;
1347}
1348
1349const char* LLFilePicker::getDirname()
1350{
1351 return NULL;
1352}
1353
1354void LLFilePicker::reset()
1355{
1356}
1357
1358#endif