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 }