File indexing completed on 2024-05-12 16:01:55

0001 /* This file is part of the KDE project
0002    SPDX-FileCopyrightText: 2000 Werner Trobin <trobin@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "KisTemplateTree.h"
0008 
0009 #include <QDir>
0010 #include <QPrinter>
0011 #include <QUrl>
0012 
0013 #include <kdesktopfile.h>
0014 #include <kconfig.h>
0015 #include <kis_debug.h>
0016 
0017 
0018 #include <KoResourcePaths.h>
0019 #include <klocalizedstring.h>
0020 #include <kconfiggroup.h>
0021 
0022 #include <KisTemplate.h>
0023 #include <KisTemplateGroup.h>
0024 #include <KisTemplates.h>
0025 
0026 static QString currentLocale()
0027 {
0028     const QStringList languages = KLocalizedString::languages();
0029     if (languages.isEmpty()) {
0030         return QLocale().name();
0031     } else {
0032         return languages.first();
0033     }
0034 }
0035 
0036 KisTemplateTree::KisTemplateTree(const QString &templatesResourcePath,
0037                                  bool readTree)
0038     :  m_templatesResourcePath(templatesResourcePath)
0039     , m_defaultGroup(0)
0040     , m_defaultTemplate(0)
0041 {
0042     if (readTree)
0043         readTemplateTree();
0044 }
0045 
0046 KisTemplateTree::~KisTemplateTree()
0047 {
0048     qDeleteAll(m_groups);
0049 }
0050 
0051 void KisTemplateTree::readTemplateTree()
0052 {
0053     readGroups();
0054     readTemplates();
0055 }
0056 
0057 void KisTemplateTree::writeTemplateTree()
0058 {
0059     QString localDir = KoResourcePaths::saveLocation("templates");
0060 
0061     Q_FOREACH (KisTemplateGroup *group, m_groups) {
0062         //dbgUI <<"---------------------------------";
0063         //dbgUI <<"group:" << group->name();
0064 
0065         bool touched = false;
0066         QList<KisTemplate*> templates = group->templates();
0067         QList<KisTemplate*>::iterator it = templates.begin();
0068         for (; it != templates.end() && !touched && !group->touched(); ++it)
0069             touched = (*it)->touched();
0070 
0071         if (group->touched() || touched) {
0072             //dbgUI <<"touched";
0073             if (!group->isHidden()) {
0074                 //dbgUI <<"not hidden";
0075                 QDir path;
0076                 path.mkpath(localDir + group->name()); // create the local group dir
0077             } else {
0078                 //dbgUI <<"hidden";
0079                 if (group->dirs().count() == 1 && group->dirs().contains(localDir)) {
0080                     //dbgUI <<"local only";
0081                     QFile f(group->dirs().first());
0082                     f.remove();
0083                     //dbgUI <<"removing:" << group->dirs().first();
0084                 } else {
0085                     //dbgUI <<"global";
0086                     QDir path;
0087                     path.mkpath(localDir + group->name());
0088                 }
0089             }
0090         }
0091         Q_FOREACH (KisTemplate *t, templates) {
0092             if (t->touched()) {
0093                 //dbgUI <<"++template:" << t->name();
0094                 writeTemplate(t, group, localDir);
0095             }
0096             if (t->isHidden() && t->touched()) {
0097                 //dbgUI <<"+++ delete local template ##############";
0098                 writeTemplate(t, group, localDir);
0099                 QFile::remove(t->file());
0100                 QFile::remove(t->picture());
0101             }
0102         }
0103     }
0104 }
0105 
0106 bool KisTemplateTree::add(KisTemplateGroup *g)
0107 {
0108 
0109     KisTemplateGroup *group = find(g->name());
0110     if (group == 0) {
0111         m_groups.append(g);
0112         return true;
0113     }
0114 
0115     group->addDir(g->dirs().first()); // "...there can be only one..." (Queen)
0116     delete g;
0117     g = 0;
0118     return false;
0119 }
0120 
0121 KisTemplateGroup *KisTemplateTree::find(const QString &name) const
0122 {
0123     QList<KisTemplateGroup*>::const_iterator it = m_groups.begin();
0124     KisTemplateGroup* ret = 0;
0125 
0126     while (it != m_groups.end()) {
0127         if ((*it)->name() == name) {
0128             ret = *it;
0129             break;
0130         }
0131 
0132         ++it;
0133     }
0134 
0135     return ret;
0136 }
0137 
0138 void KisTemplateTree::readGroups()
0139 {
0140 
0141     QStringList dirs = KoResourcePaths::findDirs("templates");
0142 
0143     Q_FOREACH (const QString & dirName, dirs) {
0144         if (!dirName.contains("templates")) continue; // Hack around broken KoResourcePaths
0145         QDir dir(dirName);
0146         // avoid the annoying warning
0147         if (!dir.exists())
0148             continue;
0149         QStringList templateDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
0150 
0151 
0152         Q_FOREACH (const QString & templateDirName, templateDirs) {
0153             QDir templateDir(dirName + "/" + templateDirName);
0154             QString name = templateDirName;
0155             QString defaultTab;
0156             int sortingWeight = 1000;
0157             if (templateDir.exists(".directory")) {
0158                 KDesktopFile config(templateDir.absoluteFilePath(".directory"));
0159                 config.setLocale(currentLocale());
0160                 KConfigGroup dg = config.desktopGroup();
0161                 name = dg.readEntry("Name");
0162                 defaultTab = dg.readEntry("X-KDE-DefaultTab");
0163                 sortingWeight = dg.readEntry("X-KDE-SortingWeight", 1000);
0164             }
0165             KisTemplateGroup *g = new KisTemplateGroup(name, templateDir.absolutePath() + '/', sortingWeight);
0166             if (add(g)) {
0167                 if (defaultTab == "true") {
0168                     m_defaultGroup = g;
0169                 }
0170             }
0171         }
0172     }
0173 }
0174 
0175 void KisTemplateTree::readTemplates()
0176 {
0177     QString dontShow = "imperial";
0178     if ( QLocale().measurementSystem() == QLocale::ImperialSystem) {
0179         dontShow = "metric";
0180     }
0181 
0182     Q_FOREACH (KisTemplateGroup* group, m_groups) {
0183         QStringList dirs = group->dirs();
0184         for (QStringList::ConstIterator it = dirs.constBegin(); it != dirs.constEnd(); ++it) {
0185             QDir d(*it);
0186             if (!d.exists())
0187                 continue;
0188             QStringList files = d.entryList(QDir::Files | QDir::Readable, QDir::Name);
0189             for (int i = 0; i < files.count(); ++i) {
0190                 QString filePath = *it + files[i];
0191                 //dbgUI <<"filePath:" << filePath;
0192                 QString icon;
0193                 QString text;
0194                 QString description;
0195                 QString hidden_str;
0196                 QString fileName;
0197                 bool hidden = false;
0198                 bool defaultTemplate = false;
0199                 QString templatePath;
0200                 QString measureSystem;
0201                 // If a desktop file, then read the name from it.
0202                 // Otherwise (or if no name in it?) use file name
0203                 if (KDesktopFile::isDesktopFile(filePath)) {
0204                     KConfig _config(filePath, KConfig::SimpleConfig);
0205                     _config.setLocale(currentLocale());
0206                     KConfigGroup config(&_config, "Desktop Entry");
0207                     if (config.readEntry("Type") == "Link") {
0208                         text = config.readEntry("Name");
0209                         fileName = filePath;
0210                         description = config.readEntry("Comment");
0211                         //dbgUI <<"name:" << text;
0212                         icon = config.readEntry("Icon");
0213                         if (icon[0] != '/' && // allow absolute paths for icons
0214                                 QFile::exists(*it + icon)) // allow icons from icontheme
0215                             icon = *it + icon;
0216                         //dbgUI <<"icon2:" << icon;
0217                         hidden = config.readEntry("X-KDE-Hidden", false);
0218                         defaultTemplate = config.readEntry("X-KDE-DefaultTemplate", false);
0219                         measureSystem = config.readEntry("X-KDE-MeasureSystem").toLower();
0220 
0221                         // Don't add a template that is for the wrong measure system
0222                         if (measureSystem == dontShow)
0223                             continue;
0224 
0225                         //dbgUI <<"hidden:" << hidden_str;
0226                         templatePath = config.readPathEntry("URL", QString());
0227                         //dbgUI <<"Link to :" << templatePath;
0228                         if (templatePath[0] != '/') {
0229                             if (templatePath.left(6) == "file:/") // I doubt this will happen
0230                                 templatePath = templatePath.right(templatePath.length() - 6);
0231                             //else
0232                             //  dbgUI <<"dirname=" << *it;
0233                             templatePath = *it + templatePath;
0234                             //dbgUI <<"templatePath:" << templatePath;
0235                         }
0236                     } else
0237                         continue; // Invalid
0238                 }
0239                 // The else if and the else branch are here for compat. with the old system
0240                 else if (files[i].right(4) != ".png")
0241                     // Ignore everything that is not a PNG file
0242                     continue;
0243                 else {
0244                     // Found a PNG file - the template must be here in the same dir.
0245                     icon = filePath;
0246                     QFileInfo fi(filePath);
0247                     text = fi.completeBaseName();
0248                     templatePath = filePath; // Note that we store the .png file as the template !
0249                     // That's the way it's always been done. Then the app replaces the extension...
0250                 }
0251                 KisTemplate *t = new KisTemplate(text, description, templatePath, icon, fileName,
0252                                                measureSystem, hidden);
0253                 group->add(t, false, false); // false -> we aren't a "user", false -> don't
0254                 // "touch" the group to avoid useless
0255                 // creation of dirs in .kde/blah/...
0256                 if (defaultTemplate)
0257                     m_defaultTemplate = t;
0258             }
0259         }
0260     }
0261 }
0262 
0263 void KisTemplateTree::writeTemplate(KisTemplate *t, KisTemplateGroup *group,
0264                                    const QString &localDir)
0265 {
0266     QString fileName;
0267     if (t->isHidden()) {
0268         fileName = t->fileName();
0269         // try to remove the file
0270         if (QFile::remove(fileName) || !QFile::exists(fileName)) {
0271             QFile::remove(t->name());
0272             QFile::remove(t->picture());
0273             return;
0274         }
0275     }
0276     // be sure that the template's file name is unique so we don't overwrite an other
0277     QString const path = localDir + group->name() + '/';
0278     QString const name = KisTemplates::trimmed(t->name());
0279     fileName = path + name + ".desktop";
0280     if (t->isHidden() && QFile::exists(fileName))
0281         return;
0282     QString fill;
0283     while (QFile(fileName).exists()) {
0284         fill += '_';
0285         fileName = path + fill + name + ".desktop";
0286     }
0287 
0288     KConfig _config(fileName, KConfig::SimpleConfig);
0289     _config.setLocale(currentLocale());
0290     KConfigGroup config(&_config, "Desktop Entry");
0291     config.writeEntry("Type", "Link");
0292     config.writePathEntry("URL", t->file());
0293     config.writeEntry("Name", t->name());
0294     config.writeEntry("Icon", t->picture());
0295     config.writeEntry("X-KDE-Hidden", t->isHidden());
0296 }