1 /* This file is part of the KDE project
2 Copyright (c) 2000 Simon Hausmann <hausmann@kde.org>
3 2006 Martin Pfeiffer <hubipete@gmx.net>
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 "KoDocumentInfoDlg.h"
23
24 #include "ui_koDocumentInfoAboutWidget.h"
25 #include "ui_koDocumentInfoAuthorWidget.h"
26
27 #include "KoDocumentInfo.h"
28 #include "KoDocumentBase.h"
29 #include "KoGlobal.h"
30 #ifdef QCA2
31 #include <KoEncryptionChecker.h>
32 #endif
33 #include "KoPageWidgetItem.h"
34 //#include <KoDocumentRdfBase.h>
35 #include <KoIcon.h>
36
37 #include <klocalizedstring.h>
38 #include <kiconloader.h>
39
40 #include <kmessagebox.h>
41 #include <kmainwindow.h>
42 #include <KoDialog.h>
43
44 #include <QUrl>
45 #include <QLineEdit>
46 #include <QDateTime>
47 #include <QMimeDatabase>
48 #include <QMimeType>
49
50
51 // see KoIcon.h
52 #define koSmallIcon(name) (SmallIcon(QStringLiteral(name)))
53
54
55 class KoPageWidgetItemAdapter : public KPageWidgetItem
56 {
57 Q_OBJECT
58 public:
KoPageWidgetItemAdapter(KoPageWidgetItem * item)59 KoPageWidgetItemAdapter(KoPageWidgetItem *item)
60 : KPageWidgetItem(item->widget(), item->name())
61 , m_item(item)
62 {
63 setHeader(item->name());
64 setIcon(QIcon::fromTheme(item->iconName()));
65 }
~KoPageWidgetItemAdapter()66 ~KoPageWidgetItemAdapter() override { delete m_item; }
67
shouldDialogCloseBeVetoed()68 bool shouldDialogCloseBeVetoed() { return m_item->shouldDialogCloseBeVetoed(); }
apply()69 void apply() { m_item->apply(); }
70
71 private:
72 KoPageWidgetItem * const m_item;
73 };
74
75
76 class KoDocumentInfoDlg::KoDocumentInfoDlgPrivate
77 {
78 public:
KoDocumentInfoDlgPrivate()79 KoDocumentInfoDlgPrivate() :
80 toggleEncryption(false),
81 applyToggleEncryption(false),
82 documentSaved(false) {}
~KoDocumentInfoDlgPrivate()83 ~KoDocumentInfoDlgPrivate() {}
84
85 KoDocumentInfo* info;
86 QList<KPageWidgetItem*> pages;
87 Ui::KoDocumentInfoAboutWidget* aboutUi;
88 Ui::KoDocumentInfoAuthorWidget* authorUi;
89
90 bool toggleEncryption;
91 bool applyToggleEncryption;
92 bool documentSaved;
93 };
94
95
KoDocumentInfoDlg(QWidget * parent,KoDocumentInfo * docInfo)96 KoDocumentInfoDlg::KoDocumentInfoDlg(QWidget* parent, KoDocumentInfo* docInfo)
97 : KPageDialog(parent)
98 , d(new KoDocumentInfoDlgPrivate)
99 {
100 d->info = docInfo;
101
102 setWindowTitle(i18n("Document Information"));
103 // setInitialSize(QSize(500, 500));
104 setFaceType(KPageDialog::List);
105 setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
106 button(QDialogButtonBox::Ok)->setDefault(true);
107
108 d->aboutUi = new Ui::KoDocumentInfoAboutWidget();
109 QWidget *infodlg = new QWidget();
110 d->aboutUi->setupUi(infodlg);
111 #ifdef QCA2
112 if (!KoEncryptionChecker::isEncryptionSupported()) {
113 #endif
114 d->aboutUi->lblEncryptedDesc->setVisible(false);
115 d->aboutUi->lblEncrypted->setVisible(false);
116 d->aboutUi->pbEncrypt->setVisible(false);
117 d->aboutUi->lblEncryptedPic->setVisible(false);
118 #ifdef QCA2
119 }
120 #endif
121 d->aboutUi->cbLanguage->addItems(KoGlobal::listOfLanguages());
122 d->aboutUi->cbLanguage->setCurrentIndex(-1);
123
124 KPageWidgetItem *page = new KPageWidgetItem(infodlg, i18n("General"));
125 page->setHeader(i18n("General"));
126
127 // Ugly hack, the mimetype should be a parameter, instead
128 KoDocumentBase* doc = dynamic_cast< KoDocumentBase* >(d->info->parent());
129 if (doc) {
130 QMimeDatabase db;
131 QMimeType mime = db.mimeTypeForName(doc->mimeType());
132 if (mime.isValid()) {
133 page->setIcon(QIcon::fromTheme(mime.iconName()));
134 }
135 } else {
136 // hide all entries not used in pages for KoDocumentInfoPropsPage
137 d->aboutUi->filePathInfoLabel->setVisible(false);
138 d->aboutUi->filePathLabel->setVisible(false);
139 d->aboutUi->filePathSeparatorLine->setVisible(false);
140 d->aboutUi->lblTypeDesc->setVisible(false);
141 d->aboutUi->lblType->setVisible(false);
142 }
143 addPage(page);
144 d->pages.append(page);
145
146 initAboutTab();
147
148 d->authorUi = new Ui::KoDocumentInfoAuthorWidget();
149 QWidget *authordlg = new QWidget();
150 d->authorUi->setupUi(authordlg);
151 page = new KPageWidgetItem(authordlg, i18n("Author"));
152 page->setHeader(i18n("Last saved by"));
153 page->setIcon(koIcon("user-identity"));
154 addPage(page);
155 d->pages.append(page);
156
157 initAuthorTab();
158 }
159
~KoDocumentInfoDlg()160 KoDocumentInfoDlg::~KoDocumentInfoDlg()
161 {
162 delete d->authorUi;
163 delete d->aboutUi;
164 delete d;
165 }
166
accept()167 void KoDocumentInfoDlg::accept()
168 {
169 // check if any pages veto the close
170 foreach(KPageWidgetItem* item, d->pages) {
171 KoPageWidgetItemAdapter *page = dynamic_cast<KoPageWidgetItemAdapter*>(item);
172 if (page) {
173 if (page->shouldDialogCloseBeVetoed()) {
174 return;
175 }
176 }
177 }
178
179 // all fine, go and apply
180 saveAboutData();
181 foreach(KPageWidgetItem* item, d->pages) {
182 KoPageWidgetItemAdapter *page = dynamic_cast<KoPageWidgetItemAdapter*>(item);
183 if (page) {
184 page->apply();
185 }
186 }
187
188 KPageDialog::accept();
189 }
190
isDocumentSaved()191 bool KoDocumentInfoDlg::isDocumentSaved()
192 {
193 return d->documentSaved;
194 }
195
initAboutTab()196 void KoDocumentInfoDlg::initAboutTab()
197 {
198 KoDocumentBase* doc = dynamic_cast< KoDocumentBase* >(d->info->parent());
199
200 if (doc) {
201 d->aboutUi->filePathLabel->setText(doc->localFilePath());
202 }
203
204 d->aboutUi->leTitle->setText(d->info->aboutInfo("title"));
205 d->aboutUi->leSubject->setText(d->info->aboutInfo("subject"));
206 QString language = KoGlobal::languageFromTag(d->info->aboutInfo("language"));
207 d->aboutUi->cbLanguage->setCurrentIndex(d->aboutUi->cbLanguage->findText(language));
208
209 d->aboutUi->leKeywords->setToolTip(i18n("Use ';' (Example: Office;KDE;Calligra)"));
210 if (!d->info->aboutInfo("keyword").isEmpty())
211 d->aboutUi->leKeywords->setText(d->info->aboutInfo("keyword"));
212
213 d->aboutUi->meComments->setPlainText(d->info->aboutInfo("description"));
214 if (doc && !doc->mimeType().isEmpty()) {
215 QMimeDatabase db;
216 QMimeType docmime = db.mimeTypeForName(doc->mimeType());
217 if (docmime.isValid())
218 d->aboutUi->lblType->setText(docmime.comment());
219 }
220 if (!d->info->aboutInfo("creation-date").isEmpty()) {
221 QDateTime t = QDateTime::fromString(d->info->aboutInfo("creation-date"),
222 Qt::ISODate);
223 QString s = QLocale().toString(t);
224 d->aboutUi->lblCreated->setText(s + ", " +
225 d->info->aboutInfo("initial-creator"));
226 }
227
228 if (!d->info->aboutInfo("date").isEmpty()) {
229 QDateTime t = QDateTime::fromString(d->info->aboutInfo("date"), Qt::ISODate);
230 QString s = QLocale().toString(t);
231 d->aboutUi->lblModified->setText(s + ", " + d->info->authorInfo("creator"));
232 }
233
234 d->aboutUi->lblRevision->setText(d->info->aboutInfo("editing-cycles"));
235
236 if (doc && (doc->supportedSpecialFormats() & KoDocumentBase::SaveEncrypted)) {
237 if (doc->specialOutputFlag() == KoDocumentBase::SaveEncrypted) {
238 if (d->toggleEncryption) {
239 d->aboutUi->lblEncrypted->setText(i18n("This document will be decrypted"));
240 d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-unlocked"));
241 d->aboutUi->pbEncrypt->setText(i18n("Do not decrypt"));
242 } else {
243 d->aboutUi->lblEncrypted->setText(i18n("This document is encrypted"));
244 d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-locked"));
245 d->aboutUi->pbEncrypt->setText(i18n("D&ecrypt"));
246 }
247 } else {
248 if (d->toggleEncryption) {
249 d->aboutUi->lblEncrypted->setText(i18n("This document will be encrypted."));
250 d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-locked"));
251 d->aboutUi->pbEncrypt->setText(i18n("Do not encrypt"));
252 } else {
253 d->aboutUi->lblEncrypted->setText(i18n("This document is not encrypted"));
254 d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-unlocked"));
255 d->aboutUi->pbEncrypt->setText(i18n("&Encrypt"));
256 }
257 }
258 } else {
259 d->aboutUi->lblEncrypted->setText(i18n("This document does not support encryption"));
260 d->aboutUi->pbEncrypt->setEnabled(false);
261 }
262 connect(d->aboutUi->pbReset, &QAbstractButton::clicked,
263 this, &KoDocumentInfoDlg::slotResetMetaData);
264 connect(d->aboutUi->pbEncrypt, &QAbstractButton::clicked,
265 this, &KoDocumentInfoDlg::slotToggleEncryption);
266 }
267
initAuthorTab()268 void KoDocumentInfoDlg::initAuthorTab()
269 {
270 d->authorUi->fullName->setText(d->info->authorInfo("creator"));
271 d->authorUi->initials->setText(d->info->authorInfo("initial"));
272 d->authorUi->title->setText(d->info->authorInfo("author-title"));
273 d->authorUi->company->setText(d->info->authorInfo("company"));
274 d->authorUi->email->setText(d->info->authorInfo("email"));
275 d->authorUi->phoneWork->setText(d->info->authorInfo("telephone-work"));
276 d->authorUi->phoneHome->setText(d->info->authorInfo("telephone"));
277 d->authorUi->fax->setText(d->info->authorInfo("fax"));
278 d->authorUi->country->setText(d->info->authorInfo("country"));
279 d->authorUi->postal->setText(d->info->authorInfo("postal-code"));
280 d->authorUi->city->setText(d->info->authorInfo("city"));
281 d->authorUi->street->setText(d->info->authorInfo("street"));
282 d->authorUi->position->setText(d->info->authorInfo("position"));
283 }
284
saveAboutData()285 void KoDocumentInfoDlg::saveAboutData()
286 {
287 d->info->setAboutInfo("keyword", d->aboutUi->leKeywords->text());
288 d->info->setAboutInfo("title", d->aboutUi->leTitle->text());
289 d->info->setAboutInfo("subject", d->aboutUi->leSubject->text());
290 d->info->setAboutInfo("description", d->aboutUi->meComments->toPlainText());
291 d->info->setAboutInfo("language", KoGlobal::tagOfLanguage(d->aboutUi->cbLanguage->currentText()));
292 d->applyToggleEncryption = d->toggleEncryption;
293 }
294
hideEvent(QHideEvent * event)295 void KoDocumentInfoDlg::hideEvent(QHideEvent *event)
296 {
297 Q_UNUSED(event);
298
299 // Saving encryption implies saving the document, this is done after closing the dialog
300 // TODO: shouldn't this be skipped if cancel is pressed?
301 saveEncryption();
302 }
303
slotResetMetaData()304 void KoDocumentInfoDlg::slotResetMetaData()
305 {
306 d->info->resetMetaData();
307
308 if (!d->info->aboutInfo("creation-date").isEmpty()) {
309 QDateTime t = QDateTime::fromString(d->info->aboutInfo("creation-date"),
310 Qt::ISODate);
311 QString s = QLocale().toString(t);
312 d->aboutUi->lblCreated->setText(s + ", " +
313 d->info->aboutInfo("initial-creator"));
314 }
315
316 if (!d->info->aboutInfo("date").isEmpty()) {
317 QDateTime t = QDateTime::fromString(d->info->aboutInfo("date"), Qt::ISODate);
318 QString s = QLocale().toString(t);
319 d->aboutUi->lblModified->setText(s + ", " + d->info->authorInfo("creator"));
320 }
321
322 d->aboutUi->lblRevision->setText(d->info->aboutInfo("editing-cycles"));
323 }
324
slotToggleEncryption()325 void KoDocumentInfoDlg::slotToggleEncryption()
326 {
327 KoDocumentBase* doc = dynamic_cast< KoDocumentBase* >(d->info->parent());
328 if (!doc)
329 return;
330
331 d->toggleEncryption = !d->toggleEncryption;
332
333 if (doc->specialOutputFlag() == KoDocumentBase::SaveEncrypted) {
334 if (d->toggleEncryption) {
335 d->aboutUi->lblEncrypted->setText(i18n("This document will be decrypted"));
336 d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-unlocked"));
337 d->aboutUi->pbEncrypt->setText(i18n("Do not decrypt"));
338 } else {
339 d->aboutUi->lblEncrypted->setText(i18n("This document is encrypted"));
340 d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-locked"));
341 d->aboutUi->pbEncrypt->setText(i18n("D&ecrypt"));
342 }
343 } else {
344 if (d->toggleEncryption) {
345 d->aboutUi->lblEncrypted->setText(i18n("This document will be encrypted."));
346 d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-locked"));
347 d->aboutUi->pbEncrypt->setText(i18n("Do not encrypt"));
348 } else {
349 d->aboutUi->lblEncrypted->setText(i18n("This document is not encrypted"));
350 d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-unlocked"));
351 d->aboutUi->pbEncrypt->setText(i18n("&Encrypt"));
352 }
353 }
354 }
355
saveEncryption()356 void KoDocumentInfoDlg::saveEncryption()
357 {
358 if (!d->applyToggleEncryption)
359 return;
360
361 KoDocumentBase* doc = dynamic_cast< KoDocumentBase* >(d->info->parent());
362 if (!doc)
363 return;
364
365 KMainWindow* mainWindow = dynamic_cast< KMainWindow* >(parent());
366
367 if (doc->specialOutputFlag() == KoDocumentBase::SaveEncrypted) {
368 // Decrypt
369 if (KMessageBox::warningContinueCancel(
370 this,
371 i18n("<qt>Decrypting the document will remove the password protection from it."
372 "<p>Do you still want to decrypt the file?</qt>"),
373 i18n("Confirm Decrypt"),
374 KGuiItem(i18n("Decrypt")),
375 KStandardGuiItem::cancel(),
376 "DecryptConfirmation"
377 ) != KMessageBox::Continue) {
378 return;
379 }
380 bool modified = doc->isModified();
381 doc->setOutputMimeType(doc->outputMimeType(), doc->specialOutputFlag() & ~KoDocumentBase::SaveEncrypted);
382 if (!mainWindow) {
383 KMessageBox::information(
384 this,
385 i18n("<qt>Your document could not be saved automatically."
386 "<p>To complete the decryption, please save the document.</qt>"),
387 i18n("Save Document"),
388 "DecryptSaveMessage");
389 return;
390 }
391 if (modified && KMessageBox::questionYesNo(
392 this,
393 i18n("<qt>The document has been changed since it was opened. To complete the decryption the document needs to be saved."
394 "<p>Do you want to save the document now?</qt>"),
395 i18n("Save Document"),
396 KStandardGuiItem::save(),
397 KStandardGuiItem::dontSave(),
398 "DecryptSaveConfirmation"
399 ) != KMessageBox::Yes) {
400 return;
401 }
402 } else {
403 // Encrypt
404 bool modified = doc->isModified();
405 if (!doc->url().isEmpty() && !(doc->mimeType().startsWith("application/vnd.oasis.opendocument.") && doc->specialOutputFlag() == 0)) {
406 QMimeDatabase db;
407 QMimeType mime = db.mimeTypeForName(doc->mimeType());
408 QString comment = mime.isValid() ? mime.comment() : i18n("%1 (unknown file type)", QString::fromLatin1(doc->mimeType()));
409 if (KMessageBox::warningContinueCancel(
410 this,
411 i18n("<qt>The document is currently saved as %1. The document needs to be changed to <b>OASIS OpenDocument</b> to be encrypted."
412 "<p>Do you want to change the file to OASIS OpenDocument?</qt>", QString("<b>%1</b>").arg(comment)),
413 i18n("Change Filetype"),
414 KGuiItem(i18n("Change")),
415 KStandardGuiItem::cancel(),
416 "EncryptChangeFiletypeConfirmation"
417 ) != KMessageBox::Continue) {
418 return;
419 }
420 doc->resetURL();
421 }
422 doc->setMimeType(doc->nativeOasisMimeType());
423 doc->setOutputMimeType(doc->nativeOasisMimeType(), KoDocumentBase::SaveEncrypted);
424 if (!mainWindow) {
425 KMessageBox::information(
426 this,
427 i18n("<qt>Your document could not be saved automatically."
428 "<p>To complete the encryption, please save the document.</qt>"),
429 i18n("Save Document"),
430 "EncryptSaveMessage");
431 return;
432 }
433 if (modified && KMessageBox::questionYesNo(
434 this,
435 i18n("<qt>The document has been changed since it was opened. To complete the encryption the document needs to be saved."
436 "<p>Do you want to save the document now?</qt>"),
437 i18n("Save Document"),
438 KStandardGuiItem::save(),
439 KStandardGuiItem::dontSave(),
440 "EncryptSaveConfirmation"
441 ) != KMessageBox::Yes) {
442 return;
443 }
444 }
445 // Why do the dirty work ourselves?
446 emit saveRequested();
447 d->toggleEncryption = false;
448 d->applyToggleEncryption = false;
449 // Detects when the user cancelled saving
450 d->documentSaved = !doc->url().isEmpty();
451 }
452
pages() const453 QList<KPageWidgetItem*> KoDocumentInfoDlg::pages() const
454 {
455 return d->pages;
456 }
457
setReadOnly(bool ro)458 void KoDocumentInfoDlg::setReadOnly(bool ro)
459 {
460 d->aboutUi->meComments->setReadOnly(ro);
461
462 Q_FOREACH(KPageWidgetItem* page, d->pages) {
463 Q_FOREACH(QLineEdit* le, page->widget()->findChildren<QLineEdit *>()) {
464 le->setReadOnly(ro);
465 }
466 Q_FOREACH(QPushButton* le, page->widget()->findChildren<QPushButton *>()) {
467 le->setDisabled(ro);
468 }
469 }
470 }
471
addPageItem(KoPageWidgetItem * item)472 void KoDocumentInfoDlg::addPageItem(KoPageWidgetItem *item)
473 {
474 KPageWidgetItem * page = new KoPageWidgetItemAdapter(item);
475
476 addPage(page);
477 d->pages.append(page);
478 }
479 #include "KoDocumentInfoDlg.moc"
480