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