compile
[kdegraphics.git] / okular / core / annotations.cpp
blob1fbd01a2ce30eb94b45670326f19e7c5547784d4
1 /***************************************************************************
2 * Copyright (C) 2005 by Enrico Ros <eros.kde@email.it> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 ***************************************************************************/
10 #include "annotations.h"
11 #include "annotations_p.h"
13 // qt/kde includes
14 #include <QtGui/QApplication>
15 #include <QtGui/QColor>
17 // local includes
18 #include "document.h"
19 #include "movie.h"
20 #include "page_p.h"
21 #include "sound.h"
23 using namespace Okular;
25 //BEGIN AnnotationUtils implementation
26 Annotation * AnnotationUtils::createAnnotation( const QDomElement & annElement )
28 // safety check on annotation element
29 if ( !annElement.hasAttribute( "type" ) )
30 return 0;
32 // build annotation of given type
33 Annotation * annotation = 0;
34 int typeNumber = annElement.attribute( "type" ).toInt();
35 switch ( typeNumber )
37 case Annotation::AText:
38 annotation = new TextAnnotation( annElement );
39 break;
40 case Annotation::ALine:
41 annotation = new LineAnnotation( annElement );
42 break;
43 case Annotation::AGeom:
44 annotation = new GeomAnnotation( annElement );
45 break;
46 case Annotation::AHighlight:
47 annotation = new HighlightAnnotation( annElement );
48 break;
49 case Annotation::AStamp:
50 annotation = new StampAnnotation( annElement );
51 break;
52 case Annotation::AInk:
53 annotation = new InkAnnotation( annElement );
54 break;
55 case Annotation::ACaret:
56 annotation = new CaretAnnotation( annElement );
57 break;
60 // return created annotation
61 return annotation;
64 void AnnotationUtils::storeAnnotation( const Annotation * ann, QDomElement & annElement,
65 QDomDocument & document )
67 // save annotation's type as element's attribute
68 annElement.setAttribute( "type", (uint)ann->subType() );
70 // append all annotation data as children of this node
71 ann->store( annElement, document );
74 QDomElement AnnotationUtils::findChildElement( const QDomNode & parentNode,
75 const QString & name )
77 // loop through the whole children and return a 'name' named element
78 QDomNode subNode = parentNode.firstChild();
79 while( subNode.isElement() )
81 QDomElement element = subNode.toElement();
82 if ( element.tagName() == name )
83 return element;
84 subNode = subNode.nextSibling();
86 // if the name can't be found, return a dummy null element
87 return QDomElement();
90 QRect AnnotationUtils::annotationGeometry( const Annotation * ann,
91 double scaledWidth, double scaledHeight )
93 if ( ann->subType() == Annotation::AText && ( ( (TextAnnotation*)ann )->textType() == TextAnnotation::Linked ) )
95 return QRect( (int)( ann->transformedBoundingRectangle().left * scaledWidth ),
96 (int)( ann->transformedBoundingRectangle().top * scaledHeight ), 24, 24 );
99 return ann->transformedBoundingRectangle().geometry( (int)scaledWidth, (int)scaledHeight );
101 //END AnnotationUtils implementation
104 //BEGIN Annotation implementation
106 class Annotation::Style::Private
108 public:
109 Private()
110 : m_opacity( 1.0 ), m_width( 1.0 ), m_style( Solid ), m_xCorners( 0.0 ),
111 m_yCorners( 0.0 ), m_marks( 3 ), m_spaces( 0 ), m_effect( NoEffect ),
112 m_effectIntensity( 1.0 )
116 QColor m_color;
117 double m_opacity;
118 double m_width;
119 LineStyle m_style;
120 double m_xCorners;
121 double m_yCorners;
122 int m_marks;
123 int m_spaces;
124 LineEffect m_effect;
125 double m_effectIntensity;
128 Annotation::Style::Style()
129 : d( new Private )
133 Annotation::Style::~Style()
135 delete d;
138 Annotation::Style::Style( const Style &other )
139 : d( new Private )
141 *d = *other.d;
144 Annotation::Style& Annotation::Style::operator=( const Style &other )
146 if ( this != &other )
147 *d = *other.d;
149 return *this;
152 void Annotation::Style::setColor( const QColor &color )
154 d->m_color = color;
157 QColor Annotation::Style::color() const
159 return d->m_color;
162 void Annotation::Style::setOpacity( double opacity )
164 d->m_opacity = opacity;
167 double Annotation::Style::opacity() const
169 return d->m_opacity;
172 void Annotation::Style::setWidth( double width )
174 d->m_width = width;
177 double Annotation::Style::width() const
179 return d->m_width;
182 void Annotation::Style::setLineStyle( LineStyle style )
184 d->m_style = style;
187 Annotation::LineStyle Annotation::Style::lineStyle() const
189 return d->m_style;
192 void Annotation::Style::setXCorners( double xCorners )
194 d->m_xCorners = xCorners;
197 double Annotation::Style::xCorners() const
199 return d->m_xCorners;
202 void Annotation::Style::setYCorners( double yCorners )
204 d->m_yCorners = yCorners;
207 double Annotation::Style::yCorners() const
209 return d->m_yCorners;
212 void Annotation::Style::setMarks( int marks )
214 d->m_marks = marks;
217 int Annotation::Style::marks() const
219 return d->m_marks;
222 void Annotation::Style::setSpaces( int spaces )
224 d->m_spaces = spaces;
227 int Annotation::Style::spaces() const
229 return d->m_spaces;
232 void Annotation::Style::setLineEffect( LineEffect effect )
234 d->m_effect = effect;
237 Annotation::LineEffect Annotation::Style::lineEffect() const
239 return d->m_effect;
242 void Annotation::Style::setEffectIntensity( double intensity )
244 d->m_effectIntensity = intensity;
247 double Annotation::Style::effectIntensity() const
249 return d->m_effectIntensity;
253 class Annotation::Window::Private
255 public:
256 Private()
257 : m_flags( -1 ), m_width( 0 ), m_height( 0 )
261 int m_flags;
262 NormalizedPoint m_topLeft;
263 int m_width;
264 int m_height;
265 QString m_title;
266 QString m_summary;
267 QString m_text;
270 Annotation::Window::Window()
271 : d( new Private )
275 Annotation::Window::~Window()
277 delete d;
280 Annotation::Window::Window( const Window &other )
281 : d( new Private )
283 *d = *other.d;
286 Annotation::Window& Annotation::Window::operator=( const Window &other )
288 if ( this != &other )
289 *d = *other.d;
291 return *this;
294 void Annotation::Window::setFlags( int flags )
296 d->m_flags = flags;
299 int Annotation::Window::flags() const
301 return d->m_flags;
304 void Annotation::Window::setTopLeft( const NormalizedPoint &point )
306 d->m_topLeft = point;
309 NormalizedPoint Annotation::Window::topLeft() const
311 return d->m_topLeft;
314 void Annotation::Window::setWidth( int width )
316 d->m_width = width;
319 int Annotation::Window::width() const
321 return d->m_width;
324 void Annotation::Window::setHeight( int height )
326 d->m_height = height;
329 int Annotation::Window::height() const
331 return d->m_height;
334 void Annotation::Window::setTitle( const QString &title )
336 d->m_title = title;
339 QString Annotation::Window::title() const
341 return d->m_title;
344 void Annotation::Window::setSummary( const QString &summary )
346 d->m_summary = summary;
349 QString Annotation::Window::summary() const
351 return d->m_summary;
354 void Annotation::Window::setText( const QString &text )
356 d->m_text = text;
359 QString Annotation::Window::text() const
361 return d->m_text;
365 class Annotation::Revision::Private
367 public:
368 Private()
369 : m_annotation( 0 ), m_scope( Reply ), m_type( None )
373 Annotation *m_annotation;
374 RevisionScope m_scope;
375 RevisionType m_type;
378 Annotation::Revision::Revision()
379 : d( new Private )
383 Annotation::Revision::~Revision()
385 delete d;
388 Annotation::Revision::Revision( const Revision &other )
389 : d( new Private )
391 *d = *other.d;
394 Annotation::Revision& Annotation::Revision::operator=( const Revision &other )
396 if ( this != &other )
397 *d = *other.d;
399 return *this;
402 void Annotation::Revision::setAnnotation( Annotation *annotation )
404 d->m_annotation = annotation;
407 Annotation *Annotation::Revision::annotation() const
409 return d->m_annotation;
412 void Annotation::Revision::setScope( RevisionScope scope )
414 d->m_scope = scope;
417 Annotation::RevisionScope Annotation::Revision::scope() const
419 return d->m_scope;
422 void Annotation::Revision::setType( RevisionType type )
424 d->m_type = type;
427 Annotation::RevisionType Annotation::Revision::type() const
429 return d->m_type;
433 AnnotationPrivate::AnnotationPrivate()
434 : m_page( 0 ), m_flags( 0 ), m_disposeFunc( 0 )
438 AnnotationPrivate::~AnnotationPrivate()
440 // delete all children revisions
441 if ( m_revisions.isEmpty() )
442 return;
444 QLinkedList< Annotation::Revision >::iterator it = m_revisions.begin(), end = m_revisions.end();
445 for ( ; it != end; ++it )
446 delete (*it).annotation();
449 Annotation::Annotation( AnnotationPrivate &dd )
450 : d_ptr( &dd )
454 Annotation::Annotation( AnnotationPrivate &dd, const QDomNode & annNode )
455 : d_ptr( &dd )
457 Q_D( Annotation );
458 // get the [base] element of the annotation node
459 QDomElement e = AnnotationUtils::findChildElement( annNode, "base" );
460 if ( e.isNull() )
461 return;
463 // parse -contents- attributes
464 if ( e.hasAttribute( "author" ) )
465 d->m_author = e.attribute( "author" );
466 if ( e.hasAttribute( "contents" ) )
467 d->m_contents = e.attribute( "contents" );
468 if ( e.hasAttribute( "uniqueName" ) )
469 d->m_uniqueName = e.attribute( "uniqueName" );
470 if ( e.hasAttribute( "modifyDate" ) )
471 d->m_modifyDate = QDateTime::fromString( e.attribute("modifyDate"), Qt::ISODate );
472 if ( e.hasAttribute( "creationDate" ) )
473 d->m_creationDate = QDateTime::fromString( e.attribute("creationDate"), Qt::ISODate );
475 // parse -other- attributes
476 if ( e.hasAttribute( "flags" ) )
477 d->m_flags = e.attribute( "flags" ).toInt();
478 if ( e.hasAttribute( "color" ) )
479 d->m_style.setColor( QColor( e.attribute( "color" ) ) );
480 if ( e.hasAttribute( "opacity" ) )
481 d->m_style.setOpacity( e.attribute( "opacity" ).toDouble() );
483 // parse -the-subnodes- (describing Style, Window, Revision(s) structures)
484 // Note: all subnodes if present must be 'attributes complete'
485 QDomNode eSubNode = e.firstChild();
486 while ( eSubNode.isElement() )
488 QDomElement ee = eSubNode.toElement();
489 eSubNode = eSubNode.nextSibling();
491 // parse boundary
492 if ( ee.tagName() == "boundary" )
494 d->m_boundary=NormalizedRect(ee.attribute( "l" ).toDouble(),
495 ee.attribute( "t" ).toDouble(),
496 ee.attribute( "r" ).toDouble(),
497 ee.attribute( "b" ).toDouble());
499 // parse penStyle if not default
500 else if ( ee.tagName() == "penStyle" )
502 d->m_style.setWidth( ee.attribute( "width" ).toDouble() );
503 d->m_style.setLineStyle( (LineStyle)ee.attribute( "style" ).toInt() );
504 d->m_style.setXCorners( ee.attribute( "xcr" ).toDouble() );
505 d->m_style.setYCorners( ee.attribute( "ycr" ).toDouble() );
506 d->m_style.setMarks( ee.attribute( "marks" ).toInt() );
507 d->m_style.setSpaces( ee.attribute( "spaces" ).toInt() );
509 // parse effectStyle if not default
510 else if ( ee.tagName() == "penEffect" )
512 d->m_style.setLineEffect( (LineEffect)ee.attribute( "effect" ).toInt() );
513 d->m_style.setEffectIntensity( ee.attribute( "intensity" ).toDouble() );
515 // parse window if present
516 else if ( ee.tagName() == "window" )
518 d->m_window.setFlags( ee.attribute( "flags" ).toInt() );
519 d->m_window.setTopLeft( NormalizedPoint( ee.attribute( "top" ).toDouble(),
520 ee.attribute( "left" ).toDouble() ) );
521 d->m_window.setWidth( ee.attribute( "width" ).toInt() );
522 d->m_window.setHeight( ee.attribute( "height" ).toInt() );
523 d->m_window.setTitle( ee.attribute( "title" ) );
524 d->m_window.setSummary( ee.attribute( "summary" ) );
525 // parse window subnodes
526 QDomNode winNode = ee.firstChild();
527 for ( ; winNode.isElement(); winNode = winNode.nextSibling() )
529 QDomElement winElement = winNode.toElement();
530 if ( winElement.tagName() == "text" )
531 d->m_window.setText( winElement.firstChild().toCDATASection().data() );
536 // get the [revisions] element of the annotation node
537 QDomNode revNode = annNode.firstChild();
538 for ( ; revNode.isElement(); revNode = revNode.nextSibling() )
540 QDomElement revElement = revNode.toElement();
541 if ( revElement.tagName() != "revision" )
542 continue;
544 // compile the Revision structure crating annotation
545 Revision revision;
546 revision.setScope( (RevisionScope)revElement.attribute( "revScope" ).toInt() );
547 revision.setType( (RevisionType)revElement.attribute( "revType" ).toInt() );
548 revision.setAnnotation( AnnotationUtils::createAnnotation( revElement ) );
550 // if annotation is valid, add revision to internal list
551 if ( revision.annotation() )
552 d->m_revisions.append( revision );
555 d->m_transformedBoundary = d->m_boundary;
558 Annotation::~Annotation()
560 if ( d_ptr->m_disposeFunc )
561 d_ptr->m_disposeFunc( this );
563 delete d_ptr;
566 void Annotation::setAuthor( const QString &author )
568 Q_D( Annotation );
569 d->m_author = author;
572 QString Annotation::author() const
574 Q_D( const Annotation );
575 return d->m_author;
578 void Annotation::setContents( const QString &contents )
580 Q_D( Annotation );
581 d->m_contents = contents;
584 QString Annotation::contents() const
586 Q_D( const Annotation );
587 return d->m_contents;
590 void Annotation::setUniqueName( const QString &name )
592 Q_D( Annotation );
593 d->m_uniqueName = name;
596 QString Annotation::uniqueName() const
598 Q_D( const Annotation );
599 return d->m_uniqueName;
602 void Annotation::setModificationDate( const QDateTime &date )
604 Q_D( Annotation );
605 d->m_modifyDate = date;
608 QDateTime Annotation::modificationDate() const
610 Q_D( const Annotation );
611 return d->m_modifyDate;
614 void Annotation::setCreationDate( const QDateTime &date )
616 Q_D( Annotation );
617 d->m_creationDate = date;
620 QDateTime Annotation::creationDate() const
622 Q_D( const Annotation );
623 return d->m_creationDate;
626 void Annotation::setFlags( int flags )
628 Q_D( Annotation );
629 d->m_flags = flags;
632 int Annotation::flags() const
634 Q_D( const Annotation );
635 return d->m_flags;
638 void Annotation::setBoundingRectangle( const NormalizedRect &rectangle )
640 Q_D( Annotation );
641 d->m_boundary = rectangle;
642 d->resetTransformation();
643 if ( d->m_page )
645 d->transform( d->m_page->rotationMatrix() );
649 NormalizedRect Annotation::boundingRectangle() const
651 Q_D( const Annotation );
652 return d->m_boundary;
655 NormalizedRect Annotation::transformedBoundingRectangle() const
657 Q_D( const Annotation );
658 return d->m_transformedBoundary;
661 void Annotation::translate( const NormalizedPoint &coord )
663 Q_D( Annotation );
664 d->translate( coord );
665 d->resetTransformation();
666 if ( d->m_page )
668 d->transform( d->m_page->rotationMatrix() );
672 Annotation::Style & Annotation::style()
674 Q_D( Annotation );
675 return d->m_style;
678 const Annotation::Style & Annotation::style() const
680 Q_D( const Annotation );
681 return d->m_style;
684 Annotation::Window & Annotation::window()
686 Q_D( Annotation );
687 return d->m_window;
690 const Annotation::Window & Annotation::window() const
692 Q_D( const Annotation );
693 return d->m_window;
696 QLinkedList< Annotation::Revision > & Annotation::revisions()
698 Q_D( Annotation );
699 return d->m_revisions;
702 const QLinkedList< Annotation::Revision > & Annotation::revisions() const
704 Q_D( const Annotation );
705 return d->m_revisions;
708 void Annotation::setNativeId( const QVariant &id )
710 Q_D( Annotation );
711 d->m_nativeId = id;
714 QVariant Annotation::nativeId() const
716 Q_D( const Annotation );
717 return d->m_nativeId;
720 void Annotation::setDisposeDataFunction( DisposeDataFunction func )
722 Q_D( Annotation );
723 d->m_disposeFunc = func;
726 bool Annotation::canBeMoved() const
728 Q_D( const Annotation );
729 // for now, it is pointless moving external annotations
730 // as we cannot change them anyway
731 if ( d->m_flags & External )
732 return false;
734 // highlight "requires" to be "bounded" to text, and that's tricky for now
735 if ( subType() == AHighlight )
736 return false;
738 return true;
741 void Annotation::store( QDomNode & annNode, QDomDocument & document ) const
743 Q_D( const Annotation );
744 // create [base] element of the annotation node
745 QDomElement e = document.createElement( "base" );
746 annNode.appendChild( e );
748 // store -contents- attributes
749 if ( !d->m_author.isEmpty() )
750 e.setAttribute( "author", d->m_author );
751 if ( !d->m_contents.isEmpty() )
752 e.setAttribute( "contents", d->m_contents );
753 if ( !d->m_uniqueName.isEmpty() )
754 e.setAttribute( "uniqueName", d->m_uniqueName );
755 if ( d->m_modifyDate.isValid() )
756 e.setAttribute( "modifyDate", d->m_modifyDate.toString(Qt::ISODate) );
757 if ( d->m_creationDate.isValid() )
758 e.setAttribute( "creationDate", d->m_creationDate.toString(Qt::ISODate) );
760 // store -other- attributes
761 if ( d->m_flags )
762 e.setAttribute( "flags", d->m_flags );
763 if ( d->m_style.color().isValid() )
764 e.setAttribute( "color", d->m_style.color().name() );
765 if ( d->m_style.opacity() != 1.0 )
766 e.setAttribute( "opacity", d->m_style.opacity() );
768 // Sub-Node-1 - boundary
769 QDomElement bE = document.createElement( "boundary" );
770 e.appendChild( bE );
771 bE.setAttribute( "l", (double)d->m_boundary.left );
772 bE.setAttribute( "t", (double)d->m_boundary.top );
773 bE.setAttribute( "r", (double)d->m_boundary.right );
774 bE.setAttribute( "b", (double)d->m_boundary.bottom );
776 // Sub-Node-2 - penStyle
777 if ( d->m_style.width() != 1 || d->m_style.lineStyle() != Solid || d->m_style.xCorners() != 0 ||
778 d->m_style.yCorners() != 0.0 || d->m_style.marks() != 3 || d->m_style.spaces() != 0 )
780 QDomElement psE = document.createElement( "penStyle" );
781 e.appendChild( psE );
782 psE.setAttribute( "width", d->m_style.width() );
783 psE.setAttribute( "style", (int)d->m_style.lineStyle() );
784 psE.setAttribute( "xcr", d->m_style.xCorners() );
785 psE.setAttribute( "ycr", d->m_style.yCorners() );
786 psE.setAttribute( "marks", d->m_style.marks() );
787 psE.setAttribute( "spaces", d->m_style.spaces() );
790 // Sub-Node-3 - penEffect
791 if ( d->m_style.lineEffect() != NoEffect || d->m_style.effectIntensity() != 1.0 )
793 QDomElement peE = document.createElement( "penEffect" );
794 e.appendChild( peE );
795 peE.setAttribute( "effect", (int)d->m_style.lineEffect() );
796 peE.setAttribute( "intensity", d->m_style.effectIntensity() );
799 // Sub-Node-4 - window
800 if ( d->m_window.flags() != -1 || !d->m_window.title().isEmpty() ||
801 !d->m_window.summary().isEmpty() || !d->m_window.text().isEmpty() )
803 QDomElement wE = document.createElement( "window" );
804 e.appendChild( wE );
805 wE.setAttribute( "flags", d->m_window.flags() );
806 wE.setAttribute( "top", d->m_window.topLeft().x );
807 wE.setAttribute( "left", d->m_window.topLeft().y );
808 wE.setAttribute( "width", d->m_window.width() );
809 wE.setAttribute( "height", d->m_window.height() );
810 wE.setAttribute( "title", d->m_window.title() );
811 wE.setAttribute( "summary", d->m_window.summary() );
812 // store window.text as a subnode, because we need escaped data
813 if ( !d->m_window.text().isEmpty() )
815 QDomElement escapedText = document.createElement( "text" );
816 wE.appendChild( escapedText );
817 QDomCDATASection textCData = document.createCDATASection( d->m_window.text() );
818 escapedText.appendChild( textCData );
822 // create [revision] element of the annotation node (if any)
823 if ( d->m_revisions.isEmpty() )
824 return;
826 // add all revisions as children of revisions element
827 QLinkedList< Revision >::const_iterator it = d->m_revisions.begin(), end = d->m_revisions.end();
828 for ( ; it != end; ++it )
830 // create revision element
831 const Revision & revision = *it;
832 QDomElement r = document.createElement( "revision" );
833 annNode.appendChild( r );
834 // set element attributes
835 r.setAttribute( "revScope", (int)revision.scope() );
836 r.setAttribute( "revType", (int)revision.type() );
837 // use revision as the annotation element, so fill it up
838 AnnotationUtils::storeAnnotation( revision.annotation(), r, document );
842 void AnnotationPrivate::annotationTransform( const QMatrix &matrix )
844 resetTransformation();
845 transform( matrix );
848 void AnnotationPrivate::transform( const QMatrix &matrix )
850 m_transformedBoundary.transform( matrix );
853 void AnnotationPrivate::baseTransform( const QMatrix &matrix )
855 m_boundary.transform( matrix );
858 void AnnotationPrivate::resetTransformation()
860 m_transformedBoundary = m_boundary;
863 void AnnotationPrivate::translate( const NormalizedPoint &coord )
865 m_boundary.left = m_boundary.left + coord.x;
866 m_boundary.right = m_boundary.right + coord.x;
867 m_boundary.top = m_boundary.top + coord.y;
868 m_boundary.bottom = m_boundary.bottom + coord.y;
871 //END Annotation implementation
874 /** TextAnnotation [Annotation] */
876 class Okular::TextAnnotationPrivate : public Okular::AnnotationPrivate
878 public:
879 TextAnnotationPrivate()
880 : AnnotationPrivate(), m_textType( TextAnnotation::Linked ),
881 m_textIcon( "Note" ), m_inplaceAlign( 0 ),
882 m_inplaceIntent( TextAnnotation::Unknown )
886 virtual void transform( const QMatrix &matrix );
887 virtual void baseTransform( const QMatrix &matrix );
888 virtual void resetTransformation();
889 virtual void translate( const NormalizedPoint &coord );
891 TextAnnotation::TextType m_textType;
892 QString m_textIcon;
893 QFont m_textFont;
894 int m_inplaceAlign;
895 QString m_inplaceText;
896 NormalizedPoint m_inplaceCallout[3];
897 NormalizedPoint m_transformedInplaceCallout[3];
898 TextAnnotation::InplaceIntent m_inplaceIntent;
902 The default textIcon for text annotation is Note as the PDF Reference says
904 TextAnnotation::TextAnnotation()
905 : Annotation( *new TextAnnotationPrivate() )
909 TextAnnotation::TextAnnotation( const QDomNode & node )
910 : Annotation( *new TextAnnotationPrivate(), node )
912 Q_D( TextAnnotation );
913 // loop through the whole children looking for a 'text' element
914 QDomNode subNode = node.firstChild();
915 while( subNode.isElement() )
917 QDomElement e = subNode.toElement();
918 subNode = subNode.nextSibling();
919 if ( e.tagName() != "text" )
920 continue;
922 // parse the attributes
923 if ( e.hasAttribute( "type" ) )
924 d->m_textType = (TextAnnotation::TextType)e.attribute( "type" ).toInt();
925 if ( e.hasAttribute( "icon" ) )
926 d->m_textIcon = e.attribute( "icon" );
927 if ( e.hasAttribute( "font" ) )
928 d->m_textFont.fromString( e.attribute( "font" ) );
929 if ( e.hasAttribute( "align" ) )
930 d->m_inplaceAlign = e.attribute( "align" ).toInt();
931 if ( e.hasAttribute( "intent" ) )
932 d->m_inplaceIntent = (TextAnnotation::InplaceIntent)e.attribute( "intent" ).toInt();
934 // parse the subnodes
935 QDomNode eSubNode = e.firstChild();
936 while ( eSubNode.isElement() )
938 QDomElement ee = eSubNode.toElement();
939 eSubNode = eSubNode.nextSibling();
941 if ( ee.tagName() == "escapedText" )
943 d->m_inplaceText = ee.firstChild().toCDATASection().data();
945 else if ( ee.tagName() == "callout" )
947 d->m_inplaceCallout[0].x = ee.attribute( "ax" ).toDouble();
948 d->m_inplaceCallout[0].y = ee.attribute( "ay" ).toDouble();
949 d->m_inplaceCallout[1].x = ee.attribute( "bx" ).toDouble();
950 d->m_inplaceCallout[1].y = ee.attribute( "by" ).toDouble();
951 d->m_inplaceCallout[2].x = ee.attribute( "cx" ).toDouble();
952 d->m_inplaceCallout[2].y = ee.attribute( "cy" ).toDouble();
956 // loading complete
957 break;
960 for ( int i = 0; i < 3; ++i )
961 d->m_transformedInplaceCallout[i] = d->m_inplaceCallout[i];
964 TextAnnotation::~TextAnnotation()
968 void TextAnnotation::setTextType( TextType textType )
970 Q_D( TextAnnotation );
971 d->m_textType = textType;
974 TextAnnotation::TextType TextAnnotation::textType() const
976 Q_D( const TextAnnotation );
977 return d->m_textType;
980 void TextAnnotation::setTextIcon( const QString &icon )
982 Q_D( TextAnnotation );
983 d->m_textIcon = icon;
986 QString TextAnnotation::textIcon() const
988 Q_D( const TextAnnotation );
989 return d->m_textIcon;
992 void TextAnnotation::setTextFont( const QFont &font )
994 Q_D( TextAnnotation );
995 d->m_textFont = font;
998 QFont TextAnnotation::textFont() const
1000 Q_D( const TextAnnotation );
1001 return d->m_textFont;
1004 void TextAnnotation::setInplaceAlignment( int alignment )
1006 Q_D( TextAnnotation );
1007 d->m_inplaceAlign = alignment;
1010 int TextAnnotation::inplaceAlignment() const
1012 Q_D( const TextAnnotation );
1013 return d->m_inplaceAlign;
1016 void TextAnnotation::setInplaceText( const QString &text )
1018 Q_D( TextAnnotation );
1019 d->m_inplaceText = text;
1022 QString TextAnnotation::inplaceText() const
1024 Q_D( const TextAnnotation );
1025 return d->m_inplaceText;
1028 void TextAnnotation::setInplaceCallout( const NormalizedPoint &point, int index )
1030 if ( index < 0 || index > 2 )
1031 return;
1033 Q_D( TextAnnotation );
1034 d->m_inplaceCallout[ index ] = point;
1037 NormalizedPoint TextAnnotation::inplaceCallout( int index ) const
1039 if ( index < 0 || index > 2 )
1040 return NormalizedPoint();
1042 Q_D( const TextAnnotation );
1043 return d->m_inplaceCallout[ index ];
1046 NormalizedPoint TextAnnotation::transformedInplaceCallout( int index ) const
1048 if ( index < 0 || index > 2 )
1049 return NormalizedPoint();
1051 Q_D( const TextAnnotation );
1052 return d->m_transformedInplaceCallout[ index ];
1055 void TextAnnotation::setInplaceIntent( InplaceIntent intent )
1057 Q_D( TextAnnotation );
1058 d->m_inplaceIntent = intent;
1061 TextAnnotation::InplaceIntent TextAnnotation::inplaceIntent() const
1063 Q_D( const TextAnnotation );
1064 return d->m_inplaceIntent;
1067 Annotation::SubType TextAnnotation::subType() const
1069 return AText;
1072 void TextAnnotation::store( QDomNode & node, QDomDocument & document ) const
1074 Q_D( const TextAnnotation );
1075 // recurse to parent objects storing properties
1076 Annotation::store( node, document );
1078 // create [text] element
1079 QDomElement textElement = document.createElement( "text" );
1080 node.appendChild( textElement );
1082 // store the optional attributes
1083 if ( d->m_textType != Linked )
1084 textElement.setAttribute( "type", (int)d->m_textType );
1085 if ( d->m_textIcon != "Comment" )
1086 textElement.setAttribute( "icon", d->m_textIcon );
1087 if ( d->m_textFont != QApplication::font() )
1088 textElement.setAttribute( "font", d->m_textFont.toString() );
1089 if ( d->m_inplaceAlign )
1090 textElement.setAttribute( "align", d->m_inplaceAlign );
1091 if ( d->m_inplaceIntent != Unknown )
1092 textElement.setAttribute( "intent", (int)d->m_inplaceIntent );
1094 // Sub-Node-1 - escapedText
1095 if ( !d->m_inplaceText.isEmpty() )
1097 QDomElement escapedText = document.createElement( "escapedText" );
1098 textElement.appendChild( escapedText );
1099 QDomCDATASection textCData = document.createCDATASection( d->m_inplaceText );
1100 escapedText.appendChild( textCData );
1103 // Sub-Node-2 - callout
1104 if ( d->m_inplaceCallout[0].x != 0.0 )
1106 QDomElement calloutElement = document.createElement( "callout" );
1107 textElement.appendChild( calloutElement );
1108 calloutElement.setAttribute( "ax", d->m_inplaceCallout[0].x );
1109 calloutElement.setAttribute( "ay", d->m_inplaceCallout[0].y );
1110 calloutElement.setAttribute( "bx", d->m_inplaceCallout[1].x );
1111 calloutElement.setAttribute( "by", d->m_inplaceCallout[1].y );
1112 calloutElement.setAttribute( "cx", d->m_inplaceCallout[2].x );
1113 calloutElement.setAttribute( "cy", d->m_inplaceCallout[2].y );
1117 void TextAnnotationPrivate::transform( const QMatrix &matrix )
1119 AnnotationPrivate::transform( matrix );
1121 for ( int i = 0; i < 3; ++i ) {
1122 m_transformedInplaceCallout[i].transform( matrix );
1126 void TextAnnotationPrivate::baseTransform( const QMatrix &matrix )
1128 AnnotationPrivate::baseTransform( matrix );
1130 for ( int i = 0; i < 3; ++i ) {
1131 m_inplaceCallout[i].transform( matrix );
1135 void TextAnnotationPrivate::resetTransformation()
1137 AnnotationPrivate::resetTransformation();
1139 for ( int i = 0; i < 3; ++i ) {
1140 m_transformedInplaceCallout[i] = m_inplaceCallout[i];
1144 void TextAnnotationPrivate::translate( const NormalizedPoint &coord )
1146 AnnotationPrivate::translate( coord );
1148 #define ADD_COORD( c1, c2 ) \
1150 c1.x = c1.x + c2.x; \
1151 c1.y = c1.y + c2.y; \
1153 ADD_COORD( m_inplaceCallout[0], coord )
1154 ADD_COORD( m_inplaceCallout[1], coord )
1155 ADD_COORD( m_inplaceCallout[2], coord )
1156 #undef ADD_COORD
1159 /** LineAnnotation [Annotation] */
1161 class Okular::LineAnnotationPrivate : public Okular::AnnotationPrivate
1163 public:
1164 LineAnnotationPrivate()
1165 : AnnotationPrivate(),
1166 m_lineStartStyle( LineAnnotation::None ), m_lineEndStyle( LineAnnotation::None ),
1167 m_lineClosed( false ), m_lineShowCaption( false ), m_lineLeadingFwdPt( 0 ),
1168 m_lineLeadingBackPt( 0 ), m_lineIntent( LineAnnotation::Unknown )
1172 virtual void transform( const QMatrix &matrix );
1173 virtual void baseTransform( const QMatrix &matrix );
1174 virtual void resetTransformation();
1175 virtual void translate( const NormalizedPoint &coord );
1177 QLinkedList<NormalizedPoint> m_linePoints;
1178 QLinkedList<NormalizedPoint> m_transformedLinePoints;
1179 LineAnnotation::TermStyle m_lineStartStyle;
1180 LineAnnotation::TermStyle m_lineEndStyle;
1181 bool m_lineClosed : 1;
1182 bool m_lineShowCaption : 1;
1183 QColor m_lineInnerColor;
1184 double m_lineLeadingFwdPt;
1185 double m_lineLeadingBackPt;
1186 LineAnnotation::LineIntent m_lineIntent;
1189 LineAnnotation::LineAnnotation()
1190 : Annotation( *new LineAnnotationPrivate() )
1194 LineAnnotation::LineAnnotation( const QDomNode & node )
1195 : Annotation( *new LineAnnotationPrivate(), node )
1197 Q_D( LineAnnotation );
1198 // loop through the whole children looking for a 'line' element
1199 QDomNode subNode = node.firstChild();
1200 while( subNode.isElement() )
1202 QDomElement e = subNode.toElement();
1203 subNode = subNode.nextSibling();
1204 if ( e.tagName() != "line" )
1205 continue;
1207 // parse the attributes
1208 if ( e.hasAttribute( "startStyle" ) )
1209 d->m_lineStartStyle = (LineAnnotation::TermStyle)e.attribute( "startStyle" ).toInt();
1210 if ( e.hasAttribute( "endStyle" ) )
1211 d->m_lineEndStyle = (LineAnnotation::TermStyle)e.attribute( "endStyle" ).toInt();
1212 if ( e.hasAttribute( "closed" ) )
1213 d->m_lineClosed = e.attribute( "closed" ).toInt();
1214 if ( e.hasAttribute( "innerColor" ) )
1215 d->m_lineInnerColor = QColor( e.attribute( "innerColor" ) );
1216 if ( e.hasAttribute( "leadFwd" ) )
1217 d->m_lineLeadingFwdPt = e.attribute( "leadFwd" ).toDouble();
1218 if ( e.hasAttribute( "leadBack" ) )
1219 d->m_lineLeadingBackPt = e.attribute( "leadBack" ).toDouble();
1220 if ( e.hasAttribute( "showCaption" ) )
1221 d->m_lineShowCaption = e.attribute( "showCaption" ).toInt();
1222 if ( e.hasAttribute( "intent" ) )
1223 d->m_lineIntent = (LineAnnotation::LineIntent)e.attribute( "intent" ).toInt();
1225 // parse all 'point' subnodes
1226 QDomNode pointNode = e.firstChild();
1227 while ( pointNode.isElement() )
1229 QDomElement pe = pointNode.toElement();
1230 pointNode = pointNode.nextSibling();
1232 if ( pe.tagName() != "point" )
1233 continue;
1235 NormalizedPoint p;
1236 p.x = pe.attribute( "x", "0.0" ).toDouble();
1237 p.y = pe.attribute( "y", "0.0" ).toDouble();
1238 d->m_linePoints.append( p );
1241 // loading complete
1242 break;
1245 d->m_transformedLinePoints = d->m_linePoints;
1248 LineAnnotation::~LineAnnotation()
1252 void LineAnnotation::setLinePoints( const QLinkedList<NormalizedPoint> &points )
1254 Q_D( LineAnnotation );
1255 d->m_linePoints = points;
1258 QLinkedList<NormalizedPoint> LineAnnotation::linePoints() const
1260 Q_D( const LineAnnotation );
1261 return d->m_linePoints;
1264 QLinkedList<NormalizedPoint> LineAnnotation::transformedLinePoints() const
1266 Q_D( const LineAnnotation );
1267 return d->m_transformedLinePoints;
1270 void LineAnnotation::setLineStartStyle( TermStyle style )
1272 Q_D( LineAnnotation );
1273 d->m_lineStartStyle = style;
1276 LineAnnotation::TermStyle LineAnnotation::lineStartStyle() const
1278 Q_D( const LineAnnotation );
1279 return d->m_lineStartStyle;
1282 void LineAnnotation::setLineEndStyle( TermStyle style )
1284 Q_D( LineAnnotation );
1285 d->m_lineEndStyle = style;
1288 LineAnnotation::TermStyle LineAnnotation::lineEndStyle() const
1290 Q_D( const LineAnnotation );
1291 return d->m_lineEndStyle;
1294 void LineAnnotation::setLineClosed( bool closed )
1296 Q_D( LineAnnotation );
1297 d->m_lineClosed = closed;
1300 bool LineAnnotation::lineClosed() const
1302 Q_D( const LineAnnotation );
1303 return d->m_lineClosed;
1306 void LineAnnotation::setLineInnerColor( const QColor &color )
1308 Q_D( LineAnnotation );
1309 d->m_lineInnerColor = color;
1312 QColor LineAnnotation::lineInnerColor() const
1314 Q_D( const LineAnnotation );
1315 return d->m_lineInnerColor;
1318 void LineAnnotation::setLineLeadingForwardPoint( double point )
1320 Q_D( LineAnnotation );
1321 d->m_lineLeadingFwdPt = point;
1324 double LineAnnotation::lineLeadingForwardPoint() const
1326 Q_D( const LineAnnotation );
1327 return d->m_lineLeadingFwdPt;
1330 void LineAnnotation::setLineLeadingBackwardPoint( double point )
1332 Q_D( LineAnnotation );
1333 d->m_lineLeadingBackPt = point;
1336 double LineAnnotation::lineLeadingBackwardPoint() const
1338 Q_D( const LineAnnotation );
1339 return d->m_lineLeadingBackPt;
1342 void LineAnnotation::setShowCaption( bool show )
1344 Q_D( LineAnnotation );
1345 d->m_lineShowCaption = show;
1348 bool LineAnnotation::showCaption() const
1350 Q_D( const LineAnnotation );
1351 return d->m_lineShowCaption;
1354 void LineAnnotation::setLineIntent( LineIntent intent )
1356 Q_D( LineAnnotation );
1357 d->m_lineIntent = intent;
1360 LineAnnotation::LineIntent LineAnnotation::lineIntent() const
1362 Q_D( const LineAnnotation );
1363 return d->m_lineIntent;
1366 Annotation::SubType LineAnnotation::subType() const
1368 return ALine;
1371 void LineAnnotation::store( QDomNode & node, QDomDocument & document ) const
1373 Q_D( const LineAnnotation );
1374 // recurse to parent objects storing properties
1375 Annotation::store( node, document );
1377 // create [line] element
1378 QDomElement lineElement = document.createElement( "line" );
1379 node.appendChild( lineElement );
1381 // store the attributes
1382 if ( d->m_lineStartStyle != None )
1383 lineElement.setAttribute( "startStyle", (int)d->m_lineStartStyle );
1384 if ( d->m_lineEndStyle != None )
1385 lineElement.setAttribute( "endStyle", (int)d->m_lineEndStyle );
1386 if ( d->m_lineClosed )
1387 lineElement.setAttribute( "closed", d->m_lineClosed );
1388 if ( d->m_lineInnerColor.isValid() )
1389 lineElement.setAttribute( "innerColor", d->m_lineInnerColor.name() );
1390 if ( d->m_lineLeadingFwdPt != 0.0 )
1391 lineElement.setAttribute( "leadFwd", d->m_lineLeadingFwdPt );
1392 if ( d->m_lineLeadingBackPt != 0.0 )
1393 lineElement.setAttribute( "leadBack", d->m_lineLeadingBackPt );
1394 if ( d->m_lineShowCaption )
1395 lineElement.setAttribute( "showCaption", d->m_lineShowCaption );
1396 if ( d->m_lineIntent != Unknown )
1397 lineElement.setAttribute( "intent", d->m_lineIntent );
1399 // append the list of points
1400 int points = d->m_linePoints.count();
1401 if ( points > 1 )
1403 QLinkedList<NormalizedPoint>::const_iterator it = d->m_linePoints.begin(), end = d->m_linePoints.end();
1404 while ( it != end )
1406 const NormalizedPoint & p = *it;
1407 QDomElement pElement = document.createElement( "point" );
1408 lineElement.appendChild( pElement );
1409 pElement.setAttribute( "x", p.x );
1410 pElement.setAttribute( "y", p.y );
1411 it++; //to avoid loop
1416 void LineAnnotationPrivate::transform( const QMatrix &matrix )
1418 AnnotationPrivate::transform( matrix );
1420 QMutableLinkedListIterator<NormalizedPoint> it( m_transformedLinePoints );
1421 while ( it.hasNext() )
1422 it.next().transform( matrix );
1425 void LineAnnotationPrivate::baseTransform( const QMatrix &matrix )
1427 AnnotationPrivate::baseTransform( matrix );
1429 QMutableLinkedListIterator<NormalizedPoint> it( m_linePoints );
1430 while ( it.hasNext() )
1431 it.next().transform( matrix );
1434 void LineAnnotationPrivate::resetTransformation()
1436 AnnotationPrivate::resetTransformation();
1438 m_transformedLinePoints = m_linePoints;
1441 void LineAnnotationPrivate::translate( const NormalizedPoint &coord )
1443 AnnotationPrivate::translate( coord );
1445 QMutableLinkedListIterator<NormalizedPoint> it( m_linePoints );
1446 while ( it.hasNext() )
1448 NormalizedPoint& p = it.next();
1449 p.x = p.x + coord.x;
1450 p.y = p.y + coord.y;
1454 /** GeomAnnotation [Annotation] */
1456 class Okular::GeomAnnotationPrivate : public Okular::AnnotationPrivate
1458 public:
1459 GeomAnnotationPrivate()
1460 : AnnotationPrivate(), m_geomType( GeomAnnotation::InscribedSquare )
1464 GeomAnnotation::GeomType m_geomType;
1465 QColor m_geomInnerColor;
1468 GeomAnnotation::GeomAnnotation()
1469 : Annotation( *new GeomAnnotationPrivate() )
1473 GeomAnnotation::GeomAnnotation( const QDomNode & node )
1474 : Annotation( *new GeomAnnotationPrivate(), node )
1476 Q_D( GeomAnnotation );
1477 // loop through the whole children looking for a 'geom' element
1478 QDomNode subNode = node.firstChild();
1479 while( subNode.isElement() )
1481 QDomElement e = subNode.toElement();
1482 subNode = subNode.nextSibling();
1483 if ( e.tagName() != "geom" )
1484 continue;
1486 // parse the attributes
1487 if ( e.hasAttribute( "type" ) )
1488 d->m_geomType = (GeomAnnotation::GeomType)e.attribute( "type" ).toInt();
1489 if ( e.hasAttribute( "color" ) )
1490 d->m_geomInnerColor = QColor( e.attribute( "color" ) );
1491 // compatibility
1492 if ( e.hasAttribute( "width" ) )
1493 d->m_style.setWidth( e.attribute( "width" ).toInt() );
1495 // loading complete
1496 break;
1500 GeomAnnotation::~GeomAnnotation()
1504 void GeomAnnotation::setGeometricalType( GeomType type )
1506 Q_D( GeomAnnotation );
1507 d->m_geomType = type;
1510 GeomAnnotation::GeomType GeomAnnotation::geometricalType() const
1512 Q_D( const GeomAnnotation );
1513 return d->m_geomType;
1516 void GeomAnnotation::setGeometricalInnerColor( const QColor &color )
1518 Q_D( GeomAnnotation );
1519 d->m_geomInnerColor = color;
1522 QColor GeomAnnotation::geometricalInnerColor() const
1524 Q_D( const GeomAnnotation );
1525 return d->m_geomInnerColor;
1528 void GeomAnnotation::setGeometricalPointWidth( int width )
1530 Q_D( GeomAnnotation );
1531 d->m_style.setWidth( width );
1534 int GeomAnnotation::geometricalPointWidth() const
1536 Q_D( const GeomAnnotation );
1537 return static_cast< int >( d->m_style.width() );
1540 Annotation::SubType GeomAnnotation::subType() const
1542 return AGeom;
1545 void GeomAnnotation::store( QDomNode & node, QDomDocument & document ) const
1547 Q_D( const GeomAnnotation );
1548 // recurse to parent objects storing properties
1549 Annotation::store( node, document );
1551 // create [geom] element
1552 QDomElement geomElement = document.createElement( "geom" );
1553 node.appendChild( geomElement );
1555 // append the optional attributes
1556 if ( d->m_geomType != InscribedSquare )
1557 geomElement.setAttribute( "type", (int)d->m_geomType );
1558 if ( d->m_geomInnerColor.isValid() )
1559 geomElement.setAttribute( "color", d->m_geomInnerColor.name() );
1562 /** HighlightAnnotation [Annotation] */
1564 class HighlightAnnotation::Quad::Private
1566 public:
1567 Private()
1571 NormalizedPoint m_points[4];
1572 NormalizedPoint m_transformedPoints[4];
1573 bool m_capStart : 1;
1574 bool m_capEnd : 1;
1575 double m_feather;
1578 HighlightAnnotation::Quad::Quad()
1579 : d( new Private )
1583 HighlightAnnotation::Quad::~Quad()
1585 delete d;
1588 HighlightAnnotation::Quad::Quad( const Quad &other )
1589 : d( new Private )
1591 *d = *other.d;
1594 HighlightAnnotation::Quad& HighlightAnnotation::Quad::operator=( const Quad &other )
1596 if ( this != &other )
1597 *d = *other.d;
1599 return *this;
1602 void HighlightAnnotation::Quad::setPoint( const NormalizedPoint &point, int index )
1604 if ( index < 0 || index > 3 )
1605 return;
1607 d->m_points[ index ] = point;
1610 NormalizedPoint HighlightAnnotation::Quad::point( int index ) const
1612 if ( index < 0 || index > 3 )
1613 return NormalizedPoint();
1615 return d->m_points[ index ];
1618 NormalizedPoint HighlightAnnotation::Quad::transformedPoint( int index ) const
1620 if ( index < 0 || index > 3 )
1621 return NormalizedPoint();
1623 return d->m_transformedPoints[ index ];
1626 void HighlightAnnotation::Quad::setCapStart( bool value )
1628 d->m_capStart = value;
1631 bool HighlightAnnotation::Quad::capStart() const
1633 return d->m_capStart;
1636 void HighlightAnnotation::Quad::setCapEnd( bool value )
1638 d->m_capEnd = value;
1641 bool HighlightAnnotation::Quad::capEnd() const
1643 return d->m_capEnd;
1646 void HighlightAnnotation::Quad::setFeather( double width )
1648 d->m_feather = width;
1651 double HighlightAnnotation::Quad::feather() const
1653 return d->m_feather;
1656 void HighlightAnnotation::Quad::transform( const QMatrix &matrix )
1658 for ( int i = 0; i < 4; ++i ) {
1659 d->m_transformedPoints[ i ] = d->m_points[ i ];
1660 d->m_transformedPoints[ i ].transform( matrix );
1665 class Okular::HighlightAnnotationPrivate : public Okular::AnnotationPrivate
1667 public:
1668 HighlightAnnotationPrivate()
1669 : AnnotationPrivate(), m_highlightType( HighlightAnnotation::Highlight )
1673 virtual void transform( const QMatrix &matrix );
1674 virtual void baseTransform( const QMatrix &matrix );
1676 HighlightAnnotation::HighlightType m_highlightType;
1677 QList< HighlightAnnotation::Quad > m_highlightQuads;
1680 HighlightAnnotation::HighlightAnnotation()
1681 : Annotation( *new HighlightAnnotationPrivate() )
1685 HighlightAnnotation::HighlightAnnotation( const QDomNode & node )
1686 : Annotation( *new HighlightAnnotationPrivate(), node )
1688 Q_D( HighlightAnnotation );
1689 // loop through the whole children looking for a 'hl' element
1690 QDomNode subNode = node.firstChild();
1691 while( subNode.isElement() )
1693 QDomElement e = subNode.toElement();
1694 subNode = subNode.nextSibling();
1695 if ( e.tagName() != "hl" )
1696 continue;
1698 // parse the attributes
1699 if ( e.hasAttribute( "type" ) )
1700 d->m_highlightType = (HighlightAnnotation::HighlightType)e.attribute( "type" ).toInt();
1702 // parse all 'quad' subnodes
1703 QDomNode quadNode = e.firstChild();
1704 for ( ; quadNode.isElement(); quadNode = quadNode.nextSibling() )
1706 QDomElement qe = quadNode.toElement();
1707 if ( qe.tagName() != "quad" )
1708 continue;
1710 HighlightAnnotation::Quad q;
1711 q.setPoint( NormalizedPoint( qe.attribute( "ax", "0.0" ).toDouble(), qe.attribute( "ay", "0.0" ).toDouble() ), 0 );
1712 q.setPoint( NormalizedPoint( qe.attribute( "bx", "0.0" ).toDouble(), qe.attribute( "by", "0.0" ).toDouble() ), 1 );
1713 q.setPoint( NormalizedPoint( qe.attribute( "cx", "0.0" ).toDouble(), qe.attribute( "cy", "0.0" ).toDouble() ), 2 );
1714 q.setPoint( NormalizedPoint( qe.attribute( "dx", "0.0" ).toDouble(), qe.attribute( "dy", "0.0" ).toDouble() ), 3 );
1715 q.setCapStart( qe.hasAttribute( "start" ) );
1716 q.setCapEnd( qe.hasAttribute( "end" ) );
1717 q.setFeather( qe.attribute( "feather", "0.1" ).toDouble() );
1719 q.transform( QMatrix() );
1721 d->m_highlightQuads.append( q );
1724 // loading complete
1725 break;
1729 HighlightAnnotation::~HighlightAnnotation()
1733 void HighlightAnnotation::setHighlightType( HighlightType type )
1735 Q_D( HighlightAnnotation );
1736 d->m_highlightType = type;
1739 HighlightAnnotation::HighlightType HighlightAnnotation::highlightType() const
1741 Q_D( const HighlightAnnotation );
1742 return d->m_highlightType;
1745 QList< HighlightAnnotation::Quad > & HighlightAnnotation::highlightQuads()
1747 Q_D( HighlightAnnotation );
1748 return d->m_highlightQuads;
1751 void HighlightAnnotation::store( QDomNode & node, QDomDocument & document ) const
1753 Q_D( const HighlightAnnotation );
1754 // recurse to parent objects storing properties
1755 Annotation::store( node, document );
1757 // create [hl] element
1758 QDomElement hlElement = document.createElement( "hl" );
1759 node.appendChild( hlElement );
1761 // append the optional attributes
1762 if ( d->m_highlightType != Highlight )
1763 hlElement.setAttribute( "type", (int)d->m_highlightType );
1764 if ( d->m_highlightQuads.count() < 1 )
1765 return;
1766 // append highlight quads, all children describe quads
1767 QList< Quad >::const_iterator it = d->m_highlightQuads.begin(), end = d->m_highlightQuads.end();
1768 for ( ; it != end; ++it )
1770 QDomElement quadElement = document.createElement( "quad" );
1771 hlElement.appendChild( quadElement );
1772 const Quad & q = *it;
1773 quadElement.setAttribute( "ax", q.point( 0 ).x );
1774 quadElement.setAttribute( "ay", q.point( 0 ).y );
1775 quadElement.setAttribute( "bx", q.point( 1 ).x );
1776 quadElement.setAttribute( "by", q.point( 1 ).y );
1777 quadElement.setAttribute( "cx", q.point( 2 ).x );
1778 quadElement.setAttribute( "cy", q.point( 2 ).y );
1779 quadElement.setAttribute( "dx", q.point( 3 ).x );
1780 quadElement.setAttribute( "dy", q.point( 3 ).y );
1781 if ( q.capStart() )
1782 quadElement.setAttribute( "start", 1 );
1783 if ( q.capEnd() )
1784 quadElement.setAttribute( "end", 1 );
1785 quadElement.setAttribute( "feather", q.feather() );
1789 Annotation::SubType HighlightAnnotation::subType() const
1791 return AHighlight;
1794 void HighlightAnnotationPrivate::transform( const QMatrix &matrix )
1796 AnnotationPrivate::transform( matrix );
1798 QMutableListIterator<HighlightAnnotation::Quad> it( m_highlightQuads );
1799 while ( it.hasNext() )
1800 it.next().transform( matrix );
1803 void HighlightAnnotationPrivate::baseTransform( const QMatrix &matrix )
1805 AnnotationPrivate::baseTransform( matrix );
1807 QMutableListIterator<HighlightAnnotation::Quad> it( m_highlightQuads );
1808 while ( it.hasNext() )
1809 it.next().transform( matrix );
1812 /** StampAnnotation [Annotation] */
1814 class Okular::StampAnnotationPrivate : public Okular::AnnotationPrivate
1816 public:
1817 StampAnnotationPrivate()
1818 : AnnotationPrivate(), m_stampIconName( "Draft" )
1822 QString m_stampIconName;
1825 StampAnnotation::StampAnnotation()
1826 : Annotation( *new StampAnnotationPrivate() )
1830 StampAnnotation::StampAnnotation( const QDomNode & node )
1831 : Annotation( *new StampAnnotationPrivate(), node )
1833 Q_D( StampAnnotation );
1834 // loop through the whole children looking for a 'stamp' element
1835 QDomNode subNode = node.firstChild();
1836 while( subNode.isElement() )
1838 QDomElement e = subNode.toElement();
1839 subNode = subNode.nextSibling();
1840 if ( e.tagName() != "stamp" )
1841 continue;
1843 // parse the attributes
1844 if ( e.hasAttribute( "icon" ) )
1845 d->m_stampIconName = e.attribute( "icon" );
1847 // loading complete
1848 break;
1852 StampAnnotation::~StampAnnotation()
1856 void StampAnnotation::setStampIconName( const QString &name )
1858 Q_D( StampAnnotation );
1859 d->m_stampIconName = name;
1862 QString StampAnnotation::stampIconName() const
1864 Q_D( const StampAnnotation );
1865 return d->m_stampIconName;
1868 Annotation::SubType StampAnnotation::subType() const
1870 return AStamp;
1873 void StampAnnotation::store( QDomNode & node, QDomDocument & document ) const
1875 Q_D( const StampAnnotation );
1876 // recurse to parent objects storing properties
1877 Annotation::store( node, document );
1879 // create [stamp] element
1880 QDomElement stampElement = document.createElement( "stamp" );
1881 node.appendChild( stampElement );
1883 // append the optional attributes
1884 if ( d->m_stampIconName != "Draft" )
1885 stampElement.setAttribute( "icon", d->m_stampIconName );
1888 /** InkAnnotation [Annotation] */
1890 class Okular::InkAnnotationPrivate : public Okular::AnnotationPrivate
1892 public:
1893 InkAnnotationPrivate()
1894 : AnnotationPrivate()
1898 virtual void transform( const QMatrix &matrix );
1899 virtual void baseTransform( const QMatrix &matrix );
1900 virtual void resetTransformation();
1901 virtual void translate( const NormalizedPoint &coord );
1903 QList< QLinkedList<NormalizedPoint> > m_inkPaths;
1904 QList< QLinkedList<NormalizedPoint> > m_transformedInkPaths;
1907 InkAnnotation::InkAnnotation()
1908 : Annotation( *new InkAnnotationPrivate() )
1912 InkAnnotation::InkAnnotation( const QDomNode & node )
1913 : Annotation( *new InkAnnotationPrivate(), node )
1915 Q_D( InkAnnotation );
1916 // loop through the whole children looking for a 'ink' element
1917 QDomNode subNode = node.firstChild();
1918 while( subNode.isElement() )
1920 QDomElement e = subNode.toElement();
1921 subNode = subNode.nextSibling();
1922 if ( e.tagName() != "ink" )
1923 continue;
1925 // parse the 'path' subnodes
1926 QDomNode pathNode = e.firstChild();
1927 while ( pathNode.isElement() )
1929 QDomElement pathElement = pathNode.toElement();
1930 pathNode = pathNode.nextSibling();
1932 if ( pathElement.tagName() != "path" )
1933 continue;
1935 // build each path parsing 'point' subnodes
1936 QLinkedList<NormalizedPoint> path;
1937 QDomNode pointNode = pathElement.firstChild();
1938 while ( pointNode.isElement() )
1940 QDomElement pointElement = pointNode.toElement();
1941 pointNode = pointNode.nextSibling();
1943 if ( pointElement.tagName() != "point" )
1944 continue;
1946 NormalizedPoint p;
1947 p.x = pointElement.attribute( "x", "0.0" ).toDouble();
1948 p.y = pointElement.attribute( "y", "0.0" ).toDouble();
1949 path.append( p );
1952 // add the path to the path list if it contains at least 2 nodes
1953 if ( path.count() >= 2 )
1954 d->m_inkPaths.append( path );
1957 // loading complete
1958 break;
1961 d->m_transformedInkPaths = d->m_inkPaths;
1964 InkAnnotation::~InkAnnotation()
1968 void InkAnnotation::setInkPaths( const QList< QLinkedList<NormalizedPoint> > &paths )
1970 Q_D( InkAnnotation );
1971 d->m_inkPaths = paths;
1974 QList< QLinkedList<NormalizedPoint> > InkAnnotation::inkPaths() const
1976 Q_D( const InkAnnotation );
1977 return d->m_inkPaths;
1980 QList< QLinkedList<NormalizedPoint> > InkAnnotation::transformedInkPaths() const
1982 Q_D( const InkAnnotation );
1983 return d->m_transformedInkPaths;
1986 Annotation::SubType InkAnnotation::subType() const
1988 return AInk;
1991 void InkAnnotation::store( QDomNode & node, QDomDocument & document ) const
1993 Q_D( const InkAnnotation );
1994 // recurse to parent objects storing properties
1995 Annotation::store( node, document );
1997 // create [ink] element
1998 QDomElement inkElement = document.createElement( "ink" );
1999 node.appendChild( inkElement );
2001 // append the optional attributes
2002 if ( d->m_inkPaths.count() < 1 )
2003 return;
2005 QList< QLinkedList<NormalizedPoint> >::const_iterator pIt = d->m_inkPaths.begin(), pEnd = d->m_inkPaths.end();
2006 for ( ; pIt != pEnd; ++pIt )
2008 QDomElement pathElement = document.createElement( "path" );
2009 inkElement.appendChild( pathElement );
2010 const QLinkedList<NormalizedPoint> & path = *pIt;
2011 QLinkedList<NormalizedPoint>::const_iterator iIt = path.begin(), iEnd = path.end();
2012 for ( ; iIt != iEnd; ++iIt )
2014 const NormalizedPoint & point = *iIt;
2015 QDomElement pointElement = document.createElement( "point" );
2016 pathElement.appendChild( pointElement );
2017 pointElement.setAttribute( "x", point.x );
2018 pointElement.setAttribute( "y", point.y );
2023 void InkAnnotationPrivate::transform( const QMatrix &matrix )
2025 AnnotationPrivate::transform( matrix );
2027 for ( int i = 0; i < m_transformedInkPaths.count(); ++i )
2029 QMutableLinkedListIterator<NormalizedPoint> it( m_transformedInkPaths[ i ] );
2030 while ( it.hasNext() )
2031 it.next().transform( matrix );
2035 void InkAnnotationPrivate::baseTransform( const QMatrix &matrix )
2037 AnnotationPrivate::baseTransform( matrix );
2039 for ( int i = 0; i < m_inkPaths.count(); ++i )
2041 QMutableLinkedListIterator<NormalizedPoint> it( m_inkPaths[ i ] );
2042 while ( it.hasNext() )
2043 it.next().transform( matrix );
2047 void InkAnnotationPrivate::resetTransformation()
2049 AnnotationPrivate::resetTransformation();
2051 m_transformedInkPaths = m_inkPaths;
2054 void InkAnnotationPrivate::translate( const NormalizedPoint &coord )
2056 AnnotationPrivate::translate( coord );
2058 for ( int i = 0; i < m_inkPaths.count(); ++i )
2060 QMutableLinkedListIterator<NormalizedPoint> it( m_inkPaths[ i ] );
2061 while ( it.hasNext() )
2063 NormalizedPoint& p = it.next();
2064 p.x = p.x + coord.x;
2065 p.y = p.y + coord.y;
2070 /** CaretAnnotation [Annotation] */
2072 class Okular::CaretAnnotationPrivate : public Okular::AnnotationPrivate
2074 public:
2075 CaretAnnotationPrivate()
2076 : AnnotationPrivate(), m_symbol( CaretAnnotation::None )
2080 CaretAnnotation::CaretSymbol m_symbol;
2083 static QString caretSymbolToString( CaretAnnotation::CaretSymbol symbol )
2085 switch ( symbol )
2087 case CaretAnnotation::None:
2088 return QString::fromLatin1( "None" );
2089 case CaretAnnotation::P:
2090 return QString::fromLatin1( "P" );
2092 return QString();
2095 static CaretAnnotation::CaretSymbol caretSymbolFromString( const QString &symbol )
2097 if ( symbol == QLatin1String( "None" ) )
2098 return CaretAnnotation::None;
2099 else if ( symbol == QLatin1String( "P" ) )
2100 return CaretAnnotation::P;
2101 return CaretAnnotation::None;
2104 CaretAnnotation::CaretAnnotation()
2105 : Annotation( *new CaretAnnotationPrivate() )
2109 CaretAnnotation::CaretAnnotation( const QDomNode & node )
2110 : Annotation( *new CaretAnnotationPrivate(), node )
2112 Q_D( CaretAnnotation );
2113 // loop through the whole children looking for a 'caret' element
2114 QDomNode subNode = node.firstChild();
2115 while( subNode.isElement() )
2117 QDomElement e = subNode.toElement();
2118 subNode = subNode.nextSibling();
2119 if ( e.tagName() != "caret" )
2120 continue;
2122 // parse the attributes
2123 if ( e.hasAttribute( "symbol" ) )
2124 d->m_symbol = caretSymbolFromString( e.attribute( "symbol" ) );
2126 // loading complete
2127 break;
2131 CaretAnnotation::~CaretAnnotation()
2135 void CaretAnnotation::setCaretSymbol( CaretAnnotation::CaretSymbol symbol )
2137 Q_D( CaretAnnotation );
2138 d->m_symbol = symbol;
2141 CaretAnnotation::CaretSymbol CaretAnnotation::caretSymbol() const
2143 Q_D( const CaretAnnotation );
2144 return d->m_symbol;
2147 Annotation::SubType CaretAnnotation::subType() const
2149 return ACaret;
2152 void CaretAnnotation::store( QDomNode & node, QDomDocument & document ) const
2154 Q_D( const CaretAnnotation );
2155 // recurse to parent objects storing properties
2156 Annotation::store( node, document );
2158 // create [caret] element
2159 QDomElement caretElement = document.createElement( "caret" );
2160 node.appendChild( caretElement );
2162 // append the optional attributes
2163 if ( d->m_symbol != None )
2164 caretElement.setAttribute( "symbol", caretSymbolToString( d->m_symbol ) );
2167 /** FileAttachmentAnnotation [Annotation] */
2169 class Okular::FileAttachmentAnnotationPrivate : public Okular::AnnotationPrivate
2171 public:
2172 FileAttachmentAnnotationPrivate()
2173 : AnnotationPrivate(), icon( "PushPin" ), embfile( 0 )
2176 ~FileAttachmentAnnotationPrivate()
2178 delete embfile;
2181 // data fields
2182 QString icon;
2183 EmbeddedFile *embfile;
2186 FileAttachmentAnnotation::FileAttachmentAnnotation()
2187 : Annotation( *new FileAttachmentAnnotationPrivate() )
2191 FileAttachmentAnnotation::FileAttachmentAnnotation( const QDomNode & node )
2192 : Annotation( *new FileAttachmentAnnotationPrivate(), node )
2194 // loop through the whole children looking for a 'fileattachment' element
2195 QDomNode subNode = node.firstChild();
2196 while( subNode.isElement() )
2198 QDomElement e = subNode.toElement();
2199 subNode = subNode.nextSibling();
2200 if ( e.tagName() != "fileattachment" )
2201 continue;
2203 // loading complete
2204 break;
2208 FileAttachmentAnnotation::~FileAttachmentAnnotation()
2212 void FileAttachmentAnnotation::store( QDomNode & node, QDomDocument & document ) const
2214 // recurse to parent objects storing properties
2215 Annotation::store( node, document );
2217 // create [fileattachment] element
2218 QDomElement fileAttachmentElement = document.createElement( "fileattachment" );
2219 node.appendChild( fileAttachmentElement );
2222 Annotation::SubType FileAttachmentAnnotation::subType() const
2224 return AFileAttachment;
2227 QString FileAttachmentAnnotation::fileIconName() const
2229 Q_D( const FileAttachmentAnnotation );
2230 return d->icon;
2233 void FileAttachmentAnnotation::setFileIconName( const QString &icon )
2235 Q_D( FileAttachmentAnnotation );
2236 d->icon = icon;
2239 EmbeddedFile* FileAttachmentAnnotation::embeddedFile() const
2241 Q_D( const FileAttachmentAnnotation );
2242 return d->embfile;
2245 void FileAttachmentAnnotation::setEmbeddedFile( EmbeddedFile *ef )
2247 Q_D( FileAttachmentAnnotation );
2248 d->embfile = ef;
2251 /** SoundAnnotation [Annotation] */
2253 class Okular::SoundAnnotationPrivate : public Okular::AnnotationPrivate
2255 public:
2256 SoundAnnotationPrivate()
2257 : AnnotationPrivate(), icon( "Speaker" ), sound( 0 )
2260 ~SoundAnnotationPrivate()
2262 delete sound;
2265 // data fields
2266 QString icon;
2267 Sound *sound;
2270 SoundAnnotation::SoundAnnotation()
2271 : Annotation( *new SoundAnnotationPrivate() )
2275 SoundAnnotation::SoundAnnotation( const QDomNode & node )
2276 : Annotation( *new SoundAnnotationPrivate(), node )
2278 // loop through the whole children looking for a 'sound' element
2279 QDomNode subNode = node.firstChild();
2280 while( subNode.isElement() )
2282 QDomElement e = subNode.toElement();
2283 subNode = subNode.nextSibling();
2284 if ( e.tagName() != "sound" )
2285 continue;
2287 // loading complete
2288 break;
2292 SoundAnnotation::~SoundAnnotation()
2296 void SoundAnnotation::store( QDomNode & node, QDomDocument & document ) const
2298 // recurse to parent objects storing properties
2299 Annotation::store( node, document );
2301 // create [sound] element
2302 QDomElement soundElement = document.createElement( "sound" );
2303 node.appendChild( soundElement );
2306 Annotation::SubType SoundAnnotation::subType() const
2308 return ASound;
2311 QString SoundAnnotation::soundIconName() const
2313 Q_D( const SoundAnnotation );
2314 return d->icon;
2317 void SoundAnnotation::setSoundIconName( const QString &icon )
2319 Q_D( SoundAnnotation );
2320 d->icon = icon;
2323 Sound* SoundAnnotation::sound() const
2325 Q_D( const SoundAnnotation );
2326 return d->sound;
2329 void SoundAnnotation::setSound( Sound *s )
2331 Q_D( SoundAnnotation );
2332 d->sound = s;
2335 /** MovieAnnotation [Annotation] */
2337 class Okular::MovieAnnotationPrivate : public Okular::AnnotationPrivate
2339 public:
2340 MovieAnnotationPrivate()
2341 : AnnotationPrivate(), movie( 0 )
2344 ~MovieAnnotationPrivate()
2346 delete movie;
2349 // data fields
2350 Movie *movie;
2353 MovieAnnotation::MovieAnnotation()
2354 : Annotation( *new MovieAnnotationPrivate() )
2358 MovieAnnotation::MovieAnnotation( const QDomNode & node )
2359 : Annotation( *new MovieAnnotationPrivate(), node )
2361 // loop through the whole children looking for a 'movie' element
2362 QDomNode subNode = node.firstChild();
2363 while( subNode.isElement() )
2365 QDomElement e = subNode.toElement();
2366 subNode = subNode.nextSibling();
2367 if ( e.tagName() != "movie" )
2368 continue;
2370 // loading complete
2371 break;
2375 MovieAnnotation::~MovieAnnotation()
2379 void MovieAnnotation::store( QDomNode & node, QDomDocument & document ) const
2381 // recurse to parent objects storing properties
2382 Annotation::store( node, document );
2384 // create [movie] element
2385 QDomElement movieElement = document.createElement( "movie" );
2386 node.appendChild( movieElement );
2389 Annotation::SubType MovieAnnotation::subType() const
2391 return AMovie;
2394 Movie* MovieAnnotation::movie() const
2396 Q_D( const MovieAnnotation );
2397 return d->movie;
2400 void MovieAnnotation::setMovie( Movie *movie )
2402 Q_D( MovieAnnotation );
2403 d->movie = movie;