SL-18996 [WIP] MacOS make picker dialogs non-modal to avoid disconnects #1

master
Andrey Kleshchev 2023-01-25 20:53:01 +02:00 committed by akleshchev
parent e3a90ba4c1
commit 2398a28af6
6 changed files with 220 additions and 17 deletions

View File

@ -678,6 +678,30 @@ bool LLFilePicker::doNavChooseDialog(ELoadFilter filter)
return false;
}
bool LLFilePicker::doNavChooseDialogModeless(ELoadFilter filter,
void (*callback)(bool, std::vector<std::string> &,void*),
void *userdata)
{
// if local file browsing is turned off, return without opening dialog
if ( check_local_file_access_enabled() == false )
{
return false;
}
gViewerWindow->getWindow()->beforeDialog();
std::vector<std::string> *allowed_types=navOpenFilterProc(filter);
doLoadDialogModeless(allowed_types,
mPickOptions,
callback,
userdata);
gViewerWindow->getWindow()->afterDialog();
return true;
}
bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filename)
{
@ -852,18 +876,52 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking)
return success;
}
BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter,
void (*callback)(bool, std::vector<std::string> &, void*),
void *userdata)
{
if( mLocked )
return FALSE;
// if local file browsing is turned off, return without opening dialog
if ( check_local_file_access_enabled() == false )
{
return FALSE;
}
reset();
mPickOptions &= ~F_MULTIPLE;
mPickOptions |= F_FILE;
if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker.
{
mPickOptions |= ( F_NAV_SUPPORT | F_DIRECTORY );
mPickOptions &= ~F_FILE;
}
if (filter == FFLOAD_ALL) // allow application bundles etc. to be traversed; important for DEV-16869, but generally useful
{
mPickOptions |= F_NAV_SUPPORT;
}
return doNavChooseDialogModeless(filter, callback, userdata);
}
BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking)
{
if( mLocked )
return FALSE;
BOOL success = FALSE;
// if local file browsing is turned off, return without opening dialog
if ( check_local_file_access_enabled() == false )
{
return FALSE;
}
BOOL success = FALSE;
reset();
@ -897,6 +955,27 @@ BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking)
return success;
}
BOOL LLFilePicker::getMultipleOpenFilesModeless( ELoadFilter filter, void (*callback)(bool, std::vector<std::string> &, void*), void *userdata )
{
if( mLocked )
return FALSE;
// if local file browsing is turned off, return without opening dialog
if ( check_local_file_access_enabled() == false )
{
return FALSE;
}
reset();
mPickOptions |= F_FILE;
mPickOptions |= F_MULTIPLE;
return doNavChooseDialogModeless(filter, callback, userdata);
}
BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, bool blocking)
{

View File

@ -115,7 +115,11 @@ public:
// open the dialog. This is a modal operation
BOOL getSaveFile( ESaveFilter filter = FFSAVE_ALL, const std::string& filename = LLStringUtil::null, bool blocking = true);
BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL, bool blocking = true );
// Todo: implement getOpenFileModeless and getMultipleOpenFilesModeless
// for windows and use directly instead of ugly LLFilePickerThread
BOOL getOpenFileModeless( ELoadFilter filter, void (*callback)(bool, std::vector<std::string> &, void*), void *userdata); // MAC only.
BOOL getMultipleOpenFiles( ELoadFilter filter = FFLOAD_ALL, bool blocking = true );
BOOL getMultipleOpenFilesModeless( ELoadFilter filter, void (*callback)(bool, std::vector<std::string> &, void*), void *userdata ); // MAC only
// Get the filename(s) found. getFirstFile() sets the pointer to
// the start of the structure and allows the start of iteration.
@ -166,6 +170,7 @@ private:
std::vector<std::string> mFileVector;
bool doNavChooseDialog(ELoadFilter filter);
bool doNavChooseDialogModeless(ELoadFilter filter, void (*callback)(bool, std::vector<std::string>&, void*), void *userdata);
bool doNavSaveDialog(ESaveFilter filter, const std::string& filename);
std::vector<std::string>* navOpenFilterProc(ELoadFilter filter);
#endif

View File

