Warning, file /office/calligra/libs/widgets/KoResourcePaths.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * Copyright (c) 2015 Boudewijn Rempt <boud@valdyas.org>
0003  * Copyright (c) 2015 Friedrich W. H. Kossebau <kossebau@kde.org>
0004  *
0005  * This library is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU Lesser General Public
0007  * License as published by the Free Software Foundation; either
0008  * version 2.1 of the License, or (at your option) any later version.
0009  *
0010  * This library is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  * Lesser General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Lesser General Public
0016  * License along with this library; if not, write to the Free Software
0017  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0018  */
0019 
0020 #include "KoResourcePaths.h"
0021 
0022 #include <QGlobalStatic>
0023 #include <QStringList>
0024 #include <QHash>
0025 #include <QStandardPaths>
0026 #include <QDir>
0027 #include <QFileInfo>
0028 #include <QDebug>
0029 #include <QSet>
0030 
0031 
0032 #ifdef Q_OS_WIN
0033 static const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
0034 #else
0035 static const Qt::CaseSensitivity cs = Qt::CaseSensitive;
0036 #endif
0037 
0038 class KoResourcePathsImpl
0039 {
0040 public:
0041     static QStandardPaths::StandardLocation mapTypeToQStandardPaths(const QString &type)
0042     {
0043         return
0044             type == QLatin1String("data") ?    QStandardPaths::GenericDataLocation :
0045             type == QLatin1String("config") ?  QStandardPaths::GenericConfigLocation :
0046             type == QLatin1String("cache") ?   QStandardPaths::CacheLocation :
0047             type == QLatin1String("tmp") ?     QStandardPaths::TempLocation :
0048             type == QLatin1String("appdata") ? QStandardPaths::DataLocation :
0049             type == QLatin1String("locale") ?  QStandardPaths::GenericDataLocation :
0050             /* default */                      QStandardPaths::GenericDataLocation;
0051     }
0052 
0053     KoResourcePathsImpl() = default;
0054     ~KoResourcePathsImpl() = default;
0055 
0056     void addResourceTypeInternal(const QString &type, const QString &basetype,
0057                                  const QString &relativeName, bool priority);
0058 
0059     void addResourceDirInternal(const QString &type, const QString &absdir, bool priority);
0060 
0061     QString findResourceInternal(const QString &type, const QString &fileName);
0062 
0063     QStringList findDirsInternal(const QString &type, const QString &relDir);
0064 
0065     QStringList findAllResourcesInternal(const QString &type,
0066                                          const QString &filter = QString(),
0067                                          KoResourcePaths::SearchOptions options = KoResourcePaths::NoSearchOptions) const;
0068 
0069     QStringList resourceDirsInternal(const QString &type);
0070 
0071     QString saveLocationInternal(const QString &type, const QString &suffix = QString(), bool create = true);
0072 
0073     QString locateLocalInternal(const QString &type, const QString &filename, bool createDir = false);
0074 
0075 private:
0076     QHash<QString, QStringList> m_absolutes; // For each resource type, the list of absolute paths, from most local (most priority) to most global
0077     QHash<QString, QStringList> m_relatives; // Same with relative paths
0078 };
0079 
0080 void KoResourcePathsImpl::addResourceTypeInternal(const QString &type, const QString &basetype,
0081                                                   const QString &relativename,
0082                                                   bool priority)
0083 {
0084     if (relativename.isEmpty()) return;
0085 
0086     QString copy = relativename;
0087 
0088     Q_ASSERT(basetype == "data");
0089 
0090     if (!copy.endsWith(QLatin1Char('/'))) {
0091         copy += QLatin1Char('/');
0092     }
0093 
0094     QStringList &rels = m_relatives[type]; // find or insert
0095 
0096     if (!rels.contains(copy, cs)) {
0097         if (priority) {
0098             rels.prepend(copy);
0099         } else {
0100             rels.append(copy);
0101         }
0102     }
0103 
0104     //qDebug() << "addResourceType: type" << type << "basetype" << basetype << "relativename" << relativename << "priority" << priority << m_relatives[type];
0105 }
0106 
0107 void KoResourcePathsImpl::addResourceDirInternal(const QString &type, const QString &absdir, bool priority)
0108 {
0109     if (absdir.isEmpty() || type.isEmpty()) return;
0110 
0111     // find or insert entry in the map
0112     QString copy = absdir;
0113     if (!copy.endsWith(QLatin1Char('/'))) {
0114         copy += QLatin1Char('/');
0115     }
0116 
0117     QStringList &paths = m_absolutes[type];
0118     if (!paths.contains(copy, cs)) {
0119         if (priority) {
0120             paths.prepend(copy);
0121         } else {
0122             paths.append(copy);
0123         }
0124     }
0125 
0126     //qDebug() << "addResourceDir: type" << type << "absdir" << absdir << "priority" << priority << m_absolutes[type];
0127 }
0128 
0129 QString KoResourcePathsImpl::findResourceInternal(const QString &type, const QString &fileName)
0130 {
0131     const QStandardPaths::StandardLocation location = mapTypeToQStandardPaths(type);
0132     QString resource = QStandardPaths::locate(location, fileName, QStandardPaths::LocateFile);
0133     if (resource.isEmpty()) {
0134         foreach(const QString &relative, m_relatives.value(type)) {
0135             resource = QStandardPaths::locate(location, relative + fileName, QStandardPaths::LocateFile);
0136             if (!resource.isEmpty()) {
0137                 break;
0138             }
0139         }
0140     }
0141     if (resource.isEmpty()) {
0142         foreach(const QString &absolute, m_absolutes.value(type)) {
0143             const QString filePath = absolute + fileName;
0144             if (QFileInfo::exists(filePath)) {
0145                 resource = filePath;
0146                 break;
0147             }
0148         }
0149     }
0150     //Q_ASSERT(!resource.isEmpty());
0151     //qDebug() << "findResource: type" << type << "filename" << fileName << "resource" << resource;
0152     return resource;
0153 }
0154 
0155 QStringList KoResourcePathsImpl::findDirsInternal(const QString &type, const QString &relDir)
0156 {
0157     const QStandardPaths::StandardLocation location = mapTypeToQStandardPaths(type);
0158 
0159     QStringList dirs = QStandardPaths::locateAll(location, relDir, QStandardPaths::LocateDirectory);
0160 
0161     foreach(const QString &relative, m_relatives.value(type)) {
0162         dirs << QStandardPaths::locateAll(location, relative + relDir, QStandardPaths::LocateDirectory);
0163     }
0164 
0165     foreach(const QString &absolute, m_absolutes.value(type)) {
0166         const QString dirPath = absolute + relDir;
0167         if (QDir(dirPath).exists()) {
0168             dirs << dirPath;
0169         }
0170     }
0171 
0172     //Q_ASSERT(!dirs.isEmpty());
0173     //qDebug() << "findDirs: type" << type << "relDir" << relDir<< "resource" << dirs;
0174     return dirs;
0175 }
0176 
0177 
0178 QStringList filesInDir(const QString &startdir, const QString & filter, bool noduplicates, bool recursive)
0179 {
0180     //qDebug() << "filesInDir: startdir" << startdir << "filter" << filter << "noduplicates" << noduplicates << "recursive" << recursive;
0181     QStringList result;
0182 
0183     // First the entries in this path
0184     QStringList nameFilters;
0185     nameFilters << filter;
0186     const QStringList fileNames = QDir(startdir).entryList(nameFilters, QDir::Files | QDir::CaseSensitive, QDir::Name);
0187     //qDebug() << "\tFound:" << fileNames.size() << ":" << fileNames;
0188     Q_FOREACH (const QString &fileName, fileNames) {
0189         QString file = startdir + '/' + fileName;
0190         result << file;
0191     }
0192 
0193     // And then everything underneath, if recursive is specified
0194     if (recursive) {
0195         const QStringList entries = QDir(startdir).entryList(QDir::Dirs | QDir::NoDotAndDotDot);
0196         Q_FOREACH (const QString &subdir, entries) {
0197             //qDebug() << "\tGoing to look in subdir" << subdir << "of" << startdir;
0198             result << filesInDir(startdir + '/' + subdir, filter, noduplicates, recursive);
0199         }
0200     }
0201     return result;
0202 }
0203 
0204 QStringList KoResourcePathsImpl::findAllResourcesInternal(const QString &type,
0205                                                           const QString &_filter,
0206                                                           KoResourcePaths::SearchOptions options) const
0207 {
0208     //qDebug() << "=====================================================";
0209 
0210     bool noDuplicates = options & KoResourcePaths::NoDuplicates;
0211     bool recursive = options & KoResourcePaths::Recursive;
0212 
0213     //qDebug() << "findAllResources: type" << type << "filter" << _filter << "no dups" << noDuplicates << "recursive" << recursive;
0214 
0215     const QStandardPaths::StandardLocation location = mapTypeToQStandardPaths(type);
0216 
0217     const QStringList relatives = m_relatives.value(type);
0218     QString filter = _filter;
0219     QString prefix;
0220 
0221     // In cases where the filter  is like "color-schemes/*.colors" instead of "*.kpp", used with unregistgered resource types
0222     if (filter.indexOf('*') > 0) {
0223         prefix = filter.split('*').first();
0224         filter = '*' + filter.split('*')[1];
0225         //qDebug() << "Split up alias" << relatives << "filter" << filter;
0226     }
0227 
0228     QStringList resources;
0229     if (relatives.isEmpty()) {
0230         resources << QStandardPaths::locateAll(location, prefix + filter, QStandardPaths::LocateFile);
0231     }
0232 
0233     ////qDebug() << "\tresources from qstandardpaths:" << resources.size();
0234 
0235 
0236     foreach(const QString &relative, relatives) {
0237         //qDebug() << "\t\relative:" << relative;
0238         const QStringList dirs = QStandardPaths::locateAll(location, relative + prefix, QStandardPaths::LocateDirectory);
0239         QSet<QString> s = QSet<QString>::fromList(dirs);
0240 
0241         //qDebug() << "\t\tdirs:" << dirs;
0242         Q_FOREACH (const QString &dir, s) {
0243             resources << filesInDir(dir, filter, noDuplicates, recursive);
0244         }
0245     }
0246 
0247     foreach(const QString &absolute, m_absolutes.value(type)) {
0248         const QString dir = absolute + prefix;
0249         if (QDir(dir).exists()) {
0250             resources << filesInDir(dir, filter, noDuplicates, recursive);
0251         }
0252     }
0253 
0254     if (noDuplicates) {
0255         QSet<QString> s = QSet<QString>::fromList(resources);
0256         resources = s.toList();
0257     }
0258 
0259     //qDebug() << "\tresources also from aliases:" << resources.size();
0260     //qDebug() << "=====================================================";
0261 
0262     //Q_ASSERT(!resources.isEmpty());
0263 
0264     return resources;
0265 }
0266 
0267 QStringList KoResourcePathsImpl::resourceDirsInternal(const QString &type)
0268 {
0269     //return KGlobal::dirs()->resourceDirs(type.toLatin1());
0270     QStringList resourceDirs;
0271 
0272     const QStandardPaths::StandardLocation location = mapTypeToQStandardPaths(type);
0273     foreach(const QString &relative, m_relatives.value(type)) {
0274         resourceDirs << QStandardPaths::locateAll(location, relative, QStandardPaths::LocateDirectory);
0275     }
0276     foreach(const QString &absolute, m_absolutes.value(type)) {
0277         if (QDir(absolute).exists()) {
0278             resourceDirs << absolute;
0279         }
0280     }
0281     //qDebug() << "resourceDirs: type" << type << resourceDirs;
0282 
0283     return resourceDirs;
0284 }
0285 
0286 QString KoResourcePathsImpl::saveLocationInternal(const QString &type, const QString &suffix, bool create)
0287 {
0288     QString path = QStandardPaths::writableLocation(mapTypeToQStandardPaths(type)) + '/' + suffix;
0289     QDir d(path);
0290     if (!d.exists() && create) {
0291         d.mkpath(path);
0292     }
0293     //qDebug() << "saveLocation: type" << type << "suffix" << suffix << "create" << create << "path" << path;
0294 
0295     return path;
0296 }
0297 
0298 QString KoResourcePathsImpl::locateLocalInternal(const QString &type, const QString &filename, bool createDir)
0299 {
0300     QString path = saveLocationInternal(type, "", createDir);
0301     //qDebug() << "locateLocal: type" << type << "filename" << filename << "CreateDir" << createDir << "path" << path;
0302     return path + '/' + filename;
0303 }
0304 
0305 Q_GLOBAL_STATIC(KoResourcePathsImpl, s_instance);
0306 
0307 
0308 void KoResourcePaths::addResourceType(const char *type, const char *basetype,
0309                                       const QString &relativeName, bool priority)
0310 {
0311     s_instance->addResourceTypeInternal(QString::fromLatin1(type), QString::fromLatin1(basetype), relativeName, priority);
0312 }
0313 
0314 void KoResourcePaths::addResourceDir(const char *type, const QString &dir, bool priority)
0315 {
0316     s_instance->addResourceDirInternal(QString::fromLatin1(type), dir, priority);
0317 }
0318 
0319 QString KoResourcePaths::findResource(const char *type, const QString &fileName)
0320 {
0321     return s_instance->findResourceInternal(QString::fromLatin1(type), fileName);
0322 }
0323 
0324 QStringList KoResourcePaths::findDirs(const char *type, const QString &reldir)
0325 {
0326     return s_instance->findDirsInternal(QString::fromLatin1(type), reldir);
0327 }
0328 
0329 QStringList KoResourcePaths::findAllResources(const char *type,
0330                                               const QString &filter,
0331                                               SearchOptions options)
0332 {
0333     return s_instance->findAllResourcesInternal(QString::fromLatin1(type), filter, options);
0334 }
0335 
0336 QStringList KoResourcePaths::resourceDirs(const char *type)
0337 {
0338     return s_instance->resourceDirsInternal(QString::fromLatin1(type));
0339 }
0340 
0341 QString KoResourcePaths::saveLocation(const char *type, const QString &suffix, bool create)
0342 {
0343     return s_instance->saveLocationInternal(QString::fromLatin1(type), suffix, create);
0344 }
0345 
0346 QString KoResourcePaths::locate(const char *type, const QString &filename)
0347 {
0348     return s_instance->findResourceInternal(QString::fromLatin1(type), filename);
0349 }
0350 
0351 QString KoResourcePaths::locateLocal(const char *type, const QString &filename, bool createDir)
0352 {
0353     return s_instance->locateLocalInternal(QString::fromLatin1(type), filename, createDir);
0354 }