okular/core/annotations.cpp
Kevin Funk a53a2402ca clang-tidy: modernize-use-nullptr run
Semi-ACK'd by Albert :)
2017-09-06 00:19:48 +02:00

3102 lines
88 KiB
C++

/***************************************************************************
* 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. *
***************************************************************************/
#include "annotations.h"
#include "annotations_p.h"
// qt/kde includes
#include <QtWidgets/QApplication>
#include <QtGui/QColor>
// DBL_MAX
#include <float.h>
// local includes
#include "action.h"
#include "document.h"
#include "document_p.h"
#include "movie.h"
#include "page_p.h"
#include "sound.h"
using namespace Okular;
/**
* 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:
* We calculate an (exact) squared distance to the ideal (centered) line, and then subtract
* 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
* boundary. Trivially, it also fulfils (a1 < a2) => ((a1^2 - b^2) < (a2^2 - b^2)) making it monotonic.
* "Inside" of the drawn line, the distance is 0 anyway.
*/
static double strokeDistance( double distance, double penWidth )
{
return fmax(distance - pow( penWidth, 2 ), 0);
}
//BEGIN AnnotationUtils implementation
Annotation * AnnotationUtils::createAnnotation( const QDomElement & annElement )
{
// safety check on annotation element
if ( !annElement.hasAttribute( QStringLiteral("type") ) )
return nullptr;
// build annotation of given type
Annotation * annotation = nullptr;
int typeNumber = annElement.attribute( QStringLiteral("type") ).toInt();
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;
case Annotation::ACaret:
annotation = new CaretAnnotation( annElement );
break;
}
// return created annotation
return annotation;
}
void AnnotationUtils::storeAnnotation( const Annotation * ann, QDomElement & annElement,
QDomDocument & document )
{
// save annotation's type as element's attribute
annElement.setAttribute( QStringLiteral("type"), (uint)ann->subType() );
// append all annotation data as children of this node
ann->store( annElement, document );
}
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();
}
QRect AnnotationUtils::annotationGeometry( const Annotation * ann,
double scaledWidth, double scaledHeight )
{
const QRect rect = ann->transformedBoundingRectangle().geometry( (int)scaledWidth, (int)scaledHeight );
if ( ann->subType() == Annotation::AText && ( ( (TextAnnotation*)ann )->textType() == TextAnnotation::Linked ) )
{
// 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?
const QRect rect24 = QRect( (int)( ann->transformedBoundingRectangle().left * scaledWidth ),
(int)( ann->transformedBoundingRectangle().top * scaledHeight ), 24, 24 );
return rect24.united(rect);
}
return rect;
}
//END AnnotationUtils implementation
AnnotationProxy::~AnnotationProxy()
{
}
//BEGIN Annotation implementation
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;
};
Annotation::Style::Style()
: 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 )
{
if ( this != &other )
*d = *other.d;
return *this;
}
void Annotation::Style::setColor( const QColor &color )
{
d->m_color = color;
}
QColor Annotation::Style::color() const
{
return d->m_color;
}
void Annotation::Style::setOpacity( double opacity )
{
d->m_opacity = opacity;
}
double Annotation::Style::opacity() const
{
return d->m_opacity;
}
void Annotation::Style::setWidth( double width )
{
d->m_width = width;
}
double Annotation::Style::width() const
{
return d->m_width;
}
void Annotation::Style::setLineStyle( LineStyle style )
{
d->m_style = style;
}
Annotation::LineStyle Annotation::Style::lineStyle() const
{
return d->m_style;
}
void Annotation::Style::setXCorners( double xCorners )
{
d->m_xCorners = xCorners;
}
double Annotation::Style::xCorners() const
{
return d->m_xCorners;
}
void Annotation::Style::setYCorners( double yCorners )
{
d->m_yCorners = yCorners;
}
double Annotation::Style::yCorners() const
{
return d->m_yCorners;
}
void Annotation::Style::setMarks( int marks )
{
d->m_marks = marks;
}
int Annotation::Style::marks() const
{
return d->m_marks;
}
void Annotation::Style::setSpaces( int spaces )
{
d->m_spaces = spaces;
}
int Annotation::Style::spaces() const
{
return d->m_spaces;
}
void Annotation::Style::setLineEffect( LineEffect effect )
{
d->m_effect = effect;
}
Annotation::LineEffect Annotation::Style::lineEffect() const
{
return d->m_effect;
}
void Annotation::Style::setEffectIntensity( double intensity )
{
d->m_effectIntensity = intensity;
}
double Annotation::Style::effectIntensity() const
{
return d->m_effectIntensity;
}
class Annotation::Window::Private
{
public:
Private()
: m_flags( -1 ), m_width( 0 ), m_height( 0 )
{
}
int m_flags;
NormalizedPoint m_topLeft;
int m_width;
int m_height;
QString m_title;
QString m_summary;
};
Annotation::Window::Window()
: d( new Private )
{
}
Annotation::Window::~Window()
{
delete d;
}
Annotation::Window::Window( const Window &other )
: d( new Private )
{
*d = *other.d;
}
Annotation::Window& Annotation::Window::operator=( const Window &other )
{
if ( this != &other )
*d = *other.d;
return *this;
}
void Annotation::Window::setFlags( int flags )
{
d->m_flags = flags;
}
int Annotation::Window::flags() const
{
return d->m_flags;
}
void Annotation::Window::setTopLeft( const NormalizedPoint &point )
{
d->m_topLeft = point;
}
NormalizedPoint Annotation::Window::topLeft() const
{
return d->m_topLeft;
}
void Annotation::Window::setWidth( int width )
{
d->m_width = width;
}
int Annotation::Window::width() const
{
return d->m_width;
}
void Annotation::Window::setHeight( int height )
{
d->m_height = height;
}
int Annotation::Window::height() const
{
return d->m_height;
}
void Annotation::Window::setTitle( const QString &title )
{
d->m_title = title;
}
QString Annotation::Window::title() const
{
return d->m_title;
}
void Annotation::Window::setSummary( const QString &summary )
{
d->m_summary = summary;
}
QString Annotation::Window::summary() const
{
return d->m_summary;
}
class Annotation::Revision::Private
{
public:
Private()
: m_annotation( nullptr ), m_scope( Reply ), m_type( None )
{
}
Annotation *m_annotation;
RevisionScope m_scope;
RevisionType m_type;
};
Annotation::Revision::Revision()
: d( new Private )
{
}
Annotation::Revision::~Revision()
{
delete d;
}
Annotation::Revision::Revision( const Revision &other )
: d( new Private )
{
*d = *other.d;
}
Annotation::Revision& Annotation::Revision::operator=( const Revision &other )
{
if ( this != &other )
*d = *other.d;
return *this;
}
void Annotation::Revision::setAnnotation( Annotation *annotation )
{
d->m_annotation = annotation;
}
Annotation *Annotation::Revision::annotation() const
{
return d->m_annotation;
}
void Annotation::Revision::setScope( RevisionScope scope )
{
d->m_scope = scope;
}
Annotation::RevisionScope Annotation::Revision::scope() const
{
return d->m_scope;
}
void Annotation::Revision::setType( RevisionType type )
{
d->m_type = type;
}
Annotation::RevisionType Annotation::Revision::type() const
{
return d->m_type;
}
AnnotationPrivate::AnnotationPrivate()
: m_page( nullptr ), m_flags( 0 ), m_disposeFunc( nullptr )
{
}
AnnotationPrivate::~AnnotationPrivate()
{
// delete all children revisions
if ( m_revisions.isEmpty() )
return;
QLinkedList< Annotation::Revision >::iterator it = m_revisions.begin(), end = m_revisions.end();
for ( ; it != end; ++it )
delete (*it).annotation();
}
Annotation::Annotation( AnnotationPrivate &dd )
: d_ptr( &dd )
{
}
Annotation::Annotation( AnnotationPrivate &dd, const QDomNode & annNode )
: d_ptr( &dd )
{
d_ptr->setAnnotationProperties( annNode );
}
Annotation::~Annotation()
{
if ( d_ptr->m_disposeFunc )
d_ptr->m_disposeFunc( this );
delete d_ptr;
}
void Annotation::setAuthor( const QString &author )
{
Q_D( Annotation );
d->m_author = author;
}
QString Annotation::author() const
{
Q_D( const Annotation );
return d->m_author;
}
void Annotation::setContents( const QString &contents )
{
Q_D( Annotation );
d->m_contents = contents;
}
QString Annotation::contents() const
{
Q_D( const Annotation );
return d->m_contents;
}
void Annotation::setUniqueName( const QString &name )
{
Q_D( Annotation );
d->m_uniqueName = name;
}
QString Annotation::uniqueName() const
{
Q_D( const Annotation );
return d->m_uniqueName;
}
void Annotation::setModificationDate( const QDateTime &date )
{
Q_D( Annotation );
d->m_modifyDate = date;
}
QDateTime Annotation::modificationDate() const
{
Q_D( const Annotation );
return d->m_modifyDate;
}
void Annotation::setCreationDate( const QDateTime &date )
{
Q_D( Annotation );
d->m_creationDate = date;
}
QDateTime Annotation::creationDate() const
{
Q_D( const Annotation );
return d->m_creationDate;
}
void Annotation::setFlags( int flags )
{
Q_D( Annotation );
d->m_flags = flags;
}
int Annotation::flags() const
{
Q_D( const Annotation );
return d->m_flags;
}
void Annotation::setBoundingRectangle( const NormalizedRect &rectangle )
{
Q_D( Annotation );
d->m_boundary = rectangle;
d->resetTransformation();
if ( d->m_page )
{
d->transform( d->m_page->rotationMatrix() );
}
}
NormalizedRect Annotation::boundingRectangle() const
{
Q_D( const Annotation );
return d->m_boundary;
}
NormalizedRect Annotation::transformedBoundingRectangle() const
{
Q_D( const Annotation );
return d->m_transformedBoundary;
}
void Annotation::translate( const NormalizedPoint &coord )
{
Q_D( Annotation );
d->translate( coord );
d->resetTransformation();
if ( d->m_page )
{
d->transform( d->m_page->rotationMatrix() );
}
}
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() );
}
}
bool Annotation::openDialogAfterCreation() const
{
Q_D( const Annotation );
return d->openDialogAfterCreation();
}
Annotation::Style & Annotation::style()
{
Q_D( Annotation );
return d->m_style;
}
const Annotation::Style & Annotation::style() const
{
Q_D( const Annotation );
return d->m_style;
}
Annotation::Window & Annotation::window()
{
Q_D( Annotation );
return d->m_window;
}
const Annotation::Window & Annotation::window() const
{
Q_D( const Annotation );
return d->m_window;
}
QLinkedList< Annotation::Revision > & Annotation::revisions()
{
Q_D( Annotation );
return d->m_revisions;
}
const QLinkedList< Annotation::Revision > & Annotation::revisions() const
{
Q_D( const Annotation );
return d->m_revisions;
}
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;
}
bool Annotation::canBeMoved() const
{
Q_D( const Annotation );
// Don't move annotations if they cannot be modified
if ( !d->m_page || !d->m_page->m_doc->m_parent->canModifyPageAnnotation(this) )
return false;
// highlight "requires" to be "bounded" to text, and that's tricky for now
if ( subType() == AHighlight )
return false;
return true;
}
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();
}
void Annotation::store( QDomNode & annNode, QDomDocument & document ) const
{
Q_D( const Annotation );
// create [base] element of the annotation node
QDomElement e = document.createElement( QStringLiteral("base") );
annNode.appendChild( e );
// store -contents- attributes
if ( !d->m_author.isEmpty() )
e.setAttribute( QStringLiteral("author"), d->m_author );
if ( !d->m_contents.isEmpty() )
e.setAttribute( QStringLiteral("contents"), d->m_contents );
if ( !d->m_uniqueName.isEmpty() )
e.setAttribute( QStringLiteral("uniqueName"), d->m_uniqueName );
if ( d->m_modifyDate.isValid() )
e.setAttribute( QStringLiteral("modifyDate"), d->m_modifyDate.toString(Qt::ISODate) );
if ( d->m_creationDate.isValid() )
e.setAttribute( QStringLiteral("creationDate"), d->m_creationDate.toString(Qt::ISODate) );
// store -other- attributes
if ( d->m_flags ) // Strip internal flags
e.setAttribute( QStringLiteral("flags"), d->m_flags & ~(External | ExternallyDrawn | BeingMoved | BeingResized ) );
if ( d->m_style.color().isValid() )
e.setAttribute( QStringLiteral("color"), d->m_style.color().name() );
if ( d->m_style.opacity() != 1.0 )
e.setAttribute( QStringLiteral("opacity"), QString::number( d->m_style.opacity() ) );
// Sub-Node-1 - boundary
QDomElement bE = document.createElement( QStringLiteral("boundary") );
e.appendChild( bE );
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 ) );
// Sub-Node-2 - penStyle
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 )
{
QDomElement psE = document.createElement( QStringLiteral("penStyle") );
e.appendChild( psE );
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() );
}
// Sub-Node-3 - penEffect
if ( d->m_style.lineEffect() != NoEffect || d->m_style.effectIntensity() != 1.0 )
{
QDomElement peE = document.createElement( QStringLiteral("penEffect") );
e.appendChild( peE );
peE.setAttribute( QStringLiteral("effect"), (int)d->m_style.lineEffect() );
peE.setAttribute( QStringLiteral("intensity"), QString::number( d->m_style.effectIntensity() ) );
}
// Sub-Node-4 - window
if ( d->m_window.flags() != -1 || !d->m_window.title().isEmpty() ||
!d->m_window.summary().isEmpty() )
{
QDomElement wE = document.createElement( QStringLiteral("window") );
e.appendChild( wE );
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() );
}
// create [revision] element of the annotation node (if any)
if ( d->m_revisions.isEmpty() )
return;
// add all revisions as children of revisions element
QLinkedList< Revision >::const_iterator it = d->m_revisions.begin(), end = d->m_revisions.end();
for ( ; it != end; ++it )
{
// create revision element
const Revision & revision = *it;
QDomElement r = document.createElement( QStringLiteral("revision") );
annNode.appendChild( r );
// set element attributes
r.setAttribute( QStringLiteral("revScope"), (int)revision.scope() );
r.setAttribute( QStringLiteral("revType"), (int)revision.type() );
// use revision as the annotation element, so fill it up
AnnotationUtils::storeAnnotation( revision.annotation(), r, document );
}
}
QDomNode Annotation::getAnnotationPropertiesDomNode() const
{
QDomDocument doc( QStringLiteral("documentInfo") );
QDomElement node = doc.createElement( QStringLiteral("annotation") );
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;
const int internalFlags = d_ptr->m_flags & (External | ExternallyDrawn | BeingMoved | BeingResized );
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;
// Transform annotation to current page rotation
d_ptr->transform( d_ptr->m_page->rotationMatrix() );
}
double AnnotationPrivate::distanceSqr( double x, double y, double xScale, double yScale )
{
return m_transformedBoundary.distanceSqr( x, y, xScale, yScale );
}
void AnnotationPrivate::annotationTransform( const QTransform &matrix )
{
resetTransformation();
transform( matrix );
}
void AnnotationPrivate::transform( const QTransform &matrix )
{
m_transformedBoundary.transform( matrix );
}
void AnnotationPrivate::baseTransform( const QTransform &matrix )
{
m_boundary.transform( matrix );
}
void AnnotationPrivate::resetTransformation()
{
m_transformedBoundary = m_boundary;
}
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;
}
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 );;
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 );
}
bool AnnotationPrivate::openDialogAfterCreation() const
{
return false;
}
void AnnotationPrivate::setAnnotationProperties( const QDomNode& node )
{
// get the [base] element of the annotation node
QDomElement e = AnnotationUtils::findChildElement( node, QStringLiteral("base") );
if ( e.isNull() )
return;
// parse -contents- attributes
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 );
// parse -other- attributes
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() );
// 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
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());
}
// parse penStyle if not default
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() );
}
// parse effectStyle if not default
else if ( ee.tagName() == QLatin1String("penEffect") )
{
m_style.setLineEffect( (Annotation::LineEffect)ee.attribute( QStringLiteral("effect") ).toInt() );
m_style.setEffectIntensity( ee.attribute( QStringLiteral("intensity") ).toDouble() );
}
// parse window if present
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") ) );
}
}
// get the [revisions] element of the annotation node
QDomNode revNode = node.firstChild();
for ( ; revNode.isElement(); revNode = revNode.nextSibling() )
{
QDomElement revElement = revNode.toElement();
if ( revElement.tagName() != QLatin1String("revision") )
continue;
// compile the Revision structure crating annotation
Annotation::Revision revision;
revision.setScope( (Annotation::RevisionScope)revElement.attribute( QStringLiteral("revScope") ).toInt() );
revision.setType( (Annotation::RevisionType)revElement.attribute( QStringLiteral("revType") ).toInt() );
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;
}
bool AnnotationPrivate::canBeResized() const
{
return false;
}
//END Annotation implementation
/** TextAnnotation [Annotation] */
class Okular::TextAnnotationPrivate : public Okular::AnnotationPrivate
{
public:
TextAnnotationPrivate()
: AnnotationPrivate(), m_textType( TextAnnotation::Linked ),
m_textIcon( QStringLiteral("Comment") ), m_inplaceAlign( 0 ),
m_inplaceIntent( TextAnnotation::Unknown )
{
}
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;
bool canBeResized() const override;
AnnotationPrivate* getNewAnnotationPrivate() override;
TextAnnotation::TextType m_textType;
QString m_textIcon;
QFont m_textFont;
int m_inplaceAlign;
NormalizedPoint m_inplaceCallout[3];
NormalizedPoint m_transformedInplaceCallout[3];
TextAnnotation::InplaceIntent m_inplaceIntent;
};
/*
The default textIcon for text annotation is Note as the PDF Reference says
*/
TextAnnotation::TextAnnotation()
: Annotation( *new TextAnnotationPrivate() )
{
}
TextAnnotation::TextAnnotation( const QDomNode & node )
: Annotation( *new TextAnnotationPrivate(), node )
{
}
TextAnnotation::~TextAnnotation()
{
}
void TextAnnotation::setTextType( TextType textType )
{
Q_D( TextAnnotation );
d->m_textType = textType;
}
TextAnnotation::TextType TextAnnotation::textType() const
{
Q_D( const TextAnnotation );
return d->m_textType;
}
void TextAnnotation::setTextIcon( const QString &icon )
{
Q_D( TextAnnotation );
d->m_textIcon = icon;
}
QString TextAnnotation::textIcon() const
{
Q_D( const TextAnnotation );
return d->m_textIcon;
}
void TextAnnotation::setTextFont( const QFont &font )
{
Q_D( TextAnnotation );
d->m_textFont = font;
}
QFont TextAnnotation::textFont() const
{
Q_D( const TextAnnotation );
return d->m_textFont;
}
void TextAnnotation::setInplaceAlignment( int alignment )
{
Q_D( TextAnnotation );
d->m_inplaceAlign = alignment;
}
int TextAnnotation::inplaceAlignment() const
{
Q_D( const TextAnnotation );
return d->m_inplaceAlign;
}
void TextAnnotation::setInplaceCallout( const NormalizedPoint &point, int index )
{
if ( index < 0 || index > 2 )
return;
Q_D( TextAnnotation );
d->m_inplaceCallout[ index ] = point;
}
NormalizedPoint TextAnnotation::inplaceCallout( int index ) const
{
if ( index < 0 || index > 2 )
return NormalizedPoint();
Q_D( const TextAnnotation );
return d->m_inplaceCallout[ index ];
}
NormalizedPoint TextAnnotation::transformedInplaceCallout( int index ) const
{
if ( index < 0 || index > 2 )
return NormalizedPoint();
Q_D( const TextAnnotation );
return d->m_transformedInplaceCallout[ index ];
}
void TextAnnotation::setInplaceIntent( InplaceIntent intent )
{
Q_D( TextAnnotation );
d->m_inplaceIntent = intent;
}
TextAnnotation::InplaceIntent TextAnnotation::inplaceIntent() const
{
Q_D( const TextAnnotation );
return d->m_inplaceIntent;
}
Annotation::SubType TextAnnotation::subType() const
{
return AText;
}
void TextAnnotation::store( QDomNode & node, QDomDocument & document ) const
{
Q_D( const TextAnnotation );
// recurse to parent objects storing properties
Annotation::store( node, document );
// create [text] element
QDomElement textElement = document.createElement( QStringLiteral("text") );
node.appendChild( textElement );
// store the optional attributes
if ( d->m_textType != Linked )
textElement.setAttribute( QStringLiteral("type"), (int)d->m_textType );
if ( !d->m_textIcon.isEmpty() )
textElement.setAttribute( QStringLiteral("icon"), d->m_textIcon );
if ( d->m_textFont != QApplication::font() )
textElement.setAttribute( QStringLiteral("font"), d->m_textFont.toString() );
if ( d->m_inplaceAlign )
textElement.setAttribute( QStringLiteral("align"), d->m_inplaceAlign );
if ( d->m_inplaceIntent != Unknown )
textElement.setAttribute( QStringLiteral("intent"), (int)d->m_inplaceIntent );
// Sub-Node - callout
if ( d->m_inplaceCallout[0].x != 0.0 )
{
QDomElement calloutElement = document.createElement( QStringLiteral("callout") );
textElement.appendChild( calloutElement );
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 ) );
}
}
void TextAnnotationPrivate::transform( const QTransform &matrix )
{
AnnotationPrivate::transform( matrix );
for ( int i = 0; i < 3; ++i ) {
m_transformedInplaceCallout[i].transform( matrix );
}
}
void TextAnnotationPrivate::baseTransform( const QTransform &matrix )
{
AnnotationPrivate::baseTransform( matrix );
for ( int i = 0; i < 3; ++i ) {
m_inplaceCallout[i].transform( matrix );
}
}
void TextAnnotationPrivate::resetTransformation()
{
AnnotationPrivate::resetTransformation();
for ( int i = 0; i < 3; ++i ) {
m_transformedInplaceCallout[i] = m_inplaceCallout[i];
}
}
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
}
bool TextAnnotationPrivate::openDialogAfterCreation() const
{
return ( m_textType == Okular::TextAnnotation::Linked );
}
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();
if ( e.tagName() != QLatin1String("text") )
continue;
// parse the attributes
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") ) );
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();
// parse the subnodes
QDomNode eSubNode = e.firstChild();
while ( eSubNode.isElement() )
{
QDomElement ee = eSubNode.toElement();
eSubNode = eSubNode.nextSibling();
if ( ee.tagName() == QLatin1String("escapedText") )
{
m_contents = ee.firstChild().toCDATASection().data();
}
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();
}
}
// loading complete
break;
}
for ( int i = 0; i < 3; ++i )
m_transformedInplaceCallout[i] = m_inplaceCallout[i];
}
bool TextAnnotationPrivate::canBeResized() const
{
if ( m_textType != TextAnnotation::Linked ) {
return true;
}
return false;
}
AnnotationPrivate* TextAnnotationPrivate::getNewAnnotationPrivate()
{
return new TextAnnotationPrivate();
}
/** LineAnnotation [Annotation] */
class Okular::LineAnnotationPrivate : public Okular::AnnotationPrivate
{
public:
LineAnnotationPrivate()
: AnnotationPrivate(),
m_lineStartStyle( LineAnnotation::None ), m_lineEndStyle( LineAnnotation::None ),
m_lineClosed( false ), m_lineShowCaption( false ), m_lineLeadingFwdPt( 0 ),
m_lineLeadingBackPt( 0 ), m_lineIntent( LineAnnotation::Unknown )
{
}
void transform( const QTransform &matrix ) override;
void baseTransform( const QTransform &matrix ) override;
void resetTransformation() override;
void translate( const NormalizedPoint &coord ) override;
double distanceSqr( double x, double y, double xScale, double yScale ) override;
void setAnnotationProperties( const QDomNode& node ) override;
AnnotationPrivate* getNewAnnotationPrivate() override;
QLinkedList<NormalizedPoint> m_linePoints;
QLinkedList<NormalizedPoint> m_transformedLinePoints;
LineAnnotation::TermStyle m_lineStartStyle;
LineAnnotation::TermStyle m_lineEndStyle;
bool m_lineClosed : 1;
bool m_lineShowCaption : 1;
QColor m_lineInnerColor;
double m_lineLeadingFwdPt;
double m_lineLeadingBackPt;
LineAnnotation::LineIntent m_lineIntent;
};
LineAnnotation::LineAnnotation()
: Annotation( *new LineAnnotationPrivate() )
{
}
LineAnnotation::LineAnnotation( const QDomNode & node )
: Annotation( *new LineAnnotationPrivate(), node )
{
}
LineAnnotation::~LineAnnotation()
{
}
void LineAnnotation::setLinePoints( const QLinkedList<NormalizedPoint> &points )
{
Q_D( LineAnnotation );
d->m_linePoints = points;
}
QLinkedList<NormalizedPoint> LineAnnotation::linePoints() const
{
Q_D( const LineAnnotation );
return d->m_linePoints;
}
QLinkedList<NormalizedPoint> LineAnnotation::transformedLinePoints() const
{
Q_D( const LineAnnotation );
return d->m_transformedLinePoints;
}
void LineAnnotation::setLineStartStyle( TermStyle style )
{
Q_D( LineAnnotation );
d->m_lineStartStyle = style;
}
LineAnnotation::TermStyle LineAnnotation::lineStartStyle() const
{
Q_D( const LineAnnotation );
return d->m_lineStartStyle;
}
void LineAnnotation::setLineEndStyle( TermStyle style )
{
Q_D( LineAnnotation );
d->m_lineEndStyle = style;
}
LineAnnotation::TermStyle LineAnnotation::lineEndStyle() const
{
Q_D( const LineAnnotation );
return d->m_lineEndStyle;
}
void LineAnnotation::setLineClosed( bool closed )
{
Q_D( LineAnnotation );
d->m_lineClosed = closed;
}
bool LineAnnotation::lineClosed() const
{
Q_D( const LineAnnotation );
return d->m_lineClosed;
}
void LineAnnotation::setLineInnerColor( const QColor &color )
{
Q_D( LineAnnotation );
d->m_lineInnerColor = color;
}
QColor LineAnnotation::lineInnerColor() const
{
Q_D( const LineAnnotation );
return d->m_lineInnerColor;
}
void LineAnnotation::setLineLeadingForwardPoint( double point )
{
Q_D( LineAnnotation );
d->m_lineLeadingFwdPt = point;
}
double LineAnnotation::lineLeadingForwardPoint() const
{
Q_D( const LineAnnotation );
return d->m_lineLeadingFwdPt;
}
void LineAnnotation::setLineLeadingBackwardPoint( double point )
{
Q_D( LineAnnotation );
d->m_lineLeadingBackPt = point;
}
double LineAnnotation::lineLeadingBackwardPoint() const
{
Q_D( const LineAnnotation );
return d->m_lineLeadingBackPt;
}
void LineAnnotation::setShowCaption( bool show )
{
Q_D( LineAnnotation );
d->m_lineShowCaption = show;
}
bool LineAnnotation::showCaption() const
{
Q_D( const LineAnnotation );
return d->m_lineShowCaption;
}
void LineAnnotation::setLineIntent( LineIntent intent )
{
Q_D( LineAnnotation );
d->m_lineIntent = intent;
}
LineAnnotation::LineIntent LineAnnotation::lineIntent() const
{
Q_D( const LineAnnotation );
return d->m_lineIntent;
}
Annotation::SubType LineAnnotation::subType() const
{
return ALine;
}
void LineAnnotation::store( QDomNode & node, QDomDocument & document ) const
{
Q_D( const LineAnnotation );
// recurse to parent objects storing properties
Annotation::store( node, document );
// create [line] element
QDomElement lineElement = document.createElement( QStringLiteral("line") );
node.appendChild( lineElement );
// store the attributes
if ( d->m_lineStartStyle != None )
lineElement.setAttribute( QStringLiteral("startStyle"), (int)d->m_lineStartStyle );
if ( d->m_lineEndStyle != None )
lineElement.setAttribute( QStringLiteral("endStyle"), (int)d->m_lineEndStyle );
if ( d->m_lineClosed )
lineElement.setAttribute( QStringLiteral("closed"), d->m_lineClosed );
if ( d->m_lineInnerColor.isValid() )
lineElement.setAttribute( QStringLiteral("innerColor"), d->m_lineInnerColor.name() );
if ( d->m_lineLeadingFwdPt != 0.0 )
lineElement.setAttribute( QStringLiteral("leadFwd"), QString::number( d->m_lineLeadingFwdPt ) );
if ( d->m_lineLeadingBackPt != 0.0 )
lineElement.setAttribute( QStringLiteral("leadBack"), QString::number( d->m_lineLeadingBackPt ) );
if ( d->m_lineShowCaption )
lineElement.setAttribute( QStringLiteral("showCaption"), d->m_lineShowCaption );
if ( d->m_lineIntent != Unknown )
lineElement.setAttribute( QStringLiteral("intent"), d->m_lineIntent );
// append the list of points
int points = d->m_linePoints.count();
if ( points > 1 )
{
QLinkedList<NormalizedPoint>::const_iterator it = d->m_linePoints.begin(), end = d->m_linePoints.end();
while ( it != end )
{
const NormalizedPoint & p = *it;
QDomElement pElement = document.createElement( QStringLiteral("point") );
lineElement.appendChild( pElement );
pElement.setAttribute( QStringLiteral("x"), QString::number( p.x ) );
pElement.setAttribute( QStringLiteral("y"), QString::number( p.y ) );
it++; //to avoid loop
}
}
}
void LineAnnotationPrivate::transform( const QTransform &matrix )
{
AnnotationPrivate::transform( matrix );
QMutableLinkedListIterator<NormalizedPoint> it( m_transformedLinePoints );
while ( it.hasNext() )
it.next().transform( matrix );
}
void LineAnnotationPrivate::baseTransform( const QTransform &matrix )
{
AnnotationPrivate::baseTransform( matrix );
QMutableLinkedListIterator<NormalizedPoint> it( m_linePoints );
while ( it.hasNext() )
it.next().transform( matrix );
}
void LineAnnotationPrivate::resetTransformation()
{
AnnotationPrivate::resetTransformation();
m_transformedLinePoints = m_linePoints;
}
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;
}
}
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();
if ( e.tagName() != QLatin1String("line") )
continue;
// parse the attributes
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();
// parse all 'point' subnodes
QDomNode pointNode = e.firstChild();
while ( pointNode.isElement() )
{
QDomElement pe = pointNode.toElement();
pointNode = pointNode.nextSibling();
if ( pe.tagName() != QLatin1String("point") )
continue;
NormalizedPoint p;
p.x = pe.attribute( QStringLiteral("x"), QStringLiteral("0.0") ).toDouble();
p.y = pe.attribute( QStringLiteral("y"), QStringLiteral("0.0") ).toDouble();
m_linePoints.append( p );
}
// loading complete
break;
}
m_transformedLinePoints = m_linePoints;
}
AnnotationPrivate* LineAnnotationPrivate::getNewAnnotationPrivate()
{
return new LineAnnotationPrivate();
}
double LineAnnotationPrivate::distanceSqr( double x, double y, double xScale, double yScale )
{
QLinkedList<NormalizedPoint> transformedLinePoints = m_transformedLinePoints;
if ( m_lineClosed ) // Close the path
transformedLinePoints.append( transformedLinePoints.first() );
if ( m_lineInnerColor.isValid() )
{
QPolygonF polygon;
foreach ( const NormalizedPoint &p, transformedLinePoints )
polygon.append( QPointF( p.x, p.y ) );
if ( polygon.containsPoint( QPointF( x, y ), Qt::WindingFill ) )
return 0;
}
return strokeDistance( ::distanceSqr( x, y, xScale, yScale, transformedLinePoints ),
m_style.width() * xScale / ( m_page->m_width * 2 ) );
}
/** GeomAnnotation [Annotation] */
class Okular::GeomAnnotationPrivate : public Okular::AnnotationPrivate
{
public:
GeomAnnotationPrivate()
: AnnotationPrivate(), m_geomType( GeomAnnotation::InscribedSquare )
{
}
void setAnnotationProperties( const QDomNode& node ) override;
bool canBeResized() const override;
AnnotationPrivate* getNewAnnotationPrivate() override;
double distanceSqr( double x, double y, double xScale, double yScale ) override;
GeomAnnotation::GeomType m_geomType;
QColor m_geomInnerColor;
};
GeomAnnotation::GeomAnnotation()
: Annotation( *new GeomAnnotationPrivate() )
{
}
GeomAnnotation::GeomAnnotation( const QDomNode & node )
: Annotation( *new GeomAnnotationPrivate(), node )
{
}
GeomAnnotation::~GeomAnnotation()
{
}
void GeomAnnotation::setGeometricalType( GeomType type )
{
Q_D( GeomAnnotation );
d->m_geomType = type;
}
GeomAnnotation::GeomType GeomAnnotation::geometricalType() const
{
Q_D( const GeomAnnotation );
return d->m_geomType;
}
void GeomAnnotation::setGeometricalInnerColor( const QColor &color )
{
Q_D( GeomAnnotation );
d->m_geomInnerColor = color;
}
QColor GeomAnnotation::geometricalInnerColor() const
{
Q_D( const GeomAnnotation );
return d->m_geomInnerColor;
}
Annotation::SubType GeomAnnotation::subType() const
{
return AGeom;
}
void GeomAnnotation::store( QDomNode & node, QDomDocument & document ) const
{
Q_D( const GeomAnnotation );
// recurse to parent objects storing properties
Annotation::store( node, document );
// create [geom] element
QDomElement geomElement = document.createElement( QStringLiteral("geom") );
node.appendChild( geomElement );
// append the optional attributes
if ( d->m_geomType != InscribedSquare )
geomElement.setAttribute( QStringLiteral("type"), (int)d->m_geomType );
if ( d->m_geomInnerColor.isValid() )
geomElement.setAttribute( QStringLiteral("color"), d->m_geomInnerColor.name() );
}
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();
if ( e.tagName() != QLatin1String("geom") )
continue;
// parse the attributes
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") ) );
// compatibility
if ( e.hasAttribute( QStringLiteral("width") ) )
m_style.setWidth( e.attribute( QStringLiteral("width") ).toInt() );
// loading complete
break;
}
}
bool GeomAnnotationPrivate::canBeResized() const
{
return true;
}
AnnotationPrivate* GeomAnnotationPrivate::getNewAnnotationPrivate()
{
return new GeomAnnotationPrivate();
}
double GeomAnnotationPrivate::distanceSqr( double x, double y, double xScale, double yScale )
{
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);
const double focusXSqr = pow( focusX, 2 );
const double focusYSqr = pow( focusY, 2 );
// 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 ) ) );
// 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;
}
/** HighlightAnnotation [Annotation] */
class HighlightAnnotation::Quad::Private
{
public:
Private()
{
}
NormalizedPoint m_points[4];
NormalizedPoint m_transformedPoints[4];
bool m_capStart : 1;
bool m_capEnd : 1;
double m_feather;
};
HighlightAnnotation::Quad::Quad()
: d( new Private )
{
}
HighlightAnnotation::Quad::~Quad()
{
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;
}
void HighlightAnnotation::Quad::setPoint( const NormalizedPoint &point, int index )
{
if ( index < 0 || index > 3 )
return;
d->m_points[ index ] = point;
}
NormalizedPoint HighlightAnnotation::Quad::point( int index ) const
{
if ( index < 0 || index > 3 )
return NormalizedPoint();
return d->m_points[ index ];
}
NormalizedPoint HighlightAnnotation::Quad::transformedPoint( int index ) const
{
if ( index < 0 || index > 3 )
return NormalizedPoint();
return d->m_transformedPoints[ index ];
}
void HighlightAnnotation::Quad::setCapStart( bool value )
{
d->m_capStart = value;
}
bool HighlightAnnotation::Quad::capStart() const
{
return d->m_capStart;
}
void HighlightAnnotation::Quad::setCapEnd( bool value )
{
d->m_capEnd = value;
}
bool HighlightAnnotation::Quad::capEnd() const
{
return d->m_capEnd;
}
void HighlightAnnotation::Quad::setFeather( double width )
{
d->m_feather = width;
}
double HighlightAnnotation::Quad::feather() const
{
return d->m_feather;
}
void HighlightAnnotation::Quad::transform( const QTransform &matrix )
{
for ( int i = 0; i < 4; ++i ) {
d->m_transformedPoints[ i ] = d->m_points[ i ];
d->m_transformedPoints[ i ].transform( matrix );
}
}
class Okular::HighlightAnnotationPrivate : public Okular::AnnotationPrivate
{
public:
HighlightAnnotationPrivate()
: AnnotationPrivate(), m_highlightType( HighlightAnnotation::Highlight )
{
}
void transform( const QTransform &matrix ) override;
void baseTransform( const QTransform &matrix ) override;
double distanceSqr( double x, double y, double xScale, double yScale ) override;
void setAnnotationProperties( const QDomNode& node ) override;
AnnotationPrivate* getNewAnnotationPrivate() override;
HighlightAnnotation::HighlightType m_highlightType;
QList< HighlightAnnotation::Quad > m_highlightQuads;
};
HighlightAnnotation::HighlightAnnotation()
: Annotation( *new HighlightAnnotationPrivate() )
{
}
HighlightAnnotation::HighlightAnnotation( const QDomNode & node )
: Annotation( *new HighlightAnnotationPrivate(), node )
{
}
HighlightAnnotation::~HighlightAnnotation()
{
}
void HighlightAnnotation::setHighlightType( HighlightType type )
{
Q_D( HighlightAnnotation );
d->m_highlightType = type;
}
HighlightAnnotation::HighlightType HighlightAnnotation::highlightType() const
{
Q_D( const HighlightAnnotation );
return d->m_highlightType;
}
QList< HighlightAnnotation::Quad > & HighlightAnnotation::highlightQuads()
{
Q_D( HighlightAnnotation );
return d->m_highlightQuads;
}
void HighlightAnnotation::store( QDomNode & node, QDomDocument & document ) const
{
Q_D( const HighlightAnnotation );
// recurse to parent objects storing properties
Annotation::store( node, document );
// create [hl] element
QDomElement hlElement = document.createElement( QStringLiteral("hl") );
node.appendChild( hlElement );
// append the optional attributes
if ( d->m_highlightType != Highlight )
hlElement.setAttribute( QStringLiteral("type"), (int)d->m_highlightType );
if ( d->m_highlightQuads.count() < 1 )
return;
// append highlight quads, all children describe quads
QList< Quad >::const_iterator it = d->m_highlightQuads.begin(), end = d->m_highlightQuads.end();
for ( ; it != end; ++it )
{
QDomElement quadElement = document.createElement( QStringLiteral("quad") );
hlElement.appendChild( quadElement );
const Quad & q = *it;
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 ) );
if ( q.capStart() )
quadElement.setAttribute( QStringLiteral("start"), 1 );
if ( q.capEnd() )
quadElement.setAttribute( QStringLiteral("end"), 1 );
quadElement.setAttribute( QStringLiteral("feather"), QString::number( q.feather() ) );
}
}
Annotation::SubType HighlightAnnotation::subType() const
{
return AHighlight;
}
void HighlightAnnotationPrivate::transform( const QTransform &matrix )
{
AnnotationPrivate::transform( matrix );
QMutableListIterator<HighlightAnnotation::Quad> it( m_highlightQuads );
while ( it.hasNext() )
it.next().transform( matrix );
}
void HighlightAnnotationPrivate::baseTransform( const QTransform &matrix )
{
AnnotationPrivate::baseTransform( matrix );
QMutableListIterator<HighlightAnnotation::Quad> it( m_highlightQuads );
while ( it.hasNext() )
it.next().transform( matrix );
}
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();
if ( e.tagName() != QLatin1String("hl") )
continue;
// parse the attributes
if ( e.hasAttribute( QStringLiteral("type") ) )
m_highlightType = (HighlightAnnotation::HighlightType)e.attribute( QStringLiteral("type") ).toInt();
// parse all 'quad' subnodes
QDomNode quadNode = e.firstChild();
for ( ; quadNode.isElement(); quadNode = quadNode.nextSibling() )
{
QDomElement qe = quadNode.toElement();
if ( qe.tagName() != QLatin1String("quad") )
continue;
HighlightAnnotation::Quad q;
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() );
q.transform( QTransform() );
m_highlightQuads.append( q );
}
// loading complete
break;
}
}
AnnotationPrivate* HighlightAnnotationPrivate::getNewAnnotationPrivate()
{
return new HighlightAnnotationPrivate();
}
double HighlightAnnotationPrivate::distanceSqr( double x, double y, double xScale, double yScale )
{
NormalizedPoint point( x, y );
double outsideDistance = DBL_MAX;
foreach ( const HighlightAnnotation::Quad& quad, m_highlightQuads )
{
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:
pathPoints << quad.transformedPoint( 0 );
int directionVote = 0;
for ( int i = 1; i < 5; ++i )
{
NormalizedPoint thisPoint = quad.transformedPoint( i % 4 );
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;
}
/** StampAnnotation [Annotation] */
class Okular::StampAnnotationPrivate : public Okular::AnnotationPrivate
{
public:
StampAnnotationPrivate()
: AnnotationPrivate(), m_stampIconName( QStringLiteral("Draft") )
{
}
void setAnnotationProperties( const QDomNode& node ) override;
bool canBeResized() const override;
AnnotationPrivate* getNewAnnotationPrivate() override;
QString m_stampIconName;
};
StampAnnotation::StampAnnotation()
: Annotation( *new StampAnnotationPrivate() )
{
}
StampAnnotation::StampAnnotation( const QDomNode & node )
: Annotation( *new StampAnnotationPrivate(), node )
{
}
StampAnnotation::~StampAnnotation()
{
}
void StampAnnotation::setStampIconName( const QString &name )
{
Q_D( StampAnnotation );
d->m_stampIconName = name;
}
QString StampAnnotation::stampIconName() const
{
Q_D( const StampAnnotation );
return d->m_stampIconName;
}
Annotation::SubType StampAnnotation::subType() const
{
return AStamp;
}
void StampAnnotation::store( QDomNode & node, QDomDocument & document ) const
{
Q_D( const StampAnnotation );
// recurse to parent objects storing properties
Annotation::store( node, document );
// create [stamp] element
QDomElement stampElement = document.createElement( QStringLiteral("stamp") );
node.appendChild( stampElement );
// append the optional attributes
if ( d->m_stampIconName != QLatin1String("Draft") )
stampElement.setAttribute( QStringLiteral("icon"), d->m_stampIconName );
}
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();
if ( e.tagName() != QLatin1String("stamp") )
continue;
// parse the attributes
if ( e.hasAttribute( QStringLiteral("icon") ) )
m_stampIconName = e.attribute( QStringLiteral("icon") );
// loading complete
break;
}
}
bool StampAnnotationPrivate::canBeResized() const
{
return true;
}
AnnotationPrivate* StampAnnotationPrivate::getNewAnnotationPrivate()
{
return new StampAnnotationPrivate();
}
/** InkAnnotation [Annotation] */
class Okular::InkAnnotationPrivate : public Okular::AnnotationPrivate
{
public:
InkAnnotationPrivate()
: AnnotationPrivate()
{
}
void transform( const QTransform &matrix ) override;
void baseTransform( const QTransform &matrix ) override;
void resetTransformation() override;
double distanceSqr( double x, double y, double xScale, double yScale ) override;
void translate( const NormalizedPoint &coord ) override;
void setAnnotationProperties( const QDomNode& node ) override;
AnnotationPrivate* getNewAnnotationPrivate() override;
QList< QLinkedList<NormalizedPoint> > m_inkPaths;
QList< QLinkedList<NormalizedPoint> > m_transformedInkPaths;
};
InkAnnotation::InkAnnotation()
: Annotation( *new InkAnnotationPrivate() )
{
}
InkAnnotation::InkAnnotation( const QDomNode & node )
: Annotation( *new InkAnnotationPrivate(), node )
{
}
InkAnnotation::~InkAnnotation()
{
}
void InkAnnotation::setInkPaths( const QList< QLinkedList<NormalizedPoint> > &paths )
{
Q_D( InkAnnotation );
d->m_inkPaths = paths;
}
QList< QLinkedList<NormalizedPoint> > InkAnnotation::inkPaths() const
{
Q_D( const InkAnnotation );
return d->m_inkPaths;
}
QList< QLinkedList<NormalizedPoint> > InkAnnotation::transformedInkPaths() const
{
Q_D( const InkAnnotation );
return d->m_transformedInkPaths;
}
Annotation::SubType InkAnnotation::subType() const
{
return AInk;
}
void InkAnnotation::store( QDomNode & node, QDomDocument & document ) const
{
Q_D( const InkAnnotation );
// recurse to parent objects storing properties
Annotation::store( node, document );
// create [ink] element
QDomElement inkElement = document.createElement( QStringLiteral("ink") );
node.appendChild( inkElement );
// append the optional attributes
if ( d->m_inkPaths.count() < 1 )
return;
QList< QLinkedList<NormalizedPoint> >::const_iterator pIt = d->m_inkPaths.begin(), pEnd = d->m_inkPaths.end();
for ( ; pIt != pEnd; ++pIt )
{
QDomElement pathElement = document.createElement( QStringLiteral("path") );
inkElement.appendChild( pathElement );
const QLinkedList<NormalizedPoint> & path = *pIt;
QLinkedList<NormalizedPoint>::const_iterator iIt = path.begin(), iEnd = path.end();
for ( ; iIt != iEnd; ++iIt )
{
const NormalizedPoint & point = *iIt;
QDomElement pointElement = document.createElement( QStringLiteral("point") );
pathElement.appendChild( pointElement );
pointElement.setAttribute( QStringLiteral("x"), QString::number( point.x ) );
pointElement.setAttribute( QStringLiteral("y"), QString::number( point.y ) );
}
}
}
double InkAnnotationPrivate::distanceSqr( double x, double y, double xScale, double yScale )
{
double distance = DBL_MAX;
foreach ( const QLinkedList<NormalizedPoint>& path, m_transformedInkPaths )
{
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 ) );
}
void InkAnnotationPrivate::transform( const QTransform &matrix )
{
AnnotationPrivate::transform( matrix );
for ( int i = 0; i < m_transformedInkPaths.count(); ++i )
{
QMutableLinkedListIterator<NormalizedPoint> it( m_transformedInkPaths[ i ] );
while ( it.hasNext() )
it.next().transform( matrix );
}
}
void InkAnnotationPrivate::baseTransform( const QTransform &matrix )
{
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 );
}
}
void InkAnnotationPrivate::resetTransformation()
{
AnnotationPrivate::resetTransformation();
m_transformedInkPaths = m_inkPaths;
}
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;
}
}
}
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();
if ( e.tagName() != QLatin1String("ink") )
continue;
// parse the 'path' subnodes
QDomNode pathNode = e.firstChild();
while ( pathNode.isElement() )
{
QDomElement pathElement = pathNode.toElement();
pathNode = pathNode.nextSibling();
if ( pathElement.tagName() != QLatin1String("path") )
continue;
// build each path parsing 'point' subnodes
QLinkedList<NormalizedPoint> path;
QDomNode pointNode = pathElement.firstChild();
while ( pointNode.isElement() )
{
QDomElement pointElement = pointNode.toElement();
pointNode = pointNode.nextSibling();
if ( pointElement.tagName() != QLatin1String("point") )
continue;
NormalizedPoint p;
p.x = pointElement.attribute( QStringLiteral("x"), QStringLiteral("0.0") ).toDouble();
p.y = pointElement.attribute( QStringLiteral("y"), QStringLiteral("0.0") ).toDouble();
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();
}
/** CaretAnnotation [Annotation] */
class Okular::CaretAnnotationPrivate : public Okular::AnnotationPrivate
{
public:
CaretAnnotationPrivate()
: AnnotationPrivate(), m_symbol( CaretAnnotation::None )
{
}
void setAnnotationProperties( const QDomNode& node ) override;
AnnotationPrivate* getNewAnnotationPrivate() override;
CaretAnnotation::CaretSymbol m_symbol;
};
static QString caretSymbolToString( CaretAnnotation::CaretSymbol symbol )
{
switch ( symbol )
{
case CaretAnnotation::None:
return QStringLiteral( "None" );
case CaretAnnotation::P:
return QStringLiteral( "P" );
}
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;
}
void CaretAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
{
Okular::AnnotationPrivate::setAnnotationProperties(node);
// loop through the whole children looking for a 'caret' element
QDomNode subNode = node.firstChild();
while( subNode.isElement() )
{
QDomElement e = subNode.toElement();
subNode = subNode.nextSibling();
if ( e.tagName() != QLatin1String("caret") )
continue;
// parse the attributes
if ( e.hasAttribute( QStringLiteral("symbol") ) )
m_symbol = caretSymbolFromString( e.attribute( QStringLiteral("symbol") ) );
// loading complete
break;
}
}
AnnotationPrivate* CaretAnnotationPrivate::getNewAnnotationPrivate()
{
return new CaretAnnotationPrivate();
}
CaretAnnotation::CaretAnnotation()
: Annotation( *new CaretAnnotationPrivate() )
{
}
CaretAnnotation::CaretAnnotation( const QDomNode & node )
: Annotation( *new CaretAnnotationPrivate(), node )
{
}
CaretAnnotation::~CaretAnnotation()
{
}
void CaretAnnotation::setCaretSymbol( CaretAnnotation::CaretSymbol symbol )
{
Q_D( CaretAnnotation );
d->m_symbol = symbol;
}
CaretAnnotation::CaretSymbol CaretAnnotation::caretSymbol() const
{
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
QDomElement caretElement = document.createElement( QStringLiteral("caret") );
node.appendChild( caretElement );
// append the optional attributes
if ( d->m_symbol != None )
caretElement.setAttribute( QStringLiteral("symbol"), caretSymbolToString( d->m_symbol ) );
}
/** FileAttachmentAnnotation [Annotation] */
class Okular::FileAttachmentAnnotationPrivate : public Okular::AnnotationPrivate
{
public:
FileAttachmentAnnotationPrivate()
: AnnotationPrivate(), icon( QStringLiteral("PushPin") ), embfile( nullptr )
{
}
~FileAttachmentAnnotationPrivate() override
{
delete embfile;
}
void setAnnotationProperties( const QDomNode& node ) override;
AnnotationPrivate* getNewAnnotationPrivate() override;
// data fields
QString icon;
EmbeddedFile *embfile;
};
void FileAttachmentAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
{
Okular::AnnotationPrivate::setAnnotationProperties(node);
// loop through the whole children looking for a 'fileattachment' element
QDomNode subNode = node.firstChild();
while( subNode.isElement() )
{
QDomElement e = subNode.toElement();
subNode = subNode.nextSibling();
if ( e.tagName() != QLatin1String("fileattachment") )
continue;
// loading complete
break;
}
}
AnnotationPrivate* FileAttachmentAnnotationPrivate::getNewAnnotationPrivate()
{
return new FileAttachmentAnnotationPrivate();
}
FileAttachmentAnnotation::FileAttachmentAnnotation()
: Annotation( *new FileAttachmentAnnotationPrivate() )
{
}
FileAttachmentAnnotation::FileAttachmentAnnotation( const QDomNode & node )
: Annotation( *new FileAttachmentAnnotationPrivate(), node )
{
}
FileAttachmentAnnotation::~FileAttachmentAnnotation()
{
}
void FileAttachmentAnnotation::store( QDomNode & node, QDomDocument & document ) const
{
// recurse to parent objects storing properties
Annotation::store( node, document );
// create [fileattachment] element
QDomElement fileAttachmentElement = document.createElement( QStringLiteral("fileattachment") );
node.appendChild( fileAttachmentElement );
}
Annotation::SubType FileAttachmentAnnotation::subType() const
{
return AFileAttachment;
}
QString FileAttachmentAnnotation::fileIconName() const
{
Q_D( const FileAttachmentAnnotation );
return d->icon;
}
void FileAttachmentAnnotation::setFileIconName( const QString &icon )
{
Q_D( FileAttachmentAnnotation );
d->icon = icon;
}
EmbeddedFile* FileAttachmentAnnotation::embeddedFile() const
{
Q_D( const FileAttachmentAnnotation );
return d->embfile;
}
void FileAttachmentAnnotation::setEmbeddedFile( EmbeddedFile *ef )
{
Q_D( FileAttachmentAnnotation );
d->embfile = ef;
}
/** SoundAnnotation [Annotation] */
class Okular::SoundAnnotationPrivate : public Okular::AnnotationPrivate
{
public:
SoundAnnotationPrivate()
: AnnotationPrivate(), icon( QStringLiteral("Speaker") ), sound( nullptr )
{
}
~SoundAnnotationPrivate() override
{
delete sound;
}
void setAnnotationProperties( const QDomNode& node ) override;
AnnotationPrivate* getNewAnnotationPrivate() override;
// data fields
QString icon;
Sound *sound;
};
void SoundAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
{
Okular::AnnotationPrivate::setAnnotationProperties(node);
// loop through the whole children looking for a 'sound' element
QDomNode subNode = node.firstChild();
while( subNode.isElement() )
{
QDomElement e = subNode.toElement();
subNode = subNode.nextSibling();
if ( e.tagName() != QLatin1String("sound") )
continue;
// loading complete
break;
}
}
AnnotationPrivate* SoundAnnotationPrivate::getNewAnnotationPrivate()
{
return new SoundAnnotationPrivate();
}
SoundAnnotation::SoundAnnotation()
: Annotation( *new SoundAnnotationPrivate() )
{
}
SoundAnnotation::SoundAnnotation( const QDomNode & node )
: Annotation( *new SoundAnnotationPrivate(), node )
{
}
SoundAnnotation::~SoundAnnotation()
{
}
void SoundAnnotation::store( QDomNode & node, QDomDocument & document ) const
{
// recurse to parent objects storing properties
Annotation::store( node, document );
// create [sound] element
QDomElement soundElement = document.createElement( QStringLiteral("sound") );
node.appendChild( soundElement );
}
Annotation::SubType SoundAnnotation::subType() const
{
return ASound;
}
QString SoundAnnotation::soundIconName() const
{
Q_D( const SoundAnnotation );
return d->icon;
}
void SoundAnnotation::setSoundIconName( const QString &icon )
{
Q_D( SoundAnnotation );
d->icon = icon;
}
Sound* SoundAnnotation::sound() const
{
Q_D( const SoundAnnotation );
return d->sound;
}
void SoundAnnotation::setSound( Sound *s )
{
Q_D( SoundAnnotation );
d->sound = s;
}
/** MovieAnnotation [Annotation] */
class Okular::MovieAnnotationPrivate : public Okular::AnnotationPrivate
{
public:
MovieAnnotationPrivate()
: AnnotationPrivate(), movie( nullptr )
{
}
~MovieAnnotationPrivate() override
{
delete movie;
}
void setAnnotationProperties( const QDomNode& node ) override;
AnnotationPrivate* getNewAnnotationPrivate() override;
// data fields
Movie *movie;
};
void MovieAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
{
Okular::AnnotationPrivate::setAnnotationProperties(node);
// loop through the whole children looking for a 'movie' element
QDomNode subNode = node.firstChild();
while( subNode.isElement() )
{
QDomElement e = subNode.toElement();
subNode = subNode.nextSibling();
if ( e.tagName() != QLatin1String("movie") )
continue;
// loading complete
break;
}
}
AnnotationPrivate* MovieAnnotationPrivate::getNewAnnotationPrivate()
{
return new MovieAnnotationPrivate();
}
MovieAnnotation::MovieAnnotation()
: Annotation( *new MovieAnnotationPrivate() )
{
}
MovieAnnotation::MovieAnnotation( const QDomNode & node )
: Annotation( *new MovieAnnotationPrivate(), node )
{
}
MovieAnnotation::~MovieAnnotation()
{
}
void MovieAnnotation::store( QDomNode & node, QDomDocument & document ) const
{
// recurse to parent objects storing properties
Annotation::store( node, document );
// create [movie] element
QDomElement movieElement = document.createElement( QStringLiteral("movie") );
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;
}
/** ScreenAnnotation [Annotation] */
class Okular::ScreenAnnotationPrivate : public Okular::AnnotationPrivate
{
public:
ScreenAnnotationPrivate();
~ScreenAnnotationPrivate() override;
void setAnnotationProperties( const QDomNode& node ) override;
AnnotationPrivate* getNewAnnotationPrivate() override;
Okular::Action* m_action;
QMap< Okular::Annotation::AdditionalActionType, Okular::Action* > m_additionalActions;
};
ScreenAnnotationPrivate::ScreenAnnotationPrivate()
: m_action( nullptr )
{
}
ScreenAnnotationPrivate::~ScreenAnnotationPrivate()
{
delete m_action;
qDeleteAll( m_additionalActions );
}
void ScreenAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
{
Okular::AnnotationPrivate::setAnnotationProperties(node);
// loop through the whole children looking for a 'screen' element
QDomNode subNode = node.firstChild();
while( subNode.isElement() )
{
QDomElement e = subNode.toElement();
subNode = subNode.nextSibling();
if ( e.tagName() != QLatin1String("screen") )
continue;
// loading complete
break;
}
}
AnnotationPrivate* ScreenAnnotationPrivate::getNewAnnotationPrivate()
{
return new ScreenAnnotationPrivate();
}
ScreenAnnotation::ScreenAnnotation()
: Annotation( *new ScreenAnnotationPrivate() )
{
}
ScreenAnnotation::ScreenAnnotation( const QDomNode & node )
: Annotation( *new ScreenAnnotationPrivate(), node )
{
}
ScreenAnnotation::~ScreenAnnotation()
{
}
void ScreenAnnotation::store( QDomNode & node, QDomDocument & document ) const
{
// recurse to parent objects storing properties
Annotation::store( node, document );
// create [screen] element
QDomElement movieElement = document.createElement( QStringLiteral("screen") );
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 ) )
return nullptr;
else
return d->m_additionalActions.value( type );
}
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;
}
/** WidgetAnnotation [Annotation] */
class Okular::WidgetAnnotationPrivate : public Okular::AnnotationPrivate
{
public:
~WidgetAnnotationPrivate() override;
void setAnnotationProperties( const QDomNode& node ) override;
AnnotationPrivate* getNewAnnotationPrivate() override;
QMap< Okular::Annotation::AdditionalActionType, Okular::Action* > m_additionalActions;
};
WidgetAnnotationPrivate::~WidgetAnnotationPrivate()
{
qDeleteAll( m_additionalActions );
}
void WidgetAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
{
Okular::AnnotationPrivate::setAnnotationProperties(node);
// loop through the whole children looking for a 'widget' element
QDomNode subNode = node.firstChild();
while( subNode.isElement() )
{
QDomElement e = subNode.toElement();
subNode = subNode.nextSibling();
if ( e.tagName() != QLatin1String("widget") )
continue;
// loading complete
break;
}
}
AnnotationPrivate* WidgetAnnotationPrivate::getNewAnnotationPrivate()
{
return new WidgetAnnotationPrivate();
}
WidgetAnnotation::WidgetAnnotation()
: Annotation( *new WidgetAnnotationPrivate() )
{
}
WidgetAnnotation::WidgetAnnotation( const QDomNode & node )
: Annotation( *new WidgetAnnotationPrivate, node )
{
}
WidgetAnnotation::~WidgetAnnotation()
{
}
void WidgetAnnotation::store( QDomNode & node, QDomDocument & document ) const
{
// recurse to parent objects storing properties
Annotation::store( node, document );
// create [widget] element
QDomElement movieElement = document.createElement( QStringLiteral("widget") );
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 ) )
return nullptr;
else
return d->m_additionalActions.value( type );
}
/** RichMediaAnnotation [Annotation] */
class Okular::RichMediaAnnotationPrivate : public Okular::AnnotationPrivate
{
public:
RichMediaAnnotationPrivate();
~RichMediaAnnotationPrivate() override;
void setAnnotationProperties( const QDomNode& node ) override;
AnnotationPrivate* getNewAnnotationPrivate() override;
// data fields
Movie *movie;
EmbeddedFile *embeddedFile;
};
RichMediaAnnotationPrivate::RichMediaAnnotationPrivate()
: movie( nullptr ), embeddedFile( nullptr )
{
}
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();
if ( e.tagName() != QLatin1String("richMedia") )
continue;
// loading complete
break;
}
}
AnnotationPrivate* RichMediaAnnotationPrivate::getNewAnnotationPrivate()
{
return new RichMediaAnnotationPrivate();
}
RichMediaAnnotation::RichMediaAnnotation()
: Annotation( *new RichMediaAnnotationPrivate() )
{
}
RichMediaAnnotation::RichMediaAnnotation( const QDomNode & node )
: Annotation( *new RichMediaAnnotationPrivate, node )
{
}
RichMediaAnnotation::~RichMediaAnnotation()
{
}
void RichMediaAnnotation::store( QDomNode & node, QDomDocument & document ) const
{
// recurse to parent objects storing properties
Annotation::store( node, document );
// create [richMedia] element
QDomElement movieElement = document.createElement( QStringLiteral("richMedia") );
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;
}