QStandardPaths: add AppConfigLocation.

ConfigLocation was erroneously inconsistent, by adding the org name
and app name on Windows (unintentionally) and not on Unix (while having
subdirs in ~/.config is actually common practice for some XDG desktops)

Therefore this adds AppConfigLocation, which always has the org name
and app name (while GenericConfigLocation never does).

[ChangeLog][QtCore][QStandardPaths] Added QStandardPaths::AppConfigLocation,
for application-specific configuration directory. ConfigLocation was inconsistent.

Task-number: QTBUG-38872
Task-number: QTBUG-38845
Change-Id: I80fb98f296436261f3996c9df87571c29b06ab35
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@theqtcompany.com>
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
David Faure 2015-01-06 11:44:22 +01:00
parent 3b9629e8bd
commit 4c980aedc1
10 changed files with 78 additions and 14 deletions

View File

@ -142,6 +142,10 @@ QT_BEGIN_NAMESPACE
\value AppLocalDataLocation Returns the local settings path on the Windows operating \value AppLocalDataLocation Returns the local settings path on the Windows operating
system. On all other platforms, it returns the same value as AppDataLocation. system. On all other platforms, it returns the same value as AppDataLocation.
This enum value was added in Qt 5.4. This enum value was added in Qt 5.4.
\value AppConfigLocation Returns a directory location where user-specific
configuration files should be written. This is an application-specific directory,
and the returned path is never empty.
This enum value was added in Qt 5.5.
The following table gives examples of paths on different operating systems. The following table gives examples of paths on different operating systems.
The first path is the writable path (unless noted). Other, additional The first path is the writable path (unless noted). Other, additional
@ -206,6 +210,9 @@ QT_BEGIN_NAMESPACE
\row \li AppLocalDataLocation \row \li AppLocalDataLocation
\li "~/Library/Application Support/<APPNAME>", "/Library/Application Support/<APPNAME>". "<APPDIR>/../Resources" \li "~/Library/Application Support/<APPNAME>", "/Library/Application Support/<APPNAME>". "<APPDIR>/../Resources"
\li "C:/Users/<USER>/AppData/Local/<APPNAME>", "C:/ProgramData/<APPNAME>", "<APPDIR>", "<APPDIR>/data" \li "C:/Users/<USER>/AppData/Local/<APPNAME>", "C:/ProgramData/<APPNAME>", "<APPDIR>", "<APPDIR>/data"
\row \li AppConfigLocation
\li "~/Library/Preferences/<APPNAME>"
\li "C:/Users/<USER>/AppData/Local/<APPNAME>", "C:/ProgramData/<APPNAME>"
\endtable \endtable
\table \table
@ -267,6 +274,9 @@ QT_BEGIN_NAMESPACE
\row \li AppLocalDataLocation \row \li AppLocalDataLocation
\li "<APPROOT>/data", "<APPROOT>/app/native/assets" \li "<APPROOT>/data", "<APPROOT>/app/native/assets"
\li "~/.local/share/<APPNAME>", "/usr/local/share/<APPNAME>", "/usr/share/<APPNAME>" \li "~/.local/share/<APPNAME>", "/usr/local/share/<APPNAME>", "/usr/share/<APPNAME>"
\row \li AppConfigLocation
\li "<APPROOT>/data/Settings"
\li "~/.config/<APPNAME>", "/etc/xdg/<APPNAME>"
\endtable \endtable
\table \table
@ -307,6 +317,8 @@ QT_BEGIN_NAMESPACE
\li "<APPROOT>/cache" (there is no shared cache) \li "<APPROOT>/cache" (there is no shared cache)
\row \li AppDataLocation \row \li AppDataLocation
\li "<APPROOT>/files", "<USER>/<APPNAME>/files" \li "<APPROOT>/files", "<USER>/<APPNAME>/files"
\row \li AppConfigLocation
\li "<APPROOT>/files/settings"
\endtable \endtable
In the table above, \c <APPNAME> is usually the organization name, the In the table above, \c <APPNAME> is usually the organization name, the
@ -565,6 +577,8 @@ QString QStandardPaths::displayName(StandardLocation type)
case AppDataLocation: case AppDataLocation:
case AppLocalDataLocation: case AppLocalDataLocation:
return QCoreApplication::translate("QStandardPaths", "Application Data"); return QCoreApplication::translate("QStandardPaths", "Application Data");
case AppConfigLocation:
return QCoreApplication::translate("QStandardPaths", "Application Configuration");
} }
// not reached // not reached
return QString(); return QString();
@ -585,7 +599,7 @@ QString QStandardPaths::displayName(StandardLocation type)
This affects the locations into which test programs might write files: This affects the locations into which test programs might write files:
GenericDataLocation, DataLocation, ConfigLocation, GenericConfigLocation, GenericDataLocation, DataLocation, ConfigLocation, GenericConfigLocation,
GenericCacheLocation, CacheLocation. AppConfigLocation, GenericCacheLocation, CacheLocation.
Other locations are not affected. Other locations are not affected.
On Unix, \c XDG_DATA_HOME is set to \e ~/.qttest/share, \c XDG_CONFIG_HOME is On Unix, \c XDG_DATA_HOME is set to \e ~/.qttest/share, \c XDG_CONFIG_HOME is

