Stamp annotation creation tool

This commit is contained in:
Jakub Melka 2020-12-10 19:27:26 +01:00
parent 75f7f38984
commit 11ad8f2821
7 changed files with 428 additions and 25 deletions

View File

@ -751,4 +751,109 @@ void PDFCreateFreehandCurveTool::resetTool()
m_pickedPoints.clear();
}
PDFCreateStampTool::PDFCreateStampTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, QActionGroup* actionGroup, QObject* parent) :
BaseClass(proxy, parent),
m_pageIndex(-1),
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, &PDFCreateStampTool::onPointPicked);
connect(m_actionGroup, &QActionGroup::triggered, this, &PDFCreateStampTool::onActionTriggered);
m_stampAnnotation.setStrokingOpacity(0.5);
m_stampAnnotation.setFillingOpacity(0.5);
updateActions();
}
void PDFCreateStampTool::drawPage(QPainter* painter,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QMatrix& pagePointToDevicePointMatrix,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
Q_UNUSED(layoutGetter);
Q_UNUSED(pagePointToDevicePointMatrix);
Q_UNUSED(errors);
if (pageIndex != m_pageIndex)
{
return;
}
const PDFPage* page = getDocument()->getCatalog()->getPage(pageIndex);
QRectF rectangle = m_stampAnnotation.getRectangle();
QMatrix matrix = getProxy()->getAnnotationManager()->prepareTransformations(pagePointToDevicePointMatrix, painter->device(), m_stampAnnotation.getFlags(), page, rectangle);
painter->setWorldMatrix(matrix, true);
AnnotationDrawParameters parameters;
parameters.painter = painter;
parameters.annotation = const_cast<PDFStampAnnotation*>(&m_stampAnnotation);
parameters.key.first = PDFAppeareanceStreams::Appearance::Normal;
parameters.invertColors = getProxy()->getFeatures().testFlag(PDFRenderer::InvertColors);
m_stampAnnotation.draw(parameters);
}
void PDFCreateStampTool::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
{
BaseClass::mouseMoveEvent(widget, event);
// Try to add point to the path
QPointF pagePoint;
m_pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
if (m_pageIndex != -1)
{
m_stampAnnotation.setRectangle(QRectF(pagePoint, QSizeF(0, 0)));
}
}
void PDFCreateStampTool::updateActions()
{
BaseClass::updateActions();
if (m_actionGroup)
{
const bool isEnabled = getDocument() && getDocument()->getStorage().getSecurityHandler()->isAllowed(PDFSecurityHandler::Permission::ModifyInteractiveItems);
m_actionGroup->setEnabled(isEnabled);
if (!isActive() && m_actionGroup->checkedAction())
{
m_actionGroup->checkedAction()->setChecked(false);
}
}
}
void PDFCreateStampTool::onActionTriggered(QAction* action)
{
setActive(action && action->isChecked());
if (action)
{
m_stampAnnotation.setStamp(static_cast<Stamp>(action->data().toInt()));
}
}
void PDFCreateStampTool::onPointPicked(PDFInteger pageIndex, QPointF pagePoint)
{
PDFDocumentModifier modifier(getDocument());
QString userName = PDFSysUtils::getUserName();
PDFObjectReference page = getDocument()->getCatalog()->getPage(pageIndex)->getPageReference();
modifier.getBuilder()->createAnnotationStamp(page, QRectF(pagePoint, QSizeF(0, 0)), m_stampAnnotation.getStamp(), userName, QString(), QString());
modifier.markAnnotationsChanged();
if (modifier.finalize())
{
emit m_toolManager->documentModified(PDFModifiedDocument(modifier.getDocument(), nullptr, modifier.getFlags()));
}
setActive(false);
}
} // namespace pdf

View File

