Refactor standard paths for OS X and iOS.
This consolidates the _mac and _ios implementations into one, since most details of OS X and iOS are shared. The code base no longer uses deprecated Carbon File Manager APIs, instead using Foundation APIs and semi-hardcoding the two cases where a modern API is not available (Preferences and Fonts). A few paths have changed in order to be more similar between OS X and iOS where appropriate. Lastly, OS X now supports QT_NO_STANDARDPATHS. Change-Id: I63fa96e3ab80f8c6cf8a24243f859977e8c46421 Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@theqtcompany.com>
This commit is contained in:
parent
924d4aefd5
commit
14960f5227
@ -149,19 +149,12 @@ win32 {
|
||||
}
|
||||
freebsd: LIBS_PRIVATE += -lutil # qlockfile_unix.cpp requires this
|
||||
mac {
|
||||
SOURCES += io/qstorageinfo_mac.cpp
|
||||
OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm
|
||||
osx {
|
||||
OBJECTIVE_SOURCES += io/qfilesystemwatcher_fsevents.mm
|
||||
HEADERS += io/qfilesystemwatcher_fsevents_p.h
|
||||
}
|
||||
macx {
|
||||
SOURCES += io/qstorageinfo_mac.cpp
|
||||
OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm
|
||||
LIBS += -framework DiskArbitration -framework IOKit
|
||||
} else:ios {
|
||||
OBJECTIVE_SOURCES += io/qstandardpaths_ios.mm
|
||||
SOURCES += io/qstorageinfo_mac.cpp
|
||||
} else {
|
||||
SOURCES += io/qstandardpaths_unix.cpp
|
||||
}
|
||||
} else:blackberry {
|
||||
SOURCES += \
|
||||
|
@ -277,13 +277,13 @@ QT_BEGIN_NAMESPACE
|
||||
\header \li Path type \li Android \li iOS
|
||||
\row \li DesktopLocation
|
||||
\li "<APPROOT>/files"
|
||||
\li "<APPROOT>/<APPDIR>" (not writable)
|
||||
\li "<APPROOT>/Documents/Desktop"
|
||||
\row \li DocumentsLocation
|
||||
\li "<USER>/Documents", "<USER>/<APPNAME>/Documents"
|
||||
\li "<APPROOT>/Documents"
|
||||
\row \li FontsLocation
|
||||
\li "/system/fonts" (not writable)
|
||||
\li "<APPROOT>/Documents/.fonts"
|
||||
\li "<APPROOT>/Library/Fonts"
|
||||
\row \li ApplicationsLocation
|
||||
\li not supported (directory not readable)
|
||||
\li not supported
|
||||
@ -301,7 +301,7 @@ QT_BEGIN_NAMESPACE
|
||||
\li "<APPROOT>/tmp"
|
||||
\row \li HomeLocation
|
||||
\li "<APPROOT>/files"
|
||||
\li "<APPROOT>/<APPDIR>" (not writable)
|
||||
\li "<APPROOT>" (not writable)
|
||||
\row \li DataLocation
|
||||
\li "<APPROOT>/files", "<USER>/<APPNAME>/files"
|
||||
\li "<APPROOT>/Library/Application Support"
|
||||
@ -316,13 +316,13 @@ QT_BEGIN_NAMESPACE
|
||||
\li not supported
|
||||
\row \li ConfigLocation
|
||||
\li "<APPROOT>/files/settings"
|
||||
\li "<APPROOT>/Documents"
|
||||
\li "<APPROOT>/Library/Preferences"
|
||||
\row \li GenericConfigLocation
|
||||
\li "<APPROOT>/files/settings" (there is no shared settings)
|
||||
\li "<APPROOT>/Documents"
|
||||
\li "<APPROOT>/Library/Preferences"
|
||||
\row \li DownloadLocation
|
||||
\li "<USER>/Downloads", "<USER>/<APPNAME>/Downloads"
|
||||
\li "<APPROOT>/Documents/Download"
|
||||
\li "<APPROOT>/Documents/Downloads"
|
||||
\row \li GenericCacheLocation
|
||||
\li "<APPROOT>/cache" (there is no shared cache)
|
||||
\li "<APPROOT>/Library/Caches"
|
||||
@ -331,7 +331,7 @@ QT_BEGIN_NAMESPACE
|
||||
\li "<APPROOT>/Library/Application Support"
|
||||
\row \li AppConfigLocation
|
||||
\li "<APPROOT>/files/settings"
|
||||
\li "<APPROOT>/Documents"
|
||||
\li "<APPROOT>/Library/Preferences/<APPNAME>"
|
||||
\row \li AppLocalDataLocation
|
||||
\li "<APPROOT>/files", "<USER>/<APPNAME>/files"
|
||||
\li "<APPROOT>/Library/Application Support"
|
||||
@ -555,7 +555,7 @@ QString QStandardPaths::findExecutable(const QString &executableName, const QStr
|
||||
an empty QString if no relevant location can be found.
|
||||
*/
|
||||
|
||||
#if !defined(Q_OS_OSX) && !defined(QT_BOOTSTRAPPED)
|
||||
#if !defined(Q_OS_MAC) && !defined(QT_BOOTSTRAPPED)
|
||||
QString QStandardPaths::displayName(StandardLocation type)
|
||||
{
|
||||
switch (type) {
|
||||
|
@ -1,133 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL21$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see http://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** As a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#include "qstandardpaths.h"
|
||||
|
||||
#ifndef QT_NO_STANDARDPATHS
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
static QString pathForDirectory(NSSearchPathDirectory directory)
|
||||
{
|
||||
return QString::fromNSString(
|
||||
[NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES) lastObject]);
|
||||
}
|
||||
|
||||
static QString bundlePath()
|
||||
{
|
||||
return QString::fromNSString([[NSBundle mainBundle] bundlePath]);
|
||||
}
|
||||
|
||||
QString QStandardPaths::writableLocation(StandardLocation type)
|
||||
{
|
||||
QString location;
|
||||
|
||||
switch (type) {
|
||||
case DocumentsLocation:
|
||||
location = pathForDirectory(NSDocumentDirectory);
|
||||
break;
|
||||
case FontsLocation:
|
||||
location = pathForDirectory(NSDocumentDirectory) + QLatin1String("/.fonts");
|
||||
break;
|
||||
case ApplicationsLocation:
|
||||
// NSApplicationDirectory points to a non-existing write-protected path.
|
||||
break;
|
||||
case MusicLocation:
|
||||
// NSMusicDirectory points to a non-existing write-protected path. Use sensible fallback.
|
||||
location = pathForDirectory(NSDocumentDirectory) + QLatin1String("/Music");
|
||||
break;
|
||||
case MoviesLocation:
|
||||
// NSMoviesDirectory points to a non-existing write-protected path. Use sensible fallback.
|
||||
location = pathForDirectory(NSDocumentDirectory) + QLatin1String("/Movies");
|
||||
break;
|
||||
case PicturesLocation:
|
||||
// NSPicturesDirectory points to a non-existing write-protected path. Use sensible fallback.
|
||||
location = pathForDirectory(NSDocumentDirectory) + QLatin1String("/Pictures");
|
||||
break;
|
||||
case TempLocation:
|
||||
location = QString::fromNSString(NSTemporaryDirectory());
|
||||
break;
|
||||
case DesktopLocation:
|
||||
case HomeLocation:
|
||||
location = bundlePath();
|
||||
break;
|
||||
case AppDataLocation:
|
||||
case AppLocalDataLocation:
|
||||
location = pathForDirectory(NSApplicationSupportDirectory);
|
||||
break;
|
||||
case GenericDataLocation:
|
||||
location = pathForDirectory(NSDocumentDirectory);
|
||||
break;
|
||||
case CacheLocation:
|
||||
case GenericCacheLocation:
|
||||
location = pathForDirectory(NSCachesDirectory);
|
||||
break;
|
||||
case ConfigLocation:
|
||||
case GenericConfigLocation:
|
||||
case AppConfigLocation:
|
||||
location = pathForDirectory(NSDocumentDirectory);
|
||||
break;
|
||||
case DownloadLocation:
|
||||
// NSDownloadsDirectory points to a non-existing write-protected path.
|
||||
location = pathForDirectory(NSDocumentDirectory) + QLatin1String("/Download");
|
||||
break;
|
||||
case RuntimeLocation:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
QStringList QStandardPaths::standardLocations(StandardLocation type)
|
||||
{
|
||||
QStringList dirs;
|
||||
|
||||
switch (type) {
|
||||
case PicturesLocation:
|
||||
dirs << writableLocation(PicturesLocation) << QLatin1String("assets-library://");
|
||||
break;
|
||||
default:
|
||||
dirs << writableLocation(type);
|
||||
break;
|
||||
}
|
||||
|
||||
return dirs;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_NO_STANDARDPATHS
|
@ -32,6 +32,9 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "qstandardpaths.h"
|
||||
|
||||
#ifndef QT_NO_STANDARDPATHS
|
||||
|
||||
#include <qdir.h>
|
||||
#include <qurl.h>
|
||||
#include <private/qcore_mac_p.h>
|
||||
@ -40,63 +43,47 @@
|
||||
#include <qcoreapplication.h>
|
||||
#endif
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*
|
||||
Translates a QStandardPaths::StandardLocation into the mac equivalent.
|
||||
*/
|
||||
OSType translateLocation(QStandardPaths::StandardLocation type)
|
||||
static QString pathForDirectory(NSSearchPathDirectory directory,
|
||||
NSSearchPathDomainMask mask)
|
||||
{
|
||||
return QString::fromNSString(
|
||||
[NSSearchPathForDirectoriesInDomains(directory, mask, YES) lastObject]);
|
||||
}
|
||||
|
||||
static NSSearchPathDirectory searchPathDirectory(QStandardPaths::StandardLocation type)
|
||||
{
|
||||
switch (type) {
|
||||
case QStandardPaths::ConfigLocation:
|
||||
case QStandardPaths::GenericConfigLocation:
|
||||
case QStandardPaths::AppConfigLocation:
|
||||
return kPreferencesFolderType;
|
||||
case QStandardPaths::DesktopLocation:
|
||||
return kDesktopFolderType;
|
||||
return NSDesktopDirectory;
|
||||
case QStandardPaths::DocumentsLocation:
|
||||
return kDocumentsFolderType;
|
||||
case QStandardPaths::FontsLocation:
|
||||
// There are at least two different font directories on the mac: /Library/Fonts and ~/Library/Fonts.
|
||||
// To select a specific one we have to specify a different first parameter when calling FSFindFolder.
|
||||
return kFontsFolderType;
|
||||
return NSDocumentDirectory;
|
||||
case QStandardPaths::ApplicationsLocation:
|
||||
return kApplicationsFolderType;
|
||||
return NSApplicationDirectory;
|
||||
case QStandardPaths::MusicLocation:
|
||||
return kMusicDocumentsFolderType;
|
||||
return NSMusicDirectory;
|
||||
case QStandardPaths::MoviesLocation:
|
||||
return kMovieDocumentsFolderType;
|
||||
return NSMoviesDirectory;
|
||||
case QStandardPaths::PicturesLocation:
|
||||
return kPictureDocumentsFolderType;
|
||||
case QStandardPaths::TempLocation:
|
||||
return kTemporaryFolderType;
|
||||
return NSPicturesDirectory;
|
||||
case QStandardPaths::GenericDataLocation:
|
||||
case QStandardPaths::RuntimeLocation:
|
||||
case QStandardPaths::AppDataLocation:
|
||||
case QStandardPaths::AppLocalDataLocation:
|
||||
return kApplicationSupportFolderType;
|
||||
return NSApplicationSupportDirectory;
|
||||
case QStandardPaths::GenericCacheLocation:
|
||||
case QStandardPaths::CacheLocation:
|
||||
return kCachedDataFolderType;
|
||||
return NSCachesDirectory;
|
||||
case QStandardPaths::DownloadLocation:
|
||||
return NSDownloadsDirectory;
|
||||
default:
|
||||
return kDesktopFolderType;
|
||||
return (NSSearchPathDirectory)0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Constructs a full unicode path from a FSRef.
|
||||
*/
|
||||
static QString getFullPath(const FSRef &ref)
|
||||
{
|
||||
QByteArray ba(2048, 0);
|
||||
if (FSRefMakePath(&ref, reinterpret_cast<UInt8 *>(ba.data()), ba.size()) == noErr)
|
||||
return QString::fromUtf8(ba.constData()).normalized(QString::NormalizationForm_C);
|
||||
return QString();
|
||||
}
|
||||
|
||||
static void appendOrganizationAndApp(QString &path)
|
||||
{
|
||||
#ifndef QT_BOOTSTRAPPED
|
||||
@ -111,28 +98,65 @@ static void appendOrganizationAndApp(QString &path)
|
||||
#endif
|
||||
}
|
||||
|
||||
static QString macLocation(QStandardPaths::StandardLocation type, short domain)
|
||||
static QString baseWritableLocation(QStandardPaths::StandardLocation type,
|
||||
NSSearchPathDomainMask mask = NSUserDomainMask,
|
||||
bool appendOrgAndApp = false)
|
||||
{
|
||||
// https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/index.html
|
||||
if (type == QStandardPaths::DownloadLocation) {
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSURL *url = [fileManager URLForDirectory:NSDownloadsDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
|
||||
if (!url)
|
||||
return QString();
|
||||
return QString::fromNSString([url path]);
|
||||
QString path;
|
||||
const NSSearchPathDirectory dir = searchPathDirectory(type);
|
||||
switch (type) {
|
||||
case QStandardPaths::HomeLocation:
|
||||
path = QDir::homePath();
|
||||
break;
|
||||
case QStandardPaths::TempLocation:
|
||||
path = QDir::tempPath();
|
||||
break;
|
||||
#ifdef Q_OS_IOS
|
||||
// These locations point to non-existing write-protected paths. Use sensible fallbacks.
|
||||
case QStandardPaths::MusicLocation:
|
||||
path = pathForDirectory(NSDocumentDirectory, mask) + QLatin1String("/Music");
|
||||
break;
|
||||
case QStandardPaths::MoviesLocation:
|
||||
path = pathForDirectory(NSDocumentDirectory, mask) + QLatin1String("/Movies");
|
||||
break;
|
||||
case QStandardPaths::PicturesLocation:
|
||||
path = pathForDirectory(NSDocumentDirectory, mask) + QLatin1String("/Pictures");
|
||||
break;
|
||||
case QStandardPaths::DownloadLocation:
|
||||
path = pathForDirectory(NSDocumentDirectory, mask) + QLatin1String("/Downloads");
|
||||
break;
|
||||
case QStandardPaths::DesktopLocation:
|
||||
path = pathForDirectory(NSDocumentDirectory, mask) + QLatin1String("/Desktop");
|
||||
break;
|
||||
case QStandardPaths::ApplicationsLocation:
|
||||
break;
|
||||
#endif
|
||||
case QStandardPaths::FontsLocation:
|
||||
path = pathForDirectory(NSLibraryDirectory, mask) + QLatin1String("/Fonts");
|
||||
break;
|
||||
case QStandardPaths::ConfigLocation:
|
||||
case QStandardPaths::GenericConfigLocation:
|
||||
case QStandardPaths::AppConfigLocation:
|
||||
path = pathForDirectory(NSLibraryDirectory, mask) + QLatin1String("/Preferences");
|
||||
break;
|
||||
default:
|
||||
path = pathForDirectory(dir, mask);
|
||||
break;
|
||||
}
|
||||
|
||||
// http://developer.apple.com/documentation/Carbon/Reference/Folder_Manager/Reference/reference.html
|
||||
FSRef ref;
|
||||
OSErr err = FSFindFolder(domain, translateLocation(type), false, &ref);
|
||||
if (err)
|
||||
return QString();
|
||||
|
||||
QString path = getFullPath(ref);
|
||||
|
||||
if (type == QStandardPaths::AppDataLocation || type == QStandardPaths::AppLocalDataLocation ||
|
||||
type == QStandardPaths::CacheLocation || type == QStandardPaths::AppConfigLocation)
|
||||
if (appendOrgAndApp) {
|
||||
switch (type) {
|
||||
case QStandardPaths::AppDataLocation:
|
||||
case QStandardPaths::AppLocalDataLocation:
|
||||
case QStandardPaths::AppConfigLocation:
|
||||
case QStandardPaths::CacheLocation:
|
||||
appendOrganizationAndApp(path);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@ -167,32 +191,33 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
||||
}
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case HomeLocation:
|
||||
return QDir::homePath();
|
||||
case TempLocation:
|
||||
return QDir::tempPath();
|
||||
case GenericDataLocation:
|
||||
case AppDataLocation:
|
||||
case AppLocalDataLocation:
|
||||
case GenericCacheLocation:
|
||||
case CacheLocation:
|
||||
case RuntimeLocation:
|
||||
return macLocation(type, kUserDomain);
|
||||
default:
|
||||
return macLocation(type, kOnAppropriateDisk);
|
||||
}
|
||||
return baseWritableLocation(type, NSUserDomainMask, true);
|
||||
}
|
||||
|
||||
QStringList QStandardPaths::standardLocations(StandardLocation type)
|
||||
{
|
||||
QStringList dirs;
|
||||
|
||||
if (type == GenericDataLocation || type == AppDataLocation || type == AppLocalDataLocation || type == GenericCacheLocation || type == CacheLocation) {
|
||||
const QString path = macLocation(type, kOnAppropriateDisk);
|
||||
if (!path.isEmpty())
|
||||
#ifdef Q_OS_IOS
|
||||
if (type == PicturesLocation)
|
||||
dirs << writableLocation(PicturesLocation) << QLatin1String("assets-library://");
|
||||
#endif
|
||||
|
||||
if (type == GenericDataLocation || type == FontsLocation || type == ApplicationsLocation
|
||||
|| type == AppDataLocation || type == AppLocalDataLocation
|
||||
|| type == GenericCacheLocation || type == CacheLocation) {
|
||||
QList<NSSearchPathDomainMask> masks;
|
||||
masks << NSLocalDomainMask;
|
||||
if (type == FontsLocation || type == GenericCacheLocation)
|
||||
masks << NSSystemDomainMask;
|
||||
|
||||
for (QList<NSSearchPathDomainMask>::const_iterator it = masks.begin();
|
||||
it != masks.end(); ++it) {
|
||||
const QString path = baseWritableLocation(type, *it, true);
|
||||
if (!path.isEmpty() && !dirs.contains(path))
|
||||
dirs.append(path);
|
||||
}
|
||||
}
|
||||
|
||||
if (type == AppDataLocation || type == AppLocalDataLocation) {
|
||||
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
||||
@ -219,6 +244,7 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
|
||||
}
|
||||
}
|
||||
const QString localDir = writableLocation(type);
|
||||
if (!localDir.isEmpty())
|
||||
dirs.prepend(localDir);
|
||||
return dirs;
|
||||
}
|
||||
@ -226,21 +252,33 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
|
||||
#ifndef QT_BOOTSTRAPPED
|
||||
QString QStandardPaths::displayName(StandardLocation type)
|
||||
{
|
||||
// Use "Home" instead of the user's Unix username
|
||||
if (QStandardPaths::HomeLocation == type)
|
||||
return QCoreApplication::translate("QStandardPaths", "Home");
|
||||
|
||||
FSRef ref;
|
||||
OSErr err = FSFindFolder(kOnAppropriateDisk, translateLocation(type), false, &ref);
|
||||
if (err)
|
||||
return QString();
|
||||
// The temporary directory returned by the old Carbon APIs is ~/Library/Caches/TemporaryItems,
|
||||
// the display name of which ("TemporaryItems") isn't translated by the system. The standard
|
||||
// temporary directory has no reasonable display name either, so use something more sensible.
|
||||
if (QStandardPaths::TempLocation == type)
|
||||
return QCoreApplication::translate("QStandardPaths", "Temporary Items");
|
||||
|
||||
QCFString displayName;
|
||||
err = LSCopyDisplayNameForRef(&ref, &displayName);
|
||||
if (err)
|
||||
return QString();
|
||||
// standardLocations() may return an empty list on some platforms
|
||||
if (QStandardPaths::ApplicationsLocation == type)
|
||||
return QCoreApplication::translate("QStandardPaths", "Applications");
|
||||
|
||||
return static_cast<QString>(displayName);
|
||||
if (QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
|
||||
standardLocations(type).first().toCFString(),
|
||||
kCFURLPOSIXPathStyle, true)) {
|
||||
QCFString name;
|
||||
CFURLCopyResourcePropertyForKey(url, kCFURLLocalizedNameKey, &name, NULL);
|
||||
if (name && CFStringGetLength(name))
|
||||
return QString::fromCFString(name);
|
||||
}
|
||||
|
||||
return QFileInfo(baseWritableLocation(type)).fileName();
|
||||
}
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_NO_STANDARDPATHS
|
||||
|
Loading…
Reference in New Issue
Block a user