File indexing completed on 2024-05-12 05:13:33
0001 /* 0002 SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "grantleetheme.h" 0008 #include "grantleetheme_debug.h" 0009 #include "grantleetheme_p.h" 0010 #include "grantleethemeengine.h" 0011 #include "qtresourcetemplateloader.h" 0012 #include <config-grantleetheme.h> 0013 0014 #include <KConfig> 0015 #include <KConfigGroup> 0016 #include <KLocalizedString> 0017 0018 #include <QDir> 0019 #include <QSharedPointer> 0020 0021 using namespace GrantleeTheme; 0022 0023 QSharedPointer<GrantleeKi18nLocalizer> GrantleeTheme::ThemePrivate::sLocalizer; 0024 KTextTemplate::Engine *GrantleeTheme::ThemePrivate::sEngine = nullptr; 0025 0026 ThemePrivate::ThemePrivate() 0027 : QSharedData() 0028 { 0029 } 0030 0031 ThemePrivate::ThemePrivate(const ThemePrivate &other) 0032 0033 = default; 0034 0035 ThemePrivate::~ThemePrivate() = default; 0036 0037 void ThemePrivate::setupEngine() 0038 { 0039 sEngine = new GrantleeTheme::Engine(); 0040 } 0041 0042 void ThemePrivate::setupLoader() 0043 { 0044 // Get the parent dir with themes, we set the theme directory separately 0045 0046 QStringList templatePaths; 0047 for (const QString &absolutePath : std::as_const(absolutePaths)) { 0048 QDir dir(absolutePath); 0049 dir.cdUp(); 0050 templatePaths << dir.absolutePath(); 0051 } 0052 loader = QSharedPointer<GrantleeTheme::QtResourceTemplateLoader>::create(); 0053 loader->setTemplateDirs(templatePaths); 0054 loader->setTheme(dirName); 0055 0056 if (!sEngine) { 0057 ThemePrivate::setupEngine(); 0058 } 0059 sEngine->addTemplateLoader(loader); 0060 } 0061 KTextTemplate::Context ThemePrivate::createContext(const QVariantHash &data, const QByteArray &applicationDomain) 0062 { 0063 if (!sLocalizer) { 0064 sLocalizer.reset(new GrantleeKi18nLocalizer()); 0065 } 0066 sLocalizer->setApplicationDomain(applicationDomain); 0067 KTextTemplate::Context ctx(data); 0068 ctx.setLocalizer(sLocalizer); 0069 return ctx; 0070 } 0071 QString ThemePrivate::errorTemplate(const QString &reason, const QString &origTemplateName, const KTextTemplate::Template &failedTemplate) 0072 { 0073 KTextTemplate::Template tpl = sEngine->newTemplate(QStringLiteral("<h1>{{ error }}</h1>\n" 0074 "<b>%1:</b> {{ templateName }}<br>\n" 0075 "<b>%2:</b> {{ errorMessage }}") 0076 .arg(i18n("Template"), i18n("Error message")), 0077 QStringLiteral("TemplateError")); 0078 0079 KTextTemplate::Context ctx = createContext(); 0080 ctx.insert(QStringLiteral("error"), reason); 0081 ctx.insert(QStringLiteral("templateName"), origTemplateName); 0082 const QString errorString = failedTemplate ? failedTemplate->errorString() : i18n("(null template)"); 0083 ctx.insert(QStringLiteral("errorMessage"), errorString); 0084 return tpl->render(&ctx); 0085 } 0086 0087 Theme::Theme() 0088 : d(new ThemePrivate) 0089 { 0090 } 0091 0092 Theme::Theme(const QString &themePath, const QString &dirName, const QString &defaultDesktopFileName) 0093 : d(new ThemePrivate) 0094 { 0095 const QString themeInfoFile = themePath + QLatin1Char('/') + defaultDesktopFileName; 0096 KConfig config(themeInfoFile); 0097 KConfigGroup group(&config, QStringLiteral("Desktop Entry")); 0098 if (group.isValid()) { 0099 d->dirName = dirName; 0100 d->absolutePaths.append(themePath); 0101 d->name = group.readEntry("Name", QString()); 0102 d->description = group.readEntry("Description", QString()); 0103 d->themeFileName = group.readEntry("FileName", QString()); 0104 d->displayExtraVariables = group.readEntry("DisplayExtraVariables", QStringList()); 0105 } 0106 } 0107 0108 Theme::Theme(const Theme &other) 0109 0110 = default; 0111 0112 Theme::~Theme() = default; 0113 0114 bool Theme::operator==(const Theme &other) const 0115 { 0116 return isValid() && other.isValid() && d->absolutePaths == other.d->absolutePaths; 0117 } 0118 0119 Theme &Theme::operator=(const Theme &other) 0120 { 0121 if (this != &other) { 0122 d = other.d; 0123 } 0124 0125 return *this; 0126 } 0127 0128 bool Theme::isValid() const 0129 { 0130 return !d->themeFileName.isEmpty() && !d->name.isEmpty(); 0131 } 0132 0133 QString Theme::description() const 0134 { 0135 return d->description; 0136 } 0137 0138 QString Theme::themeFilename() const 0139 { 0140 return d->themeFileName; 0141 } 0142 0143 QString Theme::name() const 0144 { 0145 return d->name; 0146 } 0147 0148 QStringList Theme::displayExtraVariables() const 0149 { 0150 return d->displayExtraVariables; 0151 } 0152 0153 QString Theme::dirName() const 0154 { 0155 return d->dirName; 0156 } 0157 0158 QString Theme::absolutePath() const 0159 { 0160 if (!d->absolutePaths.isEmpty()) { 0161 return d->absolutePaths.at(0); // #### 0162 } 0163 return {}; 0164 } 0165 0166 QString Theme::author() const 0167 { 0168 return d->author; 0169 } 0170 0171 QString Theme::authorEmail() const 0172 { 0173 return d->email; 0174 } 0175 0176 void Theme::addThemePath(const QString &path) 0177 { 0178 d->absolutePaths.append(path); 0179 } 0180 0181 QString Theme::render(const QString &templateName, const QVariantHash &data, const QByteArray &applicationDomain) 0182 { 0183 if (!d->loader) { 0184 d->setupLoader(); 0185 } 0186 Q_ASSERT(d->loader); 0187 0188 if (!d->loader->canLoadTemplate(templateName)) { 0189 qCWarning(GRANTLEETHEME_LOG) << "Cannot load template" << templateName 0190 << ", please check your installation. Tried in these dirs:" << d->loader->templateDirs(); 0191 return {}; 0192 } 0193 KTextTemplate::Template tpl = d->loader->loadByName(templateName, ThemePrivate::sEngine); 0194 if (!tpl || tpl->error()) { 0195 return d->errorTemplate(i18n("Template parsing error"), templateName, tpl); 0196 } 0197 KTextTemplate::Context ctx = d->createContext(data, applicationDomain); 0198 const QString result = tpl->render(&ctx); 0199 if (tpl->error()) { 0200 return d->errorTemplate(i18n("Template rendering error"), templateName, tpl); 0201 } 0202 0203 return result; 0204 } 0205 0206 void Theme::addPluginPath(const QString &path) 0207 { 0208 if (!ThemePrivate::sEngine) { 0209 ThemePrivate::setupEngine(); 0210 } 0211 0212 QStringList paths = ThemePrivate::sEngine->pluginPaths(); 0213 if (!paths.contains(path)) { 0214 paths.prepend(path); 0215 ThemePrivate::sEngine->setPluginPaths(paths); 0216 } 0217 }