@ -227,6 +227,40 @@ private:
QColor m_strokeColor;
};
/// Tool that creates 'stamp' annotations. Multiple types of stamps
/// are available, user can select a type of stamp (text).
class PDFFORQTLIBSHARED_EXPORT PDFCreateStampTool : public PDFWidgetTool
{
Q_OBJECT
private:
using BaseClass = PDFWidgetTool;
public:
explicit PDFCreateStampTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, QActionGroup* actionGroup, QObject* parent);
virtual void drawPage(QPainter* painter, PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QMatrix& pagePointToDevicePointMatrix,
QList<PDFRenderError>& errors) const override;
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
protected:
virtual void updateActions() override;
private:
void onActionTriggered(QAction* action);
void onPointPicked(PDFInteger pageIndex, QPointF pagePoint);
pdf::PDFInteger m_pageIndex;
PDFToolManager* m_toolManager;
QActionGroup* m_actionGroup;
PDFPickTool* m_pickTool;
PDFStampAnnotation m_stampAnnotation;
};
} // namespace pdf
#endif // PDFADVANCEDTOOLS_H

View File

@ -284,6 +284,101 @@ QPainterPath PDFAnnotation::parsePath(const PDFObjectStorage* storage, const PDF
return path;
}
void PDFAnnotation::setLanguage(const QString& language)
{
m_language = language;
}
void PDFAnnotation::setBlendMode(const BlendMode& blendMode)
{
m_blendMode = blendMode;
}
void PDFAnnotation::setStrokingOpacity(const PDFReal& strokingOpacity)
{
m_strokingOpacity = strokingOpacity;
}
void PDFAnnotation::setFillingOpacity(const PDFReal& fillingOpacity)
{
m_fillingOpacity = fillingOpacity;
}
void PDFAnnotation::setAssociatedFiles(const PDFObject& associatedFiles)
{
m_associatedFiles = associatedFiles;
}
void PDFAnnotation::setOptionalContentReference(const PDFObjectReference& optionalContentReference)
{
m_optionalContentReference = optionalContentReference;
}
void PDFAnnotation::setStructParent(const PDFInteger& structParent)
{
m_structParent = structParent;
}
void PDFAnnotation::setColor(const std::vector<PDFReal>& color)
{
m_color = color;
}
void PDFAnnotation::setAnnotationBorder(const PDFAnnotationBorder& annotationBorder)
{
m_annotationBorder = annotationBorder;
}
void PDFAnnotation::setAppearanceState(const QByteArray& appearanceState)
{
m_appearanceState = appearanceState;
}
void PDFAnnotation::setAppearanceStreams(const PDFAppeareanceStreams& appearanceStreams)
{
m_appearanceStreams = appearanceStreams;
}
void PDFAnnotation::setFlags(const Flags& flags)
{
m_flags = flags;
}
void PDFAnnotation::setLastModifiedString(const QString& lastModifiedString)
{
m_lastModifiedString = lastModifiedString;
}
void PDFAnnotation::setLastModified(const QDateTime& lastModified)
{
m_lastModified = lastModified;
}
void PDFAnnotation::setName(const QString& name)
{
m_name = name;
}
void PDFAnnotation::setPageReference(const PDFObjectReference& pageReference)
{
m_pageReference = pageReference;
}
void PDFAnnotation::setContents(const QString& contents)
{
m_contents = contents;
}
void PDFAnnotation::setRectangle(const QRectF& rectangle)
{
m_rectangle = rectangle;
}
void PDFAnnotation::setSelfReference(const PDFObjectReference& selfReference)
{
m_selfReference = selfReference;
}
PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObjectReference reference)
{
PDFObject object = storage->getObjectByReference(reference);
@ -1922,6 +2017,51 @@ bool PDFMarkupAnnotation::isReplyTo() const
return m_inReplyTo.isValid() && m_replyType == ReplyType::Reply;
}
void PDFMarkupAnnotation::setWindowTitle(const QString& windowTitle)
{
m_windowTitle = windowTitle;
}
void PDFMarkupAnnotation::setPopupAnnotation(const PDFObjectReference& popupAnnotation)
{
m_popupAnnotation = popupAnnotation;
}
void PDFMarkupAnnotation::setRichTextString(const QString& richTextString)
{
m_richTextString = richTextString;
}
void PDFMarkupAnnotation::setCreationDate(const QDateTime& creationDate)
{
m_creationDate = creationDate;
}
void PDFMarkupAnnotation::setInReplyTo(PDFObjectReference inReplyTo)
{
m_inReplyTo = inReplyTo;
}
void PDFMarkupAnnotation::setSubject(const QString& subject)
{
m_subject = subject;
}
void PDFMarkupAnnotation::setIntent(const QByteArray& intent)
{
m_intent = intent;
}
void PDFMarkupAnnotation::setExternalData(const PDFObject& externalData)
{
m_externalData = externalData;
}
void PDFMarkupAnnotation::setReplyType(ReplyType replyType)
{
m_replyType = replyType;
}
std::vector<PDFAppeareanceStreams::Key> PDFTextAnnotation::getDrawKeys(const PDFFormManager* formManager) const
{
Q_UNUSED(formManager);
@ -2911,71 +3051,51 @@ void PDFStampAnnotation::draw(AnnotationDrawParameters& parameters) const
QPainter& painter = *parameters.painter;
painter.setCompositionMode(getCompositionMode());
QString text;
QString text = getText(m_stamp);
QColor color(Qt::red);
switch (m_stamp)
{
case Stamp::Approved:
text = PDFTranslationContext::tr("APPROVED");
color = Qt::green;
break;
case Stamp::AsIs:
text = PDFTranslationContext::tr("AS IS");
break;
case Stamp::Confidential:
text = PDFTranslationContext::tr("CONFIDENTIAL");
break;
case Stamp::Departmental:
text = PDFTranslationContext::tr("DEPARTMENTAL");
color = Qt::blue;
break;
case Stamp::Draft:
text = PDFTranslationContext::tr("DRAFT");
break;
case Stamp::Experimental:
text = PDFTranslationContext::tr("EXPERIMENTAL");
color = Qt::blue;
break;
case Stamp::Expired:
text = PDFTranslationContext::tr("EXPIRED");
break;
case Stamp::Final:
text = PDFTranslationContext::tr("FINAL");
break;
case Stamp::ForComment:
text = PDFTranslationContext::tr("FOR COMMENT");
color = Qt::green;
break;
case Stamp::ForPublicRelease:
text = PDFTranslationContext::tr("FOR PUBLIC RELEASE");
color = Qt::green;
break;
case Stamp::NotApproved:
text = PDFTranslationContext::tr("NOT APPROVED");
break;
case Stamp::NotForPublicRelease:
text = PDFTranslationContext::tr("NOT FOR PUBLIC RELEASE");
break;
case Stamp::Sold:
text = PDFTranslationContext::tr("SOLD");
color = Qt::blue;
break;
case Stamp::TopSecret:
text = PDFTranslationContext::tr("TOP SECRET");
break;
default:
@ -2983,6 +3103,8 @@ void PDFStampAnnotation::draw(AnnotationDrawParameters& parameters) const
break;
}
color.setAlphaF(getFillOpacity());
const PDFReal textHeight = 16;
QFont font("Courier New");
font.setBold(true);
@ -3017,6 +3139,86 @@ void PDFStampAnnotation::draw(AnnotationDrawParameters& parameters) const
parameters.boundingRectangle.adjust(-penWidth, -penWidth, penWidth, penWidth);
}
QString PDFStampAnnotation::getText(Stamp stamp)
{
QString text;
switch (stamp)
{
case Stamp::Approved:
text = PDFTranslationContext::tr("APPROVED");
break;
case Stamp::AsIs:
text = PDFTranslationContext::tr("AS IS");
break;
case Stamp::Confidential:
text = PDFTranslationContext::tr("CONFIDENTIAL");
break;
case Stamp::Departmental:
text = PDFTranslationContext::tr("DEPARTMENTAL");
break;
case Stamp::Draft:
text = PDFTranslationContext::tr("DRAFT");
break;
case Stamp::Experimental:
text = PDFTranslationContext::tr("EXPERIMENTAL");
break;
case Stamp::Expired:
text = PDFTranslationContext::tr("EXPIRED");
break;
case Stamp::Final:
text = PDFTranslationContext::tr("FINAL");
break;
case Stamp::ForComment:
text = PDFTranslationContext::tr("FOR COMMENT");
break;
case Stamp::ForPublicRelease:
text = PDFTranslationContext::tr("FOR PUBLIC RELEASE");
break;
case Stamp::NotApproved:
text = PDFTranslationContext::tr("NOT APPROVED");
break;
case Stamp::NotForPublicRelease:
text = PDFTranslationContext::tr("NOT FOR PUBLIC RELEASE");
break;
case Stamp::Sold:
text = PDFTranslationContext::tr("SOLD");
break;
case Stamp::TopSecret:
text = PDFTranslationContext::tr("TOP SECRET");
break;
default:
Q_ASSERT(false);
break;
}
return text;
}
void PDFStampAnnotation::setStamp(const Stamp& stamp)
{
m_stamp = stamp;
}
void PDFStampAnnotation::setIntent(const StampIntent& intent)
{
m_intent = intent;
}
void PDFAnnotation::drawCharacterSymbol(QString text, PDFReal opacity, AnnotationDrawParameters& parameters) const
{
QColor strokeColor = QColor::fromRgbF(0.0, 0.0, 0.0, opacity);

View File

@ -543,6 +543,26 @@ public:
BlendMode getBlendMode() const { return m_blendMode; }
const QString& getLanguage() const { return m_language; }
void setSelfReference(const PDFObjectReference& selfReference);
void setRectangle(const QRectF& rectangle);
void setContents(const QString& contents);
void setPageReference(const PDFObjectReference& pageReference);
void setName(const QString& name);
void setLastModified(const QDateTime& lastModified);
void setLastModifiedString(const QString& lastModifiedString);
void setFlags(const Flags& flags);
void setAppearanceStreams(const PDFAppeareanceStreams& appearanceStreams);
void setAppearanceState(const QByteArray& appearanceState);
void setAnnotationBorder(const PDFAnnotationBorder& annotationBorder);
void setColor(const std::vector<PDFReal>& color);
void setStructParent(const PDFInteger& structParent);
void setOptionalContentReference(const PDFObjectReference& optionalContentReference);
void setAssociatedFiles(const PDFObject& associatedFiles);
void setFillingOpacity(const PDFReal& fillingOpacity);
void setStrokingOpacity(const PDFReal& strokingOpacity);
void setBlendMode(const BlendMode& blendMode);
void setLanguage(const QString& language);
/// Returns current composition mode. If blend mode is not supported by Qt,
/// then normal composition mode is returned.
QPainter::CompositionMode getCompositionMode() const;
@ -712,6 +732,16 @@ public:
const QByteArray& getIntent() const { return m_intent; }
const PDFObject& getExternalData() const { return m_externalData; }
void setWindowTitle(const QString& windowTitle);
void setPopupAnnotation(const PDFObjectReference& popupAnnotation);
void setRichTextString(const QString& richTextString);
void setCreationDate(const QDateTime& creationDate);
void setInReplyTo(PDFObjectReference inReplyTo);
void setSubject(const QString& subject);
void setReplyType(ReplyType replyType);
void setIntent(const QByteArray& intent);
void setExternalData(const PDFObject& externalData);
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObjectReference reference);
@ -1063,7 +1093,7 @@ enum class StampIntent
/// Annotation for stamps. Displays text or graphics intended to look
/// as if they were stamped on the paper.
class PDFStampAnnotation : public PDFMarkupAnnotation
class PDFFORQTLIBSHARED_EXPORT PDFStampAnnotation : public PDFMarkupAnnotation
{
public:
inline explicit PDFStampAnnotation() = default;
@ -1074,6 +1104,11 @@ public:
Stamp getStamp() const { return m_stamp; }
StampIntent getIntent() const { return m_intent; }
void setStamp(const Stamp& stamp);
void setIntent(const StampIntent& intent);
static QString getText(Stamp stamp);
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObjectReference reference);

