2005-02-12 17:42:54 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2005 by Enrico Ros <eros.kde@email.it> *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
***************************************************************************/
|
|
|
|
|
2007-04-19 18:30:20 +00:00
|
|
|
#include "annotations.h"
|
2007-05-04 20:24:12 +00:00
|
|
|
#include "annotations_p.h"
|
2007-04-19 18:30:20 +00:00
|
|
|
|
2005-03-04 23:06:24 +00:00
|
|
|
// qt/kde includes
|
2018-08-31 09:23:45 +00:00
|
|
|
#include <QApplication>
|
|
|
|
#include <QColor>
|
2006-09-21 08:45:36 +00:00
|
|
|
|
2013-06-23 17:19:25 +00:00
|
|
|
// DBL_MAX
|
|
|
|
#include <float.h>
|
|
|
|
|
2007-07-17 18:10:25 +00:00
|
|
|
// local includes
|
2012-08-16 09:53:58 +00:00
|
|
|
#include "action.h"
|
2008-04-13 16:34:33 +00:00
|
|
|
#include "document.h"
|
2012-03-09 13:59:24 +00:00
|
|
|
#include "document_p.h"
|
2008-08-23 00:07:59 +00:00
|
|
|
#include "movie.h"
|
2007-07-17 18:10:25 +00:00
|
|
|
#include "page_p.h"
|
2008-04-13 20:00:06 +00:00
|
|
|
#include "sound.h"
|
2007-07-17 18:10:25 +00:00
|
|
|
|
2006-09-21 08:45:36 +00:00
|
|
|
using namespace Okular;
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
|
2013-06-23 17:19:25 +00:00
|
|
|
/**
|
|
|
|
* True, if point @p c lies to the left of the vector from @p a to @p b
|
|
|
|
* @internal
|
|
|
|
*/
|
|
|
|
static bool isLeftOfVector(const NormalizedPoint &a, const NormalizedPoint &b, const NormalizedPoint &c)
|
|
|
|
{
|
|
|
|
// cross product
|
|
|
|
return ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Calculates distance of the given point @p x @p y @p xScale @p yScale to the @p path
|
|
|
|
*
|
|
|
|
* Does piecewise comparison and selects the distance to the closest segment
|
|
|
|
*/
|
|
|
|
static double distanceSqr(double x, double y, double xScale, double yScale, const QLinkedList<NormalizedPoint> &path)
|
|
|
|
{
|
|
|
|
double distance = DBL_MAX;
|
|
|
|
double thisDistance;
|
|
|
|
QLinkedList<NormalizedPoint>::const_iterator i = path.constBegin();
|
|
|
|
NormalizedPoint lastPoint = *i;
|
|
|
|
|
|
|
|
for (++i; i != path.constEnd(); ++i) {
|
|
|
|
thisDistance = NormalizedPoint::distanceSqr(x, y, xScale, yScale, lastPoint, (*i));
|
|
|
|
|
|
|
|
if (thisDistance < distance)
|
|
|
|
distance = thisDistance;
|
|
|
|
|
|
|
|
lastPoint = *i;
|
|
|
|
}
|
|
|
|
return distance;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Given the squared @p distance from the idealized 0-width line and a pen width @p penWidth,
|
|
|
|
* (not squared!), returns the final distance
|
|
|
|
*
|
|
|
|
* @warning The returned distance is not exact:
|
2013-06-24 10:46:16 +00:00
|
|
|
* We calculate an (exact) squared distance to the ideal (centered) line, and then subtract
|
2013-06-23 17:19:25 +00:00
|
|
|
* the squared width of the pen:
|
|
|
|
* a^2 - b^2 where a = "distance from idealized 0-width line" b = "pen width"
|
|
|
|
* For an exact result, we would want to calculate "(a - b)^2" but that would require
|
|
|
|
* a square root operation because we only know the squared distance a^2.
|
|
|
|
*
|
|
|
|
* However, the approximation is feasible, because:
|
|
|
|
* error = (a-b)^2 - (a^2 - b^2) = -2ab + 2b^2 = 2b(b - a)
|
|
|
|
* Therefore:
|
|
|
|
* lim_{a->b} a^2 - b^2 - a^2 + 2ab - b^2 --> 0
|
|
|
|
*
|
|
|
|
* In other words, this approximation will estimate the distance to be slightly more than it actually is
|
|
|
|
* for as long as we are far "outside" the line, becoming more accurate the closer we get to the line
|
2013-06-24 10:46:16 +00:00
|
|
|
* boundary. Trivially, it also fulfils (a1 < a2) => ((a1^2 - b^2) < (a2^2 - b^2)) making it monotonic.
|
2013-06-23 17:19:25 +00:00
|
|
|
* "Inside" of the drawn line, the distance is 0 anyway.
|
|
|
|
*/
|
|
|
|
static double strokeDistance(double distance, double penWidth)
|
|
|
|
{
|
|
|
|
return fmax(distance - pow(penWidth, 2), 0);
|
|
|
|
}
|
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
// BEGIN AnnotationUtils implementation
|
|
|
|
Annotation *AnnotationUtils::createAnnotation(const QDomElement &annElement)
|
2005-04-04 23:55:40 +00:00
|
|
|
{
|
2005-04-07 19:27:54 +00:00
|
|
|
// safety check on annotation element
|
2015-10-29 12:37:11 +00:00
|
|
|
if (!annElement.hasAttribute(QStringLiteral("type")))
|
2017-09-05 21:27:18 +00:00
|
|
|
return nullptr;
|
2005-04-04 23:55:40 +00:00
|
|
|
|
|
|
|
// build annotation of given type
|
2017-09-05 21:27:18 +00:00
|
|
|
Annotation *annotation = nullptr;
|
2015-10-29 12:37:11 +00:00
|
|
|
int typeNumber = annElement.attribute(QStringLiteral("type")).toInt();
|
2005-04-04 23:55:40 +00:00
|
|
|
switch (typeNumber) {
|
|
|
|
case Annotation::AText:
|
|
|
|
annotation = new TextAnnotation(annElement);
|
|
|
|
break;
|
|
|
|
case Annotation::ALine:
|
|
|
|
annotation = new LineAnnotation(annElement);
|
|
|
|
break;
|
|
|
|
case Annotation::AGeom:
|
|
|
|
annotation = new GeomAnnotation(annElement);
|
|
|
|
break;
|
|
|
|
case Annotation::AHighlight:
|
|
|
|
annotation = new HighlightAnnotation(annElement);
|
|
|
|
break;
|
|
|
|
case Annotation::AStamp:
|
|
|
|
annotation = new StampAnnotation(annElement);
|
|
|
|
break;
|
|
|
|
case Annotation::AInk:
|
|
|
|
annotation = new InkAnnotation(annElement);
|
|
|
|
break;
|
2008-04-05 14:46:07 +00:00
|
|
|
case Annotation::ACaret:
|
|
|
|
annotation = new CaretAnnotation(annElement);
|
|
|
|
break;
|
2005-04-04 23:55:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// return created annotation
|
|
|
|
return annotation;
|
|
|
|
}
|
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
void AnnotationUtils::storeAnnotation(const Annotation *ann, QDomElement &annElement, QDomDocument &document)
|
2005-04-04 23:55:40 +00:00
|
|
|
{
|
2005-04-07 19:27:54 +00:00
|
|
|
// save annotation's type as element's attribute
|
2015-10-29 12:37:11 +00:00
|
|
|
annElement.setAttribute(QStringLiteral("type"), (uint)ann->subType());
|
2005-03-04 23:06:24 +00:00
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
// append all annotation data as children of this node
|
|
|
|
ann->store(annElement, document);
|
|
|
|
}
|
2005-04-04 23:55:40 +00:00
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
QDomElement AnnotationUtils::findChildElement(const QDomNode &parentNode, const QString &name)
|
|
|
|
{
|
|
|
|
// loop through the whole children and return a 'name' named element
|
|
|
|
QDomNode subNode = parentNode.firstChild();
|
|
|
|
while (subNode.isElement()) {
|
|
|
|
QDomElement element = subNode.toElement();
|
|
|
|
if (element.tagName() == name)
|
|
|
|
return element;
|
|
|
|
subNode = subNode.nextSibling();
|
|
|
|
}
|
|
|
|
// if the name can't be found, return a dummy null element
|
|
|
|
return QDomElement();
|
2005-04-04 23:55:40 +00:00
|
|
|
}
|
2006-10-07 11:00:39 +00:00
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
QRect AnnotationUtils::annotationGeometry(const Annotation *annotation, double scaleX, double scaleY)
|
2006-11-21 21:35:45 +00:00
|
|
|
{
|
2019-12-20 15:40:59 +00:00
|
|
|
const QRect rect = annotation->transformedBoundingRectangle().geometry((int)scaleX, (int)scaleY);
|
|
|
|
if (annotation->subType() == Annotation::AText && (((TextAnnotation *)annotation)->textType() == TextAnnotation::Linked)) {
|
2013-05-16 21:51:11 +00:00
|
|
|
// To be honest i have no clue of why the 24,24 is here, maybe to make sure it's not too small?
|
|
|
|
// But why only for linked text?
|
2019-12-20 15:40:59 +00:00
|
|
|
const QRect rect24 = QRect((int)(annotation->transformedBoundingRectangle().left * scaleX), (int)(annotation->transformedBoundingRectangle().top * scaleY), 24, 24);
|
2013-05-16 21:51:11 +00:00
|
|
|
return rect24.united(rect);
|
2006-11-21 21:35:45 +00:00
|
|
|
}
|
|
|
|
|
2013-05-16 21:51:11 +00:00
|
|
|
return rect;
|
2006-11-21 21:35:45 +00:00
|
|
|
}
|
2005-04-07 19:27:54 +00:00
|
|
|
// END AnnotationUtils implementation
|
2005-04-04 23:55:40 +00:00
|
|
|
|
2020-02-21 15:11:42 +00:00
|
|
|
AnnotationProxy::AnnotationProxy()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-05-13 22:50:41 +00:00
|
|
|
AnnotationProxy::~AnnotationProxy()
|
|
|
|
{
|
|
|
|
}
|
2005-04-04 23:55:40 +00:00
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
// BEGIN Annotation implementation
|
2006-12-18 07:28:02 +00:00
|
|
|
|
|
|
|
class Annotation::Style::Private
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Private()
|
|
|
|
: m_opacity(1.0)
|
|
|
|
, m_width(1.0)
|
|
|
|
, m_style(Solid)
|
|
|
|
, m_xCorners(0.0)
|
|
|
|
, m_yCorners(0.0)
|
|
|
|
, m_marks(3)
|
|
|
|
, m_spaces(0)
|
|
|
|
, m_effect(NoEffect)
|
|
|
|
, m_effectIntensity(1.0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QColor m_color;
|
|
|
|
double m_opacity;
|
|
|
|
double m_width;
|
|
|
|
LineStyle m_style;
|
|
|
|
double m_xCorners;
|
|
|
|
double m_yCorners;
|
|
|
|
int m_marks;
|
|
|
|
int m_spaces;
|
|
|
|
LineEffect m_effect;
|
|
|
|
double m_effectIntensity;
|
|
|
|
};
|
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
Annotation::Style::Style()
|
2006-12-18 07:28:02 +00:00
|
|
|
: d(new Private)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::Style::~Style()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::Style::Style(const Style &other)
|
|
|
|
: d(new Private)
|
|
|
|
{
|
|
|
|
*d = *other.d;
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::Style &Annotation::Style::operator=(const Style &other)
|
2006-12-05 11:05:50 +00:00
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
if (this != &other)
|
|
|
|
*d = *other.d;
|
|
|
|
|
|
|
|
return *this;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Style::setColor(const QColor &color)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_color = color;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QColor Annotation::Style::color() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_color;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Style::setOpacity(double opacity)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_opacity = opacity;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double Annotation::Style::opacity() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_opacity;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Style::setWidth(double width)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_width = width;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double Annotation::Style::width() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_width;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Style::setLineStyle(LineStyle style)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_style = style;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::LineStyle Annotation::Style::lineStyle() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_style;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Style::setXCorners(double xCorners)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_xCorners = xCorners;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double Annotation::Style::xCorners() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_xCorners;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Style::setYCorners(double yCorners)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_yCorners = yCorners;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double Annotation::Style::yCorners() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_yCorners;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Style::setMarks(int marks)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_marks = marks;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int Annotation::Style::marks() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_marks;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Style::setSpaces(int spaces)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_spaces = spaces;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int Annotation::Style::spaces() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_spaces;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Style::setLineEffect(LineEffect effect)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_effect = effect;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::LineEffect Annotation::Style::lineEffect() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_effect;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Style::setEffectIntensity(double intensity)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_effectIntensity = intensity;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double Annotation::Style::effectIntensity() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_effectIntensity;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
2006-12-18 07:28:02 +00:00
|
|
|
class Annotation::Window::Private
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Private()
|
|
|
|
: m_flags(-1)
|
|
|
|
, m_width(0)
|
|
|
|
, m_height(0)
|
|
|
|
{
|
|
|
|
}
|
2006-12-05 11:05:50 +00:00
|
|
|
|
2006-12-18 07:28:02 +00:00
|
|
|
int m_flags;
|
|
|
|
NormalizedPoint m_topLeft;
|
|
|
|
int m_width;
|
|
|
|
int m_height;
|
|
|
|
QString m_title;
|
|
|
|
QString m_summary;
|
|
|
|
};
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
|
2005-04-04 23:55:40 +00:00
|
|
|
Annotation::Window::Window()
|
2006-12-18 07:28:02 +00:00
|
|
|
: d(new Private)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::Window::~Window()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::Window::Window(const Window &other)
|
|
|
|
: d(new Private)
|
2006-12-05 11:05:50 +00:00
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
*d = *other.d;
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::Window &Annotation::Window::operator=(const Window &other)
|
|
|
|
{
|
|
|
|
if (this != &other)
|
|
|
|
*d = *other.d;
|
|
|
|
|
|
|
|
return *this;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Window::setFlags(int flags)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_flags = flags;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int Annotation::Window::flags() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_flags;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Window::setTopLeft(const NormalizedPoint &point)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_topLeft = point;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NormalizedPoint Annotation::Window::topLeft() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_topLeft;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Window::setWidth(int width)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_width = width;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int Annotation::Window::width() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_width;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Window::setHeight(int height)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_height = height;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int Annotation::Window::height() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_height;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Window::setTitle(const QString &title)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_title = title;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString Annotation::Window::title() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_title;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Window::setSummary(const QString &summary)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_summary = summary;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString Annotation::Window::summary() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_summary;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
2006-12-18 07:28:02 +00:00
|
|
|
class Annotation::Revision::Private
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Private()
|
2017-09-05 21:27:18 +00:00
|
|
|
: m_annotation(nullptr)
|
|
|
|
, m_scope(Reply)
|
|
|
|
, m_type(None)
|
2006-12-18 07:28:02 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation *m_annotation;
|
|
|
|
RevisionScope m_scope;
|
|
|
|
RevisionType m_type;
|
|
|
|
};
|
2005-04-04 23:55:40 +00:00
|
|
|
|
|
|
|
Annotation::Revision::Revision()
|
2006-12-18 07:28:02 +00:00
|
|
|
: d(new Private)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::Revision::~Revision()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::Revision::Revision(const Revision &other)
|
|
|
|
: d(new Private)
|
2006-12-05 11:05:50 +00:00
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
*d = *other.d;
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::Revision &Annotation::Revision::operator=(const Revision &other)
|
|
|
|
{
|
|
|
|
if (this != &other)
|
|
|
|
*d = *other.d;
|
|
|
|
|
|
|
|
return *this;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Revision::setAnnotation(Annotation *annotation)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_annotation = annotation;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Annotation *Annotation::Revision::annotation() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_annotation;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Revision::setScope(RevisionScope scope)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_scope = scope;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::RevisionScope Annotation::Revision::scope() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_scope;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::Revision::setType(RevisionType type)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_type = type;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::RevisionType Annotation::Revision::type() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_type;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
AnnotationPrivate::AnnotationPrivate()
|
2017-09-05 21:27:18 +00:00
|
|
|
: m_page(nullptr)
|
|
|
|
, m_flags(0)
|
|
|
|
, m_disposeFunc(nullptr)
|
2006-12-05 11:05:50 +00:00
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
}
|
2006-12-18 07:28:02 +00:00
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
AnnotationPrivate::~AnnotationPrivate()
|
|
|
|
{
|
|
|
|
// delete all children revisions
|
|
|
|
if (m_revisions.isEmpty())
|
|
|
|
return;
|
2006-12-18 07:28:02 +00:00
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
QLinkedList<Annotation::Revision>::iterator it = m_revisions.begin(), end = m_revisions.end();
|
|
|
|
for (; it != end; ++it)
|
|
|
|
delete (*it).annotation();
|
|
|
|
}
|
2006-12-18 07:28:02 +00:00
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
Annotation::Annotation(AnnotationPrivate &dd)
|
|
|
|
: d_ptr(&dd)
|
2006-12-18 07:28:02 +00:00
|
|
|
{
|
2005-04-04 23:55:40 +00:00
|
|
|
}
|
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
Annotation::Annotation(AnnotationPrivate &dd, const QDomNode &description)
|
2007-05-04 20:24:12 +00:00
|
|
|
: d_ptr(&dd)
|
2005-04-07 19:27:54 +00:00
|
|
|
{
|
2019-12-20 15:40:59 +00:00
|
|
|
d_ptr->setAnnotationProperties(description);
|
2006-12-18 07:28:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::~Annotation()
|
|
|
|
{
|
2008-04-13 13:45:32 +00:00
|
|
|
if (d_ptr->m_disposeFunc)
|
|
|
|
d_ptr->m_disposeFunc(this);
|
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
delete d_ptr;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::setAuthor(const QString &author)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_author = author;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString Annotation::author() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_author;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::setContents(const QString &contents)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_contents = contents;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString Annotation::contents() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_contents;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::setUniqueName(const QString &name)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_uniqueName = name;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString Annotation::uniqueName() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_uniqueName;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::setModificationDate(const QDateTime &date)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_modifyDate = date;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QDateTime Annotation::modificationDate() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_modifyDate;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::setCreationDate(const QDateTime &date)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_creationDate = date;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QDateTime Annotation::creationDate() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_creationDate;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::setFlags(int flags)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_flags = flags;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int Annotation::flags() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_flags;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::setBoundingRectangle(const NormalizedRect &rectangle)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_boundary = rectangle;
|
2007-07-22 20:49:27 +00:00
|
|
|
d->resetTransformation();
|
2007-07-17 18:10:25 +00:00
|
|
|
if (d->m_page) {
|
|
|
|
d->transform(d->m_page->rotationMatrix());
|
|
|
|
}
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NormalizedRect Annotation::boundingRectangle() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_boundary;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NormalizedRect Annotation::transformedBoundingRectangle() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_transformedBoundary;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
2007-07-17 18:10:25 +00:00
|
|
|
void Annotation::translate(const NormalizedPoint &coord)
|
|
|
|
{
|
|
|
|
Q_D(Annotation);
|
|
|
|
d->translate(coord);
|
2007-07-22 20:49:27 +00:00
|
|
|
d->resetTransformation();
|
2007-07-17 18:10:25 +00:00
|
|
|
if (d->m_page) {
|
|
|
|
d->transform(d->m_page->rotationMatrix());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
|
|
|
void Annotation::adjust(const NormalizedPoint &deltaCoord1, const NormalizedPoint &deltaCoord2)
|
|
|
|
{
|
|
|
|
Q_D(Annotation);
|
|
|
|
d->adjust(deltaCoord1, deltaCoord2);
|
|
|
|
d->resetTransformation();
|
|
|
|
if (d->m_page) {
|
|
|
|
d->transform(d->m_page->rotationMatrix());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-27 22:16:11 +00:00
|
|
|
bool Annotation::openDialogAfterCreation() const
|
|
|
|
{
|
|
|
|
Q_D(const Annotation);
|
|
|
|
return d->openDialogAfterCreation();
|
|
|
|
}
|
|
|
|
|
2006-12-05 11:05:50 +00:00
|
|
|
Annotation::Style &Annotation::style()
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_style;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const Annotation::Style &Annotation::style() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_style;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::Window &Annotation::window()
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_window;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const Annotation::Window &Annotation::window() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_window;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QLinkedList<Annotation::Revision> &Annotation::revisions()
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_revisions;
|
2006-12-05 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const QLinkedList<Annotation::Revision> &Annotation::revisions() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const Annotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_revisions;
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
}
|
|
|
|
|
2008-04-13 13:45:32 +00:00
|
|
|
void Annotation::setNativeId(const QVariant &id)
|
|
|
|
{
|
|
|
|
Q_D(Annotation);
|
|
|
|
d->m_nativeId = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant Annotation::nativeId() const
|
|
|
|
{
|
|
|
|
Q_D(const Annotation);
|
|
|
|
return d->m_nativeId;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::setDisposeDataFunction(DisposeDataFunction func)
|
|
|
|
{
|
|
|
|
Q_D(Annotation);
|
|
|
|
d->m_disposeFunc = func;
|
|
|
|
}
|
|
|
|
|
2008-05-01 20:59:51 +00:00
|
|
|
bool Annotation::canBeMoved() const
|
|
|
|
{
|
|
|
|
Q_D(const Annotation);
|
2012-03-09 13:59:24 +00:00
|
|
|
|
|
|
|
// Don't move annotations if they cannot be modified
|
|
|
|
if (!d->m_page || !d->m_page->m_doc->m_parent->canModifyPageAnnotation(this))
|
2008-05-01 20:59:51 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// highlight "requires" to be "bounded" to text, and that's tricky for now
|
|
|
|
if (subType() == AHighlight)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
|
|
|
bool Annotation::canBeResized() const
|
|
|
|
{
|
|
|
|
Q_D(const Annotation);
|
|
|
|
|
|
|
|
// Don't resize annotations if they cannot be modified
|
|
|
|
if (!d->m_page || !d->m_page->m_doc->m_parent->canModifyPageAnnotation(this))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return d->canBeResized();
|
|
|
|
}
|
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
void Annotation::store(QDomNode &annNode, QDomDocument &document) const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const Annotation);
|
2005-04-07 19:27:54 +00:00
|
|
|
// create [base] element of the annotation node
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement e = document.createElement(QStringLiteral("base"));
|
2005-04-07 19:27:54 +00:00
|
|
|
annNode.appendChild(e);
|
2005-03-18 18:49:45 +00:00
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
// store -contents- attributes
|
2006-12-18 07:28:02 +00:00
|
|
|
if (!d->m_author.isEmpty())
|
2015-10-29 12:37:11 +00:00
|
|
|
e.setAttribute(QStringLiteral("author"), d->m_author);
|
2006-12-18 07:28:02 +00:00
|
|
|
if (!d->m_contents.isEmpty())
|
2015-10-29 12:37:11 +00:00
|
|
|
e.setAttribute(QStringLiteral("contents"), d->m_contents);
|
2006-12-18 07:28:02 +00:00
|
|
|
if (!d->m_uniqueName.isEmpty())
|
2015-10-29 12:37:11 +00:00
|
|
|
e.setAttribute(QStringLiteral("uniqueName"), d->m_uniqueName);
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_modifyDate.isValid())
|
2015-10-29 12:37:11 +00:00
|
|
|
e.setAttribute(QStringLiteral("modifyDate"), d->m_modifyDate.toString(Qt::ISODate));
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_creationDate.isValid())
|
2015-10-29 12:37:11 +00:00
|
|
|
e.setAttribute(QStringLiteral("creationDate"), d->m_creationDate.toString(Qt::ISODate));
|
2005-04-07 19:27:54 +00:00
|
|
|
|
|
|
|
// store -other- attributes
|
2012-05-13 18:10:55 +00:00
|
|
|
if (d->m_flags) // Strip internal flags
|
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
|
|
|
e.setAttribute(QStringLiteral("flags"), d->m_flags & ~(External | ExternallyDrawn | BeingMoved | BeingResized));
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_style.color().isValid())
|
2018-09-04 20:07:33 +00:00
|
|
|
e.setAttribute(QStringLiteral("color"), d->m_style.color().name(QColor::HexArgb));
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_style.opacity() != 1.0)
|
2015-10-29 12:37:11 +00:00
|
|
|
e.setAttribute(QStringLiteral("opacity"), QString::number(d->m_style.opacity()));
|
2005-04-07 19:27:54 +00:00
|
|
|
|
|
|
|
// Sub-Node-1 - boundary
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement bE = document.createElement(QStringLiteral("boundary"));
|
2005-04-07 19:27:54 +00:00
|
|
|
e.appendChild(bE);
|
2015-10-29 12:37:11 +00:00
|
|
|
bE.setAttribute(QStringLiteral("l"), QString::number(d->m_boundary.left));
|
|
|
|
bE.setAttribute(QStringLiteral("t"), QString::number(d->m_boundary.top));
|
|
|
|
bE.setAttribute(QStringLiteral("r"), QString::number(d->m_boundary.right));
|
|
|
|
bE.setAttribute(QStringLiteral("b"), QString::number(d->m_boundary.bottom));
|
2005-04-07 19:27:54 +00:00
|
|
|
|
|
|
|
// Sub-Node-2 - penStyle
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_style.width() != 1 || d->m_style.lineStyle() != Solid || d->m_style.xCorners() != 0 || d->m_style.yCorners() != 0.0 || d->m_style.marks() != 3 || d->m_style.spaces() != 0) {
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement psE = document.createElement(QStringLiteral("penStyle"));
|
2005-04-07 19:27:54 +00:00
|
|
|
e.appendChild(psE);
|
2015-10-29 12:37:11 +00:00
|
|
|
psE.setAttribute(QStringLiteral("width"), QString::number(d->m_style.width()));
|
|
|
|
psE.setAttribute(QStringLiteral("style"), (int)d->m_style.lineStyle());
|
|
|
|
psE.setAttribute(QStringLiteral("xcr"), QString::number(d->m_style.xCorners()));
|
|
|
|
psE.setAttribute(QStringLiteral("ycr"), QString::number(d->m_style.yCorners()));
|
|
|
|
psE.setAttribute(QStringLiteral("marks"), d->m_style.marks());
|
|
|
|
psE.setAttribute(QStringLiteral("spaces"), d->m_style.spaces());
|
2005-03-18 18:49:45 +00:00
|
|
|
}
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
// Sub-Node-3 - penEffect
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_style.lineEffect() != NoEffect || d->m_style.effectIntensity() != 1.0) {
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement peE = document.createElement(QStringLiteral("penEffect"));
|
2005-04-07 19:27:54 +00:00
|
|
|
e.appendChild(peE);
|
2015-10-29 12:37:11 +00:00
|
|
|
peE.setAttribute(QStringLiteral("effect"), (int)d->m_style.lineEffect());
|
|
|
|
peE.setAttribute(QStringLiteral("intensity"), QString::number(d->m_style.effectIntensity()));
|
2005-04-07 19:27:54 +00:00
|
|
|
}
|
2005-03-18 18:49:45 +00:00
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
// Sub-Node-4 - window
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_window.flags() != -1 || !d->m_window.title().isEmpty() || !d->m_window.summary().isEmpty()) {
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement wE = document.createElement(QStringLiteral("window"));
|
2005-04-07 19:27:54 +00:00
|
|
|
e.appendChild(wE);
|
2015-10-29 12:37:11 +00:00
|
|
|
wE.setAttribute(QStringLiteral("flags"), d->m_window.flags());
|
|
|
|
wE.setAttribute(QStringLiteral("top"), QString::number(d->m_window.topLeft().x));
|
|
|
|
wE.setAttribute(QStringLiteral("left"), QString::number(d->m_window.topLeft().y));
|
|
|
|
wE.setAttribute(QStringLiteral("width"), d->m_window.width());
|
|
|
|
wE.setAttribute(QStringLiteral("height"), d->m_window.height());
|
|
|
|
wE.setAttribute(QStringLiteral("title"), d->m_window.title());
|
|
|
|
wE.setAttribute(QStringLiteral("summary"), d->m_window.summary());
|
2005-03-18 18:49:45 +00:00
|
|
|
}
|
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
// create [revision] element of the annotation node (if any)
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_revisions.isEmpty())
|
2005-04-07 19:27:54 +00:00
|
|
|
return;
|
2005-03-18 18:49:45 +00:00
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
// add all revisions as children of revisions element
|
2006-12-18 07:28:02 +00:00
|
|
|
QLinkedList<Revision>::const_iterator it = d->m_revisions.begin(), end = d->m_revisions.end();
|
2005-04-07 19:27:54 +00:00
|
|
|
for (; it != end; ++it) {
|
|
|
|
// create revision element
|
|
|
|
const Revision &revision = *it;
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement r = document.createElement(QStringLiteral("revision"));
|
2005-04-07 19:27:54 +00:00
|
|
|
annNode.appendChild(r);
|
|
|
|
// set element attributes
|
2015-10-29 12:37:11 +00:00
|
|
|
r.setAttribute(QStringLiteral("revScope"), (int)revision.scope());
|
|
|
|
r.setAttribute(QStringLiteral("revType"), (int)revision.type());
|
2005-04-07 19:27:54 +00:00
|
|
|
// use revision as the annotation element, so fill it up
|
2006-12-05 11:05:50 +00:00
|
|
|
AnnotationUtils::storeAnnotation(revision.annotation(), r, document);
|
2005-04-04 23:55:40 +00:00
|
|
|
}
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
}
|
2006-11-20 07:53:32 +00:00
|
|
|
|
2013-04-05 22:28:39 +00:00
|
|
|
QDomNode Annotation::getAnnotationPropertiesDomNode() const
|
2013-04-05 22:22:48 +00:00
|
|
|
{
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomDocument doc(QStringLiteral("documentInfo"));
|
|
|
|
QDomElement node = doc.createElement(QStringLiteral("annotation"));
|
2013-04-05 22:22:48 +00:00
|
|
|
|
|
|
|
store(node, doc);
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Annotation::setAnnotationProperties(const QDomNode &node)
|
|
|
|
{
|
|
|
|
// Save off internal properties that aren't contained in node
|
|
|
|
Okular::PagePrivate *p = d_ptr->m_page;
|
|
|
|
QVariant nativeID = d_ptr->m_nativeId;
|
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
|
|
|
const int internalFlags = d_ptr->m_flags & (External | ExternallyDrawn | BeingMoved | BeingResized);
|
2013-04-05 22:22:48 +00:00
|
|
|
Annotation::DisposeDataFunction disposeFunc = d_ptr->m_disposeFunc;
|
|
|
|
|
|
|
|
// Replace AnnotationPrivate object with a fresh copy
|
|
|
|
AnnotationPrivate *new_d_ptr = d_ptr->getNewAnnotationPrivate();
|
|
|
|
delete (d_ptr);
|
|
|
|
d_ptr = new_d_ptr;
|
|
|
|
|
|
|
|
// Set the annotations properties from node
|
|
|
|
d_ptr->setAnnotationProperties(node);
|
|
|
|
|
|
|
|
// Restore internal properties
|
|
|
|
d_ptr->m_page = p;
|
|
|
|
d_ptr->m_nativeId = nativeID;
|
|
|
|
d_ptr->m_flags = d_ptr->m_flags | internalFlags;
|
|
|
|
d_ptr->m_disposeFunc = disposeFunc;
|
2013-05-07 20:05:24 +00:00
|
|
|
|
|
|
|
// Transform annotation to current page rotation
|
|
|
|
d_ptr->transform(d_ptr->m_page->rotationMatrix());
|
2013-04-05 22:22:48 +00:00
|
|
|
}
|
|
|
|
|
2019-12-03 23:23:26 +00:00
|
|
|
double AnnotationPrivate::distanceSqr(double x, double y, double xScale, double yScale) const
|
2013-06-23 17:19:25 +00:00
|
|
|
{
|
|
|
|
return m_transformedBoundary.distanceSqr(x, y, xScale, yScale);
|
|
|
|
}
|
|
|
|
|
2012-09-08 15:06:02 +00:00
|
|
|
void AnnotationPrivate::annotationTransform(const QTransform &matrix)
|
2007-07-22 20:49:27 +00:00
|
|
|
{
|
|
|
|
resetTransformation();
|
|
|
|
transform(matrix);
|
|
|
|
}
|
|
|
|
|
2012-09-08 15:06:02 +00:00
|
|
|
void AnnotationPrivate::transform(const QTransform &matrix)
|
2006-11-20 07:53:32 +00:00
|
|
|
{
|
2007-05-04 20:45:45 +00:00
|
|
|
m_transformedBoundary.transform(matrix);
|
2006-11-20 07:53:32 +00:00
|
|
|
}
|
|
|
|
|
2012-09-08 15:06:02 +00:00
|
|
|
void AnnotationPrivate::baseTransform(const QTransform &matrix)
|
2007-10-07 10:52:05 +00:00
|
|
|
{
|
|
|
|
m_boundary.transform(matrix);
|
|
|
|
}
|
|
|
|
|
2007-07-22 20:49:27 +00:00
|
|
|
void AnnotationPrivate::resetTransformation()
|
|
|
|
{
|
|
|
|
m_transformedBoundary = m_boundary;
|
|
|
|
}
|
|
|
|
|
2007-07-17 18:10:25 +00:00
|
|
|
void AnnotationPrivate::translate(const NormalizedPoint &coord)
|
|
|
|
{
|
|
|
|
m_boundary.left = m_boundary.left + coord.x;
|
|
|
|
m_boundary.right = m_boundary.right + coord.x;
|
|
|
|
m_boundary.top = m_boundary.top + coord.y;
|
|
|
|
m_boundary.bottom = m_boundary.bottom + coord.y;
|
|
|
|
}
|
|
|
|
|
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
|
|
|
void AnnotationPrivate::adjust(const NormalizedPoint &deltaCoord1, const NormalizedPoint &deltaCoord2)
|
|
|
|
{
|
|
|
|
m_boundary.left = m_boundary.left + qBound(-m_boundary.left, deltaCoord1.x, m_boundary.right - m_boundary.left);
|
|
|
|
m_boundary.top = m_boundary.top + qBound(-m_boundary.top, deltaCoord1.y, m_boundary.bottom - m_boundary.top);
|
2020-07-10 22:15:05 +00:00
|
|
|
;
|
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
|
|
|
m_boundary.right = m_boundary.right + qBound(m_boundary.left - m_boundary.right, deltaCoord2.x, 1. - m_boundary.right);
|
|
|
|
m_boundary.bottom = m_boundary.bottom + qBound(m_boundary.top - m_boundary.bottom, deltaCoord2.y, 1. - m_boundary.bottom);
|
|
|
|
}
|
|
|
|
|
2010-12-27 22:16:11 +00:00
|
|
|
bool AnnotationPrivate::openDialogAfterCreation() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
void AnnotationPrivate::setAnnotationProperties(const QDomNode &node)
|
|
|
|
{
|
|
|
|
// get the [base] element of the annotation node
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement e = AnnotationUtils::findChildElement(node, QStringLiteral("base"));
|
2013-04-05 22:22:48 +00:00
|
|
|
if (e.isNull())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// parse -contents- attributes
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.hasAttribute(QStringLiteral("author")))
|
|
|
|
m_author = e.attribute(QStringLiteral("author"));
|
|
|
|
if (e.hasAttribute(QStringLiteral("contents")))
|
|
|
|
m_contents = e.attribute(QStringLiteral("contents"));
|
|
|
|
if (e.hasAttribute(QStringLiteral("uniqueName")))
|
|
|
|
m_uniqueName = e.attribute(QStringLiteral("uniqueName"));
|
|
|
|
if (e.hasAttribute(QStringLiteral("modifyDate")))
|
|
|
|
m_modifyDate = QDateTime::fromString(e.attribute(QStringLiteral("modifyDate")), Qt::ISODate);
|
|
|
|
if (e.hasAttribute(QStringLiteral("creationDate")))
|
|
|
|
m_creationDate = QDateTime::fromString(e.attribute(QStringLiteral("creationDate")), Qt::ISODate);
|
2013-04-05 22:22:48 +00:00
|
|
|
|
|
|
|
// parse -other- attributes
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.hasAttribute(QStringLiteral("flags")))
|
|
|
|
m_flags = e.attribute(QStringLiteral("flags")).toInt();
|
|
|
|
if (e.hasAttribute(QStringLiteral("color")))
|
|
|
|
m_style.setColor(QColor(e.attribute(QStringLiteral("color"))));
|
|
|
|
if (e.hasAttribute(QStringLiteral("opacity")))
|
|
|
|
m_style.setOpacity(e.attribute(QStringLiteral("opacity")).toDouble());
|
2013-04-05 22:22:48 +00:00
|
|
|
|
|
|
|
// parse -the-subnodes- (describing Style, Window, Revision(s) structures)
|
|
|
|
// Note: all subnodes if present must be 'attributes complete'
|
|
|
|
QDomNode eSubNode = e.firstChild();
|
|
|
|
while (eSubNode.isElement()) {
|
|
|
|
QDomElement ee = eSubNode.toElement();
|
|
|
|
eSubNode = eSubNode.nextSibling();
|
|
|
|
|
|
|
|
// parse boundary
|
2015-10-29 12:37:11 +00:00
|
|
|
if (ee.tagName() == QLatin1String("boundary")) {
|
|
|
|
m_boundary = NormalizedRect(ee.attribute(QStringLiteral("l")).toDouble(), ee.attribute(QStringLiteral("t")).toDouble(), ee.attribute(QStringLiteral("r")).toDouble(), ee.attribute(QStringLiteral("b")).toDouble());
|
2013-04-05 22:22:48 +00:00
|
|
|
}
|
|
|
|
// parse penStyle if not default
|
2015-10-29 12:37:11 +00:00
|
|
|
else if (ee.tagName() == QLatin1String("penStyle")) {
|
|
|
|
m_style.setWidth(ee.attribute(QStringLiteral("width")).toDouble());
|
|
|
|
m_style.setLineStyle((Annotation::LineStyle)ee.attribute(QStringLiteral("style")).toInt());
|
|
|
|
m_style.setXCorners(ee.attribute(QStringLiteral("xcr")).toDouble());
|
|
|
|
m_style.setYCorners(ee.attribute(QStringLiteral("ycr")).toDouble());
|
|
|
|
m_style.setMarks(ee.attribute(QStringLiteral("marks")).toInt());
|
|
|
|
m_style.setSpaces(ee.attribute(QStringLiteral("spaces")).toInt());
|
2013-04-05 22:22:48 +00:00
|
|
|
}
|
|
|
|
// parse effectStyle if not default
|
2015-10-29 12:37:11 +00:00
|
|
|
else if (ee.tagName() == QLatin1String("penEffect")) {
|
|
|
|
m_style.setLineEffect((Annotation::LineEffect)ee.attribute(QStringLiteral("effect")).toInt());
|
|
|
|
m_style.setEffectIntensity(ee.attribute(QStringLiteral("intensity")).toDouble());
|
2013-04-05 22:22:48 +00:00
|
|
|
}
|
|
|
|
// parse window if present
|
2015-10-29 12:37:11 +00:00
|
|
|
else if (ee.tagName() == QLatin1String("window")) {
|
|
|
|
m_window.setFlags(ee.attribute(QStringLiteral("flags")).toInt());
|
|
|
|
m_window.setTopLeft(NormalizedPoint(ee.attribute(QStringLiteral("top")).toDouble(), ee.attribute(QStringLiteral("left")).toDouble()));
|
|
|
|
m_window.setWidth(ee.attribute(QStringLiteral("width")).toInt());
|
|
|
|
m_window.setHeight(ee.attribute(QStringLiteral("height")).toInt());
|
|
|
|
m_window.setTitle(ee.attribute(QStringLiteral("title")));
|
|
|
|
m_window.setSummary(ee.attribute(QStringLiteral("summary")));
|
2013-04-05 22:22:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the [revisions] element of the annotation node
|
|
|
|
QDomNode revNode = node.firstChild();
|
|
|
|
for (; revNode.isElement(); revNode = revNode.nextSibling()) {
|
|
|
|
QDomElement revElement = revNode.toElement();
|
2015-10-29 12:37:11 +00:00
|
|
|
if (revElement.tagName() != QLatin1String("revision"))
|
2013-04-05 22:22:48 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// compile the Revision structure crating annotation
|
|
|
|
Annotation::Revision revision;
|
2015-10-29 12:37:11 +00:00
|
|
|
revision.setScope((Annotation::RevisionScope)revElement.attribute(QStringLiteral("revScope")).toInt());
|
|
|
|
revision.setType((Annotation::RevisionType)revElement.attribute(QStringLiteral("revType")).toInt());
|
2013-04-05 22:22:48 +00:00
|
|
|
revision.setAnnotation(AnnotationUtils::createAnnotation(revElement));
|
|
|
|
|
|
|
|
// if annotation is valid, add revision to internal list
|
|
|
|
if (revision.annotation())
|
|
|
|
m_revisions.append(revision);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_transformedBoundary = m_boundary;
|
|
|
|
}
|
|
|
|
|
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
|
|
|
bool AnnotationPrivate::canBeResized() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-11-20 07:53:32 +00:00
|
|
|
// END Annotation implementation
|
2005-04-07 19:27:54 +00:00
|
|
|
|
|
|
|
/** TextAnnotation [Annotation] */
|
2006-12-18 07:28:02 +00:00
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
class Okular::TextAnnotationPrivate : public Okular::AnnotationPrivate
|
2006-12-18 07:28:02 +00:00
|
|
|
{
|
|
|
|
public:
|
2007-05-04 20:24:12 +00:00
|
|
|
TextAnnotationPrivate()
|
|
|
|
: AnnotationPrivate()
|
|
|
|
, m_textType(TextAnnotation::Linked)
|
2015-10-29 12:37:11 +00:00
|
|
|
, m_textIcon(QStringLiteral("Comment"))
|
|
|
|
, m_inplaceAlign(0)
|
2007-05-04 20:24:12 +00:00
|
|
|
, m_inplaceIntent(TextAnnotation::Unknown)
|
2006-12-18 07:28:02 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-10-29 14:38:19 +00:00
|
|
|
void transform(const QTransform &matrix) override;
|
|
|
|
void baseTransform(const QTransform &matrix) override;
|
|
|
|
void resetTransformation() override;
|
|
|
|
void translate(const NormalizedPoint &coord) override;
|
|
|
|
bool openDialogAfterCreation() const override;
|
|
|
|
void setAnnotationProperties(const QDomNode &node) override;
|
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
|
|
|
bool canBeResized() const override;
|
2016-10-29 14:38:19 +00:00
|
|
|
AnnotationPrivate *getNewAnnotationPrivate() override;
|
2020-07-10 22:15:05 +00:00
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
TextAnnotation::TextType m_textType;
|
2006-12-18 07:28:02 +00:00
|
|
|
QString m_textIcon;
|
|
|
|
QFont m_textFont;
|
2018-10-03 14:31:40 +00:00
|
|
|
QColor m_textColor;
|
2006-12-18 07:28:02 +00:00
|
|
|
int m_inplaceAlign;
|
|
|
|
NormalizedPoint m_inplaceCallout[3];
|
|
|
|
NormalizedPoint m_transformedInplaceCallout[3];
|
2007-05-04 20:24:12 +00:00
|
|
|
TextAnnotation::InplaceIntent m_inplaceIntent;
|
2006-12-18 07:28:02 +00:00
|
|
|
};
|
|
|
|
|
2006-09-08 21:08:51 +00:00
|
|
|
/*
|
|
|
|
The default textIcon for text annotation is Note as the PDF Reference says
|
|
|
|
*/
|
2005-03-04 23:06:24 +00:00
|
|
|
TextAnnotation::TextAnnotation()
|
2007-05-04 20:24:12 +00:00
|
|
|
: Annotation(*new TextAnnotationPrivate())
|
2006-12-11 07:59:02 +00:00
|
|
|
{
|
|
|
|
}
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
TextAnnotation::TextAnnotation(const QDomNode &description)
|
|
|
|
: Annotation(*new TextAnnotationPrivate(), description)
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
{
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TextAnnotation::~TextAnnotation()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextAnnotation::setTextType(TextType textType)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(TextAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_textType = textType;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TextAnnotation::TextType TextAnnotation::textType() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const TextAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_textType;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TextAnnotation::setTextIcon(const QString &icon)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(TextAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_textIcon = icon;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString TextAnnotation::textIcon() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const TextAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_textIcon;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TextAnnotation::setTextFont(const QFont &font)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(TextAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_textFont = font;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QFont TextAnnotation::textFont() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const TextAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_textFont;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
2018-10-03 14:31:40 +00:00
|
|
|
void TextAnnotation::setTextColor(const QColor &color)
|
|
|
|
{
|
|
|
|
Q_D(TextAnnotation);
|
|
|
|
d->m_textColor = color;
|
|
|
|
}
|
|
|
|
|
|
|
|
QColor TextAnnotation::textColor() const
|
|
|
|
{
|
|
|
|
Q_D(const TextAnnotation);
|
|
|
|
return d->m_textColor;
|
|
|
|
}
|
|
|
|
|
2006-12-11 07:59:02 +00:00
|
|
|
void TextAnnotation::setInplaceAlignment(int alignment)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(TextAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_inplaceAlign = alignment;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int TextAnnotation::inplaceAlignment() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const TextAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_inplaceAlign;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TextAnnotation::setInplaceCallout(const NormalizedPoint &point, int index)
|
|
|
|
{
|
|
|
|
if (index < 0 || index > 2)
|
|
|
|
return;
|
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(TextAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_inplaceCallout[index] = point;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NormalizedPoint TextAnnotation::inplaceCallout(int index) const
|
|
|
|
{
|
|
|
|
if (index < 0 || index > 2)
|
|
|
|
return NormalizedPoint();
|
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const TextAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_inplaceCallout[index];
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NormalizedPoint TextAnnotation::transformedInplaceCallout(int index) const
|
|
|
|
{
|
|
|
|
if (index < 0 || index > 2)
|
|
|
|
return NormalizedPoint();
|
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const TextAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_transformedInplaceCallout[index];
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TextAnnotation::setInplaceIntent(InplaceIntent intent)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(TextAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_inplaceIntent = intent;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TextAnnotation::InplaceIntent TextAnnotation::inplaceIntent() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const TextAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_inplaceIntent;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::SubType TextAnnotation::subType() const
|
|
|
|
{
|
|
|
|
return AText;
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
}
|
|
|
|
|
2005-03-13 13:14:44 +00:00
|
|
|
void TextAnnotation::store(QDomNode &node, QDomDocument &document) const
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const TextAnnotation);
|
2005-03-18 18:49:45 +00:00
|
|
|
// recurse to parent objects storing properties
|
2005-04-04 23:55:40 +00:00
|
|
|
Annotation::store(node, document);
|
2005-03-18 18:49:45 +00:00
|
|
|
|
|
|
|
// create [text] element
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement textElement = document.createElement(QStringLiteral("text"));
|
2005-03-18 18:49:45 +00:00
|
|
|
node.appendChild(textElement);
|
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
// store the optional attributes
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_textType != Linked)
|
2015-10-29 12:37:11 +00:00
|
|
|
textElement.setAttribute(QStringLiteral("type"), (int)d->m_textType);
|
2012-05-22 10:57:07 +00:00
|
|
|
if (!d->m_textIcon.isEmpty())
|
2015-10-29 12:37:11 +00:00
|
|
|
textElement.setAttribute(QStringLiteral("icon"), d->m_textIcon);
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_textFont != QApplication::font())
|
2015-10-29 12:37:11 +00:00
|
|
|
textElement.setAttribute(QStringLiteral("font"), d->m_textFont.toString());
|
2018-10-03 14:31:40 +00:00
|
|
|
if (d->m_textColor.isValid())
|
|
|
|
textElement.setAttribute(QStringLiteral("fontColor"), d->m_textColor.name());
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_inplaceAlign)
|
2015-10-29 12:37:11 +00:00
|
|
|
textElement.setAttribute(QStringLiteral("align"), d->m_inplaceAlign);
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_inplaceIntent != Unknown)
|
2015-10-29 12:37:11 +00:00
|
|
|
textElement.setAttribute(QStringLiteral("intent"), (int)d->m_inplaceIntent);
|
2005-04-07 19:27:54 +00:00
|
|
|
|
2013-05-14 07:37:00 +00:00
|
|
|
// Sub-Node - callout
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_inplaceCallout[0].x != 0.0) {
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement calloutElement = document.createElement(QStringLiteral("callout"));
|
2005-03-18 18:49:45 +00:00
|
|
|
textElement.appendChild(calloutElement);
|
2015-10-29 12:37:11 +00:00
|
|
|
calloutElement.setAttribute(QStringLiteral("ax"), QString::number(d->m_inplaceCallout[0].x));
|
|
|
|
calloutElement.setAttribute(QStringLiteral("ay"), QString::number(d->m_inplaceCallout[0].y));
|
|
|
|
calloutElement.setAttribute(QStringLiteral("bx"), QString::number(d->m_inplaceCallout[1].x));
|
|
|
|
calloutElement.setAttribute(QStringLiteral("by"), QString::number(d->m_inplaceCallout[1].y));
|
|
|
|
calloutElement.setAttribute(QStringLiteral("cx"), QString::number(d->m_inplaceCallout[2].x));
|
|
|
|
calloutElement.setAttribute(QStringLiteral("cy"), QString::number(d->m_inplaceCallout[2].y));
|
2005-03-18 18:49:45 +00:00
|
|
|
}
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
}
|
2005-02-26 18:05:01 +00:00
|
|
|
|
2012-09-08 15:06:02 +00:00
|
|
|
void TextAnnotationPrivate::transform(const QTransform &matrix)
|
2006-11-20 07:53:32 +00:00
|
|
|
{
|
2007-05-04 20:45:45 +00:00
|
|
|
AnnotationPrivate::transform(matrix);
|
2006-11-20 07:53:32 +00:00
|
|
|
|
2020-01-02 23:16:36 +00:00
|
|
|
for (NormalizedPoint &np : m_transformedInplaceCallout) {
|
|
|
|
np.transform(matrix);
|
2006-11-20 07:53:32 +00:00
|
|
|
}
|
|
|
|
}
|
2005-02-26 18:05:01 +00:00
|
|
|
|
2012-09-08 15:06:02 +00:00
|
|
|
void TextAnnotationPrivate::baseTransform(const QTransform &matrix)
|
2007-10-07 10:52:05 +00:00
|
|
|
{
|
|
|
|
AnnotationPrivate::baseTransform(matrix);
|
|
|
|
|
2020-01-02 23:16:36 +00:00
|
|
|
for (NormalizedPoint &np : m_inplaceCallout) {
|
|
|
|
np.transform(matrix);
|
2007-10-07 10:52:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-22 20:49:27 +00:00
|
|
|
void TextAnnotationPrivate::resetTransformation()
|
|
|
|
{
|
|
|
|
AnnotationPrivate::resetTransformation();
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
|
|
m_transformedInplaceCallout[i] = m_inplaceCallout[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-22 20:20:24 +00:00
|
|
|
void TextAnnotationPrivate::translate(const NormalizedPoint &coord)
|
|
|
|
{
|
|
|
|
AnnotationPrivate::translate(coord);
|
|
|
|
|
|
|
|
#define ADD_COORD(c1, c2) \
|
|
|
|
{ \
|
|
|
|
c1.x = c1.x + c2.x; \
|
|
|
|
c1.y = c1.y + c2.y; \
|
|
|
|
}
|
|
|
|
ADD_COORD(m_inplaceCallout[0], coord)
|
|
|
|
ADD_COORD(m_inplaceCallout[1], coord)
|
|
|
|
ADD_COORD(m_inplaceCallout[2], coord)
|
|
|
|
#undef ADD_COORD
|
|
|
|
}
|
|
|
|
|
2010-12-27 22:16:11 +00:00
|
|
|
bool TextAnnotationPrivate::openDialogAfterCreation() const
|
|
|
|
{
|
|
|
|
return (m_textType == Okular::TextAnnotation::Linked);
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
void TextAnnotationPrivate::setAnnotationProperties(const QDomNode &node)
|
|
|
|
{
|
|
|
|
Okular::AnnotationPrivate::setAnnotationProperties(node);
|
|
|
|
|
|
|
|
// loop through the whole children looking for a 'text' element
|
|
|
|
QDomNode subNode = node.firstChild();
|
|
|
|
while (subNode.isElement()) {
|
|
|
|
QDomElement e = subNode.toElement();
|
|
|
|
subNode = subNode.nextSibling();
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.tagName() != QLatin1String("text"))
|
2013-04-05 22:22:48 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// parse the attributes
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.hasAttribute(QStringLiteral("type")))
|
|
|
|
m_textType = (TextAnnotation::TextType)e.attribute(QStringLiteral("type")).toInt();
|
|
|
|
if (e.hasAttribute(QStringLiteral("icon")))
|
|
|
|
m_textIcon = e.attribute(QStringLiteral("icon"));
|
|
|
|
if (e.hasAttribute(QStringLiteral("font")))
|
|
|
|
m_textFont.fromString(e.attribute(QStringLiteral("font")));
|
2018-10-03 14:31:40 +00:00
|
|
|
if (e.hasAttribute(QStringLiteral("fontColor")))
|
|
|
|
m_textColor = QColor(e.attribute(QStringLiteral("fontColor")));
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.hasAttribute(QStringLiteral("align")))
|
|
|
|
m_inplaceAlign = e.attribute(QStringLiteral("align")).toInt();
|
|
|
|
if (e.hasAttribute(QStringLiteral("intent")))
|
|
|
|
m_inplaceIntent = (TextAnnotation::InplaceIntent)e.attribute(QStringLiteral("intent")).toInt();
|
2013-04-05 22:22:48 +00:00
|
|
|
|
|
|
|
// parse the subnodes
|
|
|
|
QDomNode eSubNode = e.firstChild();
|
|
|
|
while (eSubNode.isElement()) {
|
|
|
|
QDomElement ee = eSubNode.toElement();
|
|
|
|
eSubNode = eSubNode.nextSibling();
|
|
|
|
|
2015-10-29 12:37:11 +00:00
|
|
|
if (ee.tagName() == QLatin1String("escapedText")) {
|
2013-05-14 07:37:00 +00:00
|
|
|
m_contents = ee.firstChild().toCDATASection().data();
|
2015-10-29 12:37:11 +00:00
|
|
|
} else if (ee.tagName() == QLatin1String("callout")) {
|
|
|
|
m_inplaceCallout[0].x = ee.attribute(QStringLiteral("ax")).toDouble();
|
|
|
|
m_inplaceCallout[0].y = ee.attribute(QStringLiteral("ay")).toDouble();
|
|
|
|
m_inplaceCallout[1].x = ee.attribute(QStringLiteral("bx")).toDouble();
|
|
|
|
m_inplaceCallout[1].y = ee.attribute(QStringLiteral("by")).toDouble();
|
|
|
|
m_inplaceCallout[2].x = ee.attribute(QStringLiteral("cx")).toDouble();
|
|
|
|
m_inplaceCallout[2].y = ee.attribute(QStringLiteral("cy")).toDouble();
|
2013-04-05 22:22:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// loading complete
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
|
|
m_transformedInplaceCallout[i] = m_inplaceCallout[i];
|
|
|
|
}
|
|
|
|
|
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
|
|
|
bool TextAnnotationPrivate::canBeResized() const
|
|
|
|
{
|
|
|
|
if (m_textType != TextAnnotation::Linked) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
AnnotationPrivate *TextAnnotationPrivate::getNewAnnotationPrivate()
|
|
|
|
{
|
|
|
|
return new TextAnnotationPrivate();
|
|
|
|
}
|
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
/** LineAnnotation [Annotation] */
|
2005-02-26 18:05:01 +00:00
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
class Okular::LineAnnotationPrivate : public Okular::AnnotationPrivate
|
2006-12-18 07:28:02 +00:00
|
|
|
{
|
|
|
|
public:
|
2007-05-04 20:24:12 +00:00
|
|
|
LineAnnotationPrivate()
|
|
|
|
: AnnotationPrivate()
|
|
|
|
, m_lineStartStyle(LineAnnotation::None)
|
|
|
|
, m_lineEndStyle(LineAnnotation::None)
|
2007-09-07 13:13:50 +00:00
|
|
|
, m_lineClosed(false)
|
|
|
|
, m_lineShowCaption(false)
|
|
|
|
, m_lineLeadingFwdPt(0)
|
|
|
|
, m_lineLeadingBackPt(0)
|
|
|
|
, m_lineIntent(LineAnnotation::Unknown)
|
2006-12-18 07:28:02 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-10-29 14:38:19 +00:00
|
|
|
void transform(const QTransform &matrix) override;
|
|
|
|
void baseTransform(const QTransform &matrix) override;
|
|
|
|
void resetTransformation() override;
|
|
|
|
void translate(const NormalizedPoint &coord) override;
|
2019-12-03 23:23:26 +00:00
|
|
|
double distanceSqr(double x, double y, double xScale, double yScale) const override;
|
2016-10-29 14:38:19 +00:00
|
|
|
void setAnnotationProperties(const QDomNode &node) override;
|
|
|
|
AnnotationPrivate *getNewAnnotationPrivate() override;
|
2020-07-10 22:15:05 +00:00
|
|
|
|
2006-12-18 07:28:02 +00:00
|
|
|
QLinkedList<NormalizedPoint> m_linePoints;
|
|
|
|
QLinkedList<NormalizedPoint> m_transformedLinePoints;
|
2007-05-04 20:24:12 +00:00
|
|
|
LineAnnotation::TermStyle m_lineStartStyle;
|
|
|
|
LineAnnotation::TermStyle m_lineEndStyle;
|
2007-09-07 13:13:50 +00:00
|
|
|
bool m_lineClosed : 1;
|
|
|
|
bool m_lineShowCaption : 1;
|
2006-12-18 07:28:02 +00:00
|
|
|
QColor m_lineInnerColor;
|
|
|
|
double m_lineLeadingFwdPt;
|
|
|
|
double m_lineLeadingBackPt;
|
2007-05-04 20:24:12 +00:00
|
|
|
LineAnnotation::LineIntent m_lineIntent;
|
2006-12-18 07:28:02 +00:00
|
|
|
};
|
|
|
|
|
2005-03-04 23:06:24 +00:00
|
|
|
LineAnnotation::LineAnnotation()
|
2007-05-04 20:24:12 +00:00
|
|
|
: Annotation(*new LineAnnotationPrivate())
|
2006-12-11 07:59:02 +00:00
|
|
|
{
|
|
|
|
}
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
LineAnnotation::LineAnnotation(const QDomNode &description)
|
|
|
|
: Annotation(*new LineAnnotationPrivate(), description)
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
{
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LineAnnotation::~LineAnnotation()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void LineAnnotation::setLinePoints(const QLinkedList<NormalizedPoint> &points)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_linePoints = points;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QLinkedList<NormalizedPoint> LineAnnotation::linePoints() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_linePoints;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QLinkedList<NormalizedPoint> LineAnnotation::transformedLinePoints() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_transformedLinePoints;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void LineAnnotation::setLineStartStyle(TermStyle style)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_lineStartStyle = style;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LineAnnotation::TermStyle LineAnnotation::lineStartStyle() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_lineStartStyle;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void LineAnnotation::setLineEndStyle(TermStyle style)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_lineEndStyle = style;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LineAnnotation::TermStyle LineAnnotation::lineEndStyle() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_lineEndStyle;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void LineAnnotation::setLineClosed(bool closed)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_lineClosed = closed;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool LineAnnotation::lineClosed() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_lineClosed;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void LineAnnotation::setLineInnerColor(const QColor &color)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_lineInnerColor = color;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QColor LineAnnotation::lineInnerColor() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_lineInnerColor;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void LineAnnotation::setLineLeadingForwardPoint(double point)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_lineLeadingFwdPt = point;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double LineAnnotation::lineLeadingForwardPoint() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_lineLeadingFwdPt;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void LineAnnotation::setLineLeadingBackwardPoint(double point)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_lineLeadingBackPt = point;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double LineAnnotation::lineLeadingBackwardPoint() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_lineLeadingBackPt;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void LineAnnotation::setShowCaption(bool show)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_lineShowCaption = show;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool LineAnnotation::showCaption() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_lineShowCaption;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void LineAnnotation::setLineIntent(LineIntent intent)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_lineIntent = intent;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LineAnnotation::LineIntent LineAnnotation::lineIntent() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const LineAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_lineIntent;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::SubType LineAnnotation::subType() const
|
|
|
|
{
|
|
|
|
return ALine;
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
}
|
|
|
|
|
2005-03-13 13:14:44 +00:00
|
|
|
void LineAnnotation::store(QDomNode &node, QDomDocument &document) const
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const LineAnnotation);
|
2005-03-18 18:49:45 +00:00
|
|
|
// recurse to parent objects storing properties
|
2005-04-04 23:55:40 +00:00
|
|
|
Annotation::store(node, document);
|
2005-03-18 18:49:45 +00:00
|
|
|
|
|
|
|
// create [line] element
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement lineElement = document.createElement(QStringLiteral("line"));
|
2005-03-18 18:49:45 +00:00
|
|
|
node.appendChild(lineElement);
|
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
// store the attributes
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_lineStartStyle != None)
|
2015-10-29 12:37:11 +00:00
|
|
|
lineElement.setAttribute(QStringLiteral("startStyle"), (int)d->m_lineStartStyle);
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_lineEndStyle != None)
|
2015-10-29 12:37:11 +00:00
|
|
|
lineElement.setAttribute(QStringLiteral("endStyle"), (int)d->m_lineEndStyle);
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_lineClosed)
|
2015-10-29 12:37:11 +00:00
|
|
|
lineElement.setAttribute(QStringLiteral("closed"), d->m_lineClosed);
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_lineInnerColor.isValid())
|
2015-10-29 12:37:11 +00:00
|
|
|
lineElement.setAttribute(QStringLiteral("innerColor"), d->m_lineInnerColor.name());
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_lineLeadingFwdPt != 0.0)
|
2015-10-29 12:37:11 +00:00
|
|
|
lineElement.setAttribute(QStringLiteral("leadFwd"), QString::number(d->m_lineLeadingFwdPt));
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_lineLeadingBackPt != 0.0)
|
2015-10-29 12:37:11 +00:00
|
|
|
lineElement.setAttribute(QStringLiteral("leadBack"), QString::number(d->m_lineLeadingBackPt));
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_lineShowCaption)
|
2015-10-29 12:37:11 +00:00
|
|
|
lineElement.setAttribute(QStringLiteral("showCaption"), d->m_lineShowCaption);
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_lineIntent != Unknown)
|
2015-10-29 12:37:11 +00:00
|
|
|
lineElement.setAttribute(QStringLiteral("intent"), d->m_lineIntent);
|
2005-04-07 19:27:54 +00:00
|
|
|
|
|
|
|
// append the list of points
|
2006-12-18 07:28:02 +00:00
|
|
|
int points = d->m_linePoints.count();
|
2005-04-07 19:27:54 +00:00
|
|
|
if (points > 1) {
|
2006-12-18 07:28:02 +00:00
|
|
|
QLinkedList<NormalizedPoint>::const_iterator it = d->m_linePoints.begin(), end = d->m_linePoints.end();
|
2005-04-07 19:27:54 +00:00
|
|
|
while (it != end) {
|
|
|
|
const NormalizedPoint &p = *it;
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement pElement = document.createElement(QStringLiteral("point"));
|
2005-04-07 19:27:54 +00:00
|
|
|
lineElement.appendChild(pElement);
|
2015-10-29 12:37:11 +00:00
|
|
|
pElement.setAttribute(QStringLiteral("x"), QString::number(p.x));
|
|
|
|
pElement.setAttribute(QStringLiteral("y"), QString::number(p.y));
|
2006-12-11 07:59:02 +00:00
|
|
|
it++; // to avoid loop
|
2005-04-07 19:27:54 +00:00
|
|
|
}
|
|
|
|
}
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
}
|
2005-02-26 18:05:01 +00:00
|
|
|
|
2012-09-08 15:06:02 +00:00
|
|
|
void LineAnnotationPrivate::transform(const QTransform &matrix)
|
2006-11-20 07:53:32 +00:00
|
|
|
{
|
2007-05-04 20:45:45 +00:00
|
|
|
AnnotationPrivate::transform(matrix);
|
2006-11-20 07:53:32 +00:00
|
|
|
|
2007-05-04 20:45:45 +00:00
|
|
|
QMutableLinkedListIterator<NormalizedPoint> it(m_transformedLinePoints);
|
2006-11-20 07:53:32 +00:00
|
|
|
while (it.hasNext())
|
|
|
|
it.next().transform(matrix);
|
|
|
|
}
|
2005-02-26 18:05:01 +00:00
|
|
|
|
2012-09-08 15:06:02 +00:00
|
|
|
void LineAnnotationPrivate::baseTransform(const QTransform &matrix)
|
2007-10-07 10:52:05 +00:00
|
|
|
{
|
|
|
|
AnnotationPrivate::baseTransform(matrix);
|
|
|
|
|
|
|
|
QMutableLinkedListIterator<NormalizedPoint> it(m_linePoints);
|
|
|
|
while (it.hasNext())
|
|
|
|
it.next().transform(matrix);
|
|
|
|
}
|
|
|
|
|
2007-07-22 20:49:27 +00:00
|
|
|
void LineAnnotationPrivate::resetTransformation()
|
|
|
|
{
|
|
|
|
AnnotationPrivate::resetTransformation();
|
|
|
|
|
|
|
|
m_transformedLinePoints = m_linePoints;
|
|
|
|
}
|
|
|
|
|
2007-07-17 18:10:25 +00:00
|
|
|
void LineAnnotationPrivate::translate(const NormalizedPoint &coord)
|
|
|
|
{
|
|
|
|
AnnotationPrivate::translate(coord);
|
|
|
|
|
|
|
|
QMutableLinkedListIterator<NormalizedPoint> it(m_linePoints);
|
|
|
|
while (it.hasNext()) {
|
|
|
|
NormalizedPoint &p = it.next();
|
|
|
|
p.x = p.x + coord.x;
|
|
|
|
p.y = p.y + coord.y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
void LineAnnotationPrivate::setAnnotationProperties(const QDomNode &node)
|
|
|
|
{
|
|
|
|
Okular::AnnotationPrivate::setAnnotationProperties(node);
|
|
|
|
|
|
|
|
// loop through the whole children looking for a 'line' element
|
|
|
|
QDomNode subNode = node.firstChild();
|
|
|
|
while (subNode.isElement()) {
|
|
|
|
QDomElement e = subNode.toElement();
|
|
|
|
subNode = subNode.nextSibling();
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.tagName() != QLatin1String("line"))
|
2013-04-05 22:22:48 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// parse the attributes
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.hasAttribute(QStringLiteral("startStyle")))
|
|
|
|
m_lineStartStyle = (LineAnnotation::TermStyle)e.attribute(QStringLiteral("startStyle")).toInt();
|
|
|
|
if (e.hasAttribute(QStringLiteral("endStyle")))
|
|
|
|
m_lineEndStyle = (LineAnnotation::TermStyle)e.attribute(QStringLiteral("endStyle")).toInt();
|
|
|
|
if (e.hasAttribute(QStringLiteral("closed")))
|
|
|
|
m_lineClosed = e.attribute(QStringLiteral("closed")).toInt();
|
|
|
|
if (e.hasAttribute(QStringLiteral("innerColor")))
|
|
|
|
m_lineInnerColor = QColor(e.attribute(QStringLiteral("innerColor")));
|
|
|
|
if (e.hasAttribute(QStringLiteral("leadFwd")))
|
|
|
|
m_lineLeadingFwdPt = e.attribute(QStringLiteral("leadFwd")).toDouble();
|
|
|
|
if (e.hasAttribute(QStringLiteral("leadBack")))
|
|
|
|
m_lineLeadingBackPt = e.attribute(QStringLiteral("leadBack")).toDouble();
|
|
|
|
if (e.hasAttribute(QStringLiteral("showCaption")))
|
|
|
|
m_lineShowCaption = e.attribute(QStringLiteral("showCaption")).toInt();
|
|
|
|
if (e.hasAttribute(QStringLiteral("intent")))
|
|
|
|
m_lineIntent = (LineAnnotation::LineIntent)e.attribute(QStringLiteral("intent")).toInt();
|
2013-04-05 22:22:48 +00:00
|
|
|
|
|
|
|
// parse all 'point' subnodes
|
|
|
|
QDomNode pointNode = e.firstChild();
|
|
|
|
while (pointNode.isElement()) {
|
|
|
|
QDomElement pe = pointNode.toElement();
|
|
|
|
pointNode = pointNode.nextSibling();
|
|
|
|
|
2015-10-29 12:37:11 +00:00
|
|
|
if (pe.tagName() != QLatin1String("point"))
|
2013-04-05 22:22:48 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
NormalizedPoint p;
|
2015-10-29 12:37:11 +00:00
|
|
|
p.x = pe.attribute(QStringLiteral("x"), QStringLiteral("0.0")).toDouble();
|
|
|
|
p.y = pe.attribute(QStringLiteral("y"), QStringLiteral("0.0")).toDouble();
|
2013-04-05 22:22:48 +00:00
|
|
|
m_linePoints.append(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
// loading complete
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_transformedLinePoints = m_linePoints;
|
|
|
|
}
|
|
|
|
|
|
|
|
AnnotationPrivate *LineAnnotationPrivate::getNewAnnotationPrivate()
|
|
|
|
{
|
|
|
|
return new LineAnnotationPrivate();
|
|
|
|
}
|
|
|
|
|
2019-12-03 23:23:26 +00:00
|
|
|
double LineAnnotationPrivate::distanceSqr(double x, double y, double xScale, double yScale) const
|
2013-06-23 17:19:25 +00:00
|
|
|
{
|
2013-07-01 20:19:28 +00:00
|
|
|
QLinkedList<NormalizedPoint> transformedLinePoints = m_transformedLinePoints;
|
|
|
|
|
|
|
|
if (m_lineClosed) // Close the path
|
|
|
|
transformedLinePoints.append(transformedLinePoints.first());
|
|
|
|
|
2013-07-01 22:44:15 +00:00
|
|
|
if (m_lineInnerColor.isValid()) {
|
|
|
|
QPolygonF polygon;
|
2019-12-09 13:16:55 +00:00
|
|
|
for (const NormalizedPoint &p : qAsConst(transformedLinePoints))
|
2013-07-01 22:44:15 +00:00
|
|
|
polygon.append(QPointF(p.x, p.y));
|
|
|
|
|
|
|
|
if (polygon.containsPoint(QPointF(x, y), Qt::WindingFill))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-01 20:19:28 +00:00
|
|
|
return strokeDistance(::distanceSqr(x, y, xScale, yScale, transformedLinePoints), m_style.width() * xScale / (m_page->m_width * 2));
|
2013-06-23 17:19:25 +00:00
|
|
|
}
|
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
/** GeomAnnotation [Annotation] */
|
2005-02-26 18:05:01 +00:00
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
class Okular::GeomAnnotationPrivate : public Okular::AnnotationPrivate
|
2006-12-18 07:28:02 +00:00
|
|
|
{
|
|
|
|
public:
|
2007-05-04 20:24:12 +00:00
|
|
|
GeomAnnotationPrivate()
|
2008-04-06 23:12:04 +00:00
|
|
|
: AnnotationPrivate()
|
|
|
|
, m_geomType(GeomAnnotation::InscribedSquare)
|
2006-12-18 07:28:02 +00:00
|
|
|
{
|
|
|
|
}
|
2016-10-29 14:38:19 +00:00
|
|
|
void setAnnotationProperties(const QDomNode &node) override;
|
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
|
|
|
bool canBeResized() const override;
|
2016-10-29 14:38:19 +00:00
|
|
|
AnnotationPrivate *getNewAnnotationPrivate() override;
|
2019-12-03 23:23:26 +00:00
|
|
|
double distanceSqr(double x, double y, double xScale, double yScale) const override;
|
2006-12-18 07:28:02 +00:00
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
GeomAnnotation::GeomType m_geomType;
|
2006-12-18 07:28:02 +00:00
|
|
|
QColor m_geomInnerColor;
|
|
|
|
};
|
|
|
|
|
2005-03-04 23:06:24 +00:00
|
|
|
GeomAnnotation::GeomAnnotation()
|
2007-05-04 20:24:12 +00:00
|
|
|
: Annotation(*new GeomAnnotationPrivate())
|
2006-12-18 07:28:02 +00:00
|
|
|
{
|
|
|
|
}
|
2005-02-26 18:05:01 +00:00
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
GeomAnnotation::GeomAnnotation(const QDomNode &description)
|
|
|
|
: Annotation(*new GeomAnnotationPrivate(), description)
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
{
|
|
|
|
}
|
2005-02-26 18:05:01 +00:00
|
|
|
|
2006-12-11 07:59:02 +00:00
|
|
|
GeomAnnotation::~GeomAnnotation()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void GeomAnnotation::setGeometricalType(GeomType type)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(GeomAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_geomType = type;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GeomAnnotation::GeomType GeomAnnotation::geometricalType() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const GeomAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_geomType;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GeomAnnotation::setGeometricalInnerColor(const QColor &color)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(GeomAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_geomInnerColor = color;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QColor GeomAnnotation::geometricalInnerColor() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const GeomAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_geomInnerColor;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::SubType GeomAnnotation::subType() const
|
|
|
|
{
|
|
|
|
return AGeom;
|
|
|
|
}
|
|
|
|
|
2005-03-13 13:14:44 +00:00
|
|
|
void GeomAnnotation::store(QDomNode &node, QDomDocument &document) const
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const GeomAnnotation);
|
2005-03-18 18:49:45 +00:00
|
|
|
// recurse to parent objects storing properties
|
2005-04-04 23:55:40 +00:00
|
|
|
Annotation::store(node, document);
|
2005-03-18 18:49:45 +00:00
|
|
|
|
|
|
|
// create [geom] element
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement geomElement = document.createElement(QStringLiteral("geom"));
|
2005-03-18 18:49:45 +00:00
|
|
|
node.appendChild(geomElement);
|
|
|
|
|
|
|
|
// append the optional attributes
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_geomType != InscribedSquare)
|
2015-10-29 12:37:11 +00:00
|
|
|
geomElement.setAttribute(QStringLiteral("type"), (int)d->m_geomType);
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_geomInnerColor.isValid())
|
2015-10-29 12:37:11 +00:00
|
|
|
geomElement.setAttribute(QStringLiteral("color"), d->m_geomInnerColor.name());
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
}
|
2005-02-26 18:05:01 +00:00
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
void GeomAnnotationPrivate::setAnnotationProperties(const QDomNode &node)
|
|
|
|
{
|
|
|
|
Okular::AnnotationPrivate::setAnnotationProperties(node);
|
|
|
|
// loop through the whole children looking for a 'geom' element
|
|
|
|
QDomNode subNode = node.firstChild();
|
|
|
|
while (subNode.isElement()) {
|
|
|
|
QDomElement e = subNode.toElement();
|
|
|
|
subNode = subNode.nextSibling();
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.tagName() != QLatin1String("geom"))
|
2013-04-05 22:22:48 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// parse the attributes
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.hasAttribute(QStringLiteral("type")))
|
|
|
|
m_geomType = (GeomAnnotation::GeomType)e.attribute(QStringLiteral("type")).toInt();
|
|
|
|
if (e.hasAttribute(QStringLiteral("color")))
|
|
|
|
m_geomInnerColor = QColor(e.attribute(QStringLiteral("color")));
|
2013-04-05 22:22:48 +00:00
|
|
|
// compatibility
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.hasAttribute(QStringLiteral("width")))
|
|
|
|
m_style.setWidth(e.attribute(QStringLiteral("width")).toInt());
|
2013-04-05 22:22:48 +00:00
|
|
|
|
|
|
|
// loading complete
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
|
|
|
bool GeomAnnotationPrivate::canBeResized() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
AnnotationPrivate *GeomAnnotationPrivate::getNewAnnotationPrivate()
|
|
|
|
{
|
|
|
|
return new GeomAnnotationPrivate();
|
|
|
|
}
|
|
|
|
|
2019-12-03 23:23:26 +00:00
|
|
|
double GeomAnnotationPrivate::distanceSqr(double x, double y, double xScale, double yScale) const
|
2013-06-23 17:19:25 +00:00
|
|
|
{
|
|
|
|
double distance = 0;
|
|
|
|
// the line thickness is applied unevenly (only on the "inside") - account for this
|
|
|
|
bool withinShape = false;
|
|
|
|
switch (m_geomType) {
|
|
|
|
case GeomAnnotation::InscribedCircle: {
|
|
|
|
// calculate the center point and focus lengths of the ellipse
|
|
|
|
const double centerX = (m_transformedBoundary.left + m_transformedBoundary.right) / 2.0;
|
|
|
|
const double centerY = (m_transformedBoundary.top + m_transformedBoundary.bottom) / 2.0;
|
|
|
|
const double focusX = (m_transformedBoundary.right - centerX);
|
|
|
|
const double focusY = (m_transformedBoundary.bottom - centerY);
|
2020-07-10 22:15:05 +00:00
|
|
|
|
2013-06-23 17:19:25 +00:00
|
|
|
const double focusXSqr = pow(focusX, 2);
|
|
|
|
const double focusYSqr = pow(focusY, 2);
|
2020-07-10 22:15:05 +00:00
|
|
|
|
2013-06-23 17:19:25 +00:00
|
|
|
// to calculate the distance from the ellipse, we will first find the point "projection"
|
|
|
|
// that lies on the ellipse and is closest to the point (x,y)
|
|
|
|
// This point can obviously be written as "center + lambda(inputPoint - center)".
|
|
|
|
// Because the point lies on the ellipse, we know that:
|
|
|
|
// 1 = ((center.x - projection.x)/focusX)^2 + ((center.y - projection.y)/focusY)^2
|
|
|
|
// After filling in projection.x = center.x + lambda * (inputPoint.x - center.x)
|
|
|
|
// and its y-equivalent, we can solve for lambda:
|
|
|
|
const double lambda = sqrt(focusXSqr * focusYSqr / (focusYSqr * pow(x - centerX, 2) + focusXSqr * pow(y - centerY, 2)));
|
2020-07-10 22:15:05 +00:00
|
|
|
|
2013-06-23 17:19:25 +00:00
|
|
|
// if the ellipse is filled, we treat all points within as "on" it
|
|
|
|
if (lambda > 1) {
|
|
|
|
if (m_geomInnerColor.isValid())
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
withinShape = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise we calculate the squared distance from the projected point on the ellipse
|
|
|
|
NormalizedPoint projection(centerX, centerY);
|
|
|
|
projection.x += lambda * (x - centerX);
|
|
|
|
projection.y += lambda * (y - centerY);
|
|
|
|
|
|
|
|
distance = projection.distanceSqr(x, y, xScale, yScale);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case GeomAnnotation::InscribedSquare:
|
|
|
|
// if the square is filled, only check the bounding box
|
|
|
|
if (m_geomInnerColor.isValid())
|
|
|
|
return AnnotationPrivate::distanceSqr(x, y, xScale, yScale);
|
|
|
|
|
|
|
|
QLinkedList<NormalizedPoint> edges;
|
|
|
|
edges << NormalizedPoint(m_transformedBoundary.left, m_transformedBoundary.top);
|
|
|
|
edges << NormalizedPoint(m_transformedBoundary.right, m_transformedBoundary.top);
|
|
|
|
edges << NormalizedPoint(m_transformedBoundary.right, m_transformedBoundary.bottom);
|
|
|
|
edges << NormalizedPoint(m_transformedBoundary.left, m_transformedBoundary.bottom);
|
|
|
|
edges << NormalizedPoint(m_transformedBoundary.left, m_transformedBoundary.top);
|
|
|
|
distance = ::distanceSqr(x, y, xScale, yScale, edges);
|
|
|
|
|
|
|
|
if (m_transformedBoundary.contains(x, y))
|
|
|
|
withinShape = true;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (withinShape)
|
|
|
|
distance = strokeDistance(distance, m_style.width() * xScale / m_page->m_width);
|
|
|
|
|
|
|
|
return distance;
|
|
|
|
}
|
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
/** HighlightAnnotation [Annotation] */
|
2005-02-26 18:05:01 +00:00
|
|
|
|
2006-12-18 07:28:02 +00:00
|
|
|
class HighlightAnnotation::Quad::Private
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Private()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
NormalizedPoint m_points[4];
|
|
|
|
NormalizedPoint m_transformedPoints[4];
|
2007-09-07 13:13:50 +00:00
|
|
|
bool m_capStart : 1;
|
|
|
|
bool m_capEnd : 1;
|
2006-12-18 07:28:02 +00:00
|
|
|
double m_feather;
|
|
|
|
};
|
|
|
|
|
2006-12-11 07:59:02 +00:00
|
|
|
HighlightAnnotation::Quad::Quad()
|
2006-12-18 07:28:02 +00:00
|
|
|
: d(new Private)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
HighlightAnnotation::Quad::~Quad()
|
2006-12-11 07:59:02 +00:00
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
HighlightAnnotation::Quad::Quad(const Quad &other)
|
|
|
|
: d(new Private)
|
|
|
|
{
|
|
|
|
*d = *other.d;
|
|
|
|
}
|
|
|
|
|
|
|
|
HighlightAnnotation::Quad &HighlightAnnotation::Quad::operator=(const Quad &other)
|
|
|
|
{
|
|
|
|
if (this != &other)
|
|
|
|
*d = *other.d;
|
|
|
|
|
|
|
|
return *this;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void HighlightAnnotation::Quad::setPoint(const NormalizedPoint &point, int index)
|
|
|
|
{
|
|
|
|
if (index < 0 || index > 3)
|
|
|
|
return;
|
|
|
|
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_points[index] = point;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NormalizedPoint HighlightAnnotation::Quad::point(int index) const
|
|
|
|
{
|
|
|
|
if (index < 0 || index > 3)
|
|
|
|
return NormalizedPoint();
|
|
|
|
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_points[index];
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NormalizedPoint HighlightAnnotation::Quad::transformedPoint(int index) const
|
|
|
|
{
|
|
|
|
if (index < 0 || index > 3)
|
|
|
|
return NormalizedPoint();
|
|
|
|
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_transformedPoints[index];
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void HighlightAnnotation::Quad::setCapStart(bool value)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_capStart = value;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool HighlightAnnotation::Quad::capStart() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_capStart;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void HighlightAnnotation::Quad::setCapEnd(bool value)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_capEnd = value;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool HighlightAnnotation::Quad::capEnd() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_capEnd;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void HighlightAnnotation::Quad::setFeather(double width)
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_feather = width;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double HighlightAnnotation::Quad::feather() const
|
|
|
|
{
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_feather;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
2012-09-08 15:06:02 +00:00
|
|
|
void HighlightAnnotation::Quad::transform(const QTransform &matrix)
|
2006-12-11 07:59:02 +00:00
|
|
|
{
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_transformedPoints[i] = d->m_points[i];
|
|
|
|
d->m_transformedPoints[i].transform(matrix);
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
class Okular::HighlightAnnotationPrivate : public Okular::AnnotationPrivate
|
2006-12-18 07:28:02 +00:00
|
|
|
{
|
|
|
|
public:
|
2007-05-04 20:24:12 +00:00
|
|
|
HighlightAnnotationPrivate()
|
|
|
|
: AnnotationPrivate()
|
|
|
|
, m_highlightType(HighlightAnnotation::Highlight)
|
2006-12-18 07:28:02 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-10-29 14:38:19 +00:00
|
|
|
void transform(const QTransform &matrix) override;
|
|
|
|
void baseTransform(const QTransform &matrix) override;
|
2019-12-03 23:23:26 +00:00
|
|
|
double distanceSqr(double x, double y, double xScale, double yScale) const override;
|
2016-10-29 14:38:19 +00:00
|
|
|
void setAnnotationProperties(const QDomNode &node) override;
|
|
|
|
AnnotationPrivate *getNewAnnotationPrivate() override;
|
2007-05-04 20:45:45 +00:00
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
HighlightAnnotation::HighlightType m_highlightType;
|
|
|
|
QList<HighlightAnnotation::Quad> m_highlightQuads;
|
2006-12-18 07:28:02 +00:00
|
|
|
};
|
|
|
|
|
2005-03-04 23:06:24 +00:00
|
|
|
HighlightAnnotation::HighlightAnnotation()
|
2007-05-04 20:24:12 +00:00
|
|
|
: Annotation(*new HighlightAnnotationPrivate())
|
2006-12-11 07:59:02 +00:00
|
|
|
{
|
|
|
|
}
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
HighlightAnnotation::HighlightAnnotation(const QDomNode &description)
|
|
|
|
: Annotation(*new HighlightAnnotationPrivate(), description)
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-12-11 07:59:02 +00:00
|
|
|
HighlightAnnotation::~HighlightAnnotation()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void HighlightAnnotation::setHighlightType(HighlightType type)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(HighlightAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_highlightType = type;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HighlightAnnotation::HighlightType HighlightAnnotation::highlightType() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const HighlightAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_highlightType;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QList<HighlightAnnotation::Quad> &HighlightAnnotation::highlightQuads()
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(HighlightAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_highlightQuads;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
2005-03-13 13:14:44 +00:00
|
|
|
void HighlightAnnotation::store(QDomNode &node, QDomDocument &document) const
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const HighlightAnnotation);
|
2005-03-18 18:49:45 +00:00
|
|
|
// recurse to parent objects storing properties
|
2005-04-04 23:55:40 +00:00
|
|
|
Annotation::store(node, document);
|
2005-03-18 18:49:45 +00:00
|
|
|
|
|
|
|
// create [hl] element
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement hlElement = document.createElement(QStringLiteral("hl"));
|
2005-03-18 18:49:45 +00:00
|
|
|
node.appendChild(hlElement);
|
|
|
|
|
|
|
|
// append the optional attributes
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_highlightType != Highlight)
|
2015-10-29 12:37:11 +00:00
|
|
|
hlElement.setAttribute(QStringLiteral("type"), (int)d->m_highlightType);
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_highlightQuads.count() < 1)
|
2005-03-18 18:49:45 +00:00
|
|
|
return;
|
|
|
|
// append highlight quads, all children describe quads
|
2006-12-18 07:28:02 +00:00
|
|
|
QList<Quad>::const_iterator it = d->m_highlightQuads.begin(), end = d->m_highlightQuads.end();
|
2005-03-18 18:49:45 +00:00
|
|
|
for (; it != end; ++it) {
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement quadElement = document.createElement(QStringLiteral("quad"));
|
2005-03-18 18:49:45 +00:00
|
|
|
hlElement.appendChild(quadElement);
|
2005-04-08 08:58:49 +00:00
|
|
|
const Quad &q = *it;
|
2015-10-29 12:37:11 +00:00
|
|
|
quadElement.setAttribute(QStringLiteral("ax"), QString::number(q.point(0).x));
|
|
|
|
quadElement.setAttribute(QStringLiteral("ay"), QString::number(q.point(0).y));
|
|
|
|
quadElement.setAttribute(QStringLiteral("bx"), QString::number(q.point(1).x));
|
|
|
|
quadElement.setAttribute(QStringLiteral("by"), QString::number(q.point(1).y));
|
|
|
|
quadElement.setAttribute(QStringLiteral("cx"), QString::number(q.point(2).x));
|
|
|
|
quadElement.setAttribute(QStringLiteral("cy"), QString::number(q.point(2).y));
|
|
|
|
quadElement.setAttribute(QStringLiteral("dx"), QString::number(q.point(3).x));
|
|
|
|
quadElement.setAttribute(QStringLiteral("dy"), QString::number(q.point(3).y));
|
2006-12-11 07:59:02 +00:00
|
|
|
if (q.capStart())
|
2015-10-29 12:37:11 +00:00
|
|
|
quadElement.setAttribute(QStringLiteral("start"), 1);
|
2006-12-11 07:59:02 +00:00
|
|
|
if (q.capEnd())
|
2015-10-29 12:37:11 +00:00
|
|
|
quadElement.setAttribute(QStringLiteral("end"), 1);
|
|
|
|
quadElement.setAttribute(QStringLiteral("feather"), QString::number(q.feather()));
|
2005-03-18 18:49:45 +00:00
|
|
|
}
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
}
|
2005-02-26 18:05:01 +00:00
|
|
|
|
2006-12-11 07:59:02 +00:00
|
|
|
Annotation::SubType HighlightAnnotation::subType() const
|
|
|
|
{
|
|
|
|
return AHighlight;
|
|
|
|
}
|
|
|
|
|
2012-09-08 15:06:02 +00:00
|
|
|
void HighlightAnnotationPrivate::transform(const QTransform &matrix)
|
2006-11-20 07:53:32 +00:00
|
|
|
{
|
2007-05-04 20:45:45 +00:00
|
|
|
AnnotationPrivate::transform(matrix);
|
2006-11-20 07:53:32 +00:00
|
|
|
|
2007-05-04 20:45:45 +00:00
|
|
|
QMutableListIterator<HighlightAnnotation::Quad> it(m_highlightQuads);
|
2006-12-11 07:59:02 +00:00
|
|
|
while (it.hasNext())
|
|
|
|
it.next().transform(matrix);
|
2006-11-20 07:53:32 +00:00
|
|
|
}
|
2005-02-26 18:05:01 +00:00
|
|
|
|
2012-09-08 15:06:02 +00:00
|
|
|
void HighlightAnnotationPrivate::baseTransform(const QTransform &matrix)
|
2007-10-07 10:52:05 +00:00
|
|
|
{
|
|
|
|
AnnotationPrivate::baseTransform(matrix);
|
|
|
|
|
|
|
|
QMutableListIterator<HighlightAnnotation::Quad> it(m_highlightQuads);
|
|
|
|
while (it.hasNext())
|
|
|
|
it.next().transform(matrix);
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
void HighlightAnnotationPrivate::setAnnotationProperties(const QDomNode &node)
|
|
|
|
{
|
|
|
|
Okular::AnnotationPrivate::setAnnotationProperties(node);
|
|
|
|
m_highlightQuads.clear();
|
|
|
|
|
|
|
|
// loop through the whole children looking for a 'hl' element
|
|
|
|
QDomNode subNode = node.firstChild();
|
|
|
|
while (subNode.isElement()) {
|
|
|
|
QDomElement e = subNode.toElement();
|
|
|
|
subNode = subNode.nextSibling();
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.tagName() != QLatin1String("hl"))
|
2013-04-05 22:22:48 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// parse the attributes
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.hasAttribute(QStringLiteral("type")))
|
|
|
|
m_highlightType = (HighlightAnnotation::HighlightType)e.attribute(QStringLiteral("type")).toInt();
|
2013-04-05 22:22:48 +00:00
|
|
|
|
|
|
|
// parse all 'quad' subnodes
|
|
|
|
QDomNode quadNode = e.firstChild();
|
|
|
|
for (; quadNode.isElement(); quadNode = quadNode.nextSibling()) {
|
|
|
|
QDomElement qe = quadNode.toElement();
|
2015-10-29 12:37:11 +00:00
|
|
|
if (qe.tagName() != QLatin1String("quad"))
|
2013-04-05 22:22:48 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
HighlightAnnotation::Quad q;
|
2015-10-29 12:37:11 +00:00
|
|
|
q.setPoint(NormalizedPoint(qe.attribute(QStringLiteral("ax"), QStringLiteral("0.0")).toDouble(), qe.attribute(QStringLiteral("ay"), QStringLiteral("0.0")).toDouble()), 0);
|
|
|
|
q.setPoint(NormalizedPoint(qe.attribute(QStringLiteral("bx"), QStringLiteral("0.0")).toDouble(), qe.attribute(QStringLiteral("by"), QStringLiteral("0.0")).toDouble()), 1);
|
|
|
|
q.setPoint(NormalizedPoint(qe.attribute(QStringLiteral("cx"), QStringLiteral("0.0")).toDouble(), qe.attribute(QStringLiteral("cy"), QStringLiteral("0.0")).toDouble()), 2);
|
|
|
|
q.setPoint(NormalizedPoint(qe.attribute(QStringLiteral("dx"), QStringLiteral("0.0")).toDouble(), qe.attribute(QStringLiteral("dy"), QStringLiteral("0.0")).toDouble()), 3);
|
|
|
|
q.setCapStart(qe.hasAttribute(QStringLiteral("start")));
|
|
|
|
q.setCapEnd(qe.hasAttribute(QStringLiteral("end")));
|
|
|
|
q.setFeather(qe.attribute(QStringLiteral("feather"), QStringLiteral("0.1")).toDouble());
|
2013-04-05 22:22:48 +00:00
|
|
|
|
|
|
|
q.transform(QTransform());
|
|
|
|
|
|
|
|
m_highlightQuads.append(q);
|
|
|
|
}
|
|
|
|
|
|
|
|
// loading complete
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AnnotationPrivate *HighlightAnnotationPrivate::getNewAnnotationPrivate()
|
|
|
|
{
|
|
|
|
return new HighlightAnnotationPrivate();
|
|
|
|
}
|
|
|
|
|
2019-12-03 23:23:26 +00:00
|
|
|
double HighlightAnnotationPrivate::distanceSqr(double x, double y, double xScale, double yScale) const
|
2013-06-23 17:19:25 +00:00
|
|
|
{
|
|
|
|
NormalizedPoint point(x, y);
|
|
|
|
double outsideDistance = DBL_MAX;
|
2019-12-09 13:16:55 +00:00
|
|
|
for (const HighlightAnnotation::Quad &quad : m_highlightQuads) {
|
2013-06-23 17:19:25 +00:00
|
|
|
QLinkedList<NormalizedPoint> pathPoints;
|
|
|
|
|
|
|
|
// first, we check if the point is within the area described by the 4 quads
|
|
|
|
// this is the case, if the point is always on one side of each segments delimiting the polygon:
|
2013-07-01 22:02:30 +00:00
|
|
|
pathPoints << quad.transformedPoint(0);
|
2013-06-23 17:19:25 +00:00
|
|
|
int directionVote = 0;
|
|
|
|
for (int i = 1; i < 5; ++i) {
|
2013-07-01 22:02:30 +00:00
|
|
|
NormalizedPoint thisPoint = quad.transformedPoint(i % 4);
|
2013-06-23 17:19:25 +00:00
|
|
|
directionVote += (isLeftOfVector(pathPoints.back(), thisPoint, point)) ? 1 : -1;
|
|
|
|
pathPoints << thisPoint;
|
|
|
|
}
|
|
|
|
if (abs(directionVote) == 4)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// if that's not the case, we treat the outline as path and simply determine
|
|
|
|
// the distance from the path to the point
|
|
|
|
const double thisOutsideDistance = ::distanceSqr(x, y, xScale, yScale, pathPoints);
|
|
|
|
if (thisOutsideDistance < outsideDistance)
|
|
|
|
outsideDistance = thisOutsideDistance;
|
|
|
|
}
|
|
|
|
|
|
|
|
return outsideDistance;
|
|
|
|
}
|
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
/** StampAnnotation [Annotation] */
|
2005-02-26 18:05:01 +00:00
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
class Okular::StampAnnotationPrivate : public Okular::AnnotationPrivate
|
2006-12-18 07:28:02 +00:00
|
|
|
{
|
|
|
|
public:
|
2007-05-04 20:24:12 +00:00
|
|
|
StampAnnotationPrivate()
|
2015-10-29 12:37:11 +00:00
|
|
|
: AnnotationPrivate()
|
|
|
|
, m_stampIconName(QStringLiteral("Draft"))
|
2006-12-18 07:28:02 +00:00
|
|
|
{
|
|
|
|
}
|
2016-10-29 14:38:19 +00:00
|
|
|
void setAnnotationProperties(const QDomNode &node) override;
|
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
|
|
|
bool canBeResized() const override;
|
2016-10-29 14:38:19 +00:00
|
|
|
AnnotationPrivate *getNewAnnotationPrivate() override;
|
2006-12-18 07:28:02 +00:00
|
|
|
|
|
|
|
QString m_stampIconName;
|
|
|
|
};
|
|
|
|
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
StampAnnotation::StampAnnotation()
|
2007-05-04 20:24:12 +00:00
|
|
|
: Annotation(*new StampAnnotationPrivate())
|
2006-12-11 07:59:02 +00:00
|
|
|
{
|
|
|
|
}
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
StampAnnotation::StampAnnotation(const QDomNode &description)
|
|
|
|
: Annotation(*new StampAnnotationPrivate(), description)
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
{
|
|
|
|
}
|
2005-02-26 18:05:01 +00:00
|
|
|
|
2006-12-11 07:59:02 +00:00
|
|
|
StampAnnotation::~StampAnnotation()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void StampAnnotation::setStampIconName(const QString &name)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(StampAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_stampIconName = name;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString StampAnnotation::stampIconName() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const StampAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_stampIconName;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::SubType StampAnnotation::subType() const
|
|
|
|
{
|
|
|
|
return AStamp;
|
|
|
|
}
|
|
|
|
|
2005-03-13 13:14:44 +00:00
|
|
|
void StampAnnotation::store(QDomNode &node, QDomDocument &document) const
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const StampAnnotation);
|
2005-03-18 18:49:45 +00:00
|
|
|
// recurse to parent objects storing properties
|
2005-04-04 23:55:40 +00:00
|
|
|
Annotation::store(node, document);
|
2005-03-18 18:49:45 +00:00
|
|
|
|
|
|
|
// create [stamp] element
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement stampElement = document.createElement(QStringLiteral("stamp"));
|
2005-03-18 18:49:45 +00:00
|
|
|
node.appendChild(stampElement);
|
|
|
|
|
|
|
|
// append the optional attributes
|
2015-10-29 12:37:11 +00:00
|
|
|
if (d->m_stampIconName != QLatin1String("Draft"))
|
|
|
|
stampElement.setAttribute(QStringLiteral("icon"), d->m_stampIconName);
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
}
|
2005-02-26 18:05:01 +00:00
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
void StampAnnotationPrivate::setAnnotationProperties(const QDomNode &node)
|
|
|
|
{
|
|
|
|
Okular::AnnotationPrivate::setAnnotationProperties(node);
|
|
|
|
|
|
|
|
// loop through the whole children looking for a 'stamp' element
|
|
|
|
QDomNode subNode = node.firstChild();
|
|
|
|
while (subNode.isElement()) {
|
|
|
|
QDomElement e = subNode.toElement();
|
|
|
|
subNode = subNode.nextSibling();
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.tagName() != QLatin1String("stamp"))
|
2013-04-05 22:22:48 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// parse the attributes
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.hasAttribute(QStringLiteral("icon")))
|
|
|
|
m_stampIconName = e.attribute(QStringLiteral("icon"));
|
2013-04-05 22:22:48 +00:00
|
|
|
|
|
|
|
// loading complete
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
|
|
|
bool StampAnnotationPrivate::canBeResized() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
AnnotationPrivate *StampAnnotationPrivate::getNewAnnotationPrivate()
|
|
|
|
{
|
|
|
|
return new StampAnnotationPrivate();
|
|
|
|
}
|
|
|
|
|
2005-04-07 19:27:54 +00:00
|
|
|
/** InkAnnotation [Annotation] */
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
|
2007-05-04 20:24:12 +00:00
|
|
|
class Okular::InkAnnotationPrivate : public Okular::AnnotationPrivate
|
2006-12-18 07:28:02 +00:00
|
|
|
{
|
|
|
|
public:
|
2007-05-04 20:24:12 +00:00
|
|
|
InkAnnotationPrivate()
|
|
|
|
: AnnotationPrivate()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-10-29 14:38:19 +00:00
|
|
|
void transform(const QTransform &matrix) override;
|
|
|
|
void baseTransform(const QTransform &matrix) override;
|
|
|
|
void resetTransformation() override;
|
2019-12-03 23:23:26 +00:00
|
|
|
double distanceSqr(double x, double y, double xScale, double yScale) const override;
|
2016-10-29 14:38:19 +00:00
|
|
|
void translate(const NormalizedPoint &coord) override;
|
|
|
|
void setAnnotationProperties(const QDomNode &node) override;
|
|
|
|
AnnotationPrivate *getNewAnnotationPrivate() override;
|
2007-05-04 20:45:45 +00:00
|
|
|
|
2006-12-18 07:28:02 +00:00
|
|
|
QList<QLinkedList<NormalizedPoint>> m_inkPaths;
|
|
|
|
QList<QLinkedList<NormalizedPoint>> m_transformedInkPaths;
|
|
|
|
};
|
|
|
|
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
InkAnnotation::InkAnnotation()
|
2007-05-04 20:24:12 +00:00
|
|
|
: Annotation(*new InkAnnotationPrivate())
|
2006-12-11 07:59:02 +00:00
|
|
|
{
|
|
|
|
}
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
InkAnnotation::InkAnnotation(const QDomNode &description)
|
|
|
|
: Annotation(*new InkAnnotationPrivate(), description)
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
{
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
InkAnnotation::~InkAnnotation()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void InkAnnotation::setInkPaths(const QList<QLinkedList<NormalizedPoint>> &paths)
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(InkAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
d->m_inkPaths = paths;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QList<QLinkedList<NormalizedPoint>> InkAnnotation::inkPaths() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const InkAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_inkPaths;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QList<QLinkedList<NormalizedPoint>> InkAnnotation::transformedInkPaths() const
|
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const InkAnnotation);
|
2006-12-18 07:28:02 +00:00
|
|
|
return d->m_transformedInkPaths;
|
2006-12-11 07:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::SubType InkAnnotation::subType() const
|
|
|
|
{
|
|
|
|
return AInk;
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
}
|
|
|
|
|
2005-03-13 13:14:44 +00:00
|
|
|
void InkAnnotation::store(QDomNode &node, QDomDocument &document) const
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
{
|
2007-05-04 20:24:12 +00:00
|
|
|
Q_D(const InkAnnotation);
|
2005-03-18 18:49:45 +00:00
|
|
|
// recurse to parent objects storing properties
|
2005-04-04 23:55:40 +00:00
|
|
|
Annotation::store(node, document);
|
2005-03-13 13:14:44 +00:00
|
|
|
|
2005-03-18 18:49:45 +00:00
|
|
|
// create [ink] element
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement inkElement = document.createElement(QStringLiteral("ink"));
|
2005-03-18 18:49:45 +00:00
|
|
|
node.appendChild(inkElement);
|
|
|
|
|
|
|
|
// append the optional attributes
|
2006-12-18 07:28:02 +00:00
|
|
|
if (d->m_inkPaths.count() < 1)
|
2005-03-18 18:49:45 +00:00
|
|
|
return;
|
2006-12-11 07:59:02 +00:00
|
|
|
|
2006-12-18 07:28:02 +00:00
|
|
|
QList<QLinkedList<NormalizedPoint>>::const_iterator pIt = d->m_inkPaths.begin(), pEnd = d->m_inkPaths.end();
|
2005-03-18 18:49:45 +00:00
|
|
|
for (; pIt != pEnd; ++pIt) {
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement pathElement = document.createElement(QStringLiteral("path"));
|
2005-03-18 18:49:45 +00:00
|
|
|
inkElement.appendChild(pathElement);
|
2006-03-20 22:51:56 +00:00
|
|
|
const QLinkedList<NormalizedPoint> &path = *pIt;
|
|
|
|
QLinkedList<NormalizedPoint>::const_iterator iIt = path.begin(), iEnd = path.end();
|
2005-03-18 18:49:45 +00:00
|
|
|
for (; iIt != iEnd; ++iIt) {
|
|
|
|
const NormalizedPoint &point = *iIt;
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement pointElement = document.createElement(QStringLiteral("point"));
|
2005-03-18 18:49:45 +00:00
|
|
|
pathElement.appendChild(pointElement);
|
2015-10-29 12:37:11 +00:00
|
|
|
pointElement.setAttribute(QStringLiteral("x"), QString::number(point.x));
|
|
|
|
pointElement.setAttribute(QStringLiteral("y"), QString::number(point.y));
|
2005-03-18 18:49:45 +00:00
|
|
|
}
|
|
|
|
}
|
PDF 1.6 Annotation Parser and DSs: annotations are loaded from PDF file.
AFAIK the kpdf team is once again the first opensource reader to get
support for a cool feature. All annotations in pdf file are read and
converted to our internal data structures. Then they'll be rendered on
screen and changed/saved to our xml file.
Annotations completely supported and parsed from PDF: [markup], popup,
text, freetext, line, polygon, polyline, highlight, underline, squiggly,
strikeout, stamp, ink. Partial support for: [base], geom.
Annotations:
Added/Changed the passive annotation data structures to contain and
generalize the attributes of annotation classes. Missing attributes
(won't be handled by kpdf): base{P,AP,AS,A,AA,StructPar,OC}, geom{RD}.
Little changes to the PDF1.6 summary in header.
PDFGenerator:
Internal parser (discussed with Albert) directly in top of xpdf. Read
object nodes of type 'Annot' and parse the whole set of attributes as
defined in the PDF1.6 spec (for supported annotations).
svn path=/branches/kpdf_annotations/kdegraphics/kpdf/; revision=396909
2005-03-12 08:30:47 +00:00
|
|
|
}
|
2006-11-20 07:53:32 +00:00
|
|
|
|
2019-12-03 23:23:26 +00:00
|
|
|
double InkAnnotationPrivate::distanceSqr(double x, double y, double xScale, double yScale) const
|
2013-06-23 17:19:25 +00:00
|
|
|
{
|
|
|
|
double distance = DBL_MAX;
|
2019-12-09 13:16:55 +00:00
|
|
|
for (const QLinkedList<NormalizedPoint> &path : m_transformedInkPaths) {
|
2013-06-23 17:19:25 +00:00
|
|
|
const double thisDistance = ::distanceSqr(x, y, xScale, yScale, path);
|
|
|
|
if (thisDistance < distance)
|
|
|
|
distance = thisDistance;
|
|
|
|
}
|
|
|
|
return strokeDistance(distance, m_style.width() * xScale / (m_page->m_width * 2));
|
|
|
|
}
|
|
|
|
|
2012-09-08 15:06:02 +00:00
|
|
|
void InkAnnotationPrivate::transform(const QTransform &matrix)
|
2006-11-20 07:53:32 +00:00
|
|
|
{
|
2007-05-04 20:45:45 +00:00
|
|
|
AnnotationPrivate::transform(matrix);
|
2006-11-20 07:53:32 +00:00
|
|
|
|
2007-05-04 20:45:45 +00:00
|
|
|
for (int i = 0; i < m_transformedInkPaths.count(); ++i) {
|
|
|
|
QMutableLinkedListIterator<NormalizedPoint> it(m_transformedInkPaths[i]);
|
2006-11-20 07:53:32 +00:00
|
|
|
while (it.hasNext())
|
|
|
|
it.next().transform(matrix);
|
|
|
|
}
|
|
|
|
}
|
2007-07-17 21:52:22 +00:00
|
|
|
|
2012-09-08 15:06:02 +00:00
|
|
|
void InkAnnotationPrivate::baseTransform(const QTransform &matrix)
|
2007-10-07 10:52:05 +00:00
|
|
|
{
|
|
|
|
AnnotationPrivate::baseTransform(matrix);
|
|
|
|
|
|
|
|
for (int i = 0; i < m_inkPaths.count(); ++i) {
|
|
|
|
QMutableLinkedListIterator<NormalizedPoint> it(m_inkPaths[i]);
|
|
|
|
while (it.hasNext())
|
|
|
|
it.next().transform(matrix);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-22 20:49:27 +00:00
|
|
|
void InkAnnotationPrivate::resetTransformation()
|
|
|
|
{
|
|
|
|
AnnotationPrivate::resetTransformation();
|
|
|
|
|
|
|
|
m_transformedInkPaths = m_inkPaths;
|
|
|
|
}
|
|
|
|
|
2007-07-17 21:52:22 +00:00
|
|
|
void InkAnnotationPrivate::translate(const NormalizedPoint &coord)
|
|
|
|
{
|
|
|
|
AnnotationPrivate::translate(coord);
|
|
|
|
|
|
|
|
for (int i = 0; i < m_inkPaths.count(); ++i) {
|
|
|
|
QMutableLinkedListIterator<NormalizedPoint> it(m_inkPaths[i]);
|
|
|
|
while (it.hasNext()) {
|
|
|
|
NormalizedPoint &p = it.next();
|
|
|
|
p.x = p.x + coord.x;
|
|
|
|
p.y = p.y + coord.y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-04-05 14:46:07 +00:00
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
void InkAnnotationPrivate::setAnnotationProperties(const QDomNode &node)
|
|
|
|
{
|
|
|
|
Okular::AnnotationPrivate::setAnnotationProperties(node);
|
|
|
|
m_inkPaths.clear();
|
|
|
|
|
|
|
|
// loop through the whole children looking for a 'ink' element
|
|
|
|
QDomNode subNode = node.firstChild();
|
|
|
|
while (subNode.isElement()) {
|
|
|
|
QDomElement e = subNode.toElement();
|
|
|
|
subNode = subNode.nextSibling();
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.tagName() != QLatin1String("ink"))
|
2013-04-05 22:22:48 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// parse the 'path' subnodes
|
|
|
|
QDomNode pathNode = e.firstChild();
|
|
|
|
while (pathNode.isElement()) {
|
|
|
|
QDomElement pathElement = pathNode.toElement();
|
|
|
|
pathNode = pathNode.nextSibling();
|
|
|
|
|
2015-10-29 12:37:11 +00:00
|
|
|
if (pathElement.tagName() != QLatin1String("path"))
|
2013-04-05 22:22:48 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// build each path parsing 'point' subnodes
|
|
|
|
QLinkedList<NormalizedPoint> path;
|
|
|
|
QDomNode pointNode = pathElement.firstChild();
|
|
|
|
while (pointNode.isElement()) {
|
|
|
|
QDomElement pointElement = pointNode.toElement();
|
|
|
|
pointNode = pointNode.nextSibling();
|
|
|
|
|
2015-10-29 12:37:11 +00:00
|
|
|
if (pointElement.tagName() != QLatin1String("point"))
|
2013-04-05 22:22:48 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
NormalizedPoint p;
|
2015-10-29 12:37:11 +00:00
|
|
|
p.x = pointElement.attribute(QStringLiteral("x"), QStringLiteral("0.0")).toDouble();
|
|
|
|
p.y = pointElement.attribute(QStringLiteral("y"), QStringLiteral("0.0")).toDouble();
|
2013-04-05 22:22:48 +00:00
|
|
|
path.append(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
// add the path to the path list if it contains at least 2 nodes
|
|
|
|
if (path.count() >= 2)
|
|
|
|
m_inkPaths.append(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
// loading complete
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_transformedInkPaths = m_inkPaths;
|
|
|
|
}
|
|
|
|
|
|
|
|
AnnotationPrivate *InkAnnotationPrivate::getNewAnnotationPrivate()
|
|
|
|
{
|
|
|
|
return new InkAnnotationPrivate();
|
|
|
|
}
|
|
|
|
|
2008-04-05 14:46:07 +00:00
|
|
|
/** CaretAnnotation [Annotation] */
|
|
|
|
|
|
|
|
class Okular::CaretAnnotationPrivate : public Okular::AnnotationPrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CaretAnnotationPrivate()
|
2008-04-06 10:27:46 +00:00
|
|
|
: AnnotationPrivate()
|
|
|
|
, m_symbol(CaretAnnotation::None)
|
2008-04-05 14:46:07 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-10-29 14:38:19 +00:00
|
|
|
void setAnnotationProperties(const QDomNode &node) override;
|
|
|
|
AnnotationPrivate *getNewAnnotationPrivate() override;
|
2013-04-05 22:22:48 +00:00
|
|
|
|
2008-04-06 10:27:46 +00:00
|
|
|
CaretAnnotation::CaretSymbol m_symbol;
|
2008-04-05 14:46:07 +00:00
|
|
|
};
|
|
|
|
|
2008-04-06 10:27:46 +00:00
|
|
|
static QString caretSymbolToString(CaretAnnotation::CaretSymbol symbol)
|
|
|
|
{
|
|
|
|
switch (symbol) {
|
|
|
|
case CaretAnnotation::None:
|
2015-10-29 12:37:11 +00:00
|
|
|
return QStringLiteral("None");
|
2008-04-06 10:27:46 +00:00
|
|
|
case CaretAnnotation::P:
|
2015-10-29 12:37:11 +00:00
|
|
|
return QStringLiteral("P");
|
2008-04-06 10:27:46 +00:00
|
|
|
}
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
static CaretAnnotation::CaretSymbol caretSymbolFromString(const QString &symbol)
|
|
|
|
{
|
|
|
|
if (symbol == QLatin1String("None"))
|
|
|
|
return CaretAnnotation::None;
|
|
|
|
else if (symbol == QLatin1String("P"))
|
|
|
|
return CaretAnnotation::P;
|
|
|
|
return CaretAnnotation::None;
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
void CaretAnnotationPrivate::setAnnotationProperties(const QDomNode &node)
|
2008-04-05 14:46:07 +00:00
|
|
|
{
|
2013-04-05 22:22:48 +00:00
|
|
|
Okular::AnnotationPrivate::setAnnotationProperties(node);
|
2008-04-05 14:46:07 +00:00
|
|
|
|
|
|
|
// loop through the whole children looking for a 'caret' element
|
|
|
|
QDomNode subNode = node.firstChild();
|
|
|
|
while (subNode.isElement()) {
|
|
|
|
QDomElement e = subNode.toElement();
|
|
|
|
subNode = subNode.nextSibling();
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.tagName() != QLatin1String("caret"))
|
2008-04-05 14:46:07 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// parse the attributes
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.hasAttribute(QStringLiteral("symbol")))
|
|
|
|
m_symbol = caretSymbolFromString(e.attribute(QStringLiteral("symbol")));
|
2008-04-05 14:46:07 +00:00
|
|
|
|
|
|
|
// loading complete
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
AnnotationPrivate *CaretAnnotationPrivate::getNewAnnotationPrivate()
|
|
|
|
{
|
|
|
|
return new CaretAnnotationPrivate();
|
|
|
|
}
|
|
|
|
|
|
|
|
CaretAnnotation::CaretAnnotation()
|
|
|
|
: Annotation(*new CaretAnnotationPrivate())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
CaretAnnotation::CaretAnnotation(const QDomNode &description)
|
|
|
|
: Annotation(*new CaretAnnotationPrivate(), description)
|
2013-04-05 22:22:48 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-04-05 14:46:07 +00:00
|
|
|
CaretAnnotation::~CaretAnnotation()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-04-06 10:27:46 +00:00
|
|
|
void CaretAnnotation::setCaretSymbol(CaretAnnotation::CaretSymbol symbol)
|
2008-04-05 14:46:07 +00:00
|
|
|
{
|
|
|
|
Q_D(CaretAnnotation);
|
|
|
|
d->m_symbol = symbol;
|
|
|
|
}
|
|
|
|
|
2008-04-06 10:27:46 +00:00
|
|
|
CaretAnnotation::CaretSymbol CaretAnnotation::caretSymbol() const
|
2008-04-05 14:46:07 +00:00
|
|
|
{
|
|
|
|
Q_D(const CaretAnnotation);
|
|
|
|
return d->m_symbol;
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::SubType CaretAnnotation::subType() const
|
|
|
|
{
|
|
|
|
return ACaret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CaretAnnotation::store(QDomNode &node, QDomDocument &document) const
|
|
|
|
{
|
|
|
|
Q_D(const CaretAnnotation);
|
|
|
|
// recurse to parent objects storing properties
|
|
|
|
Annotation::store(node, document);
|
|
|
|
|
|
|
|
// create [caret] element
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement caretElement = document.createElement(QStringLiteral("caret"));
|
2008-04-05 14:46:07 +00:00
|
|
|
node.appendChild(caretElement);
|
|
|
|
|
|
|
|
// append the optional attributes
|
2008-04-06 10:27:46 +00:00
|
|
|
if (d->m_symbol != None)
|
2015-10-29 12:37:11 +00:00
|
|
|
caretElement.setAttribute(QStringLiteral("symbol"), caretSymbolToString(d->m_symbol));
|
2008-04-05 14:46:07 +00:00
|
|
|
}
|
2008-04-13 16:34:33 +00:00
|
|
|
|
|
|
|
/** FileAttachmentAnnotation [Annotation] */
|
|
|
|
|
|
|
|
class Okular::FileAttachmentAnnotationPrivate : public Okular::AnnotationPrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
FileAttachmentAnnotationPrivate()
|
2017-09-05 21:27:18 +00:00
|
|
|
: AnnotationPrivate()
|
|
|
|
, icon(QStringLiteral("PushPin"))
|
|
|
|
, embfile(nullptr)
|
2008-04-13 16:34:33 +00:00
|
|
|
{
|
|
|
|
}
|
2016-10-29 14:38:19 +00:00
|
|
|
~FileAttachmentAnnotationPrivate() override
|
2008-04-13 16:34:33 +00:00
|
|
|
{
|
|
|
|
delete embfile;
|
|
|
|
}
|
|
|
|
|
2016-10-29 14:38:19 +00:00
|
|
|
void setAnnotationProperties(const QDomNode &node) override;
|
|
|
|
AnnotationPrivate *getNewAnnotationPrivate() override;
|
2013-04-05 22:22:48 +00:00
|
|
|
|
2008-04-13 16:34:33 +00:00
|
|
|
// data fields
|
|
|
|
QString icon;
|
|
|
|
EmbeddedFile *embfile;
|
|
|
|
};
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
void FileAttachmentAnnotationPrivate::setAnnotationProperties(const QDomNode &node)
|
2008-04-13 16:34:33 +00:00
|
|
|
{
|
2013-04-05 22:22:48 +00:00
|
|
|
Okular::AnnotationPrivate::setAnnotationProperties(node);
|
2008-04-13 16:34:33 +00:00
|
|
|
|
|
|
|
// loop through the whole children looking for a 'fileattachment' element
|
|
|
|
QDomNode subNode = node.firstChild();
|
|
|
|
while (subNode.isElement()) {
|
|
|
|
QDomElement e = subNode.toElement();
|
|
|
|
subNode = subNode.nextSibling();
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.tagName() != QLatin1String("fileattachment"))
|
2008-04-13 16:34:33 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// loading complete
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
AnnotationPrivate *FileAttachmentAnnotationPrivate::getNewAnnotationPrivate()
|
|
|
|
{
|
|
|
|
return new FileAttachmentAnnotationPrivate();
|
|
|
|
}
|
|
|
|
|
|
|
|
FileAttachmentAnnotation::FileAttachmentAnnotation()
|
|
|
|
: Annotation(*new FileAttachmentAnnotationPrivate())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
FileAttachmentAnnotation::FileAttachmentAnnotation(const QDomNode &description)
|
|
|
|
: Annotation(*new FileAttachmentAnnotationPrivate(), description)
|
2013-04-05 22:22:48 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-04-13 16:34:33 +00:00
|
|
|
FileAttachmentAnnotation::~FileAttachmentAnnotation()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileAttachmentAnnotation::store(QDomNode &node, QDomDocument &document) const
|
|
|
|
{
|
|
|
|
// recurse to parent objects storing properties
|
|
|
|
Annotation::store(node, document);
|
|
|
|
|
|
|
|
// create [fileattachment] element
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement fileAttachmentElement = document.createElement(QStringLiteral("fileattachment"));
|
2008-04-13 16:34:33 +00:00
|
|
|
node.appendChild(fileAttachmentElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::SubType FileAttachmentAnnotation::subType() const
|
|
|
|
{
|
|
|
|
return AFileAttachment;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString FileAttachmentAnnotation::fileIconName() const
|
|
|
|
{
|
|
|
|
Q_D(const FileAttachmentAnnotation);
|
|
|
|
return d->icon;
|
|
|
|
}
|
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
void FileAttachmentAnnotation::setFileIconName(const QString &iconName)
|
2008-04-13 16:34:33 +00:00
|
|
|
{
|
|
|
|
Q_D(FileAttachmentAnnotation);
|
2019-12-20 15:40:59 +00:00
|
|
|
d->icon = iconName;
|
2008-04-13 16:34:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
EmbeddedFile *FileAttachmentAnnotation::embeddedFile() const
|
|
|
|
{
|
|
|
|
Q_D(const FileAttachmentAnnotation);
|
|
|
|
return d->embfile;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileAttachmentAnnotation::setEmbeddedFile(EmbeddedFile *ef)
|
|
|
|
{
|
|
|
|
Q_D(FileAttachmentAnnotation);
|
|
|
|
d->embfile = ef;
|
|
|
|
}
|
2008-04-13 20:00:06 +00:00
|
|
|
|
|
|
|
/** SoundAnnotation [Annotation] */
|
|
|
|
|
|
|
|
class Okular::SoundAnnotationPrivate : public Okular::AnnotationPrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
SoundAnnotationPrivate()
|
2017-09-05 21:27:18 +00:00
|
|
|
: AnnotationPrivate()
|
|
|
|
, icon(QStringLiteral("Speaker"))
|
|
|
|
, sound(nullptr)
|
2008-04-13 20:00:06 +00:00
|
|
|
{
|
|
|
|
}
|
2016-10-29 14:38:19 +00:00
|
|
|
~SoundAnnotationPrivate() override
|
2008-04-13 20:00:06 +00:00
|
|
|
{
|
|
|
|
delete sound;
|
|
|
|
}
|
|
|
|
|
2016-10-29 14:38:19 +00:00
|
|
|
void setAnnotationProperties(const QDomNode &node) override;
|
|
|
|
AnnotationPrivate *getNewAnnotationPrivate() override;
|
2013-04-05 22:22:48 +00:00
|
|
|
|
2008-04-13 20:00:06 +00:00
|
|
|
// data fields
|
|
|
|
QString icon;
|
|
|
|
Sound *sound;
|
|
|
|
};
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
void SoundAnnotationPrivate::setAnnotationProperties(const QDomNode &node)
|
2008-04-13 20:00:06 +00:00
|
|
|
{
|
2013-04-05 22:22:48 +00:00
|
|
|
Okular::AnnotationPrivate::setAnnotationProperties(node);
|
2008-04-13 20:00:06 +00:00
|
|
|
|
|
|
|
// loop through the whole children looking for a 'sound' element
|
|
|
|
QDomNode subNode = node.firstChild();
|
|
|
|
while (subNode.isElement()) {
|
|
|
|
QDomElement e = subNode.toElement();
|
|
|
|
subNode = subNode.nextSibling();
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.tagName() != QLatin1String("sound"))
|
2008-04-13 20:00:06 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// loading complete
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
AnnotationPrivate *SoundAnnotationPrivate::getNewAnnotationPrivate()
|
|
|
|
{
|
|
|
|
return new SoundAnnotationPrivate();
|
|
|
|
}
|
|
|
|
|
|
|
|
SoundAnnotation::SoundAnnotation()
|
|
|
|
: Annotation(*new SoundAnnotationPrivate())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
SoundAnnotation::SoundAnnotation(const QDomNode &description)
|
|
|
|
: Annotation(*new SoundAnnotationPrivate(), description)
|
2013-04-05 22:22:48 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-04-13 20:00:06 +00:00
|
|
|
SoundAnnotation::~SoundAnnotation()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void SoundAnnotation::store(QDomNode &node, QDomDocument &document) const
|
|
|
|
{
|
|
|
|
// recurse to parent objects storing properties
|
|
|
|
Annotation::store(node, document);
|
|
|
|
|
|
|
|
// create [sound] element
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement soundElement = document.createElement(QStringLiteral("sound"));
|
2008-04-13 20:00:06 +00:00
|
|
|
node.appendChild(soundElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::SubType SoundAnnotation::subType() const
|
|
|
|
{
|
|
|
|
return ASound;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SoundAnnotation::soundIconName() const
|
|
|
|
{
|
|
|
|
Q_D(const SoundAnnotation);
|
|
|
|
return d->icon;
|
|
|
|
}
|
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
void SoundAnnotation::setSoundIconName(const QString &iconName)
|
2008-04-13 20:00:06 +00:00
|
|
|
{
|
|
|
|
Q_D(SoundAnnotation);
|
2019-12-20 15:40:59 +00:00
|
|
|
d->icon = iconName;
|
2008-04-13 20:00:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Sound *SoundAnnotation::sound() const
|
|
|
|
{
|
|
|
|
Q_D(const SoundAnnotation);
|
|
|
|
return d->sound;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SoundAnnotation::setSound(Sound *s)
|
|
|
|
{
|
|
|
|
Q_D(SoundAnnotation);
|
|
|
|
d->sound = s;
|
|
|
|
}
|
2008-08-23 00:07:59 +00:00
|
|
|
|
|
|
|
/** MovieAnnotation [Annotation] */
|
|
|
|
|
|
|
|
class Okular::MovieAnnotationPrivate : public Okular::AnnotationPrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
MovieAnnotationPrivate()
|
2017-09-05 21:27:18 +00:00
|
|
|
: AnnotationPrivate()
|
|
|
|
, movie(nullptr)
|
2008-08-23 00:07:59 +00:00
|
|
|
{
|
|
|
|
}
|
2016-10-29 14:38:19 +00:00
|
|
|
~MovieAnnotationPrivate() override
|
2008-08-23 00:07:59 +00:00
|
|
|
{
|
|
|
|
delete movie;
|
|
|
|
}
|
|
|
|
|
2016-10-29 14:38:19 +00:00
|
|
|
void setAnnotationProperties(const QDomNode &node) override;
|
|
|
|
AnnotationPrivate *getNewAnnotationPrivate() override;
|
2013-04-05 22:22:48 +00:00
|
|
|
|
2008-08-23 00:07:59 +00:00
|
|
|
// data fields
|
|
|
|
Movie *movie;
|
|
|
|
};
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
void MovieAnnotationPrivate::setAnnotationProperties(const QDomNode &node)
|
2008-08-23 00:07:59 +00:00
|
|
|
{
|
2013-04-05 22:22:48 +00:00
|
|
|
Okular::AnnotationPrivate::setAnnotationProperties(node);
|
2008-08-23 00:07:59 +00:00
|
|
|
|
|
|
|
// loop through the whole children looking for a 'movie' element
|
|
|
|
QDomNode subNode = node.firstChild();
|
|
|
|
while (subNode.isElement()) {
|
|
|
|
QDomElement e = subNode.toElement();
|
|
|
|
subNode = subNode.nextSibling();
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.tagName() != QLatin1String("movie"))
|
2008-08-23 00:07:59 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// loading complete
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
AnnotationPrivate *MovieAnnotationPrivate::getNewAnnotationPrivate()
|
|
|
|
{
|
|
|
|
return new MovieAnnotationPrivate();
|
|
|
|
}
|
|
|
|
|
|
|
|
MovieAnnotation::MovieAnnotation()
|
|
|
|
: Annotation(*new MovieAnnotationPrivate())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
MovieAnnotation::MovieAnnotation(const QDomNode &description)
|
|
|
|
: Annotation(*new MovieAnnotationPrivate(), description)
|
2013-04-05 22:22:48 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-08-23 00:07:59 +00:00
|
|
|
MovieAnnotation::~MovieAnnotation()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void MovieAnnotation::store(QDomNode &node, QDomDocument &document) const
|
|
|
|
{
|
|
|
|
// recurse to parent objects storing properties
|
|
|
|
Annotation::store(node, document);
|
|
|
|
|
|
|
|
// create [movie] element
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement movieElement = document.createElement(QStringLiteral("movie"));
|
2008-08-23 00:07:59 +00:00
|
|
|
node.appendChild(movieElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::SubType MovieAnnotation::subType() const
|
|
|
|
{
|
|
|
|
return AMovie;
|
|
|
|
}
|
|
|
|
|
|
|
|
Movie *MovieAnnotation::movie() const
|
|
|
|
{
|
|
|
|
Q_D(const MovieAnnotation);
|
|
|
|
return d->movie;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MovieAnnotation::setMovie(Movie *movie)
|
|
|
|
{
|
|
|
|
Q_D(MovieAnnotation);
|
|
|
|
d->movie = movie;
|
|
|
|
}
|
2012-08-16 09:53:58 +00:00
|
|
|
|
|
|
|
/** ScreenAnnotation [Annotation] */
|
|
|
|
|
|
|
|
class Okular::ScreenAnnotationPrivate : public Okular::AnnotationPrivate
|
|
|
|
{
|
|
|
|
public:
|
2012-09-27 10:43:06 +00:00
|
|
|
ScreenAnnotationPrivate();
|
2016-10-29 14:38:19 +00:00
|
|
|
~ScreenAnnotationPrivate() override;
|
2012-09-27 10:43:06 +00:00
|
|
|
|
2016-10-29 14:38:19 +00:00
|
|
|
void setAnnotationProperties(const QDomNode &node) override;
|
|
|
|
AnnotationPrivate *getNewAnnotationPrivate() override;
|
2013-04-05 22:22:48 +00:00
|
|
|
|
2012-09-27 10:43:06 +00:00
|
|
|
Okular::Action *m_action;
|
2012-08-16 09:53:58 +00:00
|
|
|
QMap<Okular::Annotation::AdditionalActionType, Okular::Action *> m_additionalActions;
|
|
|
|
};
|
|
|
|
|
2012-09-27 10:43:06 +00:00
|
|
|
ScreenAnnotationPrivate::ScreenAnnotationPrivate()
|
2017-09-05 21:27:18 +00:00
|
|
|
: m_action(nullptr)
|
2012-09-27 10:43:06 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-08-16 09:53:58 +00:00
|
|
|
ScreenAnnotationPrivate::~ScreenAnnotationPrivate()
|
|
|
|
{
|
2012-09-27 10:43:06 +00:00
|
|
|
delete m_action;
|
2012-08-16 09:53:58 +00:00
|
|
|
qDeleteAll(m_additionalActions);
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
void ScreenAnnotationPrivate::setAnnotationProperties(const QDomNode &node)
|
2012-08-16 09:53:58 +00:00
|
|
|
{
|
2013-04-05 22:22:48 +00:00
|
|
|
Okular::AnnotationPrivate::setAnnotationProperties(node);
|
2012-08-16 09:53:58 +00:00
|
|
|
|
|
|
|
// loop through the whole children looking for a 'screen' element
|
|
|
|
QDomNode subNode = node.firstChild();
|
|
|
|
while (subNode.isElement()) {
|
|
|
|
QDomElement e = subNode.toElement();
|
|
|
|
subNode = subNode.nextSibling();
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.tagName() != QLatin1String("screen"))
|
2012-08-16 09:53:58 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// loading complete
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
AnnotationPrivate *ScreenAnnotationPrivate::getNewAnnotationPrivate()
|
|
|
|
{
|
|
|
|
return new ScreenAnnotationPrivate();
|
|
|
|
}
|
|
|
|
|
|
|
|
ScreenAnnotation::ScreenAnnotation()
|
|
|
|
: Annotation(*new ScreenAnnotationPrivate())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
ScreenAnnotation::ScreenAnnotation(const QDomNode &description)
|
|
|
|
: Annotation(*new ScreenAnnotationPrivate(), description)
|
2013-04-05 22:22:48 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-08-16 09:53:58 +00:00
|
|
|
ScreenAnnotation::~ScreenAnnotation()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScreenAnnotation::store(QDomNode &node, QDomDocument &document) const
|
|
|
|
{
|
|
|
|
// recurse to parent objects storing properties
|
|
|
|
Annotation::store(node, document);
|
|
|
|
|
|
|
|
// create [screen] element
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement movieElement = document.createElement(QStringLiteral("screen"));
|
2012-08-16 09:53:58 +00:00
|
|
|
node.appendChild(movieElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::SubType ScreenAnnotation::subType() const
|
|
|
|
{
|
|
|
|
return AScreen;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScreenAnnotation::setAdditionalAction(AdditionalActionType type, Action *action)
|
|
|
|
{
|
|
|
|
Q_D(ScreenAnnotation);
|
|
|
|
if (d->m_additionalActions.contains(type))
|
|
|
|
delete d->m_additionalActions.value(type);
|
|
|
|
|
|
|
|
d->m_additionalActions.insert(type, action);
|
|
|
|
}
|
|
|
|
|
|
|
|
Action *ScreenAnnotation::additionalAction(AdditionalActionType type) const
|
|
|
|
{
|
|
|
|
Q_D(const ScreenAnnotation);
|
|
|
|
if (!d->m_additionalActions.contains(type))
|
2017-09-05 21:27:18 +00:00
|
|
|
return nullptr;
|
2012-08-16 09:53:58 +00:00
|
|
|
else
|
|
|
|
return d->m_additionalActions.value(type);
|
|
|
|
}
|
|
|
|
|
2012-09-27 10:43:06 +00:00
|
|
|
void ScreenAnnotation::setAction(Action *action)
|
|
|
|
{
|
|
|
|
Q_D(ScreenAnnotation);
|
|
|
|
|
|
|
|
delete d->m_action;
|
|
|
|
d->m_action = action;
|
|
|
|
}
|
|
|
|
|
|
|
|
Action *ScreenAnnotation::action() const
|
|
|
|
{
|
|
|
|
Q_D(const ScreenAnnotation);
|
|
|
|
return d->m_action;
|
|
|
|
}
|
|
|
|
|
2012-08-16 09:53:58 +00:00
|
|
|
/** WidgetAnnotation [Annotation] */
|
|
|
|
|
|
|
|
class Okular::WidgetAnnotationPrivate : public Okular::AnnotationPrivate
|
|
|
|
{
|
|
|
|
public:
|
2016-10-29 14:38:19 +00:00
|
|
|
~WidgetAnnotationPrivate() override;
|
|
|
|
void setAnnotationProperties(const QDomNode &node) override;
|
|
|
|
AnnotationPrivate *getNewAnnotationPrivate() override;
|
2013-04-05 22:22:48 +00:00
|
|
|
|
2012-08-16 09:53:58 +00:00
|
|
|
QMap<Okular::Annotation::AdditionalActionType, Okular::Action *> m_additionalActions;
|
|
|
|
};
|
|
|
|
|
|
|
|
WidgetAnnotationPrivate::~WidgetAnnotationPrivate()
|
|
|
|
{
|
|
|
|
qDeleteAll(m_additionalActions);
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
void WidgetAnnotationPrivate::setAnnotationProperties(const QDomNode &node)
|
2012-08-16 09:53:58 +00:00
|
|
|
{
|
2013-04-05 22:22:48 +00:00
|
|
|
Okular::AnnotationPrivate::setAnnotationProperties(node);
|
2012-08-16 09:53:58 +00:00
|
|
|
|
|
|
|
// loop through the whole children looking for a 'widget' element
|
|
|
|
QDomNode subNode = node.firstChild();
|
|
|
|
while (subNode.isElement()) {
|
|
|
|
QDomElement e = subNode.toElement();
|
|
|
|
subNode = subNode.nextSibling();
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.tagName() != QLatin1String("widget"))
|
2012-08-16 09:53:58 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// loading complete
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:22:48 +00:00
|
|
|
AnnotationPrivate *WidgetAnnotationPrivate::getNewAnnotationPrivate()
|
|
|
|
{
|
|
|
|
return new WidgetAnnotationPrivate();
|
|
|
|
}
|
|
|
|
|
|
|
|
WidgetAnnotation::WidgetAnnotation()
|
|
|
|
: Annotation(*new WidgetAnnotationPrivate())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
WidgetAnnotation::WidgetAnnotation(const QDomNode &description)
|
|
|
|
: Annotation(*new WidgetAnnotationPrivate, description)
|
2013-04-05 22:22:48 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-08-16 09:53:58 +00:00
|
|
|
WidgetAnnotation::~WidgetAnnotation()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void WidgetAnnotation::store(QDomNode &node, QDomDocument &document) const
|
|
|
|
{
|
|
|
|
// recurse to parent objects storing properties
|
|
|
|
Annotation::store(node, document);
|
|
|
|
|
|
|
|
// create [widget] element
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement movieElement = document.createElement(QStringLiteral("widget"));
|
2012-08-16 09:53:58 +00:00
|
|
|
node.appendChild(movieElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::SubType WidgetAnnotation::subType() const
|
|
|
|
{
|
|
|
|
return AWidget;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WidgetAnnotation::setAdditionalAction(AdditionalActionType type, Action *action)
|
|
|
|
{
|
|
|
|
Q_D(WidgetAnnotation);
|
|
|
|
if (d->m_additionalActions.contains(type))
|
|
|
|
delete d->m_additionalActions.value(type);
|
|
|
|
|
|
|
|
d->m_additionalActions.insert(type, action);
|
|
|
|
}
|
|
|
|
|
|
|
|
Action *WidgetAnnotation::additionalAction(AdditionalActionType type) const
|
|
|
|
{
|
|
|
|
Q_D(const WidgetAnnotation);
|
|
|
|
if (!d->m_additionalActions.contains(type))
|
2017-09-05 21:27:18 +00:00
|
|
|
return nullptr;
|
2012-08-16 09:53:58 +00:00
|
|
|
else
|
|
|
|
return d->m_additionalActions.value(type);
|
|
|
|
}
|
2015-08-04 09:11:29 +00:00
|
|
|
|
|
|
|
/** RichMediaAnnotation [Annotation] */
|
|
|
|
|
|
|
|
class Okular::RichMediaAnnotationPrivate : public Okular::AnnotationPrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
RichMediaAnnotationPrivate();
|
2016-10-29 14:38:19 +00:00
|
|
|
~RichMediaAnnotationPrivate() override;
|
|
|
|
void setAnnotationProperties(const QDomNode &node) override;
|
|
|
|
AnnotationPrivate *getNewAnnotationPrivate() override;
|
2015-08-04 09:11:29 +00:00
|
|
|
|
|
|
|
// data fields
|
|
|
|
Movie *movie;
|
|
|
|
EmbeddedFile *embeddedFile;
|
|
|
|
};
|
|
|
|
|
|
|
|
RichMediaAnnotationPrivate::RichMediaAnnotationPrivate()
|
2017-09-05 21:27:18 +00:00
|
|
|
: movie(nullptr)
|
|
|
|
, embeddedFile(nullptr)
|
2015-08-04 09:11:29 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
RichMediaAnnotationPrivate::~RichMediaAnnotationPrivate()
|
|
|
|
{
|
|
|
|
delete movie;
|
|
|
|
delete embeddedFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RichMediaAnnotationPrivate::setAnnotationProperties(const QDomNode &node)
|
|
|
|
{
|
|
|
|
Okular::AnnotationPrivate::setAnnotationProperties(node);
|
|
|
|
|
|
|
|
// loop through the whole children looking for a 'richMedia' element
|
|
|
|
QDomNode subNode = node.firstChild();
|
|
|
|
while (subNode.isElement()) {
|
|
|
|
QDomElement e = subNode.toElement();
|
|
|
|
subNode = subNode.nextSibling();
|
2015-10-29 12:37:11 +00:00
|
|
|
if (e.tagName() != QLatin1String("richMedia"))
|
2015-08-04 09:11:29 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// loading complete
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AnnotationPrivate *RichMediaAnnotationPrivate::getNewAnnotationPrivate()
|
|
|
|
{
|
|
|
|
return new RichMediaAnnotationPrivate();
|
|
|
|
}
|
|
|
|
|
|
|
|
RichMediaAnnotation::RichMediaAnnotation()
|
|
|
|
: Annotation(*new RichMediaAnnotationPrivate())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-12-20 15:40:59 +00:00
|
|
|
RichMediaAnnotation::RichMediaAnnotation(const QDomNode &description)
|
|
|
|
: Annotation(*new RichMediaAnnotationPrivate, description)
|
2015-08-04 09:11:29 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
RichMediaAnnotation::~RichMediaAnnotation()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void RichMediaAnnotation::store(QDomNode &node, QDomDocument &document) const
|
|
|
|
{
|
|
|
|
// recurse to parent objects storing properties
|
|
|
|
Annotation::store(node, document);
|
|
|
|
|
|
|
|
// create [richMedia] element
|
2015-10-29 12:37:11 +00:00
|
|
|
QDomElement movieElement = document.createElement(QStringLiteral("richMedia"));
|
2015-08-04 09:11:29 +00:00
|
|
|
node.appendChild(movieElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
Annotation::SubType RichMediaAnnotation::subType() const
|
|
|
|
{
|
|
|
|
return ARichMedia;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RichMediaAnnotation::setMovie(Movie *movie)
|
|
|
|
{
|
|
|
|
Q_D(RichMediaAnnotation);
|
|
|
|
|
|
|
|
delete d->movie;
|
|
|
|
d->movie = movie;
|
|
|
|
}
|
|
|
|
|
|
|
|
Movie *RichMediaAnnotation::movie() const
|
|
|
|
{
|
|
|
|
Q_D(const RichMediaAnnotation);
|
|
|
|
|
|
|
|
return d->movie;
|
|
|
|
}
|
|
|
|
|
|
|
|
EmbeddedFile *RichMediaAnnotation::embeddedFile() const
|
|
|
|
{
|
|
|
|
Q_D(const RichMediaAnnotation);
|
|
|
|
|
|
|
|
return d->embeddedFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RichMediaAnnotation::setEmbeddedFile(EmbeddedFile *embeddedFile)
|
|
|
|
{
|
|
|
|
Q_D(RichMediaAnnotation);
|
|
|
|
|
|
|
|
delete d->embeddedFile;
|
|
|
|
d->embeddedFile = embeddedFile;
|
|
|
|
}
|