You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1230 lines
36 KiB
1230 lines
36 KiB
/*************************************************************************** |
|
* 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. * |
|
***************************************************************************/ |
|
|
|
// qt/kde includes |
|
#include <QtGui/QApplication> |
|
#include <QtGui/QColor> |
|
|
|
#include <kdebug.h> |
|
#include <klocale.h> |
|
|
|
// local includes |
|
#include "annotations.h" |
|
|
|
using namespace Okular; |
|
|
|
//BEGIN AnnotationUtils implementation |
|
Annotation * AnnotationUtils::createAnnotation( const QDomElement & annElement ) |
|
{ |
|
// safety check on annotation element |
|
if ( !annElement.hasAttribute( "type" ) ) |
|
return 0; |
|
|
|
// build annotation of given type |
|
Annotation * annotation = 0; |
|
int typeNumber = annElement.attribute( "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; |
|
} |
|
|
|
// 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( "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(); |
|
} |
|
|
|
QString AnnotationUtils::captionForAnnotation( Annotation * ann ) |
|
{ |
|
if ( !ann ) |
|
return QString(); |
|
|
|
QString ret; |
|
switch( ann->subType() ) |
|
{ |
|
case Okular::Annotation::AText: |
|
if( ( (Okular::TextAnnotation*)ann )->textType == Okular::TextAnnotation::Linked ) |
|
ret = i18n( "Note" ); |
|
else |
|
ret = i18n( "FreeText" ); |
|
break; |
|
case Okular::Annotation::ALine: |
|
ret = i18n( "Line" ); |
|
break; |
|
case Okular::Annotation::AGeom: |
|
ret = i18n( "Geom" ); |
|
break; |
|
case Okular::Annotation::AHighlight: |
|
ret = i18n( "Highlight" ); |
|
break; |
|
case Okular::Annotation::AStamp: |
|
ret = i18n( "Stamp" ); |
|
break; |
|
case Okular::Annotation::AInk: |
|
ret = i18n( "Ink" ); |
|
break; |
|
case Okular::Annotation::A_BASE: |
|
break; |
|
} |
|
return ret; |
|
} |
|
|
|
QRect AnnotationUtils::annotationGeometry( const Annotation * ann, |
|
double scaledWidth, double scaledHeight ) |
|
{ |
|
if ( ann->subType() == Annotation::AText && ( ( (TextAnnotation*)ann )->textType == TextAnnotation::Linked ) ) |
|
{ |
|
return QRect( (int)( ann->transformedBoundingRectangle().left * scaledWidth ), |
|
(int)( ann->transformedBoundingRectangle().top * scaledHeight ), 24, 24 ); |
|
} |
|
|
|
return ann->transformedBoundingRectangle().geometry( (int)scaledWidth, (int)scaledHeight ); |
|
} |
|
//END AnnotationUtils implementation |
|
|
|
|
|
//BEGIN Annotation implementation |
|
Annotation::Style::Style() |
|
: 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 ) |
|
{ |
|
} |
|
|
|
void Annotation::Style::setColor( const QColor &color ) |
|
{ |
|
m_color = color; |
|
} |
|
|
|
QColor Annotation::Style::color() const |
|
{ |
|
return m_color; |
|
} |
|
|
|
void Annotation::Style::setOpacity( double opacity ) |
|
{ |
|
m_opacity = opacity; |
|
} |
|
|
|
double Annotation::Style::opacity() const |
|
{ |
|
return m_opacity; |
|
} |
|
|
|
void Annotation::Style::setWidth( double width ) |
|
{ |
|
m_width = width; |
|
} |
|
|
|
double Annotation::Style::width() const |
|
{ |
|
return m_width; |
|
} |
|
|
|
void Annotation::Style::setLineStyle( LineStyle style ) |
|
{ |
|
m_style = style; |
|
} |
|
|
|
Annotation::LineStyle Annotation::Style::lineStyle() const |
|
{ |
|
return m_style; |
|
} |
|
|
|
void Annotation::Style::setXCorners( double xCorners ) |
|
{ |
|
m_xCorners = xCorners; |
|
} |
|
|
|
double Annotation::Style::xCorners() const |
|
{ |
|
return m_xCorners; |
|
} |
|
|
|
void Annotation::Style::setYCorners( double yCorners ) |
|
{ |
|
m_yCorners = yCorners; |
|
} |
|
|
|
double Annotation::Style::yCorners() const |
|
{ |
|
return m_yCorners; |
|
} |
|
|
|
void Annotation::Style::setMarks( int marks ) |
|
{ |
|
m_marks = marks; |
|
} |
|
|
|
int Annotation::Style::marks() const |
|
{ |
|
return m_marks; |
|
} |
|
|
|
void Annotation::Style::setSpaces( int spaces ) |
|
{ |
|
m_spaces = spaces; |
|
} |
|
|
|
int Annotation::Style::spaces() const |
|
{ |
|
return m_spaces; |
|
} |
|
|
|
void Annotation::Style::setLineEffect( LineEffect effect ) |
|
{ |
|
m_effect = effect; |
|
} |
|
|
|
Annotation::LineEffect Annotation::Style::lineEffect() const |
|
{ |
|
return m_effect; |
|
} |
|
|
|
void Annotation::Style::setEffectIntensity( double intensity ) |
|
{ |
|
m_effectIntensity = intensity; |
|
} |
|
|
|
double Annotation::Style::effectIntensity() const |
|
{ |
|
return m_effectIntensity; |
|
} |
|
|
|
|
|
|
|
|
|
Annotation::Window::Window() |
|
: m_flags( -1 ), m_width( 0 ), m_height( 0 ) |
|
{ |
|
} |
|
|
|
void Annotation::Window::setFlags( int flags ) |
|
{ |
|
m_flags = flags; |
|
} |
|
|
|
int Annotation::Window::flags() const |
|
{ |
|
return m_flags; |
|
} |
|
|
|
void Annotation::Window::setTopLeft( const NormalizedPoint &point ) |
|
{ |
|
m_topLeft = point; |
|
} |
|
|
|
NormalizedPoint Annotation::Window::topLeft() const |
|
{ |
|
return m_topLeft; |
|
} |
|
|
|
void Annotation::Window::setWidth( int width ) |
|
{ |
|
m_width = width; |
|
} |
|
|
|
int Annotation::Window::width() const |
|
{ |
|
return m_width; |
|
} |
|
|
|
void Annotation::Window::setHeight( int height ) |
|
{ |
|
m_height = height; |
|
} |
|
|
|
int Annotation::Window::height() const |
|
{ |
|
return m_height; |
|
} |
|
|
|
void Annotation::Window::setTitle( const QString &title ) |
|
{ |
|
m_title = title; |
|
} |
|
|
|
QString Annotation::Window::title() const |
|
{ |
|
return m_title; |
|
} |
|
|
|
void Annotation::Window::setSummary( const QString &summary ) |
|
{ |
|
m_summary = summary; |
|
} |
|
|
|
QString Annotation::Window::summary() const |
|
{ |
|
return m_summary; |
|
} |
|
|
|
void Annotation::Window::setText( const QString &text ) |
|
{ |
|
m_text = text; |
|
} |
|
|
|
QString Annotation::Window::text() const |
|
{ |
|
return m_text; |
|
} |
|
|
|
|
|
|
|
Annotation::Revision::Revision() |
|
: m_annotation( 0 ), m_scope( Reply ), m_type( None ) |
|
{ |
|
} |
|
|
|
void Annotation::Revision::setAnnotation( Annotation *annotation ) |
|
{ |
|
m_annotation = annotation; |
|
} |
|
|
|
Annotation *Annotation::Revision::annotation() const |
|
{ |
|
return m_annotation; |
|
} |
|
|
|
void Annotation::Revision::setScope( RevisionScope scope ) |
|
{ |
|
m_scope = scope; |
|
} |
|
|
|
Annotation::RevisionScope Annotation::Revision::scope() const |
|
{ |
|
return m_scope; |
|
} |
|
|
|
void Annotation::Revision::setType( RevisionType type ) |
|
{ |
|
m_type = type; |
|
} |
|
|
|
Annotation::RevisionType Annotation::Revision::type() const |
|
{ |
|
return m_type; |
|
} |
|
|
|
|
|
|
|
Annotation::Annotation() |
|
: m_flags( 0 ) |
|
{ |
|
} |
|
|
|
Annotation::~Annotation() |
|
{ |
|
// delete all children revisions |
|
if ( m_revisions.isEmpty() ) |
|
return; |
|
|
|
QLinkedList< Revision >::iterator it = m_revisions.begin(), end = m_revisions.end(); |
|
for ( ; it != end; ++it ) |
|
delete (*it).annotation(); |
|
} |
|
|
|
Annotation::Annotation( const QDomNode & annNode ) |
|
: m_flags( 0 ) |
|
{ |
|
// get the [base] element of the annotation node |
|
QDomElement e = AnnotationUtils::findChildElement( annNode, "base" ); |
|
if ( e.isNull() ) |
|
return; |
|
|
|
// parse -contents- attributes |
|
if ( e.hasAttribute( "author" ) ) |
|
m_author = e.attribute( "author" ); |
|
if ( e.hasAttribute( "contents" ) ) |
|
m_contents = e.attribute( "contents" ); |
|
if ( e.hasAttribute( "uniqueName" ) ) |
|
m_uniqueName = e.attribute( "uniqueName" ); |
|
if ( e.hasAttribute( "modifyDate" ) ) |
|
m_modifyDate = QDateTime::fromString( e.attribute("modifyDate"), Qt::ISODate ); |
|
if ( e.hasAttribute( "creationDate" ) ) |
|
m_creationDate = QDateTime::fromString( e.attribute("creationDate"), Qt::ISODate ); |
|
|
|
// parse -other- attributes |
|
if ( e.hasAttribute( "flags" ) ) |
|
m_flags = e.attribute( "flags" ).toInt(); |
|
if ( e.hasAttribute( "color" ) ) |
|
m_style.setColor( QColor( e.attribute( "color" ) ) ); |
|
if ( e.hasAttribute( "opacity" ) ) |
|
m_style.setOpacity( e.attribute( "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() == "boundary" ) |
|
{ |
|
m_boundary=NormalizedRect(ee.attribute( "l" ).toDouble(), |
|
ee.attribute( "t" ).toDouble(), |
|
ee.attribute( "r" ).toDouble(), |
|
ee.attribute( "b" ).toDouble()); |
|
} |
|
// parse penStyle if not default |
|
else if ( ee.tagName() == "penStyle" ) |
|
{ |
|
m_style.setWidth( ee.attribute( "width" ).toDouble() ); |
|
m_style.setLineStyle( (LineStyle)ee.attribute( "style" ).toInt() ); |
|
m_style.setXCorners( ee.attribute( "xcr" ).toDouble() ); |
|
m_style.setYCorners( ee.attribute( "ycr" ).toDouble() ); |
|
m_style.setMarks( ee.attribute( "marks" ).toInt() ); |
|
m_style.setSpaces( ee.attribute( "spaces" ).toInt() ); |
|
} |
|
// parse effectStyle if not default |
|
else if ( ee.tagName() == "penEffect" ) |
|
{ |
|
m_style.setLineEffect( (LineEffect)ee.attribute( "effect" ).toInt() ); |
|
m_style.setEffectIntensity( ee.attribute( "intensity" ).toDouble() ); |
|
} |
|
// parse window if present |
|
else if ( ee.tagName() == "window" ) |
|
{ |
|
m_window.setFlags( ee.attribute( "flags" ).toInt() ); |
|
m_window.setTopLeft( NormalizedPoint( ee.attribute( "top" ).toDouble(), |
|
ee.attribute( "left" ).toDouble() ) ); |
|
m_window.setWidth( ee.attribute( "width" ).toInt() ); |
|
m_window.setHeight( ee.attribute( "height" ).toInt() ); |
|
m_window.setTitle( ee.attribute( "title" ) ); |
|
m_window.setSummary( ee.attribute( "summary" ) ); |
|
// parse window subnodes |
|
QDomNode winNode = ee.firstChild(); |
|
for ( ; winNode.isElement(); winNode = winNode.nextSibling() ) |
|
{ |
|
QDomElement winElement = winNode.toElement(); |
|
if ( winElement.tagName() == "text" ) |
|
m_window.setText( winElement.firstChild().toCDATASection().data() ); |
|
} |
|
} |
|
} |
|
|
|
// get the [revisions] element of the annotation node |
|
QDomNode revNode = annNode.firstChild(); |
|
for ( ; revNode.isElement(); revNode = revNode.nextSibling() ) |
|
{ |
|
QDomElement revElement = revNode.toElement(); |
|
if ( revElement.tagName() != "revision" ) |
|
continue; |
|
|
|
// compile the Revision structure crating annotation |
|
Revision revision; |
|
revision.setScope( (RevisionScope)revElement.attribute( "revScope" ).toInt() ); |
|
revision.setType( (RevisionType)revElement.attribute( "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; |
|
} |
|
|
|
void Annotation::setAuthor( const QString &author ) |
|
{ |
|
m_author = author; |
|
} |
|
|
|
QString Annotation::author() const |
|
{ |
|
return m_author; |
|
} |
|
|
|
void Annotation::setContents( const QString &contents ) |
|
{ |
|
m_contents = contents; |
|
} |
|
|
|
QString Annotation::contents() const |
|
{ |
|
return m_contents; |
|
} |
|
|
|
void Annotation::setUniqueName( const QString &name ) |
|
{ |
|
m_uniqueName = name; |
|
} |
|
|
|
QString Annotation::uniqueName() const |
|
{ |
|
return m_uniqueName; |
|
} |
|
|
|
void Annotation::setModificationDate( const QDateTime &date ) |
|
{ |
|
m_modifyDate = date; |
|
} |
|
|
|
QDateTime Annotation::modificationDate() const |
|
{ |
|
return m_modifyDate; |
|
} |
|
|
|
void Annotation::setCreationDate( const QDateTime &date ) |
|
{ |
|
m_creationDate = date; |
|
} |
|
|
|
QDateTime Annotation::creationDate() const |
|
{ |
|
return m_creationDate; |
|
} |
|
|
|
void Annotation::setFlags( int flags ) |
|
{ |
|
m_flags = flags; |
|
} |
|
|
|
int Annotation::flags() const |
|
{ |
|
return m_flags; |
|
} |
|
|
|
void Annotation::setBoundingRectangle( const NormalizedRect &rectangle ) |
|
{ |
|
m_boundary = rectangle; |
|
} |
|
|
|
NormalizedRect Annotation::boundingRectangle() const |
|
{ |
|
return m_boundary; |
|
} |
|
|
|
NormalizedRect Annotation::transformedBoundingRectangle() const |
|
{ |
|
return m_transformedBoundary; |
|
} |
|
|
|
Annotation::SubType Annotation::subType() const |
|
{ |
|
return A_BASE; |
|
} |
|
|
|
Annotation::Style & Annotation::style() |
|
{ |
|
return m_style; |
|
} |
|
|
|
const Annotation::Style & Annotation::style() const |
|
{ |
|
return m_style; |
|
} |
|
|
|
Annotation::Window & Annotation::window() |
|
{ |
|
return m_window; |
|
} |
|
|
|
const Annotation::Window & Annotation::window() const |
|
{ |
|
return m_window; |
|
} |
|
|
|
QLinkedList< Annotation::Revision > & Annotation::revisions() |
|
{ |
|
return m_revisions; |
|
} |
|
|
|
const QLinkedList< Annotation::Revision > & Annotation::revisions() const |
|
{ |
|
return m_revisions; |
|
} |
|
|
|
void Annotation::store( QDomNode & annNode, QDomDocument & document ) const |
|
{ |
|
// create [base] element of the annotation node |
|
QDomElement e = document.createElement( "base" ); |
|
annNode.appendChild( e ); |
|
|
|
// store -contents- attributes |
|
if ( !m_author.isEmpty() ) |
|
e.setAttribute( "author", m_author ); |
|
if ( !m_contents.isEmpty() ) |
|
e.setAttribute( "contents", m_contents ); |
|
if ( !m_uniqueName.isEmpty() ) |
|
e.setAttribute( "uniqueName", m_uniqueName ); |
|
if ( m_modifyDate.isValid() ) |
|
e.setAttribute( "modifyDate", m_modifyDate.toString(Qt::ISODate) ); |
|
if ( m_creationDate.isValid() ) |
|
e.setAttribute( "creationDate", m_creationDate.toString(Qt::ISODate) ); |
|
|
|
// store -other- attributes |
|
if ( m_flags ) |
|
e.setAttribute( "flags", m_flags ); |
|
if ( m_style.color().isValid() ) |
|
e.setAttribute( "color", m_style.color().name() ); |
|
if ( m_style.opacity() != 1.0 ) |
|
e.setAttribute( "opacity", m_style.opacity() ); |
|
|
|
// Sub-Node-1 - boundary |
|
QDomElement bE = document.createElement( "boundary" ); |
|
e.appendChild( bE ); |
|
bE.setAttribute( "l", (double)m_boundary.left ); |
|
bE.setAttribute( "t", (double)m_boundary.top ); |
|
bE.setAttribute( "r", (double)m_boundary.right ); |
|
bE.setAttribute( "b", (double)m_boundary.bottom ); |
|
|
|
// Sub-Node-2 - penStyle |
|
if ( m_style.width() != 1 || m_style.lineStyle() != Solid || m_style.xCorners() != 0 || |
|
m_style.yCorners() != 0.0 || m_style.marks() != 3 || m_style.spaces() != 0 ) |
|
{ |
|
QDomElement psE = document.createElement( "penStyle" ); |
|
e.appendChild( psE ); |
|
psE.setAttribute( "width", m_style.width() ); |
|
psE.setAttribute( "style", (int)m_style.lineStyle() ); |
|
psE.setAttribute( "xcr", m_style.xCorners() ); |
|
psE.setAttribute( "ycr", m_style.yCorners() ); |
|
psE.setAttribute( "marks", m_style.marks() ); |
|
psE.setAttribute( "spaces", m_style.spaces() ); |
|
} |
|
|
|
// Sub-Node-3 - penEffect |
|
if ( m_style.lineEffect() != NoEffect || m_style.effectIntensity() != 1.0 ) |
|
{ |
|
QDomElement peE = document.createElement( "penEffect" ); |
|
e.appendChild( peE ); |
|
peE.setAttribute( "effect", (int)m_style.lineEffect() ); |
|
peE.setAttribute( "intensity", m_style.effectIntensity() ); |
|
} |
|
|
|
// Sub-Node-4 - window |
|
if ( m_window.flags() != -1 || !m_window.title().isEmpty() || |
|
!m_window.summary().isEmpty() || !m_window.text().isEmpty() ) |
|
{ |
|
QDomElement wE = document.createElement( "window" ); |
|
e.appendChild( wE ); |
|
wE.setAttribute( "flags", m_window.flags() ); |
|
wE.setAttribute( "top", m_window.topLeft().x ); |
|
wE.setAttribute( "left", m_window.topLeft().y ); |
|
wE.setAttribute( "width", m_window.width() ); |
|
wE.setAttribute( "height", m_window.height() ); |
|
wE.setAttribute( "title", m_window.title() ); |
|
wE.setAttribute( "summary", m_window.summary() ); |
|
// store window.text as a subnode, because we need escaped data |
|
if ( !m_window.text().isEmpty() ) |
|
{ |
|
QDomElement escapedText = document.createElement( "text" ); |
|
wE.appendChild( escapedText ); |
|
QDomCDATASection textCData = document.createCDATASection( m_window.text() ); |
|
escapedText.appendChild( textCData ); |
|
} |
|
} |
|
|
|
// create [revision] element of the annotation node (if any) |
|
if ( m_revisions.isEmpty() ) |
|
return; |
|
|
|
// add all revisions as children of revisions element |
|
QLinkedList< Revision >::const_iterator it = m_revisions.begin(), end = m_revisions.end(); |
|
for ( ; it != end; ++it ) |
|
{ |
|
// create revision element |
|
const Revision & revision = *it; |
|
QDomElement r = document.createElement( "revision" ); |
|
annNode.appendChild( r ); |
|
// set element attributes |
|
r.setAttribute( "revScope", (int)revision.scope() ); |
|
r.setAttribute( "revType", (int)revision.type() ); |
|
// use revision as the annotation element, so fill it up |
|
AnnotationUtils::storeAnnotation( revision.annotation(), r, document ); |
|
} |
|
} |
|
|
|
void Annotation::transform( const QMatrix &matrix ) |
|
{ |
|
m_transformedBoundary = m_boundary; |
|
m_transformedBoundary.transform( matrix ); |
|
} |
|
|
|
//END Annotation implementation |
|
|
|
|
|
/** TextAnnotation [Annotation] */ |
|
/* |
|
The default textIcon for text annotation is Note as the PDF Reference says |
|
*/ |
|
TextAnnotation::TextAnnotation() |
|
: Annotation(), textType( Linked ), textIcon( "Note" ), |
|
inplaceAlign( 0 ), inplaceIntent( Unknown ) |
|
{} |
|
|
|
TextAnnotation::TextAnnotation( const QDomNode & node ) |
|
: Annotation( node ), textType( Linked ), textIcon( "Note" ), |
|
inplaceAlign( 0 ), inplaceIntent( Unknown ) |
|
{ |
|
// 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() != "text" ) |
|
continue; |
|
|
|
// parse the attributes |
|
if ( e.hasAttribute( "type" ) ) |
|
textType = (TextAnnotation::TextType)e.attribute( "type" ).toInt(); |
|
if ( e.hasAttribute( "icon" ) ) |
|
textIcon = e.attribute( "icon" ); |
|
if ( e.hasAttribute( "font" ) ) |
|
textFont.fromString( e.attribute( "font" ) ); |
|
if ( e.hasAttribute( "align" ) ) |
|
inplaceAlign = e.attribute( "align" ).toInt(); |
|
if ( e.hasAttribute( "intent" ) ) |
|
inplaceIntent = (TextAnnotation::InplaceIntent)e.attribute( "intent" ).toInt(); |
|
|
|
// parse the subnodes |
|
QDomNode eSubNode = e.firstChild(); |
|
while ( eSubNode.isElement() ) |
|
{ |
|
QDomElement ee = eSubNode.toElement(); |
|
eSubNode = eSubNode.nextSibling(); |
|
|
|
if ( ee.tagName() == "escapedText" ) |
|
{ |
|
inplaceText = ee.firstChild().toCDATASection().data(); |
|
} |
|
else if ( ee.tagName() == "callout" ) |
|
{ |
|
inplaceCallout[0].x = ee.attribute( "ax" ).toDouble(); |
|
inplaceCallout[0].y = ee.attribute( "ay" ).toDouble(); |
|
inplaceCallout[1].x = ee.attribute( "bx" ).toDouble(); |
|
inplaceCallout[1].y = ee.attribute( "by" ).toDouble(); |
|
inplaceCallout[2].x = ee.attribute( "cx" ).toDouble(); |
|
inplaceCallout[2].y = ee.attribute( "cy" ).toDouble(); |
|
} |
|
} |
|
|
|
// loading complete |
|
break; |
|
} |
|
|
|
for ( int i = 0; i < 3; ++i ) |
|
transformedInplaceCallout[i] = inplaceCallout[i]; |
|
} |
|
|
|
void TextAnnotation::store( QDomNode & node, QDomDocument & document ) const |
|
{ |
|
// recurse to parent objects storing properties |
|
Annotation::store( node, document ); |
|
|
|
// create [text] element |
|
QDomElement textElement = document.createElement( "text" ); |
|
node.appendChild( textElement ); |
|
|
|
// store the optional attributes |
|
if ( textType != Linked ) |
|
textElement.setAttribute( "type", (int)textType ); |
|
if ( textIcon != "Comment" ) |
|
textElement.setAttribute( "icon", textIcon ); |
|
if ( textFont != QApplication::font() ) |
|
textElement.setAttribute( "font", textFont.toString() ); |
|
if ( inplaceAlign ) |
|
textElement.setAttribute( "align", inplaceAlign ); |
|
if ( inplaceIntent != Unknown ) |
|
textElement.setAttribute( "intent", (int)inplaceIntent ); |
|
|
|
// Sub-Node-1 - escapedText |
|
if ( !inplaceText.isEmpty() ) |
|
{ |
|
QDomElement escapedText = document.createElement( "escapedText" ); |
|
textElement.appendChild( escapedText ); |
|
QDomCDATASection textCData = document.createCDATASection( inplaceText ); |
|
escapedText.appendChild( textCData ); |
|
} |
|
|
|
// Sub-Node-2 - callout |
|
if ( inplaceCallout[0].x != 0.0 ) |
|
{ |
|
QDomElement calloutElement = document.createElement( "callout" ); |
|
textElement.appendChild( calloutElement ); |
|
calloutElement.setAttribute( "ax", inplaceCallout[0].x ); |
|
calloutElement.setAttribute( "ay", inplaceCallout[0].y ); |
|
calloutElement.setAttribute( "bx", inplaceCallout[1].x ); |
|
calloutElement.setAttribute( "by", inplaceCallout[1].y ); |
|
calloutElement.setAttribute( "cx", inplaceCallout[2].x ); |
|
calloutElement.setAttribute( "cy", inplaceCallout[2].y ); |
|
} |
|
} |
|
|
|
void TextAnnotation::transform( const QMatrix &matrix ) |
|
{ |
|
Annotation::transform( matrix ); |
|
|
|
for ( int i = 0; i < 3; ++i ) { |
|
transformedInplaceCallout[i] = inplaceCallout[i]; |
|
transformedInplaceCallout[i].transform( matrix ); |
|
} |
|
} |
|
|
|
/** LineAnnotation [Annotation] */ |
|
|
|
LineAnnotation::LineAnnotation() |
|
: Annotation(), lineStartStyle( None ), lineEndStyle( None ), |
|
lineClosed( false ), lineLeadingFwdPt( 0 ), lineLeadingBackPt( 0 ), |
|
lineShowCaption( false ), lineIntent( Unknown ) |
|
{} |
|
|
|
LineAnnotation::LineAnnotation( const QDomNode & node ) |
|
: Annotation( node ), lineStartStyle( None ), lineEndStyle( None ), |
|
lineClosed( false ), lineLeadingFwdPt( 0 ), lineLeadingBackPt( 0 ), |
|
lineShowCaption( false ), lineIntent( Unknown ) |
|
{ |
|
// 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() != "line" ) |
|
continue; |
|
|
|
// parse the attributes |
|
if ( e.hasAttribute( "startStyle" ) ) |
|
lineStartStyle = (LineAnnotation::TermStyle)e.attribute( "startStyle" ).toInt(); |
|
if ( e.hasAttribute( "endStyle" ) ) |
|
lineEndStyle = (LineAnnotation::TermStyle)e.attribute( "endStyle" ).toInt(); |
|
if ( e.hasAttribute( "closed" ) ) |
|
lineClosed = e.attribute( "closed" ).toInt(); |
|
if ( e.hasAttribute( "innerColor" ) ) |
|
lineInnerColor = QColor( e.attribute( "innerColor" ) ); |
|
if ( e.hasAttribute( "leadFwd" ) ) |
|
lineLeadingFwdPt = e.attribute( "leadFwd" ).toDouble(); |
|
if ( e.hasAttribute( "leadBack" ) ) |
|
lineLeadingBackPt = e.attribute( "leadBack" ).toDouble(); |
|
if ( e.hasAttribute( "showCaption" ) ) |
|
lineShowCaption = e.attribute( "showCaption" ).toInt(); |
|
if ( e.hasAttribute( "intent" ) ) |
|
lineIntent = (LineAnnotation::LineIntent)e.attribute( "intent" ).toInt(); |
|
|
|
// parse all 'point' subnodes |
|
QDomNode pointNode = e.firstChild(); |
|
while ( pointNode.isElement() ) |
|
{ |
|
QDomElement pe = pointNode.toElement(); |
|
pointNode = pointNode.nextSibling(); |
|
|
|
if ( pe.tagName() != "point" ) |
|
continue; |
|
|
|
NormalizedPoint p; |
|
p.x = pe.attribute( "x", "0.0" ).toDouble(); |
|
p.y = pe.attribute( "y", "0.0" ).toDouble(); |
|
linePoints.append( p ); |
|
} |
|
|
|
// loading complete |
|
break; |
|
} |
|
|
|
transformedLinePoints = linePoints; |
|
} |
|
|
|
void LineAnnotation::store( QDomNode & node, QDomDocument & document ) const |
|
{ |
|
// recurse to parent objects storing properties |
|
Annotation::store( node, document ); |
|
|
|
// create [line] element |
|
QDomElement lineElement = document.createElement( "line" ); |
|
node.appendChild( lineElement ); |
|
|
|
// store the attributes |
|
if ( lineStartStyle != None ) |
|
lineElement.setAttribute( "startStyle", (int)lineStartStyle ); |
|
if ( lineEndStyle != None ) |
|
lineElement.setAttribute( "endStyle", (int)lineEndStyle ); |
|
if ( lineClosed ) |
|
lineElement.setAttribute( "closed", lineClosed ); |
|
if ( lineInnerColor.isValid() ) |
|
lineElement.setAttribute( "innerColor", lineInnerColor.name() ); |
|
if ( lineLeadingFwdPt != 0.0 ) |
|
lineElement.setAttribute( "leadFwd", lineLeadingFwdPt ); |
|
if ( lineLeadingBackPt != 0.0 ) |
|
lineElement.setAttribute( "leadBack", lineLeadingBackPt ); |
|
if ( lineShowCaption ) |
|
lineElement.setAttribute( "showCaption", lineShowCaption ); |
|
if ( lineIntent != Unknown ) |
|
lineElement.setAttribute( "intent", lineIntent ); |
|
|
|
// append the list of points |
|
int points = linePoints.count(); |
|
if ( points > 1 ) |
|
{ |
|
QLinkedList<NormalizedPoint>::const_iterator it = linePoints.begin(), end = linePoints.end(); |
|
while ( it != end ) |
|
{ |
|
const NormalizedPoint & p = *it; |
|
QDomElement pElement = document.createElement( "point" ); |
|
lineElement.appendChild( pElement ); |
|
pElement.setAttribute( "x", p.x ); |
|
pElement.setAttribute( "y", p.y ); |
|
it++; //to avoid loop |
|
} |
|
} |
|
} |
|
|
|
void LineAnnotation::transform( const QMatrix &matrix ) |
|
{ |
|
Annotation::transform( matrix ); |
|
|
|
transformedLinePoints = linePoints; |
|
|
|
QMutableLinkedListIterator<NormalizedPoint> it( transformedLinePoints ); |
|
while ( it.hasNext() ) |
|
it.next().transform( matrix ); |
|
} |
|
|
|
/** GeomAnnotation [Annotation] */ |
|
|
|
GeomAnnotation::GeomAnnotation() |
|
: Annotation(), geomType( InscribedSquare ), geomWidthPt( 18 ) |
|
{} |
|
|
|
GeomAnnotation::GeomAnnotation( const QDomNode & node ) |
|
: Annotation( node ), geomType( InscribedSquare ), geomWidthPt( 18 ) |
|
{ |
|
// 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() != "geom" ) |
|
continue; |
|
|
|
// parse the attributes |
|
if ( e.hasAttribute( "type" ) ) |
|
geomType = (GeomAnnotation::GeomType)e.attribute( "type" ).toInt(); |
|
if ( e.hasAttribute( "color" ) ) |
|
geomInnerColor = QColor( e.attribute( "color" ) ); |
|
if ( e.hasAttribute( "width" ) ) |
|
geomWidthPt = e.attribute( "width" ).toInt(); |
|
|
|
// loading complete |
|
break; |
|
} |
|
} |
|
|
|
void GeomAnnotation::store( QDomNode & node, QDomDocument & document ) const |
|
{ |
|
// recurse to parent objects storing properties |
|
Annotation::store( node, document ); |
|
|
|
// create [geom] element |
|
QDomElement geomElement = document.createElement( "geom" ); |
|
node.appendChild( geomElement ); |
|
|
|
// append the optional attributes |
|
if ( geomType != InscribedSquare ) |
|
geomElement.setAttribute( "type", (int)geomType ); |
|
if ( geomInnerColor.isValid() ) |
|
geomElement.setAttribute( "color", geomInnerColor.name() ); |
|
if ( geomWidthPt != 18 ) |
|
geomElement.setAttribute( "width", geomWidthPt ); |
|
} |
|
|
|
|
|
/** HighlightAnnotation [Annotation] */ |
|
|
|
HighlightAnnotation::HighlightAnnotation() |
|
: Annotation(), highlightType( Highlight ) |
|
{} |
|
|
|
HighlightAnnotation::HighlightAnnotation( const QDomNode & node ) |
|
: Annotation( node ), highlightType( Highlight ) |
|
{ |
|
// 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() != "hl" ) |
|
continue; |
|
|
|
// parse the attributes |
|
if ( e.hasAttribute( "type" ) ) |
|
highlightType = (HighlightAnnotation::HighlightType)e.attribute( "type" ).toInt(); |
|
|
|
// parse all 'quad' subnodes |
|
QDomNode quadNode = e.firstChild(); |
|
for ( ; quadNode.isElement(); quadNode = quadNode.nextSibling() ) |
|
{ |
|
QDomElement qe = quadNode.toElement(); |
|
if ( qe.tagName() != "quad" ) |
|
continue; |
|
|
|
Quad q; |
|
q.points[0].x = qe.attribute( "ax", "0.0" ).toDouble(); |
|
q.points[0].y = qe.attribute( "ay", "0.0" ).toDouble(); |
|
q.points[1].x = qe.attribute( "bx", "0.0" ).toDouble(); |
|
q.points[1].y = qe.attribute( "by", "0.0" ).toDouble(); |
|
q.points[2].x = qe.attribute( "cx", "0.0" ).toDouble(); |
|
q.points[2].y = qe.attribute( "cy", "0.0" ).toDouble(); |
|
q.points[3].x = qe.attribute( "dx", "0.0" ).toDouble(); |
|
q.points[3].y = qe.attribute( "dy", "0.0" ).toDouble(); |
|
q.capStart = qe.hasAttribute( "start" ); |
|
q.capEnd = qe.hasAttribute( "end" ); |
|
q.feather = qe.attribute( "feather", "0.1" ).toDouble(); |
|
|
|
q.transformedPoints[0] = q.points[0]; |
|
q.transformedPoints[1] = q.points[1]; |
|
q.transformedPoints[2] = q.points[2]; |
|
q.transformedPoints[3] = q.points[3]; |
|
|
|
highlightQuads.append( q ); |
|
} |
|
|
|
// loading complete |
|
break; |
|
} |
|
} |
|
|
|
void HighlightAnnotation::store( QDomNode & node, QDomDocument & document ) const |
|
{ |
|
// recurse to parent objects storing properties |
|
Annotation::store( node, document ); |
|
|
|
// create [hl] element |
|
QDomElement hlElement = document.createElement( "hl" ); |
|
node.appendChild( hlElement ); |
|
|
|
// append the optional attributes |
|
if ( highlightType != Highlight ) |
|
hlElement.setAttribute( "type", (int)highlightType ); |
|
if ( highlightQuads.count() < 1 ) |
|
return; |
|
// append highlight quads, all children describe quads |
|
QList< Quad >::const_iterator it = highlightQuads.begin(), end = highlightQuads.end(); |
|
for ( ; it != end; ++it ) |
|
{ |
|
QDomElement quadElement = document.createElement( "quad" ); |
|
hlElement.appendChild( quadElement ); |
|
const Quad & q = *it; |
|
quadElement.setAttribute( "ax", q.points[0].x ); |
|
quadElement.setAttribute( "ay", q.points[0].y ); |
|
quadElement.setAttribute( "bx", q.points[1].x ); |
|
quadElement.setAttribute( "by", q.points[1].y ); |
|
quadElement.setAttribute( "cx", q.points[2].x ); |
|
quadElement.setAttribute( "cy", q.points[2].y ); |
|
quadElement.setAttribute( "dx", q.points[3].x ); |
|
quadElement.setAttribute( "dy", q.points[3].y ); |
|
if ( q.capStart ) |
|
quadElement.setAttribute( "start", 1 ); |
|
if ( q.capEnd ) |
|
quadElement.setAttribute( "end", 1 ); |
|
quadElement.setAttribute( "feather", q.feather ); |
|
} |
|
} |
|
|
|
void HighlightAnnotation::transform( const QMatrix &matrix ) |
|
{ |
|
Annotation::transform( matrix ); |
|
|
|
QMutableListIterator<Quad> it( highlightQuads ); |
|
while ( it.hasNext() ) { |
|
Quad &quad = it.next(); |
|
|
|
for ( int i = 0; i < 4; ++i ) { |
|
quad.transformedPoints[i] = quad.points[i]; |
|
quad.transformedPoints[i].transform( matrix ); |
|
} |
|
} |
|
} |
|
|
|
/** StampAnnotation [Annotation] */ |
|
|
|
StampAnnotation::StampAnnotation() |
|
: Annotation(), stampIconName( "Draft" ) |
|
{} |
|
|
|
StampAnnotation::StampAnnotation( const QDomNode & node ) |
|
: Annotation( node ), stampIconName( "Draft" ) |
|
{ |
|
// 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() != "stamp" ) |
|
continue; |
|
|
|
// parse the attributes |
|
if ( e.hasAttribute( "icon" ) ) |
|
stampIconName = e.attribute( "icon" ); |
|
|
|
// loading complete |
|
break; |
|
} |
|
} |
|
|
|
void StampAnnotation::store( QDomNode & node, QDomDocument & document ) const |
|
{ |
|
// recurse to parent objects storing properties |
|
Annotation::store( node, document ); |
|
|
|
// create [stamp] element |
|
QDomElement stampElement = document.createElement( "stamp" ); |
|
node.appendChild( stampElement ); |
|
|
|
// append the optional attributes |
|
if ( stampIconName != "Draft" ) |
|
stampElement.setAttribute( "icon", stampIconName ); |
|
} |
|
|
|
|
|
/** InkAnnotation [Annotation] */ |
|
|
|
InkAnnotation::InkAnnotation() |
|
: Annotation() |
|
{} |
|
|
|
InkAnnotation::InkAnnotation( const QDomNode & node ) |
|
: Annotation( node ) |
|
{ |
|
// 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() != "ink" ) |
|
continue; |
|
|
|
// parse the 'path' subnodes |
|
QDomNode pathNode = e.firstChild(); |
|
while ( pathNode.isElement() ) |
|
{ |
|
QDomElement pathElement = pathNode.toElement(); |
|
pathNode = pathNode.nextSibling(); |
|
|
|
if ( pathElement.tagName() != "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() != "point" ) |
|
continue; |
|
|
|
NormalizedPoint p; |
|
p.x = pointElement.attribute( "x", "0.0" ).toDouble(); |
|
p.y = pointElement.attribute( "y", "0.0" ).toDouble(); |
|
path.append( p ); |
|
} |
|
|
|
// add the path to the path list if it contains at least 2 nodes |
|
if ( path.count() >= 2 ) |
|
inkPaths.append( path ); |
|
} |
|
|
|
// loading complete |
|
break; |
|
} |
|
|
|
transformedInkPaths = inkPaths; |
|
} |
|
|
|
void InkAnnotation::store( QDomNode & node, QDomDocument & document ) const |
|
{ |
|
// recurse to parent objects storing properties |
|
Annotation::store( node, document ); |
|
|
|
// create [ink] element |
|
QDomElement inkElement = document.createElement( "ink" ); |
|
node.appendChild( inkElement ); |
|
|
|
// append the optional attributes |
|
if ( inkPaths.count() < 1 ) |
|
return; |
|
QList< QLinkedList<NormalizedPoint> >::const_iterator pIt = inkPaths.begin(), pEnd = inkPaths.end(); |
|
for ( ; pIt != pEnd; ++pIt ) |
|
{ |
|
QDomElement pathElement = document.createElement( "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( "point" ); |
|
pathElement.appendChild( pointElement ); |
|
pointElement.setAttribute( "x", point.x ); |
|
pointElement.setAttribute( "y", point.y ); |
|
} |
|
} |
|
} |
|
|
|
void InkAnnotation::transform( const QMatrix &matrix ) |
|
{ |
|
Annotation::transform( matrix ); |
|
|
|
transformedInkPaths = inkPaths; |
|
|
|
for ( int i = 0; i < transformedInkPaths.count(); ++i ) { |
|
QMutableLinkedListIterator<NormalizedPoint> it( transformedInkPaths[ i ] ); |
|
while ( it.hasNext() ) |
|
it.next().transform( matrix ); |
|
} |
|
}
|
|
|