File indexing completed on 2024-04-28 15:51:39

0001 /*
0002     SPDX-FileCopyrightText: 2006 Tobias Koenig <tokoe@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "annotationpopup.h"
0008 
0009 #include <KLocalizedString>
0010 #include <QApplication>
0011 #include <QClipboard>
0012 #include <QIcon>
0013 #include <QMenu>
0014 
0015 #include "annotationpropertiesdialog.h"
0016 
0017 #include "core/annotations.h"
0018 #include "core/document.h"
0019 #include "gui/guiutils.h"
0020 #include "okmenutitle.h"
0021 
0022 Q_DECLARE_METATYPE(AnnotationPopup::AnnotPagePair)
0023 
0024 namespace
0025 {
0026 bool annotationHasFileAttachment(Okular::Annotation *annotation)
0027 {
0028     return (annotation->subType() == Okular::Annotation::AFileAttachment || annotation->subType() == Okular::Annotation::ARichMedia);
0029 }
0030 
0031 Okular::EmbeddedFile *embeddedFileFromAnnotation(Okular::Annotation *annotation)
0032 {
0033     if (annotation->subType() == Okular::Annotation::AFileAttachment) {
0034         const Okular::FileAttachmentAnnotation *fileAttachAnnot = static_cast<Okular::FileAttachmentAnnotation *>(annotation);
0035         return fileAttachAnnot->embeddedFile();
0036     } else if (annotation->subType() == Okular::Annotation::ARichMedia) {
0037         const Okular::RichMediaAnnotation *richMediaAnnot = static_cast<Okular::RichMediaAnnotation *>(annotation);
0038         return richMediaAnnot->embeddedFile();
0039     } else {
0040         return nullptr;
0041     }
0042 }
0043 
0044 }
0045 
0046 AnnotationPopup::AnnotationPopup(Okular::Document *document, MenuMode mode, QWidget *parent)
0047     : mParent(parent)
0048     , mDocument(document)
0049     , mMenuMode(mode)
0050 {
0051 }
0052 
0053 void AnnotationPopup::addAnnotation(Okular::Annotation *annotation, int pageNumber)
0054 {
0055     AnnotPagePair pair(annotation, pageNumber);
0056     if (!mAnnotations.contains(pair)) {
0057         mAnnotations.append(pair);
0058     }
0059 }
0060 
0061 void AnnotationPopup::exec(const QPoint point)
0062 {
0063     if (mAnnotations.isEmpty()) {
0064         return;
0065     }
0066 
0067     QMenu menu(mParent);
0068 
0069     addActionsToMenu(&menu);
0070 
0071     menu.exec(point.isNull() ? QCursor::pos() : point);
0072 }
0073 
0074 void AnnotationPopup::addActionsToMenu(QMenu *menu)
0075 {
0076     QAction *action = nullptr;
0077 
0078     if (mMenuMode == SingleAnnotationMode) {
0079         const bool onlyOne = (mAnnotations.count() == 1);
0080 
0081         const AnnotPagePair &pair = mAnnotations.at(0);
0082 
0083         menu->addAction(new OKMenuTitle(menu, i18np("Annotation", "%1 Annotations", mAnnotations.count())));
0084 
0085         action = menu->addAction(QIcon::fromTheme(QStringLiteral("comment")), i18n("&Open Pop-up Note"));
0086         action->setEnabled(onlyOne);
0087         connect(action, &QAction::triggered, menu, [this, pair] { doOpenAnnotationWindow(pair); });
0088 
0089         if (!pair.annotation->contents().isEmpty()) {
0090             action = menu->addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("Copy Text to Clipboard"));
0091             const bool copyAllowed = mDocument->isAllowed(Okular::AllowCopy);
0092             if (!copyAllowed) {
0093                 action->setEnabled(false);
0094                 action->setText(i18n("Copy forbidden by DRM"));
0095             }
0096             connect(action, &QAction::triggered, menu, [this, pair] { doCopyAnnotation(pair); });
0097         }
0098 
0099         action = menu->addAction(QIcon::fromTheme(QStringLiteral("list-remove")), i18n("&Delete"));
0100         action->setEnabled(mDocument->isAllowed(Okular::AllowNotes));
0101         connect(action, &QAction::triggered, menu, [this] {
0102             for (const AnnotPagePair &pair : std::as_const(mAnnotations)) {
0103                 doRemovePageAnnotation(pair);
0104             }
0105         });
0106 
0107         for (const AnnotPagePair &annot : std::as_const(mAnnotations)) {
0108             if (!mDocument->canRemovePageAnnotation(annot.annotation)) {
0109                 action->setEnabled(false);
0110             }
0111         }
0112 
0113         action = menu->addAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("&Properties"));
0114         action->setEnabled(onlyOne);
0115         connect(action, &QAction::triggered, menu, [this, pair] { doOpenPropertiesDialog(pair); });
0116 
0117         if (onlyOne && annotationHasFileAttachment(pair.annotation)) {
0118             const Okular::EmbeddedFile *embeddedFile = embeddedFileFromAnnotation(pair.annotation);
0119             if (embeddedFile) {
0120                 const QString saveText = i18nc("%1 is the name of the file to save", "&Save '%1'...", embeddedFile->name());
0121 
0122                 menu->addSeparator();
0123                 action = menu->addAction(QIcon::fromTheme(QStringLiteral("document-save")), saveText);
0124                 connect(action, &QAction::triggered, menu, [this, pair] { doSaveEmbeddedFile(pair); });
0125             }
0126         }
0127     } else {
0128         for (const AnnotPagePair &pair : std::as_const(mAnnotations)) {
0129             menu->addAction(new OKMenuTitle(menu, GuiUtils::captionForAnnotation(pair.annotation)));
0130 
0131             action = menu->addAction(QIcon::fromTheme(QStringLiteral("comment")), i18n("&Open Pop-up Note"));
0132             connect(action, &QAction::triggered, menu, [this, pair] { doOpenAnnotationWindow(pair); });
0133 
0134             if (!pair.annotation->contents().isEmpty()) {
0135                 action = menu->addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("Copy Text to Clipboard"));
0136                 const bool copyAllowed = mDocument->isAllowed(Okular::AllowCopy);
0137                 if (!copyAllowed) {
0138                     action->setEnabled(false);
0139                     action->setText(i18n("Copy forbidden by DRM"));
0140                 }
0141                 connect(action, &QAction::triggered, menu, [this, pair] { doCopyAnnotation(pair); });
0142             }
0143 
0144             action = menu->addAction(QIcon::fromTheme(QStringLiteral("list-remove")), i18n("&Delete"));
0145             action->setEnabled(mDocument->isAllowed(Okular::AllowNotes) && mDocument->canRemovePageAnnotation(pair.annotation));
0146             connect(action, &QAction::triggered, menu, [this, pair] { doRemovePageAnnotation(pair); });
0147 
0148             action = menu->addAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("&Properties"));
0149             connect(action, &QAction::triggered, menu, [this, pair] { doOpenPropertiesDialog(pair); });
0150 
0151             if (annotationHasFileAttachment(pair.annotation)) {
0152                 const Okular::EmbeddedFile *embeddedFile = embeddedFileFromAnnotation(pair.annotation);
0153                 if (embeddedFile) {
0154                     const QString saveText = i18nc("%1 is the name of the file to save", "&Save '%1'...", embeddedFile->name());
0155 
0156                     menu->addSeparator();
0157                     action = menu->addAction(QIcon::fromTheme(QStringLiteral("document-save")), saveText);
0158                     connect(action, &QAction::triggered, menu, [this, pair] { doSaveEmbeddedFile(pair); });
0159                 }
0160             }
0161         }
0162     }
0163 }
0164 
0165 void AnnotationPopup::doCopyAnnotation(AnnotPagePair pair)
0166 {
0167     const QString text = pair.annotation->contents();
0168     if (!text.isEmpty()) {
0169         QClipboard *cb = QApplication::clipboard();
0170         cb->setText(text, QClipboard::Clipboard);
0171     }
0172 }
0173 
0174 void AnnotationPopup::doRemovePageAnnotation(AnnotPagePair pair)
0175 {
0176     if (pair.pageNumber != -1) {
0177         mDocument->removePageAnnotation(pair.pageNumber, pair.annotation);
0178     }
0179 }
0180 
0181 void AnnotationPopup::doOpenAnnotationWindow(AnnotPagePair pair)
0182 {
0183     Q_EMIT openAnnotationWindow(pair.annotation, pair.pageNumber);
0184 }
0185 
0186 void AnnotationPopup::doOpenPropertiesDialog(AnnotPagePair pair)
0187 {
0188     if (pair.pageNumber != -1) {
0189         AnnotsPropertiesDialog propdialog(mParent, mDocument, pair.pageNumber, pair.annotation);
0190         propdialog.exec();
0191     }
0192 }
0193 
0194 void AnnotationPopup::doSaveEmbeddedFile(AnnotPagePair pair)
0195 {
0196     Okular::EmbeddedFile *embeddedFile = embeddedFileFromAnnotation(pair.annotation);
0197     GuiUtils::saveEmbeddedFile(embeddedFile, mParent);
0198 }