8#include <QGlobalStatic>
12#include <QStandardPaths>
16#include <QCoreApplication>
19#include "ksharedconfig.h"
20#include "kconfiggroup.h"
30static QString cleanup(
const QString &path)
32 return QDir::cleanPath(path);
41 const QString writableLocation = []() {
42 QString location = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
47 if (location.back() ==
'/') {
50 return QString(location +
"/");
54 Q_FOREACH(
const QString &path, pathList) {
55 QString cleanPath = cleanup(path);
56 if (getRidOfAppDataLocation && cleanPath.startsWith(writableLocation)) {
59 cleanedPathList << cleanPath;
61 return cleanedPathList;
69 const QString writableLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
71 Q_FOREACH(
const QString &path, pathList) {
72 QString cleanPath = QDir::cleanPath(path) +
'/';
73 if (getRidOfAppDataLocation && cleanPath.startsWith(writableLocation)) {
76 cleanedPathList << cleanPath;
78 return cleanedPathList;
83 Q_FOREACH (
const QString &resource, src) {
84 QString realPath = QDir::cleanPath(resource);
85 if (!eliminateDuplicates || !dst->contains(realPath)) {
93static const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
95static const Qt::CaseSensitivity cs = Qt::CaseSensitive;
99#include <ApplicationServices/ApplicationServices.h>
100#include <CoreFoundation/CoreFoundation.h>
101#include <CoreServices/CoreServices.h>
104QString getInstallationPrefix() {
106 QString appPath = qApp->applicationDirPath();
109 appPath.chop(QString(
"MacOS/").
length());
112 bool makeInstall = QDir(appPath +
"/../../../share/kritaplugins").exists();
113 bool inBundle = QDir(appPath +
"/Resources/kritaplugins").exists();
118 bundlePath = appPath +
"/";
120 else if (makeInstall) {
121 appPath.chop(QString(
"Contents/").
length());
122 bundlePath = appPath +
"/../../";
128 QString envInstallPath = qgetenv(
"KIS_TEST_PREFIX_PATH");
129 if (!envInstallPath.isEmpty() && (
130 QDir(envInstallPath +
"/share/kritaplugins").exists()
131 || QDir(envInstallPath +
"/Resources/kritaplugins").exists() ))
133 bundlePath = envInstallPath;
136 qFatal(
"Cannot calculate the bundle path from the app path");
137 qInfo() <<
"If running tests set KIS_TEST_PREFIX_PATH to krita install prefix";
142#elif defined(Q_OS_HAIKU)
143 return qApp->applicationDirPath() +
"/";
144#elif defined(Q_OS_ANDROID)
148 return QStandardPaths::standardLocations(QStandardPaths::AppDataLocation)[1] +
"/";
150 return qApp->applicationDirPath() +
"/../";
168 relativesMutex.lock();
169 if (relatives.contains(type)) {
170 r += relatives[type];
172 relativesMutex.unlock();
173 absolutesMutex.lock();
174 if (absolutes.contains(type)) {
175 a += absolutes[type];
177 absolutesMutex.unlock();
184 if (type ==
"appdata") {
185 return QStandardPaths::AppDataLocation;
187 else if (type ==
"data") {
188 return QStandardPaths::AppDataLocation;
190 else if (type ==
"cache") {
191 return QStandardPaths::CacheLocation;
193 else if (type ==
"locale") {
194 return QStandardPaths::AppDataLocation;
196 else if (type ==
"genericdata") {
197 return QStandardPaths::GenericDataLocation;
200 return QStandardPaths::AppDataLocation;
216 return getInstallationPrefix();
227 KConfigGroup cfg(KSharedConfig::openConfig(),
"");
233 if (fi.exists() && !fi.isWritable()) {
234 path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
236 else if (!fi.exists()) {
238 if (!QDir().mkpath(path)) {
239 path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
250 standardLocation =
"";
251 privateLocation =
"";
255 standardLocation = resourcePath;
259 standardLocation = resourcePath;
264 const QDir resourceDir(resourcePath);
265 QDir appDataGeneralDir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
266 appDataGeneralDir.cdUp();
267 const QString appDataGeneralDirPath = appDataGeneralDir.path();
268 if (resourceDir.absolutePath().contains(appDataGeneralDirPath, Qt::CaseInsensitive)) {
277 const QString folderName = QFileInfo(resourcePath).fileName();
280 const QDir privateResourceDir(QDir::fromNativeSeparators(privateAppData) +
'/' + folderName);
282 standardLocation = resourcePath;
284 if (privateResourceDir.exists()) {
285 privateLocation = privateResourceDir.absolutePath();
291 standardLocation = resourcePath;
299 const QString &relativeName,
bool priority)
301 s_instance->addResourceTypeInternal(type, QString::fromLatin1(basetype), relativeName, priority);
306 s_instance->addResourceDirInternal(type, dir, priority);
311 return cleanup(s_instance->findResourceInternal(type, fileName));
316 return cleanupDirs(s_instance->findDirsInternal(type));
320 const QString &filter,
321 SearchOptions options)
323 return cleanup(s_instance->findAllResourcesInternal(type, filter, options));
328 return cleanupDirs(s_instance->resourceDirsInternal(type));
333 return QDir::cleanPath(s_instance->saveLocationInternal(type, suffix, create)) +
'/';
338 return cleanup(s_instance->locateInternal(type, filename));
343 return cleanup(s_instance->locateLocalInternal(type, filename, createDir));
347 const QString &relativename,
351 if (relativename.isEmpty())
return;
353 QString copy = relativename;
355 Q_ASSERT(basetype ==
"data");
357 if (!copy.endsWith(QLatin1Char(
'/'))) {
358 copy += QLatin1Char(
'/');
361 d->relativesMutex.lock();
364 if (!rels.contains(copy, cs)) {
371 d->relativesMutex.unlock();
373 dbgResources <<
"addResourceType: type" << type <<
"basetype" << basetype <<
"relativename" << relativename <<
"priority" << priority <<
d->relatives[type];
378 if (absdir.isEmpty() || type.isEmpty())
return;
381 QString copy = absdir;
382 if (copy.at(copy.length() - 1) != QLatin1Char(
'/')) {
383 copy += QLatin1Char(
'/');
386 d->absolutesMutex.lock();
388 if (!paths.contains(copy, cs)) {
395 d->absolutesMutex.unlock();
397 dbgResources <<
"addResourceDir: type" << type <<
"absdir" << absdir <<
"priority" << priority <<
d->absolutes[type];
404 QString resource = QStandardPaths::locate(QStandardPaths::AppDataLocation, fileName, QStandardPaths::LocateFile);
406 if (resource.isEmpty()) {
407 Q_FOREACH (
const QString &alias,
aliases) {
408 resource = QStandardPaths::locate(
d->mapTypeToQStandardPaths(type), alias +
'/' + fileName, QStandardPaths::LocateFile);
409 if (QFile::exists(resource)) {
414 if (resource.isEmpty() || !QFile::exists(resource)) {
416 Q_FOREACH (
const QString &alias,
aliases) {
417 resource = approot +
"/share/" + alias +
'/' + fileName;
418 if (QFile::exists(resource)) {
423 if (resource.isEmpty() || !QFile::exists(resource)) {
425 Q_FOREACH (
const QString &alias,
aliases) {
426 resource = approot +
"/share/krita/" + alias +
'/' + fileName;
427 if (QFile::exists(resource)) {
433 if (resource.isEmpty() || !QFile::exists(resource)) {
436 if (!extraResourceDirs.isEmpty()) {
437 Q_FOREACH(
const QString &extraResourceDir, extraResourceDirs) {
439 resource = extraResourceDir +
'/' + fileName;
441 if (QFile::exists(resource)) {
446 Q_FOREACH (
const QString &alias,
aliases) {
447 resource = extraResourceDir +
'/' + alias +
'/' + fileName;
449 if (QFile::exists(resource)) {
458 dbgResources<<
"findResource: type" << type <<
"filename" << fileName <<
"resource" << resource;
459 Q_ASSERT(!resource.isEmpty());
466 dbgResources <<
"filesInDir: startdir" << startdir <<
"filter" << filter <<
"recursive" << recursive;
471 nameFilters << filter;
472 const QStringList fileNames = QDir(startdir).entryList(nameFilters, QDir::Files | QDir::CaseSensitive, QDir::Name);
473 dbgResources <<
"\tFound:" << fileNames.size() <<
":" << fileNames;
474 Q_FOREACH (
const QString &fileName, fileNames) {
475 QString file = startdir +
'/' + fileName;
481 const QStringList entries = QDir(startdir).entryList(QDir::Dirs | QDir::NoDotAndDotDot);
482 Q_FOREACH (
const QString &subdir, entries) {
483 dbgResources <<
"\tGoing to look in subdir" << subdir <<
"of" << startdir;
484 result <<
filesInDir(startdir +
'/' + subdir, filter, recursive);
497 QStandardPaths::locateAll(
d->mapTypeToQStandardPaths(type),
"", QStandardPaths::LocateDirectory);
499 appendResources(&dirs, standardDirs,
true);
501 Q_FOREACH (
const QString &alias,
aliases) {
503 QStandardPaths::locateAll(
d->mapTypeToQStandardPaths(type), alias +
'/', QStandardPaths::LocateDirectory);
504 appendResources(&dirs, aliasDirs,
true);
512 appendResources(&dirs, bundlePaths,
true);
513 Q_ASSERT(!dirs.isEmpty());
519 appendResources(&dirs, fallbackPaths,
true);
524 saveLocationList <<
saveLocation(type, QString(),
true);
525 appendResources(&dirs, saveLocationList,
true);
527 dbgResources <<
"findDirs: type" << type <<
"resource" << dirs;
533 const QString &_filter,
534 SearchOptions options)
const
536 dbgResources <<
"=====================================================";
537 dbgResources << type << _filter << QStandardPaths::standardLocations(
d->mapTypeToQStandardPaths(type));
541 dbgResources <<
"findAllResources: type" << type <<
"filter" << _filter <<
"recursive" << recursive;
544 QString filter = _filter;
547 if (filter.indexOf(
'*') > 0) {
548 aliases << filter.split(
'*').first();
549 filter =
'*' + filter.split(
'*')[1];
556 QStandardPaths::locateAll(
d->mapTypeToQStandardPaths(type),
557 filter, QStandardPaths::LocateFile);
558 dbgResources <<
"standardResources" << standardResources;
559 appendResources(&resources, standardResources,
true);
565 if (!extraResourceDirs.isEmpty()) {
566 Q_FOREACH(
const QString &extraResourceDir, extraResourceDirs) {
568 appendResources(&resources,
filesInDir(extraResourceDir +
'/' + type, filter, recursive),
true);
571 Q_FOREACH (
const QString &alias,
aliases) {
572 appendResources(&resources,
filesInDir(extraResourceDir +
'/' + alias +
'/', filter, recursive),
true);
579 dbgResources <<
"\tresources from qstandardpaths:" << resources.size();
581 Q_FOREACH (
const QString &alias,
aliases) {
585 QFileInfo dirInfo(alias);
586 if (dirInfo.exists() && dirInfo.isDir() && dirInfo.isAbsolute()) {
589 dirs << QStandardPaths::locateAll(
d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory)
590 << getInstallationPrefix() +
"share/" + alias +
"/"
591 << getInstallationPrefix() +
"share/krita/" + alias +
"/";
594 Q_FOREACH (
const QString &dir, dirs) {
595 appendResources(&resources,
601 dbgResources <<
"\tresources also from aliases:" << resources.size();
605 QFileInfo fi(_filter);
608 prefixResources <<
filesInDir(getInstallationPrefix() +
"share/" + fi.path(), fi.fileName(),
false);
609 prefixResources <<
filesInDir(getInstallationPrefix() +
"share/krita/" + fi.path(), fi.fileName(),
false);
610 appendResources(&resources, prefixResources,
true);
612 dbgResources <<
"\tresources from installation:" << resources.size();
613 dbgResources <<
"=====================================================";
623 Q_FOREACH (
const QString &alias,
aliases) {
626 aliasDirs << QStandardPaths::locateAll(
d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory);
628 aliasDirs << getInstallationPrefix() +
"share/" + alias +
"/"
629 << QStandardPaths::locateAll(
d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory);
630 aliasDirs << getInstallationPrefix() +
"share/krita/" + alias +
"/"
631 << QStandardPaths::locateAll(
d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory);
633 appendResources(&resourceDirs, aliasDirs,
true);
636 dbgResources <<
"resourceDirs: type" << type << resourceDirs;
645 bool useStandardLocation =
false;
647 const QStandardPaths::StandardLocation location =
d->mapTypeToQStandardPaths(type);
649 if (location == QStandardPaths::AppDataLocation) {
650 KConfigGroup cfg(KSharedConfig::openConfig(),
"");
654 if (path.isEmpty()) {
655 path = QStandardPaths::writableLocation(location);
656 useStandardLocation =
true;
662 if (!path.endsWith(
"krita") && useStandardLocation) {
671 if (!suffix.isEmpty()) {
672 path +=
"/" + suffix;
677 if (!
d.exists() && create) {
680 dbgResources <<
"saveLocation: type" << type <<
"suffix" << suffix <<
"create" << create <<
"path" << path;
691 locations << QStandardPaths::locate(
d->mapTypeToQStandardPaths(type), filename, QStandardPaths::LocateFile);
694 Q_FOREACH (
const QString &alias,
aliases) {
695 locations << QStandardPaths::locate(
d->mapTypeToQStandardPaths(type),
696 (alias.endsWith(
'/') ? alias : alias +
'/') + filename, QStandardPaths::LocateFile);
698 dbgResources <<
"locate: type" << type <<
"filename" << filename <<
"locations" << locations;
699 if (locations.size() > 0) {
700 return locations.first();
710 dbgResources <<
"locateLocal: type" << type <<
"filename" << filename <<
"CreateDir" << createDir <<
"path" << path;
711 return path +
'/' + filename;
717 QString::fromUtf8(qgetenv(
"EXTRA_RESOURCE_DIRS"))
718 .split(
';', Qt::SkipEmptyParts);
720 const KConfigGroup cfg(KSharedConfig::openConfig(),
"");
721 const QString customPath =
723 if (!customPath.isEmpty()) {
724 extraResourceDirs << customPath;
727 if (
getAppDataLocation() != QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)) {
731 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()