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