View File

@ -64,6 +64,7 @@ public:
GenericCacheLocation, GenericCacheLocation,
GenericConfigLocation, GenericConfigLocation,
AppDataLocation, AppDataLocation,
AppConfigLocation,
AppLocalDataLocation = DataLocation AppLocalDataLocation = DataLocation
}; };

View File

@ -233,6 +233,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
return getExternalStoragePublicDirectory("DIRECTORY_DOWNLOADS"); return getExternalStoragePublicDirectory("DIRECTORY_DOWNLOADS");
case QStandardPaths::GenericConfigLocation: case QStandardPaths::GenericConfigLocation:
case QStandardPaths::ConfigLocation: case QStandardPaths::ConfigLocation:
case QStandardPaths::AppConfigLocation:
return getFilesDir() + testDir() + QLatin1String("/settings"); return getFilesDir() + testDir() + QLatin1String("/settings");
case QStandardPaths::GenericDataLocation: case QStandardPaths::GenericDataLocation:
return getExternalStorageDirectory() + testDir(); return getExternalStorageDirectory() + testDir();

View File

@ -69,6 +69,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
return QDir::homePath() + testModeInsert() + QLatin1String("/Cache"); return QDir::homePath() + testModeInsert() + QLatin1String("/Cache");
case ConfigLocation: case ConfigLocation:
case GenericConfigLocation: case GenericConfigLocation:
case AppConfigLocation:
return QDir::homePath() + testModeInsert() + QLatin1String("/Settings"); return QDir::homePath() + testModeInsert() + QLatin1String("/Settings");
case GenericDataLocation: case GenericDataLocation:
return sharedRoot + testModeInsert() + QLatin1String("/misc"); return sharedRoot + testModeInsert() + QLatin1String("/misc");

View File

@ -103,6 +103,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
break; break;
case ConfigLocation: case ConfigLocation:
case GenericConfigLocation: case GenericConfigLocation:
case AppConfigLocation:
location = pathForDirectory(NSDocumentDirectory); location = pathForDirectory(NSDocumentDirectory);
break; break;
case DownloadLocation: case DownloadLocation:

View File

