Skip to content

Instantly share code, notes, and snippets.

@sarah-j-smith
Last active September 15, 2017 23:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sarah-j-smith/9801615 to your computer and use it in GitHub Desktop.
Save sarah-j-smith/9801615 to your computer and use it in GitHub Desktop.
QString MacUtils::getOpenFileName(QWidget *parent, const QString &title, const QString &dirName, const QString &filter, MacUtils::OpenType openType)
{
qDebug() << Q_FUNC_INFO << "dirName:" << dirName;
NSOpenPanel *panel = [NSOpenPanel openPanel];
QWidget *window = parent->window();
Q_ASSERT_X(window != 0, Q_FUNC_INFO, "Expected non-nil window");
Q_ASSERT_X(window->isWindow(), Q_FUNC_INFO, "Expected window");
NSView *v = reinterpret_cast<NSView *>(window->winId());
NSWindow *macWindow = [v window];
__block QEventLoop *loop = new QEventLoop;
__block NSURL *result = nil;
NSURL *promptUrl = [NSURL fileURLWithPath:dirName.toNSString() isDirectory:YES];
[panel setTitle:title.toNSString()];
[panel setCanChooseFiles:YES];
if (openType == DirectoriesOnly)
{
// On Mac you cannot choose bundles if this is set
[panel setCanChooseFiles:NO];
[panel setCanChooseDirectories:YES];
[panel setShowsHiddenFiles:YES];
// allow bundles
[panel setTreatsFilePackagesAsDirectories:YES];
[panel setMessage:@"Choose a directory for the Navigator Pane"];
}
else
{
[panel setAllowsOtherFileTypes:YES];
[panel setAllowedFileTypes:@[ filter.toNSString() ]];
[panel setCanChooseFiles:YES];
[panel setCanChooseDirectories:NO];
[panel setMessage:@"Choose a file"];
}
[panel setAllowsMultipleSelection:NO];
[panel setDirectoryURL:promptUrl];
[panel beginSheetModalForWindow:macWindow completionHandler:^(NSInteger returnCode)
{
NSLog(@"Return completion handler: %ld", (long)returnCode);
if (returnCode == NSOKButton)
{
result = [[panel URLs] objectAtIndex:0];
NSLog(@"NSOpenPanel completion handler block - URL is: %@", result);
}
loop->quit();
NSLog(@"Sent quit to loop");
}];
loop->exec();
QString answer;
NSLog(@"Exited loop: %@", result);
if (result != nil)
{
NSLog(@"Got URL as %@ - is a file url: %s", result, ([result isFileURL] ? "YES" : "NO"));
if ([result isFileURL])
{
answer = QString::fromNSString([result path]);
if (instance()->isSandboxed())
{
QScopedPointer<SecurityBookmarkManager> smgr(new SecurityBookmarkManager);
smgr->storeSecurityScope(result);
}
}
else
{
NSLog(@"### LOGIC ERROR: panel returned a non-file URL: %@!!!!!!!", result);
}
}
delete loop;
return answer;
}
// Cannot create a security scoped book-mark for a file that doesn't exist, so
// instead we create a small placeholder file just to allow book-mark creation.
static bool writePlaceHolderFile(const QUrl &url)
{
QString filePath = url.toLocalFile();
QFile placeHolder(filePath);
bool success = placeHolder.open(QIODevice::WriteOnly);
if (!success)
{
qDebug() << Q_FUNC_INFO << "Could not open for writing" << placeHolder.fileName() << placeHolder.errorString();
return false;
}
qint64 r = placeHolder.write(QByteArray("Hello World!"));
if (r <= 0)
{
qDebug() << Q_FUNC_INFO << "Could not write bytes" << url << placeHolder.errorString();
return false;
}
qDebug() << Q_FUNC_INFO << "Wrote placeholder" << url;
placeHolder.close();
return true;
}
QString MacUtils::getSaveFileName(QWidget *parent, const QString &title, const QString &dirName, const QString &filter)
{
qDebug() << Q_FUNC_INFO << "dirName:" << dirName;
NSSavePanel *panel = [NSSavePanel savePanel];
QWidget *window = parent->window();
Q_ASSERT_X(window != 0, Q_FUNC_INFO, "Expected non-nil window");
Q_ASSERT_X(window->isWindow(), Q_FUNC_INFO, "Expected window");
NSView *v = reinterpret_cast<NSView *>(window->winId());
NSWindow *macWindow = [v window];
__block QEventLoop *loop = new QEventLoop;
__block NSURL *result = nil;
NSURL *promptUrl = [NSURL fileURLWithPath:dirName.toNSString() isDirectory:YES];
[panel setTitle:title.toNSString()];
[panel setDirectoryURL:promptUrl];
[panel setAllowsOtherFileTypes:YES];
[panel setAllowedFileTypes:@[ filter.toNSString() ]];
[panel beginSheetModalForWindow:macWindow completionHandler:^(NSInteger returnCode)
{
NSLog(@"Return completion handler: %ld", (long)returnCode);
if (returnCode == NSOKButton)
{
result = [panel URL];
[result retain];
NSLog(@"NSOpenPanel completion handler block - URL is: %@", result);
}
loop->quit();
NSLog(@"Sent quit to loop");
}];
loop->exec();
qDebug() << Q_FUNC_INFO << "Loop quit";
QString answer;
if (result != nil)
{
NSLog(@"Got URL as %@ - is a file url: %s", result, ([result isFileURL] ? "YES" : "NO"));
if ([result isFileURL])
{
answer = QString::fromNSString([result path]);
if (instance()->isSandboxed())
{
QUrl url = QUrl::fromLocalFile(answer);
NSLog(@"Got Qt URL from NSURL - %s", qPrintable(url.toLocalFile()));
writePlaceHolderFile(url);
QScopedPointer<SecurityBookmarkManager> smgr(new SecurityBookmarkManager);
smgr->storeSecurityScope(result);
}
}
else
{
NSLog(@"### LOGIC ERROR: panel returned a non-file URL!!!!!!!");
}
[result release];
}
delete loop;
return answer;
}
void MacUtils::macLog(const QString &message)
{
NSLog(@"%s", qPrintable(message));
}
bool MacUtils::isSandboxed() const
{
NSLog(@"MacUtils::isSandboxed()");
if (!pvt->isInitialized)
{
NSDictionary* env = [[NSProcessInfo processInfo] environment];
BOOL freedom = ([env objectForKey:@"APP_SANDBOX_CONTAINER_ID"] == nil);
NSLog(@"APP_SANDBOX_CONTAINER_ID: %@", [env objectForKey:@"APP_SANDBOX_CONTAINER_ID"] );
pvt->isSandboxed = !freedom;
}
return pvt->isSandboxed;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment