1 /* This file is part of the KDE project
2 Copyright (C) 2000 Werner Trobin <trobin@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include "KoTemplateTree.h"
21
22 #include <QDir>
23 #include <QPrinter>
24 #include <QUrl>
25
26 #include <kdesktopfile.h>
27 #include <kconfig.h>
28 #include <MainDebug.h>
29 #include <klocalizedstring.h>
30 #include <kconfiggroup.h>
31
32 #include <KoNetAccess.h>
33 #include <KoResourcePaths.h>
34 #include <KoTemplate.h>
35 #include <KoTemplateGroup.h>
36 #include <KoTemplates.h>
37
KoTemplateTree(const QString & templatesResourcePath,bool readTree)38 KoTemplateTree::KoTemplateTree(const QString &templatesResourcePath, bool readTree) :
39 m_templatesResourcePath(templatesResourcePath), m_defaultGroup(0),
40 m_defaultTemplate(0)
41 {
42 if (readTree)
43 readTemplateTree();
44 }
45
~KoTemplateTree()46 KoTemplateTree::~KoTemplateTree()
47 {
48 qDeleteAll(m_groups);
49 }
50
readTemplateTree()51 void KoTemplateTree::readTemplateTree()
52 {
53
54 readGroups();
55 readTemplates();
56 }
57
writeTemplateTree()58 void KoTemplateTree::writeTemplateTree()
59 {
60
61 const QString localDir = KoResourcePaths::saveLocation("data", m_templatesResourcePath);
62
63 foreach (KoTemplateGroup *group, m_groups) {
64 //kDebug( 30003 ) <<"---------------------------------";
65 //kDebug( 30003 ) <<"group:" << group->name();
66
67 bool touched = false;
68 const QList<KoTemplate*> templates = group->templates();
69 QList<KoTemplate*>::ConstIterator it = templates.begin();
70 for (; it != templates.end() && !touched && !group->touched(); ++it)
71 touched = (*it)->touched();
72
73 if (group->touched() || touched) {
74 //kDebug( 30003 ) <<"touched";
75 if (!group->isHidden()) {
76 //kDebug( 30003 ) <<"not hidden";
77 QDir().mkpath(localDir + group->name()); // create the local group dir
78 } else {
79 //kDebug( 30003 ) <<"hidden";
80 if (group->dirs().count() == 1 && group->dirs().contains(localDir)) {
81 //kDebug( 30003 ) <<"local only";
82 KIO::NetAccess::del(QUrl::fromLocalFile(group->dirs().first()), 0);
83 //kDebug( 30003 ) <<"removing:" << group->dirs().first();
84 } else {
85 //kDebug( 30003 ) <<"global";
86 QDir().mkpath(localDir + group->name());
87 }
88 }
89 }
90 foreach (KoTemplate *t, templates) {
91 if (t->touched()) {
92 //kDebug( 30003 ) <<"++template:" << t->name();
93 writeTemplate(t, group, localDir);
94 }
95 if (t->isHidden() && t->touched()) {
96 //kDebug( 30003 ) <<"+++ delete local template ##############";
97 writeTemplate(t, group, localDir);
98 QFile::remove(t->file());
99 QFile::remove(t->picture());
100 }
101 }
102 }
103 }
104
add(KoTemplateGroup * g)105 void KoTemplateTree::add(KoTemplateGroup *g)
106 {
107
108 KoTemplateGroup *group = find(g->name());
109 if (group == nullptr)
110 m_groups.append(g);
111 else {
112 group->addDir(g->dirs().first()); // "...there can be only one..." (Queen)
113 delete g;
114 g = nullptr;
115 }
116 }
117
find(const QString & name) const118 KoTemplateGroup *KoTemplateTree::find(const QString &name) const
119 {
120 QList<KoTemplateGroup*>::const_iterator it = m_groups.begin();
121 KoTemplateGroup* ret = nullptr;
122
123 while (it != m_groups.end()) {
124 if ((*it)->name() == name) {
125 ret = *it;
126 break;
127 }
128
129 ++it;
130 }
131
132 return ret;
133 }
134
readGroups()135 void KoTemplateTree::readGroups()
136 {
137
138 const QStringList dirs = KoResourcePaths::findDirs("data", m_templatesResourcePath);
139 foreach(const QString & dirName, dirs) {
140 //kDebug( 30003 ) <<"dir:" << *it;
141 QDir dir(dirName);
142 // avoid the annoying warning
143 if (!dir.exists())
144 continue;
145 QStringList templateDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
146 foreach(const QString & templateDirName, templateDirs) {
147 QDir templateDir(dirName + templateDirName);
148 QString name = templateDirName;
149 QString defaultTab;
150 int sortingWeight = 1000;
151 if (templateDir.exists(".directory")) {
152 KDesktopFile config(templateDir.absoluteFilePath(".directory"));
153 KConfigGroup dg = config.desktopGroup();
154 name = dg.readEntry("Name");
155 defaultTab = dg.readEntry("X-KDE-DefaultTab");
156 sortingWeight = dg.readEntry("X-KDE-SortingWeight", 1000);
157 //kDebug( 30003 ) <<"name:" << name;
158 }
159 KoTemplateGroup *g = new KoTemplateGroup(name, templateDir.absolutePath() + QDir::separator(), sortingWeight);
160 add(g);
161 if (defaultTab == "true")
162 m_defaultGroup = g;
163 }
164 }
165 }
166
readTemplates()167 void KoTemplateTree::readTemplates()
168 {
169 QString dontShow = "hide nothing at all - show all the templates, please, and let the user make the choice";
170
171 foreach (KoTemplateGroup* group, m_groups) {
172 QStringList dirs = group->dirs();
173 for (QStringList::ConstIterator it = dirs.constBegin(); it != dirs.constEnd(); ++it) {
174 QDir d(*it);
175 if (!d.exists())
176 continue;
177 QStringList files = d.entryList(QDir::Files | QDir::Readable, QDir::Name);
178 for (int i = 0; i < files.count(); ++i) {
179 QString filePath = *it + files[i];
180 //kDebug( 30003 ) <<"filePath:" << filePath;
181 QString icon;
182 QString text;
183 QString description;
184 QString hidden_str;
185 QString fileName;
186 QString color;
187 QString swatch;
188 QString variantName;
189 QString thumbnail;
190 bool wide = false;
191 bool hidden = false;
192 bool defaultTemplate = false;
193 QString templatePath;
194 QString measureSystem;
195 // If a desktop file, then read the name from it.
196 // Otherwise (or if no name in it?) use file name
197 if (KDesktopFile::isDesktopFile(filePath)) {
198 KConfig _config(filePath, KConfig::SimpleConfig);
199 KConfigGroup config(&_config, "Desktop Entry");
200 if (config.readEntry("Type") == "Link") {
201 text = config.readEntry("Name");
202 fileName = filePath;
203 description = config.readEntry("Comment");
204 //kDebug( 30003 ) <<"name:" << text;
205 icon = config.readEntry("Icon");
206 if (icon[0] != '/' && // allow absolute paths for icons
207 QFile::exists(*it + icon)) // allow icons from icontheme
208 icon = *it + icon;
209 //kDebug( 30003 ) <<"icon2:" << icon;
210 color = config.readEntry("X-KDE-Color");
211 swatch = config.readEntry("X-KDE-Swatch");
212 wide = config.readEntry("X-KDE-TemplateIsWideFormat", false);
213 variantName = config.readEntry("X-KDE-VariantName");
214 thumbnail = config.readEntry("X-KDE-Thumbnail");
215 hidden = config.readEntry("X-KDE-Hidden", false);
216 defaultTemplate = config.readEntry("X-KDE-DefaultTemplate", false);
217 measureSystem = config.readEntry("X-KDE-MeasureSystem").toLower();
218
219 // Don't add a template that is for the wrong measure system
220 if (measureSystem == dontShow)
221 continue;
222
223 //kDebug( 30003 ) <<"hidden:" << hidden_str;
224 templatePath = config.readPathEntry("URL", QString());
225 //kDebug( 30003 ) <<"Link to :" << templatePath;
226 if (templatePath[0] != '/') {
227 if (templatePath.left(6) == "file:/") // I doubt this will happen
228 templatePath = templatePath.right(templatePath.length() - 6);
229 //else
230 // kDebug( 30003 ) <<"dirname=" << *it;
231 templatePath = *it + templatePath;
232 //kDebug( 30003 ) <<"templatePath:" << templatePath;
233 }
234 } else
235 continue; // Invalid
236 }
237 // The else if and the else branch are here for compat. with the old system
238 else if (files[i].right(4) != ".png")
239 // Ignore everything that is not a PNG file
240 continue;
241 else {
242 // Found a PNG file - the template must be here in the same dir.
243 icon = filePath;
244 QFileInfo fi(filePath);
245 text = fi.baseName();
246 templatePath = filePath; // Note that we store the .png file as the template !
247 // That's the way it's always been done. Then the app replaces the extension...
248 }
249 KoTemplate *t = new KoTemplate(text, description, templatePath, icon, fileName,
250 measureSystem, color, swatch, variantName, wide, hidden);
251 if (!thumbnail.isEmpty())
252 t->setThumbnail(*it + thumbnail);
253 group->add(t, false, false); // false -> we aren't a "user", false -> don't
254 // "touch" the group to avoid useless
255 // creation of dirs in .kde/blah/...
256 if (defaultTemplate)
257 m_defaultTemplate = t;
258 }
259 }
260 }
261 }
262
writeTemplate(KoTemplate * t,KoTemplateGroup * group,const QString & localDir)263 void KoTemplateTree::writeTemplate(KoTemplate *t, KoTemplateGroup *group,
264 const QString &localDir)
265 {
266 QString fileName;
267 if (t->isHidden()) {
268 fileName = t->fileName();
269 // try to remove the file
270 if (QFile::remove(fileName) || !QFile::exists(fileName)) {
271 QFile::remove(t->name());
272 QFile::remove(t->picture());
273 return;
274 }
275 }
276 // be sure that the template's file name is unique so we don't overwrite an other
277 QString const path = localDir + group->name() + '/';
278 QString const name = KoTemplates::trimmed(t->name());
279 fileName = path + name + ".desktop";
280 if (t->isHidden() && QFile::exists(fileName))
281 return;
282 QString fill;
283 while (QFile(fileName).exists()) {
284 fill += '_';
285 fileName = path + fill + name + ".desktop";
286 }
287
288 KConfig _config(fileName, KConfig::SimpleConfig);
289 KConfigGroup config(&_config, "Desktop Entry");
290 config.writeEntry("Type", "Link");
291 config.writePathEntry("URL", t->file());
292 config.writeEntry("Name", t->name());
293 config.writeEntry("Icon", t->picture());
294 config.writeEntry("X-KDE-Hidden", t->isHidden());
295 }
296