@ -53,6 +53,7 @@ OSType translateLocation(QStandardPaths::StandardLocation type)
switch (type) { switch (type) {
case QStandardPaths::ConfigLocation: case QStandardPaths::ConfigLocation:
case QStandardPaths::GenericConfigLocation: case QStandardPaths::GenericConfigLocation:
case QStandardPaths::AppConfigLocation:
return kPreferencesFolderType; return kPreferencesFolderType;
case QStandardPaths::DesktopLocation: case QStandardPaths::DesktopLocation:
return kDesktopFolderType; return kDesktopFolderType;
@ -129,7 +130,8 @@ static QString macLocation(QStandardPaths::StandardLocation type, short domain)
QString path = getFullPath(ref); QString path = getFullPath(ref);
if (type == QStandardPaths::AppDataLocation || type == QStandardPaths::AppLocalDataLocation || type == QStandardPaths::CacheLocation) if (type == QStandardPaths::AppDataLocation || type == QStandardPaths::AppLocalDataLocation ||
type == QStandardPaths::CacheLocation || type == QStandardPaths::AppConfigLocation)
appendOrganizationAndApp(path); appendOrganizationAndApp(path);
return path; return path;
} }
@ -155,7 +157,11 @@ QString QStandardPaths::writableLocation(StandardLocation type)
return path; return path;
case GenericConfigLocation: case GenericConfigLocation:
case ConfigLocation: case ConfigLocation:
return qttestDir + QLatin1String("/Preferences"); case AppConfigLocation:
path = qttestDir + QLatin1String("/Preferences");
if (type == AppConfigLocation)
appendOrganizationAndApp(path);
return path;
default: default:
break; break;
} }

View File

