8#include <QGlobalStatic>
12#include <QStandardPaths>
16#include <QCoreApplication>
18#include <QRegularExpression>
20#include "ksharedconfig.h"
21#include "kconfiggroup.h"
31static QString cleanup(
const QString &path)
33 return QDir::cleanPath(path);
42 const QString writableLocation = []() {
43 QString location = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
48 if (location.back() ==
'/') {
51 return QString(location +
"/");
55 Q_FOREACH(
const QString &path, pathList) {
56 QString cleanPath = cleanup(path);
57 if (getRidOfAppDataLocation && cleanPath.startsWith(writableLocation)) {
60 cleanedPathList << cleanPath;
62 return cleanedPathList;
70 const QString writableLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
72 Q_FOREACH(
const QString &path, pathList) {
73 QString cleanPath = QDir::cleanPath(path) +
'/';
74 if (getRidOfAppDataLocation && cleanPath.startsWith(writableLocation)) {
77 cleanedPathList << cleanPath;
79 return cleanedPathList;
84 Q_FOREACH (
const QString &resource, src) {
85 QString realPath = QDir::cleanPath(resource);
86 if (!eliminateDuplicates || !dst->contains(realPath)) {
94static const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
96static const Qt::CaseSensitivity cs = Qt::CaseSensitive;
100#include <ApplicationServices/ApplicationServices.h>
101#include <CoreFoundation/CoreFoundation.h>
102#include <CoreServices/CoreServices.h>
105QString getInstallationPrefix() {
107 QString appPath = qApp->applicationDirPath();
110 appPath.chop(QString(
"MacOS/").
length());
113 bool makeInstall = QDir(appPath +
"/../../../share/kritaplugins").exists();
114 bool inBundle = QDir(appPath +
"/Resources/kritaplugins").exists();
119 bundlePath = appPath +
"/";
121 else if (makeInstall) {
122 appPath.chop(QString(
"Contents/").
length());
123 bundlePath = appPath +
"/../../";
129 QString envInstallPath = qgetenv(
"KIS_TEST_PREFIX_PATH");
130 if (!envInstallPath.isEmpty() && (
131 QDir(envInstallPath +
"/share/kritaplugins").exists()
132 || QDir(envInstallPath +
"/Resources/kritaplugins").exists() ))
134 bundlePath = envInstallPath;
137 qFatal(
"Cannot calculate the bundle path from the app path");
138 qInfo() <<
"If running tests set KIS_TEST_PREFIX_PATH to krita install prefix";
143#elif defined(Q_OS_HAIKU)
144 return qApp->applicationDirPath() +
"/";
145#elif defined(Q_OS_ANDROID)
149 return QStandardPaths::standardLocations(QStandardPaths::AppDataLocation)[1] +
"/";
151 return qApp->applicationDirPath() +
"/../";
169 relativesMutex.lock();
170 if (relatives.contains(type)) {
171 r += relatives[type];
173 relativesMutex.unlock();
174 absolutesMutex.lock();
175 if (absolutes.contains(type)) {
176 a += absolutes[type];
178 absolutesMutex.unlock();
185 if (type ==
"appdata") {
186 return QStandardPaths::AppDataLocation;
188 else if (type ==
"data") {
189 return QStandardPaths::AppDataLocation;
191 else if (type ==
"cache") {
192 return QStandardPaths::CacheLocation;
194 else if (type ==
"locale") {
195 return QStandardPaths::AppDataLocation;
197 else if (type ==
"genericdata") {
198 return QStandardPaths::GenericDataLocation;
201 return QStandardPaths::AppDataLocation;
217 return getInstallationPrefix();
228 KConfigGroup cfg(KSharedConfig::openConfig(),
"");
237 QRegularExpression windowsPathPattern(
"^[A-Za-z]:/");
238 if (windowsPathPattern.match(path).hasMatch()) {
239 warnResources <<
"WARNING: KoResourcePaths::getAppDataLocation(): path appears to be a Windows path! Resetting to default..."
242 << QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
243 path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
247#elif defined Q_OS_WIN
250 QRegularExpression windowsPathPattern(
"^/[^/]");
251 if (windowsPathPattern.match(path).hasMatch()) {
252 warnResources <<
"WARNING: KoResourcePaths::getAppDataLocation(): path appears to be a Unix path! Resetting to default..."
255 << QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
256 path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
266 if (fi.isRelative()) {
267 warnResources <<
"WARNING: KoResourcePaths::getAppDataLocation(): resources location is not absolute! Fixing..." << path;
268 path = fi.absoluteFilePath();
274 if (fi.exists() && !fi.isWritable()) {
275 path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
277 else if (!fi.exists()) {
279 if (!QDir().mkpath(path)) {
280 path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
291 standardLocation =
"";
292 privateLocation =
"";
296 standardLocation = resourcePath;
300 standardLocation = resourcePath;
305 const QDir resourceDir(resourcePath);
306 QDir appDataGeneralDir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
307 appDataGeneralDir.cdUp();
308 const QString appDataGeneralDirPath = appDataGeneralDir.path();
309 if (resourceDir.absolutePath().contains(appDataGeneralDirPath, Qt::CaseInsensitive)) {
318 const QString folderName = QFileInfo(resourcePath).fileName();
321 const QDir privateResourceDir(QDir::fromNativeSeparators(privateAppData) +
'/' + folderName);
323 standardLocation = resourcePath;
325 if (privateResourceDir.exists()) {
326 privateLocation = privateResourceDir.absolutePath();
332 standardLocation = resourcePath;
340 const QString &relativeName,
bool priority)
342 s_instance->addResourceTypeInternal(type, QString::fromLatin1(basetype), relativeName, priority);
347 s_instance->addResourceDirInternal(type, dir, priority);
352 return cleanup(s_instance->findResourceInternal(type, fileName));
357 return cleanupDirs(s_instance->findDirsInternal(type));
361 const QString &filter,
362 SearchOptions options)
364 return cleanup(s_instance->findAllResourcesInternal(type, filter, options));
369 return cleanupDirs(s_instance->resourceDirsInternal(type));
374 return QDir::cleanPath(s_instance->saveLocationInternal(type, suffix, create)) +
'/';
379 return cleanup(s_instance->locateInternal(type, filename));
384 return cleanup(s_instance->locateLocalInternal(type, filename, createDir));
388 const QString &relativename,
392 if (relativename.isEmpty())
return;
394 QString copy = relativename;
396 Q_ASSERT(basetype ==
"data");
398 if (!copy.endsWith(QLatin1Char(
'/'))) {
399 copy += QLatin1Char(
'/');
402 d->relativesMutex.lock();
405 if (!rels.contains(copy, cs)) {
412 d->relativesMutex.unlock();
414 dbgResources <<
"addResourceType: type" << type <<
"basetype" << basetype <<
"relativename" << relativename <<
"priority" << priority <<
d->relatives[type];
419 if (absdir.isEmpty() || type.isEmpty())
return;
422 QString copy = absdir;
423 if (copy.at(copy.length() - 1) != QLatin1Char(
'/')) {
424 copy += QLatin1Char(
'/');
427 d->absolutesMutex.lock();
429 if (!paths.contains(copy, cs)) {
436 d->absolutesMutex.unlock();
438 dbgResources <<
"addResourceDir: type" << type <<
"absdir" << absdir <<
"priority" << priority <<
d->absolutes[type];
445 QString resource = QStandardPaths::locate(QStandardPaths::AppDataLocation, fileName, QStandardPaths::LocateFile);
447 if (resource.isEmpty()) {
448 Q_FOREACH (
const QString &alias,
aliases) {
449 resource = QStandardPaths::locate(
d->mapTypeToQStandardPaths(type), alias +
'/' + fileName, QStandardPaths::LocateFile);
450 if (QFile::exists(resource)) {
455 if (resource.isEmpty() || !QFile::exists(resource)) {
457 Q_FOREACH (
const QString &alias,
aliases) {
458 resource = approot +
"/share/" + alias +
'/' + fileName;
459 if (QFile::exists(resource)) {
464 if (resource.isEmpty() || !QFile::exists(resource)) {
466 Q_FOREACH (
const QString &alias,
aliases) {
467 resource = approot +
"/share/krita/" + alias +
'/' + fileName;
468 if (QFile::exists(resource)) {
474 if (resource.isEmpty() || !QFile::exists(resource)) {
477 if (!extraResourceDirs.isEmpty()) {
478 Q_FOREACH(
const QString &extraResourceDir, extraResourceDirs) {
480 resource = extraResourceDir +
'/' + fileName;
482 if (QFile::exists(resource)) {
487 Q_FOREACH (
const QString &alias,
aliases) {
488 resource = extraResourceDir +
'/' + alias +
'/' + fileName;
490 if (QFile::exists(resource)) {
499 dbgResources<<
"findResource: type" << type <<
"filename" << fileName <<
"resource" << resource;
500 Q_ASSERT(!resource.isEmpty());
507 dbgResources <<
"filesInDir: startdir" << startdir <<
"filter" << filter <<
"recursive" << recursive;
512 nameFilters << filter;
513 const QStringList fileNames = QDir(startdir).entryList(nameFilters, QDir::Files | QDir::CaseSensitive, QDir::Name);
514 dbgResources <<
"\tFound:" << fileNames.size() <<
":" << fileNames;
515 Q_FOREACH (
const QString &fileName, fileNames) {
516 QString file = startdir +
'/' + fileName;
522 const QStringList entries = QDir(startdir).entryList(QDir::Dirs | QDir::NoDotAndDotDot);
523 Q_FOREACH (
const QString &subdir, entries) {
524 dbgResources <<
"\tGoing to look in subdir" << subdir <<
"of" << startdir;
525 result <<
filesInDir(startdir +
'/' + subdir, filter, recursive);
538 QStandardPaths::locateAll(
d->mapTypeToQStandardPaths(type),
"", QStandardPaths::LocateDirectory);
540 appendResources(&dirs, standardDirs,
true);
542 Q_FOREACH (
const QString &alias,
aliases) {
544 QStandardPaths::locateAll(
d->mapTypeToQStandardPaths(type), alias +
'/', QStandardPaths::LocateDirectory);
545 appendResources(&dirs, aliasDirs,
true);
553 appendResources(&dirs, bundlePaths,
true);
554 Q_ASSERT(!dirs.isEmpty());
560 appendResources(&dirs, fallbackPaths,
true);
565 saveLocationList <<
saveLocation(type, QString(),
true);
566 appendResources(&dirs, saveLocationList,
true);
568 dbgResources <<
"findDirs: type" << type <<
"resource" << dirs;
574 const QString &_filter,
575 SearchOptions options)
const
577 dbgResources <<
"=====================================================";
578 dbgResources << type << _filter << QStandardPaths::standardLocations(
d->mapTypeToQStandardPaths(type));
582 dbgResources <<
"findAllResources: type" << type <<
"filter" << _filter <<
"recursive" << recursive;
585 QString filter = _filter;
588 if (filter.indexOf(
'*') > 0) {
589 aliases << filter.split(
'*').first();
590 filter =
'*' + filter.split(
'*')[1];
597 QStandardPaths::locateAll(
d->mapTypeToQStandardPaths(type),
598 filter, QStandardPaths::LocateFile);
599 dbgResources <<
"standardResources" << standardResources;
600 appendResources(&resources, standardResources,
true);
606 if (!extraResourceDirs.isEmpty()) {
607 Q_FOREACH(
const QString &extraResourceDir, extraResourceDirs) {
609 appendResources(&resources,
filesInDir(extraResourceDir +
'/' + type, filter, recursive),
true);
612 Q_FOREACH (
const QString &alias,
aliases) {
613 appendResources(&resources,
filesInDir(extraResourceDir +
'/' + alias +
'/', filter, recursive),
true);
620 dbgResources <<
"\tresources from qstandardpaths:" << resources.size();
622 Q_FOREACH (
const QString &alias,
aliases) {
626 QFileInfo dirInfo(alias);
627 if (dirInfo.exists() && dirInfo.isDir() && dirInfo.isAbsolute()) {
630 dirs << QStandardPaths::locateAll(
d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory)
631 << getInstallationPrefix() +
"share/" + alias +
"/"
632 << getInstallationPrefix() +
"share/krita/" + alias +
"/";
635 Q_FOREACH (
const QString &dir, dirs) {
636 appendResources(&resources,
642 dbgResources <<
"\tresources also from aliases:" << resources.size();
646 QFileInfo fi(_filter);
649 prefixResources <<
filesInDir(getInstallationPrefix() +
"share/" + fi.path(), fi.fileName(),
false);
650 prefixResources <<
filesInDir(getInstallationPrefix() +
"share/krita/" + fi.path(), fi.fileName(),
false);
651 appendResources(&resources, prefixResources,
true);
653 dbgResources <<
"\tresources from installation:" << resources.size();
654 dbgResources <<
"=====================================================";
664 Q_FOREACH (
const QString &alias,
aliases) {
667 aliasDirs << QStandardPaths::locateAll(
d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory);
669 aliasDirs << getInstallationPrefix() +
"share/" + alias +
"/"
670 << QStandardPaths::locateAll(
d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory);
671 aliasDirs << getInstallationPrefix() +
"share/krita/" + alias +
"/"
672 << QStandardPaths::locateAll(
d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory);
674 appendResources(&resourceDirs, aliasDirs,
true);
677 dbgResources <<
"resourceDirs: type" << type << resourceDirs;
686 bool useStandardLocation =
false;
688 const QStandardPaths::StandardLocation location =
d->mapTypeToQStandardPaths(type);
690 if (location == QStandardPaths::AppDataLocation) {
691 KConfigGroup cfg(KSharedConfig::openConfig(),
"");
695 if (path.isEmpty()) {
696 path = QStandardPaths::writableLocation(location);
697 useStandardLocation =
true;
703 if (!path.endsWith(
"krita") && useStandardLocation) {
712 if (!suffix.isEmpty()) {
713 path +=
"/" + suffix;
718 if (!
d.exists() && create) {
721 dbgResources <<
"saveLocation: type" << type <<
"suffix" << suffix <<
"create" << create <<
"path" << path;
732 locations << QStandardPaths::locate(
d->mapTypeToQStandardPaths(type), filename, QStandardPaths::LocateFile);
735 Q_FOREACH (
const QString &alias,
aliases) {
736 locations << QStandardPaths::locate(
d->mapTypeToQStandardPaths(type),
737 (alias.endsWith(
'/') ? alias : alias +
'/') + filename, QStandardPaths::LocateFile);
739 dbgResources <<
"locate: type" << type <<
"filename" << filename <<
"locations" << locations;
740 if (locations.size() > 0) {
741 return locations.first();
751 dbgResources <<
"locateLocal: type" << type <<
"filename" << filename <<
"CreateDir" << createDir <<
"path" << path;
752 return path +
'/' + filename;
758 QString::fromUtf8(qgetenv(
"EXTRA_RESOURCE_DIRS"))
759 .split(
';', Qt::SkipEmptyParts);
761 const KConfigGroup cfg(KSharedConfig::openConfig(),
"");
762 const QString customPath =
764 if (!customPath.isEmpty()) {
765 extraResourceDirs << customPath;
768 if (
getAppDataLocation() != QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)) {
772 return extraResourceDirs;
qreal length(const QPointF &vec)
Q_GLOBAL_STATIC(KisStoragePluginRegistry, s_instance)
QStringList filesInDir(const QString &startdir, const QString &filter, bool recursive)
static const QString resourceLocationKey
static KisResourceLocator * instance()
static void getAllUserResourceFoldersLocationsForWindowsStore(QString &standardLocation, QString &privateLocation)
getAllAppDataLocationsForWindowsStore Use this to get both private and general appdata folders which ...
virtual ~KoResourcePaths()
QStringList aliases(const QString &type)
QMap< QString, QStringList > absolutes
static QString locateLocal(const QString &type, const QString &filename, bool createDir=false)
static void addAssetDir(const QString &type, const QString &dir, bool priority=true)
QScopedPointer< Private > d
static QString locate(const QString &type, const QString &filename)
static QString getAppDataLocation()
QString locateLocalInternal(const QString &type, const QString &filename, bool createDir=false)
static void addAssetType(const QString &type, const char *basetype, const QString &relativeName, bool priority=true)
QStringList resourceDirsInternal(const QString &type)
static QString getApplicationRoot()
QString saveLocationInternal(const QString &type, const QString &suffix=QString(), bool create=true)
QStandardPaths::StandardLocation mapTypeToQStandardPaths(const QString &type)
void addResourceDirInternal(const QString &type, const QString &absdir, bool priority)
static QStringList findAllAssets(const QString &type, const QString &filter=QString(), SearchOptions options=NoSearchOptions)
QStringList findAllResourcesInternal(const QString &type, const QString &filter=QString(), SearchOptions options=NoSearchOptions) const
static QStringList findDirs(const QString &type)
QMap< QString, QStringList > relatives
QStringList findExtraResourceDirs() const
static QString saveLocation(const QString &type, const QString &suffix=QString(), bool create=true)
static QStringList assetDirs(const QString &type)
static QString s_overrideAppDataLocation
getAppDataLocation Use this instead of QStandardPaths::AppDataLocation! The user can configure the lo...
static QString findAsset(const QString &type, const QString &fileName)
QString locateInternal(const QString &type, const QString &filename)
QString findResourceInternal(const QString &type, const QString &fileName)
QStringList findDirsInternal(const QString &type)
void addResourceTypeInternal(const QString &type, const QString &basetype, const QString &relativeName, bool priority)
QString getPackageRoamingAppDataLocation()
bool isRunningInPackage()