View File

@ -95,6 +95,7 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
m_taskbarButton(new QWinTaskbarButton(this)),
m_progressTaskbarIndicator(nullptr),
m_insertStickyNoteGroup(nullptr),
m_insertStampGroup(nullptr),
m_futureWatcher(nullptr),
m_progressDialog(nullptr),
m_isBusy(false),
@ -187,6 +188,23 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
m_insertStickyNoteGroup->addAction(ui->actionStickyNoteNote);
m_insertStickyNoteGroup->addAction(ui->actionStickyNoteParagraph);
m_insertStampGroup = new QActionGroup(this);
m_insertStampGroup->setExclusionPolicy(QActionGroup::ExclusionPolicy::ExclusiveOptional);
for (pdf::Stamp stamp : { pdf::Stamp::Approved, pdf::Stamp::AsIs, pdf::Stamp::Confidential,
pdf::Stamp::Departmental, pdf::Stamp::Draft, pdf::Stamp::Experimental,
pdf::Stamp::Expired, pdf::Stamp::Final, pdf::Stamp::ForComment,
pdf::Stamp::ForPublicRelease, pdf::Stamp::NotApproved, pdf::Stamp::NotForPublicRelease,
pdf::Stamp::Sold, pdf::Stamp::TopSecret })
{
QString text = pdf::PDFStampAnnotation::getText(stamp);
QAction* action = new QAction(text, this);
action->setObjectName(QString("Stamp_%1").arg(int(stamp)));
action->setData(int(stamp));
action->setCheckable(true);
m_insertStampGroup->addAction(action);
ui->menuStamp->addAction(action);
}
ui->actionStickyNoteComment->setData(int(pdf::TextAnnotationIcon::Comment));
ui->actionStickyNoteHelp->setData(int(pdf::TextAnnotationIcon::Help));
ui->actionStickyNoteInsert->setData(int(pdf::TextAnnotationIcon::Insert));
@ -349,6 +367,8 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
m_toolManager->addTool(createEllipseTool);
pdf::PDFCreateFreehandCurveTool* createFreehandCurveTool = new pdf::PDFCreateFreehandCurveTool(m_pdfWidget->getDrawWidgetProxy(), m_toolManager, ui->actionCreateFreehandCurve, this);
m_toolManager->addTool(createFreehandCurveTool);
pdf::PDFCreateStampTool* createStampTool = new pdf::PDFCreateStampTool(m_pdfWidget->getDrawWidgetProxy(), m_toolManager, m_insertStampGroup, this);
m_toolManager->addTool(createStampTool);
m_annotationManager = new pdf::PDFWidgetAnnotationManager(m_pdfWidget->getDrawWidgetProxy(), this);
connect(m_annotationManager, &pdf::PDFWidgetAnnotationManager::actionTriggered, this, &PDFViewerMainWindow::onActionTriggered);

