1 /* This file is part of the KDE project
2 Copyright (C) 1998, 1999, 2000 Torben Weis <weis@kde.org>
3 Copyright (C) 2004 David Faure <faure@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 // clazy:excludeall=qstring-arg
22 #include "KoDocumentInfo.h"
23
24 #include "config.h"
25 #include "KoDocumentBase.h"
26 #include "KoOdfWriteStore.h"
27 #include "KoXmlNS.h"
28
29 #include <QDateTime>
30 #include <KoStoreDevice.h>
31 #include <KoXmlWriter.h>
32
33 #include <kconfig.h>
34 #include <kconfiggroup.h>
35 #include <OdfDebug.h>
36 #include <klocalizedstring.h>
37 #include <kuser.h>
38 #include <kemailsettings.h>
39
40
KoDocumentInfo(QObject * parent)41 KoDocumentInfo::KoDocumentInfo(QObject *parent) : QObject(parent)
42 {
43 m_aboutTags << "title" << "description" << "subject" << "comments"
44 << "keyword" << "initial-creator" << "editing-cycles"
45 << "date" << "creation-date" << "language";
46
47 m_authorTags << "creator" << "initial" << "author-title"
48 << "email" << "telephone" << "telephone-work"
49 << "fax" << "country" << "postal-code" << "city"
50 << "street" << "position" << "company";
51
52 setAboutInfo("editing-cycles", "0");
53 setAboutInfo("initial-creator", i18n("Unknown"));
54 setAboutInfo("creation-date", QDateTime::currentDateTime()
55 .toString(Qt::ISODate));
56 }
57
~KoDocumentInfo()58 KoDocumentInfo::~KoDocumentInfo()
59 {
60 }
61
load(const KoXmlDocument & doc)62 bool KoDocumentInfo::load(const KoXmlDocument &doc)
63 {
64 m_authorInfo.clear();
65
66 if (!loadAboutInfo(doc.documentElement()))
67 return false;
68
69 if (!loadAuthorInfo(doc.documentElement()))
70 return false;
71
72 return true;
73 }
74
loadOasis(const KoXmlDocument & metaDoc)75 bool KoDocumentInfo::loadOasis(const KoXmlDocument &metaDoc)
76 {
77 m_authorInfo.clear();
78
79 KoXmlNode t = KoXml::namedItemNS(metaDoc, KoXmlNS::office, "document-meta");
80 KoXmlNode office = KoXml::namedItemNS(t, KoXmlNS::office, "meta");
81
82 if (office.isNull())
83 return false;
84
85 if (!loadOasisAboutInfo(office))
86 return false;
87
88 if (!loadOasisAuthorInfo(office))
89 return false;
90
91 return true;
92 }
93
save(QDomDocument & doc)94 QDomDocument KoDocumentInfo::save(QDomDocument &doc)
95 {
96 updateParametersAndBumpNumCycles();
97
98 QDomElement s = saveAboutInfo(doc);
99 if (!s.isNull())
100 doc.documentElement().appendChild(s);
101
102 s = saveAuthorInfo(doc);
103 if (!s.isNull())
104 doc.documentElement().appendChild(s);
105
106
107 if (doc.documentElement().isNull())
108 return QDomDocument();
109
110 return doc;
111 }
112
saveOasis(KoStore * store)113 bool KoDocumentInfo::saveOasis(KoStore *store)
114 {
115 updateParametersAndBumpNumCycles();
116
117 KoStoreDevice dev(store);
118 KoXmlWriter* xmlWriter = KoOdfWriteStore::createOasisXmlWriter(&dev,
119 "office:document-meta");
120 xmlWriter->startElement("office:meta");
121
122 xmlWriter->startElement("meta:generator");
123 xmlWriter->addTextNode(QString("Calligra Plan/%1")
124 .arg(PLAN_VERSION_STRING));
125 xmlWriter->endElement();
126
127 if (!saveOasisAboutInfo(*xmlWriter))
128 return false;
129 if (!saveOasisAuthorInfo(*xmlWriter))
130 return false;
131
132 xmlWriter->endElement();
133 xmlWriter->endElement(); // root element
134 xmlWriter->endDocument();
135 delete xmlWriter;
136 return true;
137 }
138
setAuthorInfo(const QString & info,const QString & data)139 void KoDocumentInfo::setAuthorInfo(const QString &info, const QString &data)
140 {
141 if (!m_authorTags.contains(info)) {
142 return;
143 }
144
145 m_authorInfoOverride.insert(info, data);
146 }
147
setActiveAuthorInfo(const QString & info,const QString & data)148 void KoDocumentInfo::setActiveAuthorInfo(const QString &info, const QString &data)
149 {
150 if (!m_authorTags.contains(info)) {
151 return;
152 }
153
154 if (data.isEmpty()) {
155 m_authorInfo.remove(info);
156 } else {
157 m_authorInfo.insert(info, data);
158 }
159 emit infoUpdated(info, data);
160 }
161
authorInfo(const QString & info) const162 QString KoDocumentInfo::authorInfo(const QString &info) const
163 {
164 if (!m_authorTags.contains(info))
165 return QString();
166
167 return m_authorInfo[ info ];
168 }
169
setAboutInfo(const QString & info,const QString & data)170 void KoDocumentInfo::setAboutInfo(const QString &info, const QString &data)
171 {
172 if (!m_aboutTags.contains(info))
173 return;
174
175 m_aboutInfo.insert(info, data);
176 emit infoUpdated(info, data);
177 }
178
aboutInfo(const QString & info) const179 QString KoDocumentInfo::aboutInfo(const QString &info) const
180 {
181 if (!m_aboutTags.contains(info)) {
182 return QString();
183 }
184
185 return m_aboutInfo[info];
186 }
187
saveOasisAuthorInfo(KoXmlWriter & xmlWriter)188 bool KoDocumentInfo::saveOasisAuthorInfo(KoXmlWriter &xmlWriter)
189 {
190 foreach(const QString & tag, m_authorTags) {
191 if (!authorInfo(tag).isEmpty() && tag == "creator") {
192 xmlWriter.startElement("dc:creator");
193 xmlWriter.addTextNode(authorInfo("creator"));
194 xmlWriter.endElement();
195 } else if (!authorInfo(tag).isEmpty()) {
196 xmlWriter.startElement("meta:user-defined");
197 xmlWriter.addAttribute("meta:name", tag);
198 xmlWriter.addTextNode(authorInfo(tag));
199 xmlWriter.endElement();
200 }
201 }
202
203 return true;
204 }
205
loadOasisAuthorInfo(const KoXmlNode & metaDoc)206 bool KoDocumentInfo::loadOasisAuthorInfo(const KoXmlNode &metaDoc)
207 {
208 KoXmlElement e = KoXml::namedItemNS(metaDoc, KoXmlNS::dc, "creator");
209 if (!e.isNull() && !e.text().isEmpty())
210 setActiveAuthorInfo("creator", e.text());
211
212 KoXmlNode n = metaDoc.firstChild();
213 for (; !n.isNull(); n = n.nextSibling()) {
214 if (!n.isElement())
215 continue;
216
217 KoXmlElement e = n.toElement();
218 if (!(e.namespaceURI() == KoXmlNS::meta &&
219 e.localName() == "user-defined" && !e.text().isEmpty()))
220 continue;
221
222 QString name = e.attributeNS(KoXmlNS::meta, "name", QString());
223 setActiveAuthorInfo(name, e.text());
224 }
225
226 return true;
227 }
228
loadAuthorInfo(const KoXmlElement & e)229 bool KoDocumentInfo::loadAuthorInfo(const KoXmlElement &e)
230 {
231 KoXmlNode n = e.namedItem("author").firstChild();
232 for (; !n.isNull(); n = n.nextSibling()) {
233 KoXmlElement e = n.toElement();
234 if (e.isNull())
235 continue;
236
237 if (e.tagName() == "full-name")
238 setActiveAuthorInfo("creator", e.text().trimmed());
239 else
240 setActiveAuthorInfo(e.tagName(), e.text().trimmed());
241 }
242
243 return true;
244 }
245
saveAuthorInfo(QDomDocument & doc)246 QDomElement KoDocumentInfo::saveAuthorInfo(QDomDocument &doc)
247 {
248 QDomElement e = doc.createElement("author");
249 QDomElement t;
250
251 foreach(const QString &tag, m_authorTags) {
252 if (tag == "creator")
253 t = doc.createElement("full-name");
254 else
255 t = doc.createElement(tag);
256
257 e.appendChild(t);
258 t.appendChild(doc.createTextNode(authorInfo(tag)));
259 }
260
261 return e;
262 }
263
saveOasisAboutInfo(KoXmlWriter & xmlWriter)264 bool KoDocumentInfo::saveOasisAboutInfo(KoXmlWriter &xmlWriter)
265 {
266 foreach(const QString &tag, m_aboutTags) {
267 if (!aboutInfo(tag).isEmpty() || tag == "title") {
268 if (tag == "keyword") {
269 foreach(const QString & tmp, aboutInfo("keyword").split(m_keywordSeparator)) {
270 xmlWriter.startElement("meta:keyword");
271 xmlWriter.addTextNode(tmp);
272 xmlWriter.endElement();
273 }
274 } else if (tag == "title" || tag == "description" || tag == "subject" ||
275 tag == "date" || tag == "language") {
276 QByteArray elementName(QString("dc:" + tag).toLatin1());
277 xmlWriter.startElement(elementName.constData());
278 xmlWriter.addTextNode(aboutInfo(tag));
279 xmlWriter.endElement();
280 } else {
281 QByteArray elementName(QString("meta:" + tag).toLatin1());
282 xmlWriter.startElement(elementName.constData());
283 xmlWriter.addTextNode(aboutInfo(tag));
284 xmlWriter.endElement();
285 }
286 }
287 }
288
289 return true;
290 }
291
loadOasisAboutInfo(const KoXmlNode & metaDoc)292 bool KoDocumentInfo::loadOasisAboutInfo(const KoXmlNode &metaDoc)
293 {
294 QStringList keywords;
295 KoXmlElement e;
296 forEachElement(e, metaDoc) {
297 QString tag(e.localName());
298 if (! m_aboutTags.contains(tag) && tag != "generator") {
299 continue;
300 }
301
302 //debugOdf<<"localName="<<e.localName();
303 if (tag == "keyword") {
304 if (!e.text().isEmpty())
305 keywords << e.text().trimmed();
306 } else if (tag == "description") {
307 //this is the odf way but add meta:comment if is already loaded
308 KoXmlElement e = KoXml::namedItemNS(metaDoc, KoXmlNS::dc, tag);
309 if (!e.isNull() && !e.text().isEmpty())
310 setAboutInfo("description", aboutInfo("description") + e.text().trimmed());
311 } else if (tag == "comments") {
312 //this was the old way so add it to dc:description
313 KoXmlElement e = KoXml::namedItemNS(metaDoc, KoXmlNS::meta, tag);
314 if (!e.isNull() && !e.text().isEmpty())
315 setAboutInfo("description", aboutInfo("description") + e.text().trimmed());
316 } else if (tag == "title"|| tag == "subject"
317 || tag == "date" || tag == "language") {
318 KoXmlElement e = KoXml::namedItemNS(metaDoc, KoXmlNS::dc, tag);
319 if (!e.isNull() && !e.text().isEmpty())
320 setAboutInfo(tag, e.text().trimmed());
321 } else if (tag == "generator") {
322 setOriginalGenerator(e.text().trimmed());
323 } else {
324 KoXmlElement e = KoXml::namedItemNS(metaDoc, KoXmlNS::meta, tag);
325 if (!e.isNull() && !e.text().isEmpty())
326 setAboutInfo(tag, e.text().trimmed());
327 }
328 }
329
330 if (keywords.count() > 0) {
331 setAboutInfo("keyword", keywords.join(m_keywordSeparator));
332 }
333
334 return true;
335 }
336
loadAboutInfo(const KoXmlElement & e)337 bool KoDocumentInfo::loadAboutInfo(const KoXmlElement &e)
338 {
339 KoXmlNode n = e.namedItem("about").firstChild();
340 KoXmlElement tmp;
341 for (; !n.isNull(); n = n.nextSibling()) {
342 tmp = n.toElement();
343 if (tmp.isNull())
344 continue;
345
346 if (tmp.tagName() == "abstract")
347 setAboutInfo("comments", tmp.text());
348
349 setAboutInfo(tmp.tagName(), tmp.text());
350 }
351
352 return true;
353 }
354
saveAboutInfo(QDomDocument & doc)355 QDomElement KoDocumentInfo::saveAboutInfo(QDomDocument &doc)
356 {
357 QDomElement e = doc.createElement("about");
358 QDomElement t;
359
360 foreach(const QString &tag, m_aboutTags) {
361 if (tag == "comments") {
362 t = doc.createElement("abstract");
363 e.appendChild(t);
364 t.appendChild(doc.createCDATASection(aboutInfo(tag)));
365 } else {
366 t = doc.createElement(tag);
367 e.appendChild(t);
368 t.appendChild(doc.createTextNode(aboutInfo(tag)));
369 }
370 }
371
372 return e;
373 }
374
updateParametersAndBumpNumCycles()375 void KoDocumentInfo::updateParametersAndBumpNumCycles()
376 {
377 KoDocumentBase *doc = dynamic_cast< KoDocumentBase *>(parent());
378 if (doc && doc->isAutosaving()) {
379 return;
380 }
381
382 setAboutInfo("editing-cycles", QString::number(aboutInfo("editing-cycles").toInt() + 1));
383 setAboutInfo("date", QDateTime::currentDateTime().toString(Qt::ISODate));
384
385 updateParameters();
386 }
387
updateParameters()388 void KoDocumentInfo::updateParameters()
389 {
390 KoDocumentBase *doc = dynamic_cast< KoDocumentBase *>(parent());
391 if (doc && (!doc->isModified() && !doc->isEmpty())) {
392 return;
393 }
394
395 KConfig config("calligrarc");
396 config.reparseConfiguration();
397 KConfigGroup authorGroup(&config, "Author");
398 QStringList profiles = authorGroup.readEntry("profile-names", QStringList());
399
400 config.reparseConfiguration();
401 KConfigGroup appAuthorGroup(&config, "Author");
402 QString profile = appAuthorGroup.readEntry("active-profile", "");
403
404 if (profiles.contains(profile)) {
405 KConfigGroup cgs(&authorGroup, "Author-" + profile);
406 setActiveAuthorInfo("creator", cgs.readEntry("creator"));
407 setActiveAuthorInfo("initial", cgs.readEntry("initial"));
408 setActiveAuthorInfo("author-title", cgs.readEntry("author-title"));
409 setActiveAuthorInfo("email", cgs.readEntry("email"));
410 setActiveAuthorInfo("telephone", cgs.readEntry("telephone"));
411 setActiveAuthorInfo("telephone-work", cgs.readEntry("telephone-work"));
412 setActiveAuthorInfo("fax", cgs.readEntry("fax"));
413 setActiveAuthorInfo("country",cgs.readEntry("country"));
414 setActiveAuthorInfo("postal-code",cgs.readEntry("postal-code"));
415 setActiveAuthorInfo("city", cgs.readEntry("city"));
416 setActiveAuthorInfo("street", cgs.readEntry("street"));
417 setActiveAuthorInfo("position", cgs.readEntry("position"));
418 setActiveAuthorInfo("company", cgs.readEntry("company"));
419 } else {
420 if (profile == "anonymous") {
421 setActiveAuthorInfo("creator", QString());
422 setActiveAuthorInfo("telephone", QString());
423 setActiveAuthorInfo("telephone-work", QString());
424 setActiveAuthorInfo("email", QString());
425 } else {
426 KUser user(KUser::UseRealUserID);
427 setActiveAuthorInfo("creator", user.property(KUser::FullName).toString());
428 setActiveAuthorInfo("telephone-work", user.property(KUser::WorkPhone).toString());
429 setActiveAuthorInfo("telephone", user.property(KUser::HomePhone).toString());
430 KEMailSettings eMailSettings;
431 setActiveAuthorInfo("email", eMailSettings.getSetting(KEMailSettings::EmailAddress));
432 }
433 setActiveAuthorInfo("initial", "");
434 setActiveAuthorInfo("author-title", "");
435 setActiveAuthorInfo("fax", "");
436 setActiveAuthorInfo("country", "");
437 setActiveAuthorInfo("postal-code", "");
438 setActiveAuthorInfo("city", "");
439 setActiveAuthorInfo("street", "");
440 setActiveAuthorInfo("position", "");
441 setActiveAuthorInfo("company", "");
442 }
443
444 //alllow author info set programatically to override info from author profile
445 foreach(const QString &tag, m_authorTags) {
446 if (m_authorInfoOverride.contains(tag)) {
447 setActiveAuthorInfo(tag, m_authorInfoOverride.value(tag));
448 }
449 }
450 }
451
resetMetaData()452 void KoDocumentInfo::resetMetaData()
453 {
454 setAboutInfo("editing-cycles", QString::number(0));
455 setAboutInfo("initial-creator", authorInfo("creator"));
456 setAboutInfo("creation-date", QDateTime::currentDateTime().toString(Qt::ISODate));
457 }
458
originalGenerator() const459 QString KoDocumentInfo::originalGenerator() const
460 {
461 return m_generator;
462 }
463
setOriginalGenerator(const QString & generator)464 void KoDocumentInfo::setOriginalGenerator(const QString &generator)
465 {
466 m_generator = generator;
467 }
468