@ -41,6 +41,12 @@
//void modelessPicker();
std::vector<std::string>* doLoadDialog(const std::vector<std::string>* allowed_types,
unsigned int flags);
void doLoadDialogModeless(const std::vector<std::string>* allowed_types,
unsigned int flags,
void (*callback)(bool, std::vector<std::string>&, void*),
void *userdata);
std::string* doSaveDialog(const std::string* file,
const std::string* type,
const std::string* creator,

View File

@ -29,27 +29,22 @@
#include <iostream>
#include "llfilepicker_mac.h"
std::vector<std::string>* doLoadDialog(const std::vector<std::string>* allowed_types,
unsigned int flags)
NSOpenPanel *init_panel(const std::vector<std::string>* allowed_types, unsigned int flags)
{
int i, result;
//Aura TODO: We could init a small window and release it at the end of this routine
//for a modeless interface.
int i;
NSOpenPanel *panel = [NSOpenPanel openPanel];
//NSString *fileName = nil;
NSMutableArray *fileTypes = nil;
if ( allowed_types && !allowed_types->empty())
if ( allowed_types && !allowed_types->empty())
{
fileTypes = [[NSMutableArray alloc] init];
for (i=0;i<allowed_types->size();++i)
{
[fileTypes addObject:
[NSString stringWithCString:(*allowed_types)[i].c_str()
[fileTypes addObject:
[NSString stringWithCString:(*allowed_types)[i].c_str()
encoding:[NSString defaultCStringEncoding]]];
}
}
@ -62,21 +57,30 @@ std::vector<std::string>* doLoadDialog(const std::vector<std::string>* allowed_t
[panel setCanChooseFiles: ( (flags & F_FILE)?true:false )];
[panel setTreatsFilePackagesAsDirectories: ( flags & F_NAV_SUPPORT ) ];
std::vector<std::string>* outfiles = NULL;
if (fileTypes)
{
[panel setAllowedFileTypes:fileTypes];
result = [panel runModal];
}
else
else
{
// I suggest it's better to open the last path and let this default to home dir as necessary
// for consistency with other OS X apps
//
//[panel setDirectoryURL: fileURLWithPath(NSHomeDirectory()) ];
result = [panel runModal];
}
return panel;
}
std::vector<std::string>* doLoadDialog(const std::vector<std::string>* allowed_types,
unsigned int flags)
{
int result;
NSOpenPanel *panel = init_panel(allowed_types,flags);
result = [panel runModal];
std::vector<std::string>* outfiles = NULL;
if (result == NSOKButton)
{
@ -97,6 +101,40 @@ std::vector<std::string>* doLoadDialog(const std::vector<std::string>* allowed_t
return outfiles;
}
void doLoadDialogModeless(const std::vector<std::string>* allowed_types,
unsigned int flags,
void (*callback)(bool, std::vector<std::string> &, void*),
void *userdata)
{
// Note: might need to return and save this panel
// so that it does not close immediately
NSOpenPanel *panel = init_panel(allowed_types,flags);
[panel beginWithCompletionHandler:^(NSModalResponse result)
{
if (result == NSOKButton)
{
std::vector<std::string> outfiles;
NSArray *filesToOpen = [panel URLs];
int i, count = [filesToOpen count];
if (count > 0)
{
for (i=0; i<count; i++) {
NSString *aFile = [[filesToOpen objectAtIndex:i] path];
std::string *afilestr = new std::string([aFile UTF8String]);
outfiles.push_back(*afilestr);
}
callback(true, outfiles, userdata);
}
else
{
callback(false, outfiles, userdata);
}
}
}];
}
std::string* doSaveDialog(const std::string* file,
const std::string* type,

View File

@ -124,6 +124,16 @@ void LLFilePickerThread::getFile()
{
#if LL_WINDOWS
start();
#elif LL_DARWIN
if (!mIsSaveDialog)
{
runModeless();
}
else
{
// Todo: implement Modeless
run();
}
#else
run();
#endif
@ -166,7 +176,70 @@ void LLFilePickerThread::run()
LLMutexLock lock(sMutex);
sDeadQ.push(this);
}
}
void LLFilePickerThread::runModeless()
{
BOOL result = FALSE;
LLFilePicker picker;
if (mIsSaveDialog)
{
// TODO: not implemented
/*if (picker.getSaveFile(mSaveFilter, mProposedName, blocking))
{
mResponses.push_back(picker.getFirstFile());
}*/
}
else
{
if (mIsGetMultiple)
{
result = picker.getMultipleOpenFilesModeless(mLoadFilter, modelessCallback, this);
}
else
{
result = picker.getOpenFileModeless(mLoadFilter, modelessCallback, this);
}
}
if (!result)
{
LLMutexLock lock(sMutex);
sDeadQ.push(this);
}
}
void LLFilePickerThread::modelessCallback(bool result,
std::vector<std::string> &responses,
void *user_data)
{
LLFilePickerThread *picker = (LLFilePickerThread*)user_data;
if (result)
{
if (picker->mIsGetMultiple)
{
picker->mResponses = responses;
}
else
{
std::vector<std::string>::iterator iter = responses.begin();
while (iter != responses.end())
{
if (!iter->empty())
{
picker->mResponses.push_back(*iter);
break;
}
iter++;
}
}
}
{
LLMutexLock lock(sMutex);
sDeadQ.push(picker);
}
}
//static

View File

@ -105,6 +105,8 @@ public:
void getFile();
virtual void run();
void runModeless();
static void modelessCallback(bool result, std::vector<std::string> &responses, void *user_data);
virtual void notify(const std::vector<std::string>& filenames) = 0;
};