File indexing completed on 2024-05-12 15:59:56
0001 /* 0002 * SPDX-FileCopyrightText: 2015 Boudewijn Rempt <boud@valdyas.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 #include "KoResourcePaths.h" 0007 0008 #include <QGlobalStatic> 0009 #include <QString> 0010 #include <QStringList> 0011 #include <QMap> 0012 #include <QStandardPaths> 0013 #include <QDir> 0014 #include <QFileInfo> 0015 #include <QDebug> 0016 #include <QCoreApplication> 0017 #include <QMutex> 0018 #include "kis_debug.h" 0019 #include "ksharedconfig.h" 0020 #include "kconfiggroup.h" 0021 #include "KisResourceLocator.h" 0022 #include "KisWindowsPackageUtils.h" 0023 0024 Q_GLOBAL_STATIC(KoResourcePaths, s_instance) 0025 0026 QString KoResourcePaths::s_overrideAppDataLocation; 0027 0028 namespace { 0029 0030 static QString cleanup(const QString &path) 0031 { 0032 return QDir::cleanPath(path); 0033 } 0034 0035 0036 static QStringList cleanup(const QStringList &pathList) 0037 { 0038 QStringList cleanedPathList; 0039 0040 bool getRidOfAppDataLocation = KoResourcePaths::getAppDataLocation() != QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); 0041 const QString writableLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); 0042 0043 Q_FOREACH(const QString &path, pathList) { 0044 QString cleanPath = cleanup(path); 0045 if (getRidOfAppDataLocation && cleanPath.startsWith(writableLocation)) { 0046 continue; 0047 } 0048 cleanedPathList << cleanPath; 0049 } 0050 return cleanedPathList; 0051 } 0052 0053 static QStringList cleanupDirs(const QStringList &pathList) 0054 { 0055 QStringList cleanedPathList; 0056 0057 bool getRidOfAppDataLocation = KoResourcePaths::getAppDataLocation() != QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); 0058 const QString writableLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); 0059 0060 Q_FOREACH(const QString &path, pathList) { 0061 QString cleanPath = QDir::cleanPath(path) + '/'; 0062 if (getRidOfAppDataLocation && cleanPath.startsWith(writableLocation)) { 0063 continue; 0064 } 0065 cleanedPathList << cleanPath; 0066 } 0067 return cleanedPathList; 0068 } 0069 0070 void appendResources(QStringList *dst, const QStringList &src, bool eliminateDuplicates) 0071 { 0072 Q_FOREACH (const QString &resource, src) { 0073 QString realPath = QDir::cleanPath(resource); 0074 if (!eliminateDuplicates || !dst->contains(realPath)) { 0075 *dst << realPath; 0076 } 0077 } 0078 } 0079 0080 0081 #ifdef Q_OS_WIN 0082 static const Qt::CaseSensitivity cs = Qt::CaseInsensitive; 0083 #else 0084 static const Qt::CaseSensitivity cs = Qt::CaseSensitive; 0085 #endif 0086 0087 #ifdef Q_OS_MACOS 0088 #include <ApplicationServices/ApplicationServices.h> 0089 #include <CoreFoundation/CoreFoundation.h> 0090 #include <CoreServices/CoreServices.h> 0091 #endif 0092 0093 QString getInstallationPrefix() { 0094 #ifdef Q_OS_MACOS 0095 QString appPath = qApp->applicationDirPath(); 0096 0097 dbgResources << "1" << appPath; 0098 appPath.chop(QString("MacOS/").length()); 0099 dbgResources << "2" << appPath; 0100 0101 bool makeInstall = QDir(appPath + "/../../../share/kritaplugins").exists(); 0102 bool inBundle = QDir(appPath + "/Resources/kritaplugins").exists(); 0103 0104 QString bundlePath; 0105 0106 if (inBundle) { 0107 bundlePath = appPath + "/"; 0108 } 0109 else if (makeInstall) { 0110 appPath.chop(QString("Contents/").length()); 0111 bundlePath = appPath + "/../../"; 0112 } 0113 else { 0114 // This is needed as tests will not run outside of the 0115 // install directory without this 0116 // This needs krita to be installed. 0117 QString envInstallPath = qgetenv("KIS_TEST_PREFIX_PATH"); 0118 if (!envInstallPath.isEmpty() && ( 0119 QDir(envInstallPath + "/share/kritaplugins").exists() 0120 || QDir(envInstallPath + "/Resources/kritaplugins").exists() )) 0121 { 0122 bundlePath = envInstallPath; 0123 } 0124 else { 0125 qFatal("Cannot calculate the bundle path from the app path"); 0126 qInfo() << "If running tests set KIS_TEST_PREFIX_PATH to krita install prefix"; 0127 } 0128 } 0129 0130 return bundlePath; 0131 #elif defined(Q_OS_ANDROID) 0132 // qApp->applicationDirPath() isn't writable and android system won't allow 0133 // any files other than libraries 0134 // NOTE the subscript [1]. It points to the internal location. 0135 return QStandardPaths::standardLocations(QStandardPaths::AppDataLocation)[1] + "/"; 0136 #else 0137 return qApp->applicationDirPath() + "/../"; 0138 #endif 0139 } 0140 0141 } 0142 0143 class Q_DECL_HIDDEN KoResourcePaths::Private { 0144 public: 0145 QMap<QString, QStringList> absolutes; // For each resource type, the list of absolute paths, from most local (most priority) to most global 0146 QMap<QString, QStringList> relatives; // Same with relative paths 0147 0148 QMutex relativesMutex; 0149 QMutex absolutesMutex; 0150 0151 QStringList aliases(const QString &type) 0152 { 0153 QStringList r; 0154 QStringList a; 0155 relativesMutex.lock(); 0156 if (relatives.contains(type)) { 0157 r += relatives[type]; 0158 } 0159 relativesMutex.unlock(); 0160 absolutesMutex.lock(); 0161 if (absolutes.contains(type)) { 0162 a += absolutes[type]; 0163 } 0164 absolutesMutex.unlock(); 0165 0166 return r + a; 0167 } 0168 0169 QStandardPaths::StandardLocation mapTypeToQStandardPaths(const QString &type) 0170 { 0171 if (type == "appdata") { 0172 return QStandardPaths::AppDataLocation; 0173 } 0174 else if (type == "data") { 0175 return QStandardPaths::AppDataLocation; 0176 } 0177 else if (type == "cache") { 0178 return QStandardPaths::CacheLocation; 0179 } 0180 else if (type == "locale") { 0181 return QStandardPaths::AppDataLocation; 0182 } 0183 else if (type == "genericdata") { 0184 return QStandardPaths::GenericDataLocation; 0185 } 0186 else { 0187 return QStandardPaths::AppDataLocation; 0188 } 0189 } 0190 }; 0191 0192 KoResourcePaths::KoResourcePaths() 0193 : d(new Private) 0194 { 0195 } 0196 0197 KoResourcePaths::~KoResourcePaths() 0198 { 0199 } 0200 0201 QString KoResourcePaths::getApplicationRoot() 0202 { 0203 return getInstallationPrefix(); 0204 } 0205 0206 QString KoResourcePaths::getAppDataLocation() 0207 { 0208 if (!s_overrideAppDataLocation.isEmpty()) { 0209 return s_overrideAppDataLocation; 0210 } 0211 0212 QString path; 0213 0214 KConfigGroup cfg(KSharedConfig::openConfig(), ""); 0215 path = cfg.readEntry(KisResourceLocator::resourceLocationKey, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); 0216 0217 return path; 0218 0219 } 0220 0221 void KoResourcePaths::getAllUserResourceFoldersLocationsForWindowsStore(QString &standardLocation, QString &privateLocation) 0222 { 0223 standardLocation = ""; 0224 privateLocation = ""; 0225 QString resourcePath = QDir(KisResourceLocator::instance()->resourceLocationBase()).absolutePath(); 0226 #ifndef Q_OS_WIN 0227 // not Windows, no problem 0228 standardLocation = resourcePath; 0229 return; 0230 #else 0231 if (!KisWindowsPackageUtils::isRunningInPackage()) { 0232 standardLocation = resourcePath; // Windows, but not Windows Store, so no problem 0233 return; 0234 } 0235 0236 // running inside Windows Store 0237 const QDir resourceDir(resourcePath); 0238 QDir appDataGeneralDir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); 0239 appDataGeneralDir.cdUp(); 0240 const QString appDataGeneralDirPath = appDataGeneralDir.path(); 0241 if (resourceDir.absolutePath().contains(appDataGeneralDirPath, Qt::CaseInsensitive)) { 0242 // resource folder location is inside appdata, so it can cause issues 0243 // from inside of Krita, we can't determine whether it uses genuine %AppData% or the private Windows Store one 0244 // so, half of the time, a custom folder inside %AppData% wouldn't work 0245 // we can't fix that, we can only inform users about it or prevent them from choosing such folder 0246 // in any case, here we need to return both folders: inside normal appdata and the private one 0247 // (note that this case also handles the default resource folder called "krita" inside the appdata) 0248 0249 0250 const QString folderName = QFileInfo(resourcePath).fileName(); 0251 0252 const QString privateAppData = KisWindowsPackageUtils::getPackageRoamingAppDataLocation(); 0253 const QDir privateResourceDir(QDir::fromNativeSeparators(privateAppData) + '/' + folderName); 0254 0255 standardLocation = resourcePath; 0256 0257 if (privateResourceDir.exists()) { 0258 privateLocation = privateResourceDir.absolutePath(); 0259 } 0260 0261 return; 0262 0263 } else { 0264 standardLocation = resourcePath; // custom folder not inside AppData, so no problem (hopefully) 0265 return; 0266 } 0267 0268 #endif 0269 } 0270 0271 void KoResourcePaths::addAssetType(const QString &type, const char *basetype, 0272 const QString &relativeName, bool priority) 0273 { 0274 s_instance->addResourceTypeInternal(type, QString::fromLatin1(basetype), relativeName, priority); 0275 } 0276 0277 void KoResourcePaths::addAssetDir(const QString &type, const QString &dir, bool priority) 0278 { 0279 s_instance->addResourceDirInternal(type, dir, priority); 0280 } 0281 0282 QString KoResourcePaths::findAsset(const QString &type, const QString &fileName) 0283 { 0284 return cleanup(s_instance->findResourceInternal(type, fileName)); 0285 } 0286 0287 QStringList KoResourcePaths::findDirs(const QString &type) 0288 { 0289 return cleanupDirs(s_instance->findDirsInternal(type)); 0290 } 0291 0292 QStringList KoResourcePaths::findAllAssets(const QString &type, 0293 const QString &filter, 0294 SearchOptions options) 0295 { 0296 return cleanup(s_instance->findAllResourcesInternal(type, filter, options)); 0297 } 0298 0299 QStringList KoResourcePaths::assetDirs(const QString &type) 0300 { 0301 return cleanupDirs(s_instance->resourceDirsInternal(type)); 0302 } 0303 0304 QString KoResourcePaths::saveLocation(const QString &type, const QString &suffix, bool create) 0305 { 0306 return QDir::cleanPath(s_instance->saveLocationInternal(type, suffix, create)) + '/'; 0307 } 0308 0309 QString KoResourcePaths::locate(const QString &type, const QString &filename) 0310 { 0311 return cleanup(s_instance->locateInternal(type, filename)); 0312 } 0313 0314 QString KoResourcePaths::locateLocal(const QString &type, const QString &filename, bool createDir) 0315 { 0316 return cleanup(s_instance->locateLocalInternal(type, filename, createDir)); 0317 } 0318 0319 void KoResourcePaths::addResourceTypeInternal(const QString &type, const QString &basetype, 0320 const QString &relativename, 0321 bool priority) 0322 { 0323 Q_UNUSED(basetype); 0324 if (relativename.isEmpty()) return; 0325 0326 QString copy = relativename; 0327 0328 Q_ASSERT(basetype == "data"); 0329 0330 if (!copy.endsWith(QLatin1Char('/'))) { 0331 copy += QLatin1Char('/'); 0332 } 0333 0334 d->relativesMutex.lock(); 0335 QStringList &rels = d->relatives[type]; // find or insert 0336 0337 if (!rels.contains(copy, cs)) { 0338 if (priority) { 0339 rels.prepend(copy); 0340 } else { 0341 rels.append(copy); 0342 } 0343 } 0344 d->relativesMutex.unlock(); 0345 0346 dbgResources << "addResourceType: type" << type << "basetype" << basetype << "relativename" << relativename << "priority" << priority << d->relatives[type]; 0347 } 0348 0349 void KoResourcePaths::addResourceDirInternal(const QString &type, const QString &absdir, bool priority) 0350 { 0351 if (absdir.isEmpty() || type.isEmpty()) return; 0352 0353 // find or insert entry in the map 0354 QString copy = absdir; 0355 if (copy.at(copy.length() - 1) != QLatin1Char('/')) { 0356 copy += QLatin1Char('/'); 0357 } 0358 0359 d->absolutesMutex.lock(); 0360 QStringList &paths = d->absolutes[type]; 0361 if (!paths.contains(copy, cs)) { 0362 if (priority) { 0363 paths.prepend(copy); 0364 } else { 0365 paths.append(copy); 0366 } 0367 } 0368 d->absolutesMutex.unlock(); 0369 0370 dbgResources << "addResourceDir: type" << type << "absdir" << absdir << "priority" << priority << d->absolutes[type]; 0371 } 0372 0373 QString KoResourcePaths::findResourceInternal(const QString &type, const QString &fileName) 0374 { 0375 QStringList aliases = d->aliases(type); 0376 dbgResources<< "aliases" << aliases << getApplicationRoot(); 0377 QString resource = QStandardPaths::locate(QStandardPaths::AppDataLocation, fileName, QStandardPaths::LocateFile); 0378 0379 if (resource.isEmpty()) { 0380 Q_FOREACH (const QString &alias, aliases) { 0381 resource = QStandardPaths::locate(d->mapTypeToQStandardPaths(type), alias + '/' + fileName, QStandardPaths::LocateFile); 0382 if (QFile::exists(resource)) { 0383 break; 0384 } 0385 } 0386 } 0387 if (resource.isEmpty() || !QFile::exists(resource)) { 0388 QString approot = getApplicationRoot(); 0389 Q_FOREACH (const QString &alias, aliases) { 0390 resource = approot + "/share/" + alias + '/' + fileName; 0391 if (QFile::exists(resource)) { 0392 break; 0393 } 0394 } 0395 } 0396 if (resource.isEmpty() || !QFile::exists(resource)) { 0397 QString approot = getApplicationRoot(); 0398 Q_FOREACH (const QString &alias, aliases) { 0399 resource = approot + "/share/krita/" + alias + '/' + fileName; 0400 if (QFile::exists(resource)) { 0401 break; 0402 } 0403 } 0404 } 0405 0406 if (resource.isEmpty() || !QFile::exists(resource)) { 0407 QStringList extraResourceDirs = findExtraResourceDirs(); 0408 0409 if (!extraResourceDirs.isEmpty()) { 0410 Q_FOREACH(const QString &extraResourceDir, extraResourceDirs) { 0411 if (aliases.isEmpty()) { 0412 resource = extraResourceDir + '/' + fileName; 0413 dbgResources<< "\t4" << resource; 0414 if (QFile::exists(resource)) { 0415 break; 0416 } 0417 } 0418 else { 0419 Q_FOREACH (const QString &alias, aliases) { 0420 resource = extraResourceDir + '/' + alias + '/' + fileName; 0421 dbgResources<< "\t4" << resource; 0422 if (QFile::exists(resource)) { 0423 break; 0424 } 0425 } 0426 } 0427 } 0428 } 0429 } 0430 0431 dbgResources<< "findResource: type" << type << "filename" << fileName << "resource" << resource; 0432 Q_ASSERT(!resource.isEmpty()); 0433 return resource; 0434 } 0435 0436 0437 QStringList filesInDir(const QString &startdir, const QString & filter, bool recursive) 0438 { 0439 dbgResources << "filesInDir: startdir" << startdir << "filter" << filter << "recursive" << recursive; 0440 QStringList result; 0441 0442 // First the entries in this path 0443 QStringList nameFilters; 0444 nameFilters << filter; 0445 const QStringList fileNames = QDir(startdir).entryList(nameFilters, QDir::Files | QDir::CaseSensitive, QDir::Name); 0446 dbgResources << "\tFound:" << fileNames.size() << ":" << fileNames; 0447 Q_FOREACH (const QString &fileName, fileNames) { 0448 QString file = startdir + '/' + fileName; 0449 result << file; 0450 } 0451 0452 // And then everything underneath, if recursive is specified 0453 if (recursive) { 0454 const QStringList entries = QDir(startdir).entryList(QDir::Dirs | QDir::NoDotAndDotDot); 0455 Q_FOREACH (const QString &subdir, entries) { 0456 dbgResources << "\tGoing to look in subdir" << subdir << "of" << startdir; 0457 result << filesInDir(startdir + '/' + subdir, filter, recursive); 0458 } 0459 } 0460 return result; 0461 } 0462 0463 QStringList KoResourcePaths::findDirsInternal(const QString &type) 0464 { 0465 QStringList aliases = d->aliases(type); 0466 dbgResources << type << aliases << d->mapTypeToQStandardPaths(type); 0467 0468 QStringList dirs; 0469 QStringList standardDirs = 0470 QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), "", QStandardPaths::LocateDirectory); 0471 0472 appendResources(&dirs, standardDirs, true); 0473 0474 Q_FOREACH (const QString &alias, aliases) { 0475 QStringList aliasDirs = 0476 QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias + '/', QStandardPaths::LocateDirectory); 0477 appendResources(&dirs, aliasDirs, true); 0478 0479 #ifdef Q_OS_MACOS 0480 dbgResources << "MAC:" << getApplicationRoot(); 0481 QStringList bundlePaths; 0482 bundlePaths << getApplicationRoot() + "/share/krita/" + alias; 0483 bundlePaths << getApplicationRoot() + "/../share/krita/" + alias; 0484 dbgResources << "bundlePaths" << bundlePaths; 0485 appendResources(&dirs, bundlePaths, true); 0486 Q_ASSERT(!dirs.isEmpty()); 0487 #endif 0488 0489 QStringList fallbackPaths; 0490 fallbackPaths << getApplicationRoot() + "/share/" + alias; 0491 fallbackPaths << getApplicationRoot() + "/share/krita/" + alias; 0492 appendResources(&dirs, fallbackPaths, true); 0493 0494 } 0495 0496 QStringList saveLocationList; 0497 saveLocationList << saveLocation(type, QString(), true); 0498 appendResources(&dirs, saveLocationList, true); 0499 0500 dbgResources << "findDirs: type" << type << "resource" << dirs; 0501 return dirs; 0502 } 0503 0504 0505 QStringList KoResourcePaths::findAllResourcesInternal(const QString &type, 0506 const QString &_filter, 0507 SearchOptions options) const 0508 { 0509 dbgResources << "====================================================="; 0510 dbgResources << type << _filter << QStandardPaths::standardLocations(d->mapTypeToQStandardPaths(type)); 0511 0512 bool recursive = options & KoResourcePaths::Recursive; 0513 0514 dbgResources << "findAllResources: type" << type << "filter" << _filter << "recursive" << recursive; 0515 0516 QStringList aliases = d->aliases(type); 0517 QString filter = _filter; 0518 0519 // In cases where the filter is like "color-schemes/*.colors" instead of "*.kpp", used with unregistered resource types 0520 if (filter.indexOf('*') > 0) { 0521 aliases << filter.split('*').first(); 0522 filter = '*' + filter.split('*')[1]; 0523 dbgResources << "Split up alias" << aliases << "filter" << filter; 0524 } 0525 0526 QStringList resources; 0527 if (aliases.isEmpty()) { 0528 QStringList standardResources = 0529 QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), 0530 filter, QStandardPaths::LocateFile); 0531 dbgResources << "standardResources" << standardResources; 0532 appendResources(&resources, standardResources, true); 0533 dbgResources << "1" << resources; 0534 } 0535 0536 QStringList extraResourceDirs = findExtraResourceDirs(); 0537 0538 if (!extraResourceDirs.isEmpty()) { 0539 Q_FOREACH(const QString &extraResourceDir, extraResourceDirs) { 0540 if (aliases.isEmpty()) { 0541 appendResources(&resources, filesInDir(extraResourceDir + '/' + type, filter, recursive), true); 0542 } 0543 else { 0544 Q_FOREACH (const QString &alias, aliases) { 0545 appendResources(&resources, filesInDir(extraResourceDir + '/' + alias + '/', filter, recursive), true); 0546 } 0547 } 0548 } 0549 0550 } 0551 0552 dbgResources << "\tresources from qstandardpaths:" << resources.size(); 0553 0554 Q_FOREACH (const QString &alias, aliases) { 0555 dbgResources << "\t\talias:" << alias; 0556 QStringList dirs; 0557 0558 QFileInfo dirInfo(alias); 0559 if (dirInfo.exists() && dirInfo.isDir() && dirInfo.isAbsolute()) { 0560 dirs << alias; 0561 } else { 0562 dirs << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory) 0563 << getInstallationPrefix() + "share/" + alias + "/" 0564 << getInstallationPrefix() + "share/krita/" + alias + "/"; 0565 } 0566 0567 Q_FOREACH (const QString &dir, dirs) { 0568 appendResources(&resources, 0569 filesInDir(dir, filter, recursive), 0570 true); 0571 } 0572 } 0573 0574 dbgResources << "\tresources also from aliases:" << resources.size(); 0575 0576 // if the original filter is "input/*", we only want share/input/* and share/krita/input/* here, but not 0577 // share/*. therefore, use _filter here instead of filter which was split into alias and "*". 0578 QFileInfo fi(_filter); 0579 0580 QStringList prefixResources; 0581 prefixResources << filesInDir(getInstallationPrefix() + "share/" + fi.path(), fi.fileName(), false); 0582 prefixResources << filesInDir(getInstallationPrefix() + "share/krita/" + fi.path(), fi.fileName(), false); 0583 appendResources(&resources, prefixResources, true); 0584 0585 dbgResources << "\tresources from installation:" << resources.size(); 0586 dbgResources << "====================================================="; 0587 0588 return resources; 0589 } 0590 0591 QStringList KoResourcePaths::resourceDirsInternal(const QString &type) 0592 { 0593 QStringList resourceDirs; 0594 QStringList aliases = d->aliases(type); 0595 0596 Q_FOREACH (const QString &alias, aliases) { 0597 QStringList aliasDirs; 0598 0599 aliasDirs << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory); 0600 0601 aliasDirs << getInstallationPrefix() + "share/" + alias + "/" 0602 << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory); 0603 aliasDirs << getInstallationPrefix() + "share/krita/" + alias + "/" 0604 << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory); 0605 0606 appendResources(&resourceDirs, aliasDirs, true); 0607 } 0608 0609 dbgResources << "resourceDirs: type" << type << resourceDirs; 0610 0611 return resourceDirs; 0612 } 0613 0614 QString KoResourcePaths::saveLocationInternal(const QString &type, const QString &suffix, bool create) 0615 { 0616 QString path; 0617 0618 bool useStandardLocation = false; 0619 const QStringList aliases = d->aliases(type); 0620 const QStandardPaths::StandardLocation location = d->mapTypeToQStandardPaths(type); 0621 0622 if (location == QStandardPaths::AppDataLocation) { 0623 KConfigGroup cfg(KSharedConfig::openConfig(), ""); 0624 path = cfg.readEntry(KisResourceLocator::resourceLocationKey, ""); 0625 } 0626 0627 if (path.isEmpty()) { 0628 path = QStandardPaths::writableLocation(location); 0629 useStandardLocation = true; 0630 } 0631 0632 #ifndef Q_OS_ANDROID 0633 // on Android almost all config locations we save to are app specific, 0634 // and don't end with "krita". 0635 if (!path.endsWith("krita") && useStandardLocation) { 0636 path += "/krita"; 0637 } 0638 #endif 0639 0640 if (!aliases.isEmpty()) { 0641 path += '/' + aliases.first(); 0642 } else { 0643 0644 if (!suffix.isEmpty()) { 0645 path += "/" + suffix; 0646 } 0647 } 0648 0649 QDir d(path); 0650 if (!d.exists() && create) { 0651 d.mkpath(path); 0652 } 0653 dbgResources << "saveLocation: type" << type << "suffix" << suffix << "create" << create << "path" << path; 0654 0655 return path; 0656 } 0657 0658 QString KoResourcePaths::locateInternal(const QString &type, const QString &filename) 0659 { 0660 QStringList aliases = d->aliases(type); 0661 0662 QStringList locations; 0663 if (aliases.isEmpty()) { 0664 locations << QStandardPaths::locate(d->mapTypeToQStandardPaths(type), filename, QStandardPaths::LocateFile); 0665 } 0666 0667 Q_FOREACH (const QString &alias, aliases) { 0668 locations << QStandardPaths::locate(d->mapTypeToQStandardPaths(type), 0669 (alias.endsWith('/') ? alias : alias + '/') + filename, QStandardPaths::LocateFile); 0670 } 0671 dbgResources << "locate: type" << type << "filename" << filename << "locations" << locations; 0672 if (locations.size() > 0) { 0673 return locations.first(); 0674 } 0675 else { 0676 return ""; 0677 } 0678 } 0679 0680 QString KoResourcePaths::locateLocalInternal(const QString &type, const QString &filename, bool createDir) 0681 { 0682 QString path = saveLocationInternal(type, "", createDir); 0683 dbgResources << "locateLocal: type" << type << "filename" << filename << "CreateDir" << createDir << "path" << path; 0684 return path + '/' + filename; 0685 } 0686 0687 QStringList KoResourcePaths::findExtraResourceDirs() const 0688 { 0689 QStringList extraResourceDirs = 0690 QString::fromUtf8(qgetenv("EXTRA_RESOURCE_DIRS")) 0691 .split(';', QString::SkipEmptyParts); 0692 0693 const KConfigGroup cfg(KSharedConfig::openConfig(), ""); 0694 const QString customPath = 0695 cfg.readEntry(KisResourceLocator::resourceLocationKey, ""); 0696 if (!customPath.isEmpty()) { 0697 extraResourceDirs << customPath; 0698 } 0699 0700 if (getAppDataLocation() != QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)) { 0701 extraResourceDirs << getAppDataLocation(); 0702 } 0703 0704 return extraResourceDirs; 0705 }