@ -97,6 +97,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
} }
case ConfigLocation: case ConfigLocation:
case GenericConfigLocation: case GenericConfigLocation:
case AppConfigLocation:
{ {
// http://standards.freedesktop.org/basedir-spec/latest/ // http://standards.freedesktop.org/basedir-spec/latest/
QString xdgConfigHome = QFile::decodeName(qgetenv("XDG_CONFIG_HOME")); QString xdgConfigHome = QFile::decodeName(qgetenv("XDG_CONFIG_HOME"));
@ -104,6 +105,8 @@ QString QStandardPaths::writableLocation(StandardLocation type)
xdgConfigHome = QDir::homePath() + QLatin1String("/.qttest/config"); xdgConfigHome = QDir::homePath() + QLatin1String("/.qttest/config");
if (xdgConfigHome.isEmpty()) if (xdgConfigHome.isEmpty())
xdgConfigHome = QDir::homePath() + QLatin1String("/.config"); xdgConfigHome = QDir::homePath() + QLatin1String("/.config");
if (type == AppConfigLocation)
appendOrganizationAndApp(xdgConfigHome);
return xdgConfigHome; return xdgConfigHome;
} }
case RuntimeLocation: case RuntimeLocation:
@ -278,20 +281,30 @@ static QStringList xdgDataDirs()
return dirs; return dirs;
} }
QStringList QStandardPaths::standardLocations(StandardLocation type) static QStringList xdgConfigDirs()
{ {
QStringList dirs; QStringList dirs;
switch (type) {
case ConfigLocation:
case GenericConfigLocation:
{
// http://standards.freedesktop.org/basedir-spec/latest/ // http://standards.freedesktop.org/basedir-spec/latest/
const QString xdgConfigDirs = QFile::decodeName(qgetenv("XDG_CONFIG_DIRS")); const QString xdgConfigDirs = QFile::decodeName(qgetenv("XDG_CONFIG_DIRS"));
if (xdgConfigDirs.isEmpty()) if (xdgConfigDirs.isEmpty())
dirs.append(QString::fromLatin1("/etc/xdg")); dirs.append(QString::fromLatin1("/etc/xdg"));
else else
dirs = xdgConfigDirs.split(QLatin1Char(':')); dirs = xdgConfigDirs.split(QLatin1Char(':'));
} return dirs;
}
QStringList QStandardPaths::standardLocations(StandardLocation type)
{
QStringList dirs;
switch (type) {
case ConfigLocation:
case GenericConfigLocation:
dirs = xdgConfigDirs();
break;
case AppConfigLocation:
dirs = xdgConfigDirs();
for (int i = 0; i < dirs.count(); ++i)
appendOrganizationAndApp(dirs[i]);
break; break;
case GenericDataLocation: case GenericDataLocation:
dirs = xdgDataDirs(); dirs = xdgDataDirs();

View File

@ -98,6 +98,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
switch (type) { switch (type) {
case ConfigLocation: // same as AppLocalDataLocation, on Windows case ConfigLocation: // same as AppLocalDataLocation, on Windows
case GenericConfigLocation: // same as GenericDataLocation on Windows case GenericConfigLocation: // same as GenericDataLocation on Windows
case AppConfigLocation:
case AppDataLocation: case AppDataLocation:
case AppLocalDataLocation: case AppLocalDataLocation:
case GenericDataLocation: case GenericDataLocation:
@ -195,6 +196,7 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
switch (type) { switch (type) {
case ConfigLocation: // same as AppLocalDataLocation, on Windows (oversight, but too late to fix it) case ConfigLocation: // same as AppLocalDataLocation, on Windows (oversight, but too late to fix it)
case GenericConfigLocation: // same as GenericDataLocation, on Windows case GenericConfigLocation: // same as GenericDataLocation, on Windows
case AppConfigLocation: // same as AppLocalDataLocation, that one on purpose
case AppDataLocation: case AppDataLocation:
case AppLocalDataLocation: case AppLocalDataLocation:
case GenericDataLocation: case GenericDataLocation:

View File

@ -67,6 +67,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
switch (type) { switch (type) {
case ConfigLocation: // same as AppLocalDataLocation, on Windows case ConfigLocation: // same as AppLocalDataLocation, on Windows
case GenericConfigLocation: // same as GenericDataLocation, on Windows case GenericConfigLocation: // same as GenericDataLocation, on Windows
case AppConfigLocation:
case AppDataLocation: case AppDataLocation:
case AppLocalDataLocation: case AppLocalDataLocation:
case GenericDataLocation: { case GenericDataLocation: {

View File

@ -48,7 +48,8 @@
#define Q_XDG_PLATFORM #define Q_XDG_PLATFORM
#endif #endif
static const int MaxStandardLocation = QStandardPaths::AppDataLocation; // Update this when adding new enum values; update enumNames too
static const int MaxStandardLocation = QStandardPaths::AppConfigLocation;
class tst_qstandardpaths : public QObject class tst_qstandardpaths : public QObject
{ {
@ -61,6 +62,7 @@ private slots:
void enableTestMode(); void enableTestMode();
void testLocateAll(); void testLocateAll();
void testDataLocation(); void testDataLocation();
void testAppConfigLocation();
void testFindExecutable_data(); void testFindExecutable_data();
void testFindExecutable(); void testFindExecutable();
void testFindExecutableLinkToDirectory(); void testFindExecutableLinkToDirectory();
@ -122,7 +124,8 @@ static const char * const enumNames[MaxStandardLocation + 1 - int(QStandardPaths
"DownloadLocation", "DownloadLocation",
"GenericCacheLocation", "GenericCacheLocation",
"GenericConfigLocation", "GenericConfigLocation",
"AppDataLocation" "AppDataLocation",
"AppConfigLocation"
}; };
void tst_qstandardpaths::dump() void tst_qstandardpaths::dump()
@ -305,6 +308,27 @@ void tst_qstandardpaths::testDataLocation()
QCOMPARE(appDataDirs.at(1), QString::fromLatin1("/usr/local/share/Qt/QtTest")); QCOMPARE(appDataDirs.at(1), QString::fromLatin1("/usr/local/share/Qt/QtTest"));
QCOMPARE(appDataDirs.at(2), QString::fromLatin1("/usr/share/Qt/QtTest")); QCOMPARE(appDataDirs.at(2), QString::fromLatin1("/usr/share/Qt/QtTest"));
#endif #endif
// reset for other tests
QCoreApplication::setOrganizationName(QString());
QCoreApplication::setApplicationName(QString());
}
void tst_qstandardpaths::testAppConfigLocation()
{
// On all platforms where applications are not sandboxed,
// AppConfigLocation should be GenericConfigLocation / organization name / app name
#if !defined(Q_OS_BLACKBERRY) && !defined(Q_OS_ANDROID) && !defined(Q_OS_WINRT)
const QString base = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation), base + "/tst_qstandardpaths");
QCoreApplication::setOrganizationName("Qt");
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation), base + "/Qt/tst_qstandardpaths");
QCoreApplication::setApplicationName("QtTest");
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation), base + "/Qt/QtTest");
// reset for other tests
QCoreApplication::setOrganizationName(QString());
QCoreApplication::setApplicationName(QString());
#endif
} }
#ifndef Q_OS_WIN #ifndef Q_OS_WIN