Krita Source Code Documentation
Loading...
Searching...
No Matches
KoResourcePaths.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2015 Boudewijn Rempt <boud@valdyas.org>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6#include "KoResourcePaths.h"
7
8#include <QGlobalStatic>
9#include <QString>
10#include <QStringList>
11#include <QMap>
12#include <QStandardPaths>
13#include <QDir>
14#include <QFileInfo>
15#include <QDebug>
16#include <QCoreApplication>
17#include <QMutex>
18#include "kis_debug.h"
19#include "ksharedconfig.h"
20#include "kconfiggroup.h"
21#include "KisResourceLocator.h"
23
25
27
28namespace {
29
30static QString cleanup(const QString &path)
31{
32 return QDir::cleanPath(path);
33}
34
35
36static QStringList cleanup(const QStringList &pathList)
37{
38 QStringList cleanedPathList;
39
40 bool getRidOfAppDataLocation = KoResourcePaths::getAppDataLocation() != QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
41 const QString writableLocation = []() {
42 QString location = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
43 // we have to ensure that the location has a trailing separator, because otherwise when we'll do startsWith
44 // check it will skip paths that start have the same path but different directory name. E.g:
45 // ~/.local/share/krita -> AppDataLocation
46 // ~/.local/share/krita3 -> custom location, but this will be skipped in getRidOfAppDataLocation.
47 if (location.back() == '/') {
48 return location;
49 } else {
50 return QString(location + "/");
51 }
52 }();
53
54 Q_FOREACH(const QString &path, pathList) {
55 QString cleanPath = cleanup(path);
56 if (getRidOfAppDataLocation && cleanPath.startsWith(writableLocation)) {
57 continue;
58 }
59 cleanedPathList << cleanPath;
60 }
61 return cleanedPathList;
62}
63
64static QStringList cleanupDirs(const QStringList &pathList)
65{
66 QStringList cleanedPathList;
67
68 bool getRidOfAppDataLocation = KoResourcePaths::getAppDataLocation() != QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
69 const QString writableLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
70
71 Q_FOREACH(const QString &path, pathList) {
72 QString cleanPath = QDir::cleanPath(path) + '/';
73 if (getRidOfAppDataLocation && cleanPath.startsWith(writableLocation)) {
74 continue;
75 }
76 cleanedPathList << cleanPath;
77 }
78 return cleanedPathList;
79}
80
81void appendResources(QStringList *dst, const QStringList &src, bool eliminateDuplicates)
82{
83 Q_FOREACH (const QString &resource, src) {
84 QString realPath = QDir::cleanPath(resource);
85 if (!eliminateDuplicates || !dst->contains(realPath)) {
86 *dst << realPath;
87 }
88 }
89}
90
91
92#ifdef Q_OS_WIN
93static const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
94#else
95static const Qt::CaseSensitivity cs = Qt::CaseSensitive;
96#endif
97
98#ifdef Q_OS_MACOS
99#include <ApplicationServices/ApplicationServices.h>
100#include <CoreFoundation/CoreFoundation.h>
101#include <CoreServices/CoreServices.h>
102#endif
103
104QString getInstallationPrefix() {
105#ifdef Q_OS_MACOS
106 QString appPath = qApp->applicationDirPath();
107
108 dbgResources << "1" << appPath;
109 appPath.chop(QString("MacOS/").length());
110 dbgResources << "2" << appPath;
111
112 bool makeInstall = QDir(appPath + "/../../../share/kritaplugins").exists();
113 bool inBundle = QDir(appPath + "/Resources/kritaplugins").exists();
114
115 QString bundlePath;
116
117 if (inBundle) {
118 bundlePath = appPath + "/";
119 }
120 else if (makeInstall) {
121 appPath.chop(QString("Contents/").length());
122 bundlePath = appPath + "/../../";
123 }
124 else {
125 // This is needed as tests will not run outside of the
126 // install directory without this
127 // This needs krita to be installed.
128 QString envInstallPath = qgetenv("KIS_TEST_PREFIX_PATH");
129 if (!envInstallPath.isEmpty() && (
130 QDir(envInstallPath + "/share/kritaplugins").exists()
131 || QDir(envInstallPath + "/Resources/kritaplugins").exists() ))
132 {
133 bundlePath = envInstallPath;
134 }
135 else {
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";
138 }
139 }
140
141 return bundlePath;
142#elif defined(Q_OS_HAIKU)
143 return qApp->applicationDirPath() + "/";
144#elif defined(Q_OS_ANDROID)
145 // qApp->applicationDirPath() isn't writable and android system won't allow
146 // any files other than libraries
147 // NOTE the subscript [1]. It points to the internal location.
148 return QStandardPaths::standardLocations(QStandardPaths::AppDataLocation)[1] + "/";
149#else
150 return qApp->applicationDirPath() + "/../";
151#endif
152}
153
154}
155
156class Q_DECL_HIDDEN KoResourcePaths::Private {
157public:
158 QMap<QString, QStringList> absolutes; // For each resource type, the list of absolute paths, from most local (most priority) to most global
159 QMap<QString, QStringList> relatives; // Same with relative paths
160
163
164 QStringList aliases(const QString &type)
165 {
166 QStringList r;
167 QStringList a;
168 relativesMutex.lock();
169 if (relatives.contains(type)) {
170 r += relatives[type];
171 }
172 relativesMutex.unlock();
173 absolutesMutex.lock();
174 if (absolutes.contains(type)) {
175 a += absolutes[type];
176 }
177 absolutesMutex.unlock();
178
179 return r + a;
180 }
181
182 QStandardPaths::StandardLocation mapTypeToQStandardPaths(const QString &type)
183 {
184 if (type == "appdata") {
185 return QStandardPaths::AppDataLocation;
186 }
187 else if (type == "data") {
188 return QStandardPaths::AppDataLocation;
189 }
190 else if (type == "cache") {
191 return QStandardPaths::CacheLocation;
192 }
193 else if (type == "locale") {
194 return QStandardPaths::AppDataLocation;
195 }
196 else if (type == "genericdata") {
197 return QStandardPaths::GenericDataLocation;
198 }
199 else {
200 return QStandardPaths::AppDataLocation;
201 }
202 }
203};
204
209
213
215{
216 return getInstallationPrefix();
217}
218
220{
221 if (!s_overrideAppDataLocation.isEmpty()) {
223 }
224
225 QString path;
226
227 KConfigGroup cfg(KSharedConfig::openConfig(), "");
228 path = cfg.readEntry(KisResourceLocator::resourceLocationKey, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
229
230 QFileInfo fi(path);
231
232 // Check whether an existing location is writable
233 if (fi.exists() && !fi.isWritable()) {
234 path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
235 }
236 else if (!fi.exists()) {
237 // Check whether a non-existing location can be created
238 if (!QDir().mkpath(path)) {
239 path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
240 }
241 QDir().rmpath(path);
242 }
243 return path;
244
245
246}
247
248void KoResourcePaths::getAllUserResourceFoldersLocationsForWindowsStore(QString &standardLocation, QString &privateLocation)
249{
250 standardLocation = "";
251 privateLocation = "";
252 QString resourcePath = QDir(KisResourceLocator::instance()->resourceLocationBase()).absolutePath();
253#ifndef Q_OS_WIN
254 // not Windows, no problem
255 standardLocation = resourcePath;
256 return;
257#else
259 standardLocation = resourcePath; // Windows, but not Windows Store, so no problem
260 return;
261 }
262
263 // running inside Windows Store
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)) {
269 // resource folder location is inside appdata, so it can cause issues
270 // from inside of Krita, we can't determine whether it uses genuine %AppData% or the private Windows Store one
271 // so, half of the time, a custom folder inside %AppData% wouldn't work
272 // we can't fix that, we can only inform users about it or prevent them from choosing such folder
273 // in any case, here we need to return both folders: inside normal appdata and the private one
274 // (note that this case also handles the default resource folder called "krita" inside the appdata)
275
276
277 const QString folderName = QFileInfo(resourcePath).fileName();
278
279 const QString privateAppData = KisWindowsPackageUtils::getPackageRoamingAppDataLocation();
280 const QDir privateResourceDir(QDir::fromNativeSeparators(privateAppData) + '/' + folderName);
281
282 standardLocation = resourcePath;
283
284 if (privateResourceDir.exists()) {
285 privateLocation = privateResourceDir.absolutePath();
286 }
287
288 return;
289
290 } else {
291 standardLocation = resourcePath; // custom folder not inside AppData, so no problem (hopefully)
292 return;
293 }
294
295#endif
296}
297
298void KoResourcePaths::addAssetType(const QString &type, const char *basetype,
299 const QString &relativeName, bool priority)
300{
301 s_instance->addResourceTypeInternal(type, QString::fromLatin1(basetype), relativeName, priority);
302}
303
304void KoResourcePaths::addAssetDir(const QString &type, const QString &dir, bool priority)
305{
306 s_instance->addResourceDirInternal(type, dir, priority);
307}
308
309QString KoResourcePaths::findAsset(const QString &type, const QString &fileName)
310{
311 return cleanup(s_instance->findResourceInternal(type, fileName));
312}
313
315{
316 return cleanupDirs(s_instance->findDirsInternal(type));
317}
318
320 const QString &filter,
321 SearchOptions options)
322{
323 return cleanup(s_instance->findAllResourcesInternal(type, filter, options));
324}
325
327{
328 return cleanupDirs(s_instance->resourceDirsInternal(type));
329}
330
331QString KoResourcePaths::saveLocation(const QString &type, const QString &suffix, bool create)
332{
333 return QDir::cleanPath(s_instance->saveLocationInternal(type, suffix, create)) + '/';
334}
335
336QString KoResourcePaths::locate(const QString &type, const QString &filename)
337{
338 return cleanup(s_instance->locateInternal(type, filename));
339}
340
341QString KoResourcePaths::locateLocal(const QString &type, const QString &filename, bool createDir)
342{
343 return cleanup(s_instance->locateLocalInternal(type, filename, createDir));
344}
345
346void KoResourcePaths::addResourceTypeInternal(const QString &type, const QString &basetype,
347 const QString &relativename,
348 bool priority)
349{
350 Q_UNUSED(basetype);
351 if (relativename.isEmpty()) return;
352
353 QString copy = relativename;
354
355 Q_ASSERT(basetype == "data");
356
357 if (!copy.endsWith(QLatin1Char('/'))) {
358 copy += QLatin1Char('/');
359 }
360
361 d->relativesMutex.lock();
362 QStringList &rels = d->relatives[type]; // find or insert
363
364 if (!rels.contains(copy, cs)) {
365 if (priority) {
366 rels.prepend(copy);
367 } else {
368 rels.append(copy);
369 }
370 }
371 d->relativesMutex.unlock();
372
373 dbgResources << "addResourceType: type" << type << "basetype" << basetype << "relativename" << relativename << "priority" << priority << d->relatives[type];
374}
375
376void KoResourcePaths::addResourceDirInternal(const QString &type, const QString &absdir, bool priority)
377{
378 if (absdir.isEmpty() || type.isEmpty()) return;
379
380 // find or insert entry in the map
381 QString copy = absdir;
382 if (copy.at(copy.length() - 1) != QLatin1Char('/')) {
383 copy += QLatin1Char('/');
384 }
385
386 d->absolutesMutex.lock();
387 QStringList &paths = d->absolutes[type];
388 if (!paths.contains(copy, cs)) {
389 if (priority) {
390 paths.prepend(copy);
391 } else {
392 paths.append(copy);
393 }
394 }
395 d->absolutesMutex.unlock();
396
397 dbgResources << "addResourceDir: type" << type << "absdir" << absdir << "priority" << priority << d->absolutes[type];
398}
399
400QString KoResourcePaths::findResourceInternal(const QString &type, const QString &fileName)
401{
402 QStringList aliases = d->aliases(type);
403 dbgResources<< "aliases" << aliases << getApplicationRoot();
404 QString resource = QStandardPaths::locate(QStandardPaths::AppDataLocation, fileName, QStandardPaths::LocateFile);
405
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)) {
410 break;
411 }
412 }
413 }
414 if (resource.isEmpty() || !QFile::exists(resource)) {
415 QString approot = getApplicationRoot();
416 Q_FOREACH (const QString &alias, aliases) {
417 resource = approot + "/share/" + alias + '/' + fileName;
418 if (QFile::exists(resource)) {
419 break;
420 }
421 }
422 }
423 if (resource.isEmpty() || !QFile::exists(resource)) {
424 QString approot = getApplicationRoot();
425 Q_FOREACH (const QString &alias, aliases) {
426 resource = approot + "/share/krita/" + alias + '/' + fileName;
427 if (QFile::exists(resource)) {
428 break;
429 }
430 }
431 }
432
433 if (resource.isEmpty() || !QFile::exists(resource)) {
434 QStringList extraResourceDirs = findExtraResourceDirs();
435
436 if (!extraResourceDirs.isEmpty()) {
437 Q_FOREACH(const QString &extraResourceDir, extraResourceDirs) {
438 if (aliases.isEmpty()) {
439 resource = extraResourceDir + '/' + fileName;
440 dbgResources<< "\t4" << resource;
441 if (QFile::exists(resource)) {
442 break;
443 }
444 }
445 else {
446 Q_FOREACH (const QString &alias, aliases) {
447 resource = extraResourceDir + '/' + alias + '/' + fileName;
448 dbgResources<< "\t4" << resource;
449 if (QFile::exists(resource)) {
450 break;
451 }
452 }
453 }
454 }
455 }
456 }
457
458 dbgResources<< "findResource: type" << type << "filename" << fileName << "resource" << resource;
459 Q_ASSERT(!resource.isEmpty());
460 return resource;
461}
462
463
464QStringList filesInDir(const QString &startdir, const QString & filter, bool recursive)
465{
466 dbgResources << "filesInDir: startdir" << startdir << "filter" << filter << "recursive" << recursive;
467 QStringList result;
468
469 // First the entries in this path
470 QStringList nameFilters;
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;
476 result << file;
477 }
478
479 // And then everything underneath, if recursive is specified
480 if (recursive) {
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);
485 }
486 }
487 return result;
488}
489
491{
492 QStringList aliases = d->aliases(type);
493 dbgResources << type << aliases << d->mapTypeToQStandardPaths(type);
494
495 QStringList dirs;
496 QStringList standardDirs =
497 QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), "", QStandardPaths::LocateDirectory);
498
499 appendResources(&dirs, standardDirs, true);
500
501 Q_FOREACH (const QString &alias, aliases) {
502 QStringList aliasDirs =
503 QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias + '/', QStandardPaths::LocateDirectory);
504 appendResources(&dirs, aliasDirs, true);
505
506#ifdef Q_OS_MACOS
507 dbgResources << "MAC:" << getApplicationRoot();
508 QStringList bundlePaths;
509 bundlePaths << getApplicationRoot() + "/share/krita/" + alias;
510 bundlePaths << getApplicationRoot() + "/../share/krita/" + alias;
511 dbgResources << "bundlePaths" << bundlePaths;
512 appendResources(&dirs, bundlePaths, true);
513 Q_ASSERT(!dirs.isEmpty());
514#endif
515
516 QStringList fallbackPaths;
517 fallbackPaths << getApplicationRoot() + "/share/" + alias;
518 fallbackPaths << getApplicationRoot() + "/share/krita/" + alias;
519 appendResources(&dirs, fallbackPaths, true);
520
521 }
522
523 QStringList saveLocationList;
524 saveLocationList << saveLocation(type, QString(), true);
525 appendResources(&dirs, saveLocationList, true);
526
527 dbgResources << "findDirs: type" << type << "resource" << dirs;
528 return dirs;
529}
530
531
533 const QString &_filter,
534 SearchOptions options) const
535{
536 dbgResources << "=====================================================";
537 dbgResources << type << _filter << QStandardPaths::standardLocations(d->mapTypeToQStandardPaths(type));
538
539 bool recursive = options & KoResourcePaths::Recursive;
540
541 dbgResources << "findAllResources: type" << type << "filter" << _filter << "recursive" << recursive;
542
543 QStringList aliases = d->aliases(type);
544 QString filter = _filter;
545
546 // In cases where the filter is like "color-schemes/*.colors" instead of "*.kpp", used with unregistered resource types
547 if (filter.indexOf('*') > 0) {
548 aliases << filter.split('*').first();
549 filter = '*' + filter.split('*')[1];
550 dbgResources << "Split up alias" << aliases << "filter" << filter;
551 }
552
553 QStringList resources;
554 if (aliases.isEmpty()) {
555 QStringList standardResources =
556 QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type),
557 filter, QStandardPaths::LocateFile);
558 dbgResources << "standardResources" << standardResources;
559 appendResources(&resources, standardResources, true);
560 dbgResources << "1" << resources;
561 }
562
563 QStringList extraResourceDirs = findExtraResourceDirs();
564
565 if (!extraResourceDirs.isEmpty()) {
566 Q_FOREACH(const QString &extraResourceDir, extraResourceDirs) {
567 if (aliases.isEmpty()) {
568 appendResources(&resources, filesInDir(extraResourceDir + '/' + type, filter, recursive), true);
569 }
570 else {
571 Q_FOREACH (const QString &alias, aliases) {
572 appendResources(&resources, filesInDir(extraResourceDir + '/' + alias + '/', filter, recursive), true);
573 }
574 }
575 }
576
577 }
578
579 dbgResources << "\tresources from qstandardpaths:" << resources.size();
580
581 Q_FOREACH (const QString &alias, aliases) {
582 dbgResources << "\t\talias:" << alias;
583 QStringList dirs;
584
585 QFileInfo dirInfo(alias);
586 if (dirInfo.exists() && dirInfo.isDir() && dirInfo.isAbsolute()) {
587 dirs << alias;
588 } else {
589 dirs << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory)
590 << getInstallationPrefix() + "share/" + alias + "/"
591 << getInstallationPrefix() + "share/krita/" + alias + "/";
592 }
593
594 Q_FOREACH (const QString &dir, dirs) {
595 appendResources(&resources,
596 filesInDir(dir, filter, recursive),
597 true);
598 }
599 }
600
601 dbgResources << "\tresources also from aliases:" << resources.size();
602
603 // if the original filter is "input/*", we only want share/input/* and share/krita/input/* here, but not
604 // share/*. therefore, use _filter here instead of filter which was split into alias and "*".
605 QFileInfo fi(_filter);
606
607 QStringList prefixResources;
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);
611
612 dbgResources << "\tresources from installation:" << resources.size();
613 dbgResources << "=====================================================";
614
615 return resources;
616}
617
619{
620 QStringList resourceDirs;
621 QStringList aliases = d->aliases(type);
622
623 Q_FOREACH (const QString &alias, aliases) {
624 QStringList aliasDirs;
625
626 aliasDirs << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory);
627
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);
632
633 appendResources(&resourceDirs, aliasDirs, true);
634 }
635
636 dbgResources << "resourceDirs: type" << type << resourceDirs;
637
638 return resourceDirs;
639}
640
641QString KoResourcePaths::saveLocationInternal(const QString &type, const QString &suffix, bool create)
642{
643 QString path;
644
645 bool useStandardLocation = false;
646 const QStringList aliases = d->aliases(type);
647 const QStandardPaths::StandardLocation location = d->mapTypeToQStandardPaths(type);
648
649 if (location == QStandardPaths::AppDataLocation) {
650 KConfigGroup cfg(KSharedConfig::openConfig(), "");
651 path = cfg.readEntry(KisResourceLocator::resourceLocationKey, "");
652 }
653
654 if (path.isEmpty()) {
655 path = QStandardPaths::writableLocation(location);
656 useStandardLocation = true;
657 }
658
659#ifndef Q_OS_ANDROID
660 // on Android almost all config locations we save to are app specific,
661 // and don't end with "krita".
662 if (!path.endsWith("krita") && useStandardLocation) {
663 path += "/krita";
664 }
665#endif
666
667 if (!aliases.isEmpty()) {
668 path += '/' + aliases.first();
669 } else {
670
671 if (!suffix.isEmpty()) {
672 path += "/" + suffix;
673 }
674 }
675
676 QDir d(path);
677 if (!d.exists() && create) {
678 d.mkpath(path);
679 }
680 dbgResources << "saveLocation: type" << type << "suffix" << suffix << "create" << create << "path" << path;
681
682 return path;
683}
684
685QString KoResourcePaths::locateInternal(const QString &type, const QString &filename)
686{
687 QStringList aliases = d->aliases(type);
688
689 QStringList locations;
690 if (aliases.isEmpty()) {
691 locations << QStandardPaths::locate(d->mapTypeToQStandardPaths(type), filename, QStandardPaths::LocateFile);
692 }
693
694 Q_FOREACH (const QString &alias, aliases) {
695 locations << QStandardPaths::locate(d->mapTypeToQStandardPaths(type),
696 (alias.endsWith('/') ? alias : alias + '/') + filename, QStandardPaths::LocateFile);
697 }
698 dbgResources << "locate: type" << type << "filename" << filename << "locations" << locations;
699 if (locations.size() > 0) {
700 return locations.first();
701 }
702 else {
703 return "";
704 }
705}
706
707QString KoResourcePaths::locateLocalInternal(const QString &type, const QString &filename, bool createDir)
708{
709 QString path = saveLocationInternal(type, "", createDir);
710 dbgResources << "locateLocal: type" << type << "filename" << filename << "CreateDir" << createDir << "path" << path;
711 return path + '/' + filename;
712}
713
715{
716 QStringList extraResourceDirs =
717 QString::fromUtf8(qgetenv("EXTRA_RESOURCE_DIRS"))
718 .split(';', Qt::SkipEmptyParts);
719
720 const KConfigGroup cfg(KSharedConfig::openConfig(), "");
721 const QString customPath =
723 if (!customPath.isEmpty()) {
724 extraResourceDirs << customPath;
725 }
726
727 if (getAppDataLocation() != QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)) {
728 extraResourceDirs << getAppDataLocation();
729 }
730
731 return extraResourceDirs;
732}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
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 ...
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)
#define dbgResources
Definition kis_debug.h:43