diff --git a/PdfForQtLib/PdfForQtLib.pro b/PdfForQtLib/PdfForQtLib.pro index 9d1fd5e..3288f0a 100644 --- a/PdfForQtLib/PdfForQtLib.pro +++ b/PdfForQtLib/PdfForQtLib.pro @@ -43,6 +43,7 @@ DESTDIR = $$OUT_PWD/.. SOURCES += \ sources/pdfaction.cpp \ + sources/pdfadvancedtools.cpp \ sources/pdfannotation.cpp \ sources/pdfblendfunction.cpp \ sources/pdfccittfaxdecoder.cpp \ @@ -101,6 +102,7 @@ SOURCES += \ HEADERS += \ sources/pdfaction.h \ + sources/pdfadvancedtools.h \ sources/pdfannotation.h \ sources/pdfblendfunction.h \ sources/pdfccittfaxdecoder.h \ diff --git a/PdfForQtLib/sources/pdfadvancedtools.cpp b/PdfForQtLib/sources/pdfadvancedtools.cpp new file mode 100644 index 0000000..782ff75 --- /dev/null +++ b/PdfForQtLib/sources/pdfadvancedtools.cpp @@ -0,0 +1,65 @@ +// Copyright (C) 2020 Jakub Melka +// +// This file is part of PdfForQt. +// +// PdfForQt is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// PdfForQt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with PDFForQt. If not, see . + +#include "pdfadvancedtools.h" + +#include + +namespace pdf +{ + +PDFCreateStickyNoteTool::PDFCreateStickyNoteTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, QActionGroup* actionGroup, QObject* parent) : + BaseClass(proxy, parent), + m_toolManager(toolManager), + m_actionGroup(actionGroup), + m_pickTool(nullptr) +{ + m_pickTool = new PDFPickTool(proxy, PDFPickTool::Mode::Points, this); + addTool(m_pickTool); + connect(m_pickTool, &PDFPickTool::pointPicked, this, &PDFCreateStickyNoteTool::onPointPicked); + connect(m_actionGroup, &QActionGroup::triggered, this, &PDFCreateStickyNoteTool::onActionTriggered); + + updateActions(); +} + +void PDFCreateStickyNoteTool::updateActions() +{ + BaseClass::updateActions(); + + if (m_actionGroup) + { + const bool isEnabled = getDocument() && getDocument()->getStorage().getSecurityHandler()->isAllowed(PDFSecurityHandler::Permission::Modify); + m_actionGroup->setEnabled(isEnabled); + + if (!isActive() && m_actionGroup->checkedAction()) + { + m_actionGroup->checkedAction()->setChecked(false); + } + } +} + +void PDFCreateStickyNoteTool::onActionTriggered(QAction* action) +{ + setActive(action && action->isChecked()); +} + +void PDFCreateStickyNoteTool::onPointPicked(PDFInteger pageIndex, QPointF pagePoint) +{ + +} + +} // namespace pdf diff --git a/PdfForQtLib/sources/pdfadvancedtools.h b/PdfForQtLib/sources/pdfadvancedtools.h new file mode 100644 index 0000000..8ce2cf8 --- /dev/null +++ b/PdfForQtLib/sources/pdfadvancedtools.h @@ -0,0 +1,56 @@ +// Copyright (C) 2020 Jakub Melka +// +// This file is part of PdfForQt. +// +// PdfForQt is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// PdfForQt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with PDFForQt. If not, see . + +#ifndef PDFADVANCEDTOOLS_H +#define PDFADVANCEDTOOLS_H + +#include "pdfwidgettool.h" +#include "pdfannotation.h" + +class QActionGroup; + +namespace pdf +{ + +/// Tool that creates 'sticky note' annotations. Multiple types of sticky +/// notes are available, user can select a type of sticky note. When +/// user select a point, popup window appears and user can enter a text. +class PDFFORQTLIBSHARED_EXPORT PDFCreateStickyNoteTool : public PDFWidgetTool +{ + Q_OBJECT + +private: + using BaseClass = PDFWidgetTool; + +public: + explicit PDFCreateStickyNoteTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, QActionGroup* actionGroup, QObject* parent); + +protected: + virtual void updateActions() override; + +private: + void onActionTriggered(QAction* action); + void onPointPicked(PDFInteger pageIndex, QPointF pagePoint); + + PDFToolManager* m_toolManager; + QActionGroup* m_actionGroup; + PDFPickTool* m_pickTool; +}; + +} // namespace pdf + +#endif // PDFADVANCEDTOOLS_H diff --git a/PdfForQtLib/sources/pdfannotation.cpp b/PdfForQtLib/sources/pdfannotation.cpp index 2f9a63d..ce9029b 100644 --- a/PdfForQtLib/sources/pdfannotation.cpp +++ b/PdfForQtLib/sources/pdfannotation.cpp @@ -1960,35 +1960,7 @@ void PDFTextAnnotation::draw(AnnotationDrawParameters& parameters) const QFont font = QApplication::font(); font.setPixelSize(16.0); - QString text = "?"; - if (m_iconName == "Comment") - { - text = QString::fromUtf16(u"\U0001F4AC"); - } - else if (m_iconName == "Help") - { - text = "?"; - } - else if (m_iconName == "Insert") - { - text = QString::fromUtf16(u"\u2380"); - } - else if (m_iconName == "Key") - { - text = QString::fromUtf16(u"\U0001F511"); - } - else if (m_iconName == "NewParagraph") - { - text = QString::fromUtf16(u"\u2606"); - } - else if (m_iconName == "Note") - { - text = QString::fromUtf16(u"\u266A"); - } - else if (m_iconName == "Paragraph") - { - text = QString::fromUtf16(u"\u00B6"); - } + QString text = getTextForIcon(m_iconName); QPainterPath textPath; textPath.addText(0.0, 0.0, font, text); @@ -2006,6 +1978,71 @@ PDFTextAnnotation::Flags PDFTextAnnotation::getEffectiveFlags() const return getFlags() | NoZoom | NoRotate; } +QIcon PDFTextAnnotation::createIcon(QString key, QSize size) +{ + QIcon icon; + + QPixmap pixmap(size); + pixmap.fill(Qt::transparent); + + QRect rectangle(QPoint(0, 0), size); + rectangle.adjust(1, 1, -1, -1); + + QPainter painter(&pixmap); + painter.setRenderHint(QPainter::Antialiasing); + painter.setRenderHint(QPainter::TextAntialiasing); + + QString text = getTextForIcon(key); + + QFont font = QApplication::font(); + font.setPixelSize(size.height() * 0.75); + + QPainterPath textPath; + textPath.addText(0.0, 0.0, font, text); + QRectF textBoundingRect = textPath.boundingRect(); + QPointF offset = rectangle.center() - textBoundingRect.center(); + textPath.translate(offset); + painter.fillPath(textPath, QBrush(Qt::black, Qt::SolidPattern)); + painter.end(); + + icon.addPixmap(qMove(pixmap)); + return icon; +} + +QString PDFTextAnnotation::getTextForIcon(const QString& key) +{ + QString text = "?"; + if (key == "Comment") + { + text = QString::fromUtf16(u"\U0001F4AC"); + } + else if (key == "Help") + { + text = "?"; + } + else if (key == "Insert") + { + text = QString::fromUtf16(u"\u2380"); + } + else if (key == "Key") + { + text = QString::fromUtf16(u"\U0001F511"); + } + else if (key == "NewParagraph") + { + text = QString::fromUtf16(u"\u2606"); + } + else if (key == "Note") + { + text = QString::fromUtf16(u"\u266A"); + } + else if (key == "Paragraph") + { + text = QString::fromUtf16(u"\u00B6"); + } + return text; +} + void PDFLineAnnotation::draw(AnnotationDrawParameters& parameters) const { QLineF line = getLine(); diff --git a/PdfForQtLib/sources/pdfannotation.h b/PdfForQtLib/sources/pdfannotation.h index 3895693..2eb9a00 100644 --- a/PdfForQtLib/sources/pdfannotation.h +++ b/PdfForQtLib/sources/pdfannotation.h @@ -742,7 +742,7 @@ enum class TextAnnotationIcon /// as if flag NoZoom and NoRotate were set). When this annotation is opened, /// it displays popup window containing the text of the note, font and size /// is implementation dependent by viewer application. -class PDFTextAnnotation : public PDFMarkupAnnotation +class PDFFORQTLIBSHARED_EXPORT PDFTextAnnotation : public PDFMarkupAnnotation { public: inline explicit PDFTextAnnotation() = default; @@ -757,9 +757,13 @@ public: const QString& getState() const { return m_state; } const QString& getStateModel() const { return m_stateModel; } + static QIcon createIcon(QString key, QSize size); + private: friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObjectReference reference); + static QString getTextForIcon(const QString& key); + bool m_open = false; QByteArray m_iconName; QString m_state; diff --git a/PdfForQtViewer/pdfviewermainwindow.cpp b/PdfForQtViewer/pdfviewermainwindow.cpp index 9fdd0bb..56336c9 100644 --- a/PdfForQtViewer/pdfviewermainwindow.cpp +++ b/PdfForQtViewer/pdfviewermainwindow.cpp @@ -40,6 +40,7 @@ #include "pdfwidgetutils.h" #include "pdfdocumentwriter.h" #include "pdfsignaturehandler.h" +#include "pdfadvancedtools.h" #include #include @@ -65,6 +66,7 @@ #include #include #include +#include #ifdef Q_OS_WIN #include "Windows.h" @@ -92,6 +94,7 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) : m_progress(new pdf::PDFProgress(this)), m_taskbarButton(new QWinTaskbarButton(this)), m_progressTaskbarIndicator(nullptr), + m_insertStickyNoteGroup(nullptr), m_futureWatcher(nullptr), m_progressDialog(nullptr), m_isBusy(false), @@ -174,6 +177,24 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) : m_pageNumberSpinBox->setAlignment(Qt::AlignCenter); connect(m_pageNumberSpinBox, &QSpinBox::editingFinished, this, &PDFViewerMainWindow::onPageNumberSpinboxEditingFinished); + m_insertStickyNoteGroup = new QActionGroup(this); + m_insertStickyNoteGroup->setExclusionPolicy(QActionGroup::ExclusionPolicy::ExclusiveOptional); + m_insertStickyNoteGroup->addAction(ui->actionStickyNoteComment); + m_insertStickyNoteGroup->addAction(ui->actionStickyNoteHelp); + m_insertStickyNoteGroup->addAction(ui->actionStickyNoteInsert); + m_insertStickyNoteGroup->addAction(ui->actionStickyNoteKey); + m_insertStickyNoteGroup->addAction(ui->actionStickyNoteNewParagraph); + m_insertStickyNoteGroup->addAction(ui->actionStickyNoteNote); + m_insertStickyNoteGroup->addAction(ui->actionStickyNoteParagraph); + + ui->actionStickyNoteComment->setIcon(pdf::PDFTextAnnotation::createIcon("Comment", iconSize)); + ui->actionStickyNoteHelp->setIcon(pdf::PDFTextAnnotation::createIcon("Help", iconSize)); + ui->actionStickyNoteInsert->setIcon(pdf::PDFTextAnnotation::createIcon("Insert", iconSize)); + ui->actionStickyNoteKey->setIcon(pdf::PDFTextAnnotation::createIcon("Key", iconSize)); + ui->actionStickyNoteNewParagraph->setIcon(pdf::PDFTextAnnotation::createIcon("NewParagraph", iconSize)); + ui->actionStickyNoteNote->setIcon(pdf::PDFTextAnnotation::createIcon("Note", iconSize)); + ui->actionStickyNoteParagraph->setIcon(pdf::PDFTextAnnotation::createIcon("Paragraph", iconSize)); + // Page control ui->mainToolBar->addSeparator(); ui->mainToolBar->addAction(actionGoToDocumentStart); @@ -209,6 +230,28 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) : ui->mainToolBar->addAction(ui->actionMagnifier); ui->mainToolBar->addAction(ui->actionScreenshot); ui->mainToolBar->addAction(ui->actionExtractImage); + ui->mainToolBar->addSeparator(); + + // Special tools + QToolButton* insertStickyNoteButton = new QToolButton(ui->mainToolBar); + insertStickyNoteButton->setPopupMode(QToolButton::MenuButtonPopup); + insertStickyNoteButton->setMenu(new QMenu(insertStickyNoteButton)); + QList insertStickyNotesActions = m_insertStickyNoteGroup->actions(); + auto onInsertStickyNotesActionTriggered = [insertStickyNoteButton](QAction* action) + { + if (action) + { + insertStickyNoteButton->setDefaultAction(action); + } + }; + connect(m_insertStickyNoteGroup, &QActionGroup::triggered, insertStickyNoteButton, onInsertStickyNotesActionTriggered); + for (QAction* action : insertStickyNotesActions) + { + insertStickyNoteButton->menu()->addAction(action); + } + insertStickyNoteButton->setDefaultAction(insertStickyNotesActions.front()); + ui->mainToolBar->addWidget(insertStickyNoteButton); + ui->mainToolBar->addSeparator(); connect(ui->actionZoom_In, &QAction::triggered, this, [this] { m_pdfWidget->getDrawWidgetProxy()->performOperation(pdf::PDFDrawWidgetProxy::ZoomIn); }); connect(ui->actionZoom_Out, &QAction::triggered, this, [this] { m_pdfWidget->getDrawWidgetProxy()->performOperation(pdf::PDFDrawWidgetProxy::ZoomOut); }); @@ -280,6 +323,10 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) : updateMagnifierToolSettings(); connect(m_toolManager, &pdf::PDFToolManager::messageDisplayRequest, statusBar(), &QStatusBar::showMessage); + // Add special tools + pdf::PDFCreateStickyNoteTool* createStickyNoteTool = new pdf::PDFCreateStickyNoteTool(m_pdfWidget->getDrawWidgetProxy(), m_toolManager, m_insertStickyNoteGroup, this); + m_toolManager->addTool(createStickyNoteTool); + m_annotationManager = new pdf::PDFWidgetAnnotationManager(m_pdfWidget->getDrawWidgetProxy(), this); connect(m_annotationManager, &pdf::PDFWidgetAnnotationManager::actionTriggered, this, &PDFViewerMainWindow::onActionTriggered); m_pdfWidget->setAnnotationManager(m_annotationManager); diff --git a/PdfForQtViewer/pdfviewermainwindow.h b/PdfForQtViewer/pdfviewermainwindow.h index c3177f7..0fd3c68 100644 --- a/PdfForQtViewer/pdfviewermainwindow.h +++ b/PdfForQtViewer/pdfviewermainwindow.h @@ -159,6 +159,8 @@ private: int adjustDpiX(int value); + QIcon createStickyNoteIcon(QString key) const; + struct AsyncReadingResult { pdf::PDFDocumentPointer document; @@ -188,6 +190,7 @@ private: PDFFileInfo m_fileInfo; pdf::PDFCertificateStore m_certificateStore; std::vector m_signatures; + QActionGroup* m_insertStickyNoteGroup; QFuture m_future; QFutureWatcher* m_futureWatcher; diff --git a/PdfForQtViewer/pdfviewermainwindow.ui b/PdfForQtViewer/pdfviewermainwindow.ui index adc8b64..e025d75 100644 --- a/PdfForQtViewer/pdfviewermainwindow.ui +++ b/PdfForQtViewer/pdfviewermainwindow.ui @@ -130,9 +130,28 @@ + + + Insert + + + + Sticky Note + + + + + + + + + + + + @@ -549,6 +568,62 @@ Save + + + true + + + Comment + + + + + true + + + Help + + + + + true + + + Insert + + + + + true + + + Key + + + + + true + + + New Paragraph + + + + + true + + + Note + + + + + true + + + Paragraph + +