View File

@ -191,6 +191,7 @@ private:
pdf::PDFCertificateStore m_certificateStore;
std::vector<pdf::PDFSignatureVerificationResult> m_signatures;
QActionGroup* m_insertStickyNoteGroup;
QActionGroup* m_insertStampGroup;
QFuture<AsyncReadingResult> m_future;
QFutureWatcher<AsyncReadingResult>* m_futureWatcher;

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>431</width>
<height>333</height>
<width>590</width>
<height>476</height>
</rect>
</property>
<property name="windowTitle">
@ -19,7 +19,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>431</width>
<width>590</width>
<height>21</height>
</rect>
</property>
@ -146,6 +146,11 @@
<addaction name="actionStickyNoteNote"/>
<addaction name="actionStickyNoteParagraph"/>
</widget>
<widget class="QMenu" name="menuStamp">
<property name="title">
<string>Stamp</string>
</property>
</widget>
<addaction name="menuSticky_Note"/>
<addaction name="actionCreateHyperlink"/>
<addaction name="actionInlineText"/>
@ -154,6 +159,7 @@
<addaction name="actionCreatePolygon"/>
<addaction name="actionCreateEllipse"/>
<addaction name="actionCreateFreehandCurve"/>
<addaction name="menuStamp"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuEdit"/>