Okular

annotations.cpp
1 /***************************************************************************
2  * Copyright (C) 2005 by Enrico Ros <[email protected]> *
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  ***************************************************************************/
9 
10 #include "annotations.h"
11 #include "annotations_p.h"
12 
13 // qt/kde includes
14 #include <QApplication>
15 #include <QColor>
16 
17 // DBL_MAX
18 #include <float.h>
19 
20 // local includes
21 #include "action.h"
22 #include "document.h"
23 #include "document_p.h"
24 #include "movie.h"
25 #include "page_p.h"
26 #include "sound.h"
27 
28 using namespace Okular;
29 
34 static bool isLeftOfVector( const NormalizedPoint& a, const NormalizedPoint& b, const NormalizedPoint& c )
35 {
36  //cross product
37  return ( (b.x - a.x) * ( c.y - a.y) - ( b.y - a.y ) * ( c.x - a.x ) ) > 0;
38 }
39 
45 static double distanceSqr( double x, double y, double xScale, double yScale, const QLinkedList<NormalizedPoint>& path )
46 {
47  double distance = DBL_MAX;
48  double thisDistance;
50  NormalizedPoint lastPoint = *i;
51 
52  for (++i; i != path.constEnd(); ++i) {
53  thisDistance = NormalizedPoint::distanceSqr( x, y, xScale, yScale, lastPoint, (*i) );
54 
55  if ( thisDistance < distance )
56  distance = thisDistance;
57 
58  lastPoint = *i;
59  }
60  return distance;
61 }
62 
84 static double strokeDistance( double distance, double penWidth )
85 {
86  return fmax(distance - pow( penWidth, 2 ), 0);
87 }
88 
89 //BEGIN AnnotationUtils implementation
91 {
92  // safety check on annotation element
93  if ( !annElement.hasAttribute( QStringLiteral("type") ) )
94  return nullptr;
95 
96  // build annotation of given type
97  Annotation * annotation = nullptr;
98  int typeNumber = annElement.attribute( QStringLiteral("type") ).toInt();
99  switch ( typeNumber )
100  {
101  case Annotation::AText:
102  annotation = new TextAnnotation( annElement );
103  break;
104  case Annotation::ALine:
105  annotation = new LineAnnotation( annElement );
106  break;
107  case Annotation::AGeom:
108  annotation = new GeomAnnotation( annElement );
109  break;
111  annotation = new HighlightAnnotation( annElement );
112  break;
113  case Annotation::AStamp:
114  annotation = new StampAnnotation( annElement );
115  break;
116  case Annotation::AInk:
117  annotation = new InkAnnotation( annElement );
118  break;
119  case Annotation::ACaret:
120  annotation = new CaretAnnotation( annElement );
121  break;
122  }
123 
124  // return created annotation
125  return annotation;
126 }
127 
129  QDomDocument & document )
130 {
131  // save annotation's type as element's attribute
132  annElement.setAttribute( QStringLiteral("type"), (uint)ann->subType() );
133 
134  // append all annotation data as children of this node
135  ann->store( annElement, document );
136 }
137 
139  const QString & name )
140 {
141  // loop through the whole children and return a 'name' named element
142  QDomNode subNode = parentNode.firstChild();
143  while( subNode.isElement() )
144  {
145  QDomElement element = subNode.toElement();
146  if ( element.tagName() == name )
147  return element;
148  subNode = subNode.nextSibling();
149  }
150  // if the name can't be found, return a dummy null element
151  return QDomElement();
152 }
153 
155  double scaleX, double scaleY )
156 {
157  const QRect rect = annotation->transformedBoundingRectangle().geometry( (int)scaleX, (int)scaleY );
158  if ( annotation->subType() == Annotation::AText && ( ( (TextAnnotation*)annotation )->textType() == TextAnnotation::Linked ) )
159  {
160  // To be honest i have no clue of why the 24,24 is here, maybe to make sure it's not too small?
161  // But why only for linked text?
162  const QRect rect24 = QRect( (int)( annotation->transformedBoundingRectangle().left * scaleX ),
163  (int)( annotation->transformedBoundingRectangle().top * scaleY ), 24, 24 );
164  return rect24.united(rect);
165  }
166 
167  return rect;
168 }
169 //END AnnotationUtils implementation
170 
171 AnnotationProxy::AnnotationProxy()
172 {
173 }
174 
176 {
177 }
178 
179 //BEGIN Annotation implementation
180 
181 class Annotation::Style::Private
182 {
183  public:
184  Private()
185  : m_opacity( 1.0 ), m_width( 1.0 ), m_style( Solid ), m_xCorners( 0.0 ),
186  m_yCorners( 0.0 ), m_marks( 3 ), m_spaces( 0 ), m_effect( NoEffect ),
187  m_effectIntensity( 1.0 )
188  {
189  }
190 
191  QColor m_color;
192  double m_opacity;
193  double m_width;
194  LineStyle m_style;
195  double m_xCorners;
196  double m_yCorners;
197  int m_marks;
198  int m_spaces;
199  LineEffect m_effect;
200  double m_effectIntensity;
201 };
202 
204  : d( new Private )
205 {
206 }
207 
209 {
210  delete d;
211 }
212 
213 Annotation::Style::Style( const Style &other )
214  : d( new Private )
215 {
216  *d = *other.d;
217 }
218 
219 Annotation::Style& Annotation::Style::operator=( const Style &other )
220 {
221  if ( this != &other )
222  *d = *other.d;
223 
224  return *this;
225 }
226 
228 {
229  d->m_color = color;
230 }
231 
233 {
234  return d->m_color;
235 }
236 
238 {
239  d->m_opacity = opacity;
240 }
241 
243 {
244  return d->m_opacity;
245 }
246 
248 {
249  d->m_width = width;
250 }
251 
253 {
254  return d->m_width;
255 }
256 
258 {
259  d->m_style = style;
260 }
261 
263 {
264  return d->m_style;
265 }
266 
268 {
269  d->m_xCorners = xCorners;
270 }
271 
273 {
274  return d->m_xCorners;
275 }
276 
278 {
279  d->m_yCorners = yCorners;
280 }
281 
283 {
284  return d->m_yCorners;
285 }
286 
288 {
289  d->m_marks = marks;
290 }
291 
293 {
294  return d->m_marks;
295 }
296 
298 {
299  d->m_spaces = spaces;
300 }
301 
303 {
304  return d->m_spaces;
305 }
306 
308 {
309  d->m_effect = effect;
310 }
311 
313 {
314  return d->m_effect;
315 }
316 
318 {
319  d->m_effectIntensity = intensity;
320 }
321 
323 {
324  return d->m_effectIntensity;
325 }
326 
327 
328 class Annotation::Window::Private
329 {
330  public:
331  Private()
332  : m_flags( -1 ), m_width( 0 ), m_height( 0 )
333  {
334  }
335 
336  int m_flags;
337  NormalizedPoint m_topLeft;
338  int m_width;
339  int m_height;
340  QString m_title;
341  QString m_summary;
342 };
343 
345  : d( new Private )
346 {
347 }
348 
350 {
351  delete d;
352 }
353 
354 Annotation::Window::Window( const Window &other )
355  : d( new Private )
356 {
357  *d = *other.d;
358 }
359 
360 Annotation::Window& Annotation::Window::operator=( const Window &other )
361 {
362  if ( this != &other )
363  *d = *other.d;
364 
365  return *this;
366 }
367 
369 {
370  d->m_flags = flags;
371 }
372 
374 {
375  return d->m_flags;
376 }
377 
379 {
380  d->m_topLeft = point;
381 }
382 
384 {
385  return d->m_topLeft;
386 }
387 
389 {
390  d->m_width = width;
391 }
392 
394 {
395  return d->m_width;
396 }
397 
399 {
400  d->m_height = height;
401 }
402 
404 {
405  return d->m_height;
406 }
407 
409 {
410  d->m_title = title;
411 }
412 
414 {
415  return d->m_title;
416 }
417 
419 {
420  d->m_summary = summary;
421 }
422 
424 {
425  return d->m_summary;
426 }
427 
428 class Annotation::Revision::Private
429 {
430  public:
431  Private()
432  : m_annotation( nullptr ), m_scope( Reply ), m_type( None )
433  {
434  }
435 
436  Annotation *m_annotation;
437  RevisionScope m_scope;
438  RevisionType m_type;
439 };
440 
442  : d( new Private )
443 {
444 }
445 
447 {
448  delete d;
449 }
450 
452  : d( new Private )
453 {
454  *d = *other.d;
455 }
456 
457 Annotation::Revision& Annotation::Revision::operator=( const Revision &other )
458 {
459  if ( this != &other )
460  *d = *other.d;
461 
462  return *this;
463 }
464 
466 {
467  d->m_annotation = annotation;
468 }
469 
471 {
472  return d->m_annotation;
473 }
474 
476 {
477  d->m_scope = scope;
478 }
479 
481 {
482  return d->m_scope;
483 }
484 
486 {
487  d->m_type = type;
488 }
489 
491 {
492  return d->m_type;
493 }
494 
495 
496 AnnotationPrivate::AnnotationPrivate()
497  : m_page( nullptr ), m_flags( 0 ), m_disposeFunc( nullptr )
498 {
499 }
500 
501 AnnotationPrivate::~AnnotationPrivate()
502 {
503  // delete all children revisions
504  if ( m_revisions.isEmpty() )
505  return;
506 
507  QLinkedList< Annotation::Revision >::iterator it = m_revisions.begin(), end = m_revisions.end();
508  for ( ; it != end; ++it )
509  delete (*it).annotation();
510 }
511 
512 Annotation::Annotation( AnnotationPrivate &dd )
513  : d_ptr( &dd )
514 {
515 }
516 
517 Annotation::Annotation( AnnotationPrivate &dd, const QDomNode & description )
518  : d_ptr( &dd )
519 {
520  d_ptr->setAnnotationProperties( description );
521 }
522 
524 {
525  if ( d_ptr->m_disposeFunc )
526  d_ptr->m_disposeFunc( this );
527 
528  delete d_ptr;
529 }
530 
532 {
533  Q_D( Annotation );
534  d->m_author = author;
535 }
536 
538 {
539  Q_D( const Annotation );
540  return d->m_author;
541 }
542 
544 {
545  Q_D( Annotation );
546  d->m_contents = contents;
547 }
548 
550 {
551  Q_D( const Annotation );
552  return d->m_contents;
553 }
554 
556 {
557  Q_D( Annotation );
558  d->m_uniqueName = name;
559 }
560 
562 {
563  Q_D( const Annotation );
564  return d->m_uniqueName;
565 }
566 
568 {
569  Q_D( Annotation );
570  d->m_modifyDate = date;
571 }
572 
574 {
575  Q_D( const Annotation );
576  return d->m_modifyDate;
577 }
578 
580 {
581  Q_D( Annotation );
582  d->m_creationDate = date;
583 }
584 
586 {
587  Q_D( const Annotation );
588  return d->m_creationDate;
589 }
590 
592 {
593  Q_D( Annotation );
594  d->m_flags = flags;
595 }
596 
597 int Annotation::flags() const
598 {
599  Q_D( const Annotation );
600  return d->m_flags;
601 }
602 
604 {
605  Q_D( Annotation );
606  d->m_boundary = rectangle;
607  d->resetTransformation();
608  if ( d->m_page )
609  {
610  d->transform( d->m_page->rotationMatrix() );
611  }
612 }
613 
615 {
616  Q_D( const Annotation );
617  return d->m_boundary;
618 }
619 
621 {
622  Q_D( const Annotation );
623  return d->m_transformedBoundary;
624 }
625 
627 {
628  Q_D( Annotation );
629  d->translate( coord );
630  d->resetTransformation();
631  if ( d->m_page )
632  {
633  d->transform( d->m_page->rotationMatrix() );
634  }
635 }
636 
637 void Annotation::adjust( const NormalizedPoint & deltaCoord1, const NormalizedPoint & deltaCoord2 )
638 {
639  Q_D( Annotation );
640  d->adjust( deltaCoord1, deltaCoord2 );
641  d->resetTransformation();
642  if ( d->m_page )
643  {
644  d->transform( d->m_page->rotationMatrix() );
645  }
646 }
647 
649 {
650  Q_D( const Annotation );
651  return d->openDialogAfterCreation();
652 }
653 
655 {
656  Q_D( Annotation );
657  return d->m_style;
658 }
659 
661 {
662  Q_D( const Annotation );
663  return d->m_style;
664 }
665 
667 {
668  Q_D( Annotation );
669  return d->m_window;
670 }
671 
673 {
674  Q_D( const Annotation );
675  return d->m_window;
676 }
677 
679 {
680  Q_D( Annotation );
681  return d->m_revisions;
682 }
683 
685 {
686  Q_D( const Annotation );
687  return d->m_revisions;
688 }
689 
691 {
692  Q_D( Annotation );
693  d->m_nativeId = id;
694 }
695 
697 {
698  Q_D( const Annotation );
699  return d->m_nativeId;
700 }
701 
703 {
704  Q_D( Annotation );
705  d->m_disposeFunc = func;
706 }
707 
709 {
710  Q_D( const Annotation );
711 
712  // Don't move annotations if they cannot be modified
713  if ( !d->m_page || !d->m_page->m_doc->m_parent->canModifyPageAnnotation(this) )
714  return false;
715 
716  // highlight "requires" to be "bounded" to text, and that's tricky for now
717  if ( subType() == AHighlight )
718  return false;
719 
720  return true;
721 }
722 
724 {
725  Q_D( const Annotation );
726 
727  // Don't resize annotations if they cannot be modified
728  if ( !d->m_page || !d->m_page->m_doc->m_parent->canModifyPageAnnotation(this) )
729  return false;
730 
731  return d->canBeResized();
732 }
733 
734 void Annotation::store( QDomNode & annNode, QDomDocument & document ) const
735 {
736  Q_D( const Annotation );
737  // create [base] element of the annotation node
738  QDomElement e = document.createElement( QStringLiteral("base") );
739  annNode.appendChild( e );
740 
741  // store -contents- attributes
742  if ( !d->m_author.isEmpty() )
743  e.setAttribute( QStringLiteral("author"), d->m_author );
744  if ( !d->m_contents.isEmpty() )
745  e.setAttribute( QStringLiteral("contents"), d->m_contents );
746  if ( !d->m_uniqueName.isEmpty() )
747  e.setAttribute( QStringLiteral("uniqueName"), d->m_uniqueName );
748  if ( d->m_modifyDate.isValid() )
749  e.setAttribute( QStringLiteral("modifyDate"), d->m_modifyDate.toString(Qt::ISODate) );
750  if ( d->m_creationDate.isValid() )
751  e.setAttribute( QStringLiteral("creationDate"), d->m_creationDate.toString(Qt::ISODate) );
752 
753  // store -other- attributes
754  if ( d->m_flags ) // Strip internal flags
755  e.setAttribute( QStringLiteral("flags"), d->m_flags & ~(External | ExternallyDrawn | BeingMoved | BeingResized ) );
756  if ( d->m_style.color().isValid() )
757  e.setAttribute( QStringLiteral("color"), d->m_style.color().name( QColor::HexArgb ) );
758  if ( d->m_style.opacity() != 1.0 )
759  e.setAttribute( QStringLiteral("opacity"), QString::number( d->m_style.opacity() ) );
760 
761  // Sub-Node-1 - boundary
762  QDomElement bE = document.createElement( QStringLiteral("boundary") );
763  e.appendChild( bE );
764  bE.setAttribute( QStringLiteral("l"), QString::number( d->m_boundary.left ) );
765  bE.setAttribute( QStringLiteral("t"), QString::number( d->m_boundary.top ) );
766  bE.setAttribute( QStringLiteral("r"), QString::number( d->m_boundary.right ) );
767  bE.setAttribute( QStringLiteral("b"), QString::number( d->m_boundary.bottom ) );
768 
769  // Sub-Node-2 - penStyle
770  if ( d->m_style.width() != 1 || d->m_style.lineStyle() != Solid || d->m_style.xCorners() != 0 ||
771  d->m_style.yCorners() != 0.0 || d->m_style.marks() != 3 || d->m_style.spaces() != 0 )
772  {
773  QDomElement psE = document.createElement( QStringLiteral("penStyle") );
774  e.appendChild( psE );
775  psE.setAttribute( QStringLiteral("width"), QString::number( d->m_style.width() ) );
776  psE.setAttribute( QStringLiteral("style"), (int)d->m_style.lineStyle() );
777  psE.setAttribute( QStringLiteral("xcr"), QString::number( d->m_style.xCorners() ) );
778  psE.setAttribute( QStringLiteral("ycr"), QString::number( d->m_style.yCorners() ) );
779  psE.setAttribute( QStringLiteral("marks"), d->m_style.marks() );
780  psE.setAttribute( QStringLiteral("spaces"), d->m_style.spaces() );
781  }
782 
783  // Sub-Node-3 - penEffect
784  if ( d->m_style.lineEffect() != NoEffect || d->m_style.effectIntensity() != 1.0 )
785  {
786  QDomElement peE = document.createElement( QStringLiteral("penEffect") );
787  e.appendChild( peE );
788  peE.setAttribute( QStringLiteral("effect"), (int)d->m_style.lineEffect() );
789  peE.setAttribute( QStringLiteral("intensity"), QString::number( d->m_style.effectIntensity() ) );
790  }
791 
792  // Sub-Node-4 - window
793  if ( d->m_window.flags() != -1 || !d->m_window.title().isEmpty() ||
794  !d->m_window.summary().isEmpty() )
795  {
796  QDomElement wE = document.createElement( QStringLiteral("window") );
797  e.appendChild( wE );
798  wE.setAttribute( QStringLiteral("flags"), d->m_window.flags() );
799  wE.setAttribute( QStringLiteral("top"), QString::number( d->m_window.topLeft().x ) );
800  wE.setAttribute( QStringLiteral("left"), QString::number( d->m_window.topLeft().y ) );
801  wE.setAttribute( QStringLiteral("width"), d->m_window.width() );
802  wE.setAttribute( QStringLiteral("height"), d->m_window.height() );
803  wE.setAttribute( QStringLiteral("title"), d->m_window.title() );
804  wE.setAttribute( QStringLiteral("summary"), d->m_window.summary() );
805  }
806 
807  // create [revision] element of the annotation node (if any)
808  if ( d->m_revisions.isEmpty() )
809  return;
810 
811  // add all revisions as children of revisions element
812  QLinkedList< Revision >::const_iterator it = d->m_revisions.begin(), end = d->m_revisions.end();
813  for ( ; it != end; ++it )
814  {
815  // create revision element
816  const Revision & revision = *it;
817  QDomElement r = document.createElement( QStringLiteral("revision") );
818  annNode.appendChild( r );
819  // set element attributes
820  r.setAttribute( QStringLiteral("revScope"), (int)revision.scope() );
821  r.setAttribute( QStringLiteral("revType"), (int)revision.type() );
822  // use revision as the annotation element, so fill it up
823  AnnotationUtils::storeAnnotation( revision.annotation(), r, document );
824  }
825 }
826 
828 {
829  QDomDocument doc( QStringLiteral("documentInfo") );
830  QDomElement node = doc.createElement( QStringLiteral("annotation") );
831 
832  store(node, doc);
833  return node;
834 }
835 
837 {
838  // Save off internal properties that aren't contained in node
839  Okular::PagePrivate *p = d_ptr->m_page;
840  QVariant nativeID = d_ptr->m_nativeId;
841  const int internalFlags = d_ptr->m_flags & (External | ExternallyDrawn | BeingMoved | BeingResized );
842  Annotation::DisposeDataFunction disposeFunc = d_ptr->m_disposeFunc;
843 
844  // Replace AnnotationPrivate object with a fresh copy
845  AnnotationPrivate *new_d_ptr = d_ptr->getNewAnnotationPrivate();
846  delete( d_ptr );
847  d_ptr = new_d_ptr;
848 
849  // Set the annotations properties from node
850  d_ptr->setAnnotationProperties(node);
851 
852  // Restore internal properties
853  d_ptr->m_page = p;
854  d_ptr->m_nativeId = nativeID;
855  d_ptr->m_flags = d_ptr->m_flags | internalFlags;
856  d_ptr->m_disposeFunc = disposeFunc;
857 
858  // Transform annotation to current page rotation
859  d_ptr->transform( d_ptr->m_page->rotationMatrix() );
860 }
861 
862 double AnnotationPrivate::distanceSqr( double x, double y, double xScale, double yScale ) const
863 {
864  return m_transformedBoundary.distanceSqr( x, y, xScale, yScale );
865 }
866 
867 void AnnotationPrivate::annotationTransform( const QTransform &matrix )
868 {
869  resetTransformation();
870  transform( matrix );
871 }
872 
873 void AnnotationPrivate::transform( const QTransform &matrix )
874 {
875  m_transformedBoundary.transform( matrix );
876 }
877 
878 void AnnotationPrivate::baseTransform( const QTransform &matrix )
879 {
880  m_boundary.transform( matrix );
881 }
882 
883 void AnnotationPrivate::resetTransformation()
884 {
885  m_transformedBoundary = m_boundary;
886 }
887 
888 void AnnotationPrivate::translate( const NormalizedPoint &coord )
889 {
890  m_boundary.left = m_boundary.left + coord.x;
891  m_boundary.right = m_boundary.right + coord.x;
892  m_boundary.top = m_boundary.top + coord.y;
893  m_boundary.bottom = m_boundary.bottom + coord.y;
894 }
895 
896 void AnnotationPrivate::adjust( const NormalizedPoint &deltaCoord1, const NormalizedPoint &deltaCoord2 )
897 {
898  m_boundary.left = m_boundary.left + qBound( -m_boundary.left, deltaCoord1.x, m_boundary.right - m_boundary.left );
899  m_boundary.top = m_boundary.top + qBound( -m_boundary.top, deltaCoord1.y, m_boundary.bottom - m_boundary.top );;
900  m_boundary.right = m_boundary.right + qBound( m_boundary.left - m_boundary.right, deltaCoord2.x, 1. - m_boundary.right );
901  m_boundary.bottom = m_boundary.bottom + qBound( m_boundary.top - m_boundary.bottom, deltaCoord2.y, 1. - m_boundary.bottom );
902 }
903 
904 bool AnnotationPrivate::openDialogAfterCreation() const
905 {
906  return false;
907 }
908 
909 void AnnotationPrivate::setAnnotationProperties( const QDomNode& node )
910 {
911  // get the [base] element of the annotation node
912  QDomElement e = AnnotationUtils::findChildElement( node, QStringLiteral("base") );
913  if ( e.isNull() )
914  return;
915 
916  // parse -contents- attributes
917  if ( e.hasAttribute( QStringLiteral("author") ) )
918  m_author = e.attribute( QStringLiteral("author") );
919  if ( e.hasAttribute( QStringLiteral("contents") ) )
920  m_contents = e.attribute( QStringLiteral("contents") );
921  if ( e.hasAttribute( QStringLiteral("uniqueName") ) )
922  m_uniqueName = e.attribute( QStringLiteral("uniqueName") );
923  if ( e.hasAttribute( QStringLiteral("modifyDate") ) )
924  m_modifyDate = QDateTime::fromString( e.attribute(QStringLiteral("modifyDate")), Qt::ISODate );
925  if ( e.hasAttribute( QStringLiteral("creationDate") ) )
926  m_creationDate = QDateTime::fromString( e.attribute(QStringLiteral("creationDate")), Qt::ISODate );
927 
928  // parse -other- attributes
929  if ( e.hasAttribute( QStringLiteral("flags") ) )
930  m_flags = e.attribute( QStringLiteral("flags") ).toInt();
931  if ( e.hasAttribute( QStringLiteral("color") ) )
932  m_style.setColor( QColor( e.attribute( QStringLiteral("color") ) ) );
933  if ( e.hasAttribute( QStringLiteral("opacity") ) )
934  m_style.setOpacity( e.attribute( QStringLiteral("opacity") ).toDouble() );
935 
936  // parse -the-subnodes- (describing Style, Window, Revision(s) structures)
937  // Note: all subnodes if present must be 'attributes complete'
938  QDomNode eSubNode = e.firstChild();
939  while ( eSubNode.isElement() )
940  {
941  QDomElement ee = eSubNode.toElement();
942  eSubNode = eSubNode.nextSibling();
943 
944  // parse boundary
945  if ( ee.tagName() == QLatin1String("boundary") )
946  {
947  m_boundary=NormalizedRect(ee.attribute( QStringLiteral("l") ).toDouble(),
948  ee.attribute( QStringLiteral("t") ).toDouble(),
949  ee.attribute( QStringLiteral("r") ).toDouble(),
950  ee.attribute( QStringLiteral("b") ).toDouble());
951  }
952  // parse penStyle if not default
953  else if ( ee.tagName() == QLatin1String("penStyle") )
954  {
955  m_style.setWidth( ee.attribute( QStringLiteral("width") ).toDouble() );
956  m_style.setLineStyle( (Annotation::LineStyle)ee.attribute( QStringLiteral("style") ).toInt() );
957  m_style.setXCorners( ee.attribute( QStringLiteral("xcr") ).toDouble() );
958  m_style.setYCorners( ee.attribute( QStringLiteral("ycr") ).toDouble() );
959  m_style.setMarks( ee.attribute( QStringLiteral("marks") ).toInt() );
960  m_style.setSpaces( ee.attribute( QStringLiteral("spaces") ).toInt() );
961  }
962  // parse effectStyle if not default
963  else if ( ee.tagName() == QLatin1String("penEffect") )
964  {
965  m_style.setLineEffect( (Annotation::LineEffect)ee.attribute( QStringLiteral("effect") ).toInt() );
966  m_style.setEffectIntensity( ee.attribute( QStringLiteral("intensity") ).toDouble() );
967  }
968  // parse window if present
969  else if ( ee.tagName() == QLatin1String("window") )
970  {
971  m_window.setFlags( ee.attribute( QStringLiteral("flags") ).toInt() );
972  m_window.setTopLeft( NormalizedPoint( ee.attribute( QStringLiteral("top") ).toDouble(),
973  ee.attribute( QStringLiteral("left") ).toDouble() ) );
974  m_window.setWidth( ee.attribute( QStringLiteral("width") ).toInt() );
975  m_window.setHeight( ee.attribute( QStringLiteral("height") ).toInt() );
976  m_window.setTitle( ee.attribute( QStringLiteral("title") ) );
977  m_window.setSummary( ee.attribute( QStringLiteral("summary") ) );
978  }
979  }
980 
981  // get the [revisions] element of the annotation node
982  QDomNode revNode = node.firstChild();
983  for ( ; revNode.isElement(); revNode = revNode.nextSibling() )
984  {
985  QDomElement revElement = revNode.toElement();
986  if ( revElement.tagName() != QLatin1String("revision") )
987  continue;
988 
989  // compile the Revision structure crating annotation
990  Annotation::Revision revision;
991  revision.setScope( (Annotation::RevisionScope)revElement.attribute( QStringLiteral("revScope") ).toInt() );
992  revision.setType( (Annotation::RevisionType)revElement.attribute( QStringLiteral("revType") ).toInt() );
993  revision.setAnnotation( AnnotationUtils::createAnnotation( revElement ) );
994 
995  // if annotation is valid, add revision to internal list
996  if ( revision.annotation() )
997  m_revisions.append( revision );
998  }
999 
1000  m_transformedBoundary = m_boundary;
1001 }
1002 
1003 bool AnnotationPrivate::canBeResized() const
1004 {
1005  return false;
1006 }
1007 
1008 //END Annotation implementation
1009 
1010 
1013 class Okular::TextAnnotationPrivate : public Okular::AnnotationPrivate
1014 {
1015  public:
1016  TextAnnotationPrivate()
1017  : AnnotationPrivate(), m_textType( TextAnnotation::Linked ),
1018  m_textIcon( QStringLiteral("Comment") ), m_inplaceAlign( 0 ),
1019  m_inplaceIntent( TextAnnotation::Unknown )
1020  {
1021  }
1022 
1023  void transform( const QTransform &matrix ) override;
1024  void baseTransform( const QTransform &matrix ) override;
1025  void resetTransformation() override;
1026  void translate( const NormalizedPoint &coord ) override;
1027  bool openDialogAfterCreation() const override;
1028  void setAnnotationProperties( const QDomNode& node ) override;
1029  bool canBeResized() const override;
1030  AnnotationPrivate* getNewAnnotationPrivate() override;
1031 
1032  TextAnnotation::TextType m_textType;
1033  QString m_textIcon;
1034  QFont m_textFont;
1035  QColor m_textColor;
1036  int m_inplaceAlign;
1037  NormalizedPoint m_inplaceCallout[3];
1038  NormalizedPoint m_transformedInplaceCallout[3];
1039  TextAnnotation::InplaceIntent m_inplaceIntent;
1040 };
1041 
1042 /*
1043  The default textIcon for text annotation is Note as the PDF Reference says
1044 */
1045 TextAnnotation::TextAnnotation()
1046  : Annotation( *new TextAnnotationPrivate() )
1047 {
1048 }
1049 
1050 TextAnnotation::TextAnnotation( const QDomNode & description )
1051  : Annotation( *new TextAnnotationPrivate(), description )
1052 {
1053 }
1054 
1055 TextAnnotation::~TextAnnotation()
1056 {
1057 }
1058 
1059 void TextAnnotation::setTextType( TextType textType )
1060 {
1061  Q_D( TextAnnotation );
1062  d->m_textType = textType;
1063 }
1064 
1065 TextAnnotation::TextType TextAnnotation::textType() const
1066 {
1067  Q_D( const TextAnnotation );
1068  return d->m_textType;
1069 }
1070 
1071 void TextAnnotation::setTextIcon( const QString &icon )
1072 {
1073  Q_D( TextAnnotation );
1074  d->m_textIcon = icon;
1075 }
1076 
1077 QString TextAnnotation::textIcon() const
1078 {
1079  Q_D( const TextAnnotation );
1080  return d->m_textIcon;
1081 }
1082 
1083 void TextAnnotation::setTextFont( const QFont &font )
1084 {
1085  Q_D( TextAnnotation );
1086  d->m_textFont = font;
1087 }
1088 
1089 QFont TextAnnotation::textFont() const
1090 {
1091  Q_D( const TextAnnotation );
1092  return d->m_textFont;
1093 }
1094 
1095 void TextAnnotation::setTextColor( const QColor &color )
1096 {
1097  Q_D( TextAnnotation );
1098  d->m_textColor = color;
1099 }
1100 
1101 QColor TextAnnotation::textColor() const
1102 {
1103  Q_D( const TextAnnotation );
1104  return d->m_textColor;
1105 }
1106 
1107 void TextAnnotation::setInplaceAlignment( int alignment )
1108 {
1109  Q_D( TextAnnotation );
1110  d->m_inplaceAlign = alignment;
1111 }
1112 
1113 int TextAnnotation::inplaceAlignment() const
1114 {
1115  Q_D( const TextAnnotation );
1116  return d->m_inplaceAlign;
1117 }
1118 
1119 void TextAnnotation::setInplaceCallout( const NormalizedPoint &point, int index )
1120 {
1121  if ( index < 0 || index > 2 )
1122  return;
1123 
1124  Q_D( TextAnnotation );
1125  d->m_inplaceCallout[ index ] = point;
1126 }
1127 
1128 NormalizedPoint TextAnnotation::inplaceCallout( int index ) const
1129 {
1130  if ( index < 0 || index > 2 )
1131  return NormalizedPoint();
1132 
1133  Q_D( const TextAnnotation );
1134  return d->m_inplaceCallout[ index ];
1135 }
1136 
1137 NormalizedPoint TextAnnotation::transformedInplaceCallout( int index ) const
1138 {
1139  if ( index < 0 || index > 2 )
1140  return NormalizedPoint();
1141 
1142  Q_D( const TextAnnotation );
1143  return d->m_transformedInplaceCallout[ index ];
1144 }
1145 
1146 void TextAnnotation::setInplaceIntent( InplaceIntent intent )
1147 {
1148  Q_D( TextAnnotation );
1149  d->m_inplaceIntent = intent;
1150 }
1151 
1152 TextAnnotation::InplaceIntent TextAnnotation::inplaceIntent() const
1153 {
1154  Q_D( const TextAnnotation );
1155  return d->m_inplaceIntent;
1156 }
1157 
1158 Annotation::SubType TextAnnotation::subType() const
1159 {
1160  return AText;
1161 }
1162 
1163 void TextAnnotation::store( QDomNode & node, QDomDocument & document ) const
1164 {
1165  Q_D( const TextAnnotation );
1166  // recurse to parent objects storing properties
1167  Annotation::store( node, document );
1168 
1169  // create [text] element
1170  QDomElement textElement = document.createElement( QStringLiteral("text") );
1171  node.appendChild( textElement );
1172 
1173  // store the optional attributes
1174  if ( d->m_textType != Linked )
1175  textElement.setAttribute( QStringLiteral("type"), (int)d->m_textType );
1176  if ( !d->m_textIcon.isEmpty() )
1177  textElement.setAttribute( QStringLiteral("icon"), d->m_textIcon );
1178  if ( d->m_textFont != QApplication::font() )
1179  textElement.setAttribute( QStringLiteral("font"), d->m_textFont.toString() );
1180  if ( d->m_textColor.isValid() )
1181  textElement.setAttribute( QStringLiteral("fontColor"), d->m_textColor.name() );
1182  if ( d->m_inplaceAlign )
1183  textElement.setAttribute( QStringLiteral("align"), d->m_inplaceAlign );
1184  if ( d->m_inplaceIntent != Unknown )
1185  textElement.setAttribute( QStringLiteral("intent"), (int)d->m_inplaceIntent );
1186 
1187  // Sub-Node - callout
1188  if ( d->m_inplaceCallout[0].x != 0.0 )
1189  {
1190  QDomElement calloutElement = document.createElement( QStringLiteral("callout") );
1191  textElement.appendChild( calloutElement );
1192  calloutElement.setAttribute( QStringLiteral("ax"), QString::number( d->m_inplaceCallout[0].x ) );
1193  calloutElement.setAttribute( QStringLiteral("ay"), QString::number( d->m_inplaceCallout[0].y ) );
1194  calloutElement.setAttribute( QStringLiteral("bx"), QString::number( d->m_inplaceCallout[1].x ) );
1195  calloutElement.setAttribute( QStringLiteral("by"), QString::number( d->m_inplaceCallout[1].y ) );
1196  calloutElement.setAttribute( QStringLiteral("cx"), QString::number( d->m_inplaceCallout[2].x ) );
1197  calloutElement.setAttribute( QStringLiteral("cy"), QString::number( d->m_inplaceCallout[2].y ) );
1198  }
1199 }
1200 
1201 void TextAnnotationPrivate::transform( const QTransform &matrix )
1202 {
1203  AnnotationPrivate::transform( matrix );
1204 
1205  for ( NormalizedPoint &np : m_transformedInplaceCallout ) {
1206  np.transform( matrix );
1207  }
1208 }
1209 
1210 void TextAnnotationPrivate::baseTransform( const QTransform &matrix )
1211 {
1212  AnnotationPrivate::baseTransform( matrix );
1213 
1214  for ( NormalizedPoint &np : m_inplaceCallout ) {
1215  np.transform( matrix );
1216  }
1217 }
1218 
1219 void TextAnnotationPrivate::resetTransformation()
1220 {
1221  AnnotationPrivate::resetTransformation();
1222 
1223  for ( int i = 0; i < 3; ++i ) {
1224  m_transformedInplaceCallout[i] = m_inplaceCallout[i];
1225  }
1226 }
1227 
1228 void TextAnnotationPrivate::translate( const NormalizedPoint &coord )
1229 {
1230  AnnotationPrivate::translate( coord );
1231 
1232 #define ADD_COORD( c1, c2 ) \
1233 { \
1234  c1.x = c1.x + c2.x; \
1235  c1.y = c1.y + c2.y; \
1236 }
1237  ADD_COORD( m_inplaceCallout[0], coord )
1238  ADD_COORD( m_inplaceCallout[1], coord )
1239  ADD_COORD( m_inplaceCallout[2], coord )
1240 #undef ADD_COORD
1241 }
1242 
1243 bool TextAnnotationPrivate::openDialogAfterCreation() const
1244 {
1245  return ( m_textType == Okular::TextAnnotation::Linked );
1246 }
1247 
1248 void TextAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
1249 {
1250  Okular::AnnotationPrivate::setAnnotationProperties(node);
1251 
1252  // loop through the whole children looking for a 'text' element
1253  QDomNode subNode = node.firstChild();
1254  while( subNode.isElement() )
1255  {
1256  QDomElement e = subNode.toElement();
1257  subNode = subNode.nextSibling();
1258  if ( e.tagName() != QLatin1String("text") )
1259  continue;
1260 
1261  // parse the attributes
1262  if ( e.hasAttribute( QStringLiteral("type") ) )
1263  m_textType = (TextAnnotation::TextType)e.attribute( QStringLiteral("type") ).toInt();
1264  if ( e.hasAttribute( QStringLiteral("icon") ) )
1265  m_textIcon = e.attribute( QStringLiteral("icon") );
1266  if ( e.hasAttribute( QStringLiteral("font") ) )
1267  m_textFont.fromString( e.attribute( QStringLiteral("font") ) );
1268  if ( e.hasAttribute( QStringLiteral("fontColor") ) )
1269  m_textColor = QColor( e.attribute( QStringLiteral("fontColor") ) );
1270  if ( e.hasAttribute( QStringLiteral("align") ) )
1271  m_inplaceAlign = e.attribute( QStringLiteral("align") ).toInt();
1272  if ( e.hasAttribute( QStringLiteral("intent") ) )
1273  m_inplaceIntent = (TextAnnotation::InplaceIntent)e.attribute( QStringLiteral("intent") ).toInt();
1274 
1275  // parse the subnodes
1276  QDomNode eSubNode = e.firstChild();
1277  while ( eSubNode.isElement() )
1278  {
1279  QDomElement ee = eSubNode.toElement();
1280  eSubNode = eSubNode.nextSibling();
1281 
1282  if ( ee.tagName() == QLatin1String("escapedText") )
1283  {
1284  m_contents = ee.firstChild().toCDATASection().data();
1285  }
1286  else if ( ee.tagName() == QLatin1String("callout") )
1287  {
1288  m_inplaceCallout[0].x = ee.attribute( QStringLiteral("ax") ).toDouble();
1289  m_inplaceCallout[0].y = ee.attribute( QStringLiteral("ay") ).toDouble();
1290  m_inplaceCallout[1].x = ee.attribute( QStringLiteral("bx") ).toDouble();
1291  m_inplaceCallout[1].y = ee.attribute( QStringLiteral("by") ).toDouble();
1292  m_inplaceCallout[2].x = ee.attribute( QStringLiteral("cx") ).toDouble();
1293  m_inplaceCallout[2].y = ee.attribute( QStringLiteral("cy") ).toDouble();
1294  }
1295  }
1296 
1297  // loading complete
1298  break;
1299  }
1300 
1301  for ( int i = 0; i < 3; ++i )
1302  m_transformedInplaceCallout[i] = m_inplaceCallout[i];
1303 }
1304 
1305 bool TextAnnotationPrivate::canBeResized() const
1306 {
1307  if ( m_textType != TextAnnotation::Linked ) {
1308  return true;
1309  }
1310  return false;
1311 }
1312 
1313 AnnotationPrivate* TextAnnotationPrivate::getNewAnnotationPrivate()
1314 {
1315  return new TextAnnotationPrivate();
1316 }
1317 
1320 class Okular::LineAnnotationPrivate : public Okular::AnnotationPrivate
1321 {
1322  public:
1323  LineAnnotationPrivate()
1324  : AnnotationPrivate(),
1325  m_lineStartStyle( LineAnnotation::None ), m_lineEndStyle( LineAnnotation::None ),
1326  m_lineClosed( false ), m_lineShowCaption( false ), m_lineLeadingFwdPt( 0 ),
1327  m_lineLeadingBackPt( 0 ), m_lineIntent( LineAnnotation::Unknown )
1328  {
1329  }
1330 
1331  void transform( const QTransform &matrix ) override;
1332  void baseTransform( const QTransform &matrix ) override;
1333  void resetTransformation() override;
1334  void translate( const NormalizedPoint &coord ) override;
1335  double distanceSqr( double x, double y, double xScale, double yScale ) const override;
1336  void setAnnotationProperties( const QDomNode& node ) override;
1337  AnnotationPrivate* getNewAnnotationPrivate() override;
1338 
1339  QLinkedList<NormalizedPoint> m_linePoints;
1340  QLinkedList<NormalizedPoint> m_transformedLinePoints;
1341  LineAnnotation::TermStyle m_lineStartStyle;
1342  LineAnnotation::TermStyle m_lineEndStyle;
1343  bool m_lineClosed : 1;
1344  bool m_lineShowCaption : 1;
1345  QColor m_lineInnerColor;
1346  double m_lineLeadingFwdPt;
1347  double m_lineLeadingBackPt;
1348  LineAnnotation::LineIntent m_lineIntent;
1349 };
1350 
1351 LineAnnotation::LineAnnotation()
1352  : Annotation( *new LineAnnotationPrivate() )
1353 {
1354 }
1355 
1356 LineAnnotation::LineAnnotation( const QDomNode & description )
1357  : Annotation( *new LineAnnotationPrivate(), description )
1358 {
1359 }
1360 
1361 LineAnnotation::~LineAnnotation()
1362 {
1363 }
1364 
1365 void LineAnnotation::setLinePoints( const QLinkedList<NormalizedPoint> &points )
1366 {
1367  Q_D( LineAnnotation );
1368  d->m_linePoints = points;
1369 }
1370 
1371 QLinkedList<NormalizedPoint> LineAnnotation::linePoints() const
1372 {
1373  Q_D( const LineAnnotation );
1374  return d->m_linePoints;
1375 }
1376 
1377 QLinkedList<NormalizedPoint> LineAnnotation::transformedLinePoints() const
1378 {
1379  Q_D( const LineAnnotation );
1380  return d->m_transformedLinePoints;
1381 }
1382 
1383 void LineAnnotation::setLineStartStyle( TermStyle style )
1384 {
1385  Q_D( LineAnnotation );
1386  d->m_lineStartStyle = style;
1387 }
1388 
1389 LineAnnotation::TermStyle LineAnnotation::lineStartStyle() const
1390 {
1391  Q_D( const LineAnnotation );
1392  return d->m_lineStartStyle;
1393 }
1394 
1395 void LineAnnotation::setLineEndStyle( TermStyle style )
1396 {
1397  Q_D( LineAnnotation );
1398  d->m_lineEndStyle = style;
1399 }
1400 
1401 LineAnnotation::TermStyle LineAnnotation::lineEndStyle() const
1402 {
1403  Q_D( const LineAnnotation );
1404  return d->m_lineEndStyle;
1405 }
1406 
1407 void LineAnnotation::setLineClosed( bool closed )
1408 {
1409  Q_D( LineAnnotation );
1410  d->m_lineClosed = closed;
1411 }
1412 
1413 bool LineAnnotation::lineClosed() const
1414 {
1415  Q_D( const LineAnnotation );
1416  return d->m_lineClosed;
1417 }
1418 
1419 void LineAnnotation::setLineInnerColor( const QColor &color )
1420 {
1421  Q_D( LineAnnotation );
1422  d->m_lineInnerColor = color;
1423 }
1424 
1425 QColor LineAnnotation::lineInnerColor() const
1426 {
1427  Q_D( const LineAnnotation );
1428  return d->m_lineInnerColor;
1429 }
1430 
1431 void LineAnnotation::setLineLeadingForwardPoint( double point )
1432 {
1433  Q_D( LineAnnotation );
1434  d->m_lineLeadingFwdPt = point;
1435 }
1436 
1437 double LineAnnotation::lineLeadingForwardPoint() const
1438 {
1439  Q_D( const LineAnnotation );
1440  return d->m_lineLeadingFwdPt;
1441 }
1442 
1443 void LineAnnotation::setLineLeadingBackwardPoint( double point )
1444 {
1445  Q_D( LineAnnotation );
1446  d->m_lineLeadingBackPt = point;
1447 }
1448 
1449 double LineAnnotation::lineLeadingBackwardPoint() const
1450 {
1451  Q_D( const LineAnnotation );
1452  return d->m_lineLeadingBackPt;
1453 }
1454 
1455 void LineAnnotation::setShowCaption( bool show )
1456 {
1457  Q_D( LineAnnotation );
1458  d->m_lineShowCaption = show;
1459 }
1460 
1461 bool LineAnnotation::showCaption() const
1462 {
1463  Q_D( const LineAnnotation );
1464  return d->m_lineShowCaption;
1465 }
1466 
1467 void LineAnnotation::setLineIntent( LineIntent intent )
1468 {
1469  Q_D( LineAnnotation );
1470  d->m_lineIntent = intent;
1471 }
1472 
1473 LineAnnotation::LineIntent LineAnnotation::lineIntent() const
1474 {
1475  Q_D( const LineAnnotation );
1476  return d->m_lineIntent;
1477 }
1478 
1479 Annotation::SubType LineAnnotation::subType() const
1480 {
1481  return ALine;
1482 }
1483 
1484 void LineAnnotation::store( QDomNode & node, QDomDocument & document ) const
1485 {
1486  Q_D( const LineAnnotation );
1487  // recurse to parent objects storing properties
1488  Annotation::store( node, document );
1489 
1490  // create [line] element
1491  QDomElement lineElement = document.createElement( QStringLiteral("line") );
1492  node.appendChild( lineElement );
1493 
1494  // store the attributes
1495  if ( d->m_lineStartStyle != None )
1496  lineElement.setAttribute( QStringLiteral("startStyle"), (int)d->m_lineStartStyle );
1497  if ( d->m_lineEndStyle != None )
1498  lineElement.setAttribute( QStringLiteral("endStyle"), (int)d->m_lineEndStyle );
1499  if ( d->m_lineClosed )
1500  lineElement.setAttribute( QStringLiteral("closed"), d->m_lineClosed );
1501  if ( d->m_lineInnerColor.isValid() )
1502  lineElement.setAttribute( QStringLiteral("innerColor"), d->m_lineInnerColor.name() );
1503  if ( d->m_lineLeadingFwdPt != 0.0 )
1504  lineElement.setAttribute( QStringLiteral("leadFwd"), QString::number( d->m_lineLeadingFwdPt ) );
1505  if ( d->m_lineLeadingBackPt != 0.0 )
1506  lineElement.setAttribute( QStringLiteral("leadBack"), QString::number( d->m_lineLeadingBackPt ) );
1507  if ( d->m_lineShowCaption )
1508  lineElement.setAttribute( QStringLiteral("showCaption"), d->m_lineShowCaption );
1509  if ( d->m_lineIntent != Unknown )
1510  lineElement.setAttribute( QStringLiteral("intent"), d->m_lineIntent );
1511 
1512  // append the list of points
1513  int points = d->m_linePoints.count();
1514  if ( points > 1 )
1515  {
1516  QLinkedList<NormalizedPoint>::const_iterator it = d->m_linePoints.begin(), end = d->m_linePoints.end();
1517  while ( it != end )
1518  {
1519  const NormalizedPoint & p = *it;
1520  QDomElement pElement = document.createElement( QStringLiteral("point") );
1521  lineElement.appendChild( pElement );
1522  pElement.setAttribute( QStringLiteral("x"), QString::number( p.x ) );
1523  pElement.setAttribute( QStringLiteral("y"), QString::number( p.y ) );
1524  it++; //to avoid loop
1525  }
1526  }
1527 }
1528 
1529 void LineAnnotationPrivate::transform( const QTransform &matrix )
1530 {
1531  AnnotationPrivate::transform( matrix );
1532 
1533  QMutableLinkedListIterator<NormalizedPoint> it( m_transformedLinePoints );
1534  while ( it.hasNext() )
1535  it.next().transform( matrix );
1536 }
1537 
1538 void LineAnnotationPrivate::baseTransform( const QTransform &matrix )
1539 {
1540  AnnotationPrivate::baseTransform( matrix );
1541 
1543  while ( it.hasNext() )
1544  it.next().transform( matrix );
1545 }
1546 
1547 void LineAnnotationPrivate::resetTransformation()
1548 {
1549  AnnotationPrivate::resetTransformation();
1550 
1551  m_transformedLinePoints = m_linePoints;
1552 }
1553 
1554 void LineAnnotationPrivate::translate( const NormalizedPoint &coord )
1555 {
1556  AnnotationPrivate::translate( coord );
1557 
1559  while ( it.hasNext() )
1560  {
1561  NormalizedPoint& p = it.next();
1562  p.x = p.x + coord.x;
1563  p.y = p.y + coord.y;
1564  }
1565 }
1566 
1567 void LineAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
1568 {
1569  Okular::AnnotationPrivate::setAnnotationProperties(node);
1570 
1571  // loop through the whole children looking for a 'line' element
1572  QDomNode subNode = node.firstChild();
1573  while( subNode.isElement() )
1574  {
1575  QDomElement e = subNode.toElement();
1576  subNode = subNode.nextSibling();
1577  if ( e.tagName() != QLatin1String("line") )
1578  continue;
1579 
1580  // parse the attributes
1581  if ( e.hasAttribute( QStringLiteral("startStyle") ) )
1582  m_lineStartStyle = (LineAnnotation::TermStyle)e.attribute( QStringLiteral("startStyle") ).toInt();
1583  if ( e.hasAttribute( QStringLiteral("endStyle") ) )
1584  m_lineEndStyle = (LineAnnotation::TermStyle)e.attribute( QStringLiteral("endStyle") ).toInt();
1585  if ( e.hasAttribute( QStringLiteral("closed") ) )
1586  m_lineClosed = e.attribute( QStringLiteral("closed") ).toInt();
1587  if ( e.hasAttribute( QStringLiteral("innerColor") ) )
1588  m_lineInnerColor = QColor( e.attribute( QStringLiteral("innerColor") ) );
1589  if ( e.hasAttribute( QStringLiteral("leadFwd") ) )
1590  m_lineLeadingFwdPt = e.attribute( QStringLiteral("leadFwd") ).toDouble();
1591  if ( e.hasAttribute( QStringLiteral("leadBack") ) )
1592  m_lineLeadingBackPt = e.attribute( QStringLiteral("leadBack") ).toDouble();
1593  if ( e.hasAttribute( QStringLiteral("showCaption") ) )
1594  m_lineShowCaption = e.attribute( QStringLiteral("showCaption") ).toInt();
1595  if ( e.hasAttribute( QStringLiteral("intent") ) )
1596  m_lineIntent = (LineAnnotation::LineIntent)e.attribute( QStringLiteral("intent") ).toInt();
1597 
1598  // parse all 'point' subnodes
1599  QDomNode pointNode = e.firstChild();
1600  while ( pointNode.isElement() )
1601  {
1602  QDomElement pe = pointNode.toElement();
1603  pointNode = pointNode.nextSibling();
1604 
1605  if ( pe.tagName() != QLatin1String("point") )
1606  continue;
1607 
1608  NormalizedPoint p;
1609  p.x = pe.attribute( QStringLiteral("x"), QStringLiteral("0.0") ).toDouble();
1610  p.y = pe.attribute( QStringLiteral("y"), QStringLiteral("0.0") ).toDouble();
1611  m_linePoints.append( p );
1612  }
1613 
1614  // loading complete
1615  break;
1616  }
1617 
1618  m_transformedLinePoints = m_linePoints;
1619 }
1620 
1621 AnnotationPrivate* LineAnnotationPrivate::getNewAnnotationPrivate()
1622 {
1623  return new LineAnnotationPrivate();
1624 }
1625 
1626 double LineAnnotationPrivate::distanceSqr( double x, double y, double xScale, double yScale ) const
1627 {
1628  QLinkedList<NormalizedPoint> transformedLinePoints = m_transformedLinePoints;
1629 
1630  if ( m_lineClosed ) // Close the path
1631  transformedLinePoints.append( transformedLinePoints.first() );
1632 
1633  if ( m_lineInnerColor.isValid() )
1634  {
1635  QPolygonF polygon;
1636  for ( const NormalizedPoint &p : qAsConst(transformedLinePoints) )
1637  polygon.append( QPointF( p.x, p.y ) );
1638 
1639  if ( polygon.containsPoint( QPointF( x, y ), Qt::WindingFill ) )
1640  return 0;
1641  }
1642 
1643  return strokeDistance( ::distanceSqr( x, y, xScale, yScale, transformedLinePoints ),
1644  m_style.width() * xScale / ( m_page->m_width * 2 ) );
1645 }
1646 
1649 class Okular::GeomAnnotationPrivate : public Okular::AnnotationPrivate
1650 {
1651  public:
1652  GeomAnnotationPrivate()
1653  : AnnotationPrivate(), m_geomType( GeomAnnotation::InscribedSquare )
1654  {
1655  }
1656  void setAnnotationProperties( const QDomNode& node ) override;
1657  bool canBeResized() const override;
1658  AnnotationPrivate* getNewAnnotationPrivate() override;
1659  double distanceSqr( double x, double y, double xScale, double yScale ) const override;
1660 
1661  GeomAnnotation::GeomType m_geomType;
1662  QColor m_geomInnerColor;
1663 };
1664 
1665 GeomAnnotation::GeomAnnotation()
1666  : Annotation( *new GeomAnnotationPrivate() )
1667 {
1668 }
1669 
1670 GeomAnnotation::GeomAnnotation( const QDomNode & description )
1671  : Annotation( *new GeomAnnotationPrivate(), description )
1672 {
1673 }
1674 
1675 GeomAnnotation::~GeomAnnotation()
1676 {
1677 }
1678 
1679 void GeomAnnotation::setGeometricalType( GeomType type )
1680 {
1681  Q_D( GeomAnnotation );
1682  d->m_geomType = type;
1683 }
1684 
1685 GeomAnnotation::GeomType GeomAnnotation::geometricalType() const
1686 {
1687  Q_D( const GeomAnnotation );
1688  return d->m_geomType;
1689 }
1690 
1691 void GeomAnnotation::setGeometricalInnerColor( const QColor &color )
1692 {
1693  Q_D( GeomAnnotation );
1694  d->m_geomInnerColor = color;
1695 }
1696 
1697 QColor GeomAnnotation::geometricalInnerColor() const
1698 {
1699  Q_D( const GeomAnnotation );
1700  return d->m_geomInnerColor;
1701 }
1702 
1703 Annotation::SubType GeomAnnotation::subType() const
1704 {
1705  return AGeom;
1706 }
1707 
1708 void GeomAnnotation::store( QDomNode & node, QDomDocument & document ) const
1709 {
1710  Q_D( const GeomAnnotation );
1711  // recurse to parent objects storing properties
1712  Annotation::store( node, document );
1713 
1714  // create [geom] element
1715  QDomElement geomElement = document.createElement( QStringLiteral("geom") );
1716  node.appendChild( geomElement );
1717 
1718  // append the optional attributes
1719  if ( d->m_geomType != InscribedSquare )
1720  geomElement.setAttribute( QStringLiteral("type"), (int)d->m_geomType );
1721  if ( d->m_geomInnerColor.isValid() )
1722  geomElement.setAttribute( QStringLiteral("color"), d->m_geomInnerColor.name() );
1723 }
1724 
1725 void GeomAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
1726 {
1727  Okular::AnnotationPrivate::setAnnotationProperties(node);
1728  // loop through the whole children looking for a 'geom' element
1729  QDomNode subNode = node.firstChild();
1730  while( subNode.isElement() )
1731  {
1732  QDomElement e = subNode.toElement();
1733  subNode = subNode.nextSibling();
1734  if ( e.tagName() != QLatin1String("geom") )
1735  continue;
1736 
1737  // parse the attributes
1738  if ( e.hasAttribute( QStringLiteral("type") ) )
1739  m_geomType = (GeomAnnotation::GeomType)e.attribute( QStringLiteral("type") ).toInt();
1740  if ( e.hasAttribute( QStringLiteral("color") ) )
1741  m_geomInnerColor = QColor( e.attribute( QStringLiteral("color") ) );
1742  // compatibility
1743  if ( e.hasAttribute( QStringLiteral("width") ) )
1744  m_style.setWidth( e.attribute( QStringLiteral("width") ).toInt() );
1745 
1746  // loading complete
1747  break;
1748  }
1749 }
1750 
1751 bool GeomAnnotationPrivate::canBeResized() const
1752 {
1753  return true;
1754 }
1755 
1756 AnnotationPrivate* GeomAnnotationPrivate::getNewAnnotationPrivate()
1757 {
1758  return new GeomAnnotationPrivate();
1759 }
1760 
1761 double GeomAnnotationPrivate::distanceSqr( double x, double y, double xScale, double yScale ) const
1762 {
1763  double distance = 0;
1764  //the line thickness is applied unevenly (only on the "inside") - account for this
1765  bool withinShape = false;
1766  switch (m_geomType) {
1767  case GeomAnnotation::InscribedCircle:
1768  {
1769  //calculate the center point and focus lengths of the ellipse
1770  const double centerX = ( m_transformedBoundary.left + m_transformedBoundary.right ) / 2.0;
1771  const double centerY = ( m_transformedBoundary.top + m_transformedBoundary.bottom ) / 2.0;
1772  const double focusX = ( m_transformedBoundary.right - centerX);
1773  const double focusY = ( m_transformedBoundary.bottom - centerY);
1774 
1775  const double focusXSqr = pow( focusX, 2 );
1776  const double focusYSqr = pow( focusY, 2 );
1777 
1778  // to calculate the distance from the ellipse, we will first find the point "projection"
1779  // that lies on the ellipse and is closest to the point (x,y)
1780  // This point can obviously be written as "center + lambda(inputPoint - center)".
1781  // Because the point lies on the ellipse, we know that:
1782  // 1 = ((center.x - projection.x)/focusX)^2 + ((center.y - projection.y)/focusY)^2
1783  // After filling in projection.x = center.x + lambda * (inputPoint.x - center.x)
1784  // and its y-equivalent, we can solve for lambda:
1785  const double lambda = sqrt( focusXSqr * focusYSqr /
1786  ( focusYSqr * pow( x - centerX, 2 ) + focusXSqr * pow( y - centerY, 2 ) ) );
1787 
1788  // if the ellipse is filled, we treat all points within as "on" it
1789  if ( lambda > 1 )
1790  {
1791  if ( m_geomInnerColor.isValid() )
1792  return 0;
1793  else
1794  withinShape = true;
1795  }
1796 
1797  //otherwise we calculate the squared distance from the projected point on the ellipse
1798  NormalizedPoint projection( centerX, centerY );
1799  projection.x += lambda * ( x - centerX );
1800  projection.y += lambda * ( y - centerY );
1801 
1802  distance = projection.distanceSqr( x, y, xScale, yScale );
1803  break;
1804  }
1805 
1806  case GeomAnnotation::InscribedSquare:
1807  //if the square is filled, only check the bounding box
1808  if ( m_geomInnerColor.isValid() )
1809  return AnnotationPrivate::distanceSqr( x, y, xScale, yScale );
1810 
1812  edges << NormalizedPoint( m_transformedBoundary.left, m_transformedBoundary.top );
1813  edges << NormalizedPoint( m_transformedBoundary.right, m_transformedBoundary.top );
1814  edges << NormalizedPoint( m_transformedBoundary.right, m_transformedBoundary.bottom );
1815  edges << NormalizedPoint( m_transformedBoundary.left, m_transformedBoundary.bottom );
1816  edges << NormalizedPoint( m_transformedBoundary.left, m_transformedBoundary.top );
1817  distance = ::distanceSqr( x, y, xScale, yScale, edges );
1818 
1819  if ( m_transformedBoundary.contains( x, y ) )
1820  withinShape = true;
1821 
1822  break;
1823  }
1824  if ( withinShape )
1825  distance = strokeDistance( distance, m_style.width() * xScale / m_page->m_width );
1826 
1827  return distance;
1828 }
1829 
1832 class HighlightAnnotation::Quad::Private
1833 {
1834  public:
1835  Private()
1836  {
1837  }
1838 
1839  NormalizedPoint m_points[4];
1840  NormalizedPoint m_transformedPoints[4];
1841  bool m_capStart : 1;
1842  bool m_capEnd : 1;
1843  double m_feather;
1844 };
1845 
1847  : d( new Private )
1848 {
1849 }
1850 
1852 {
1853  delete d;
1854 }
1855 
1856 HighlightAnnotation::Quad::Quad( const Quad &other )
1857  : d( new Private )
1858 {
1859  *d = *other.d;
1860 }
1861 
1862 HighlightAnnotation::Quad& HighlightAnnotation::Quad::operator=( const Quad &other )
1863 {
1864  if ( this != &other )
1865  *d = *other.d;
1866 
1867  return *this;
1868 }
1869 
1871 {
1872  if ( index < 0 || index > 3 )
1873  return;
1874 
1875  d->m_points[ index ] = point;
1876 }
1877 
1879 {
1880  if ( index < 0 || index > 3 )
1881  return NormalizedPoint();
1882 
1883  return d->m_points[ index ];
1884 }
1885 
1887 {
1888  if ( index < 0 || index > 3 )
1889  return NormalizedPoint();
1890 
1891  return d->m_transformedPoints[ index ];
1892 }
1893 
1895 {
1896  d->m_capStart = value;
1897 }
1898 
1900 {
1901  return d->m_capStart;
1902 }
1903 
1905 {
1906  d->m_capEnd = value;
1907 }
1908 
1910 {
1911  return d->m_capEnd;
1912 }
1913 
1915 {
1916  d->m_feather = width;
1917 }
1918 
1920 {
1921  return d->m_feather;
1922 }
1923 
1925 {
1926  for ( int i = 0; i < 4; ++i ) {
1927  d->m_transformedPoints[ i ] = d->m_points[ i ];
1928  d->m_transformedPoints[ i ].transform( matrix );
1929  }
1930 }
1931 
1932 
1933 class Okular::HighlightAnnotationPrivate : public Okular::AnnotationPrivate
1934 {
1935  public:
1936  HighlightAnnotationPrivate()
1937  : AnnotationPrivate(), m_highlightType( HighlightAnnotation::Highlight )
1938  {
1939  }
1940 
1941  void transform( const QTransform &matrix ) override;
1942  void baseTransform( const QTransform &matrix ) override;
1943  double distanceSqr( double x, double y, double xScale, double yScale ) const override;
1944  void setAnnotationProperties( const QDomNode& node ) override;
1945  AnnotationPrivate* getNewAnnotationPrivate() override;
1946 
1947  HighlightAnnotation::HighlightType m_highlightType;
1948  QList< HighlightAnnotation::Quad > m_highlightQuads;
1949 };
1950 
1951 HighlightAnnotation::HighlightAnnotation()
1952  : Annotation( *new HighlightAnnotationPrivate() )
1953 {
1954 }
1955 
1956 HighlightAnnotation::HighlightAnnotation( const QDomNode & description )
1957  : Annotation( *new HighlightAnnotationPrivate(), description )
1958 {
1959 }
1960 
1961 HighlightAnnotation::~HighlightAnnotation()
1962 {
1963 }
1964 
1965 void HighlightAnnotation::setHighlightType( HighlightType type )
1966 {
1967  Q_D( HighlightAnnotation );
1968  d->m_highlightType = type;
1969 }
1970 
1971 HighlightAnnotation::HighlightType HighlightAnnotation::highlightType() const
1972 {
1973  Q_D( const HighlightAnnotation );
1974  return d->m_highlightType;
1975 }
1976 
1977 QList< HighlightAnnotation::Quad > & HighlightAnnotation::highlightQuads()
1978 {
1979  Q_D( HighlightAnnotation );
1980  return d->m_highlightQuads;
1981 }
1982 
1983 void HighlightAnnotation::store( QDomNode & node, QDomDocument & document ) const
1984 {
1985  Q_D( const HighlightAnnotation );
1986  // recurse to parent objects storing properties
1987  Annotation::store( node, document );
1988 
1989  // create [hl] element
1990  QDomElement hlElement = document.createElement( QStringLiteral("hl") );
1991  node.appendChild( hlElement );
1992 
1993  // append the optional attributes
1994  if ( d->m_highlightType != Highlight )
1995  hlElement.setAttribute( QStringLiteral("type"), (int)d->m_highlightType );
1996  if ( d->m_highlightQuads.count() < 1 )
1997  return;
1998  // append highlight quads, all children describe quads
1999  QList< Quad >::const_iterator it = d->m_highlightQuads.begin(), end = d->m_highlightQuads.end();
2000  for ( ; it != end; ++it )
2001  {
2002  QDomElement quadElement = document.createElement( QStringLiteral("quad") );
2003  hlElement.appendChild( quadElement );
2004  const Quad & q = *it;
2005  quadElement.setAttribute( QStringLiteral("ax"), QString::number( q.point( 0 ).x ) );
2006  quadElement.setAttribute( QStringLiteral("ay"), QString::number( q.point( 0 ).y ) );
2007  quadElement.setAttribute( QStringLiteral("bx"), QString::number( q.point( 1 ).x ) );
2008  quadElement.setAttribute( QStringLiteral("by"), QString::number( q.point( 1 ).y ) );
2009  quadElement.setAttribute( QStringLiteral("cx"), QString::number( q.point( 2 ).x ) );
2010  quadElement.setAttribute( QStringLiteral("cy"), QString::number( q.point( 2 ).y ) );
2011  quadElement.setAttribute( QStringLiteral("dx"), QString::number( q.point( 3 ).x ) );
2012  quadElement.setAttribute( QStringLiteral("dy"), QString::number( q.point( 3 ).y ) );
2013  if ( q.capStart() )
2014  quadElement.setAttribute( QStringLiteral("start"), 1 );
2015  if ( q.capEnd() )
2016  quadElement.setAttribute( QStringLiteral("end"), 1 );
2017  quadElement.setAttribute( QStringLiteral("feather"), QString::number( q.feather() ) );
2018  }
2019 }
2020 
2021 Annotation::SubType HighlightAnnotation::subType() const
2022 {
2023  return AHighlight;
2024 }
2025 
2026 void HighlightAnnotationPrivate::transform( const QTransform &matrix )
2027 {
2028  AnnotationPrivate::transform( matrix );
2029 
2030  QMutableListIterator<HighlightAnnotation::Quad> it( m_highlightQuads );
2031  while ( it.hasNext() )
2032  it.next().transform( matrix );
2033 }
2034 
2035 void HighlightAnnotationPrivate::baseTransform( const QTransform &matrix )
2036 {
2037  AnnotationPrivate::baseTransform( matrix );
2038 
2039  QMutableListIterator<HighlightAnnotation::Quad> it( m_highlightQuads );
2040  while ( it.hasNext() )
2041  it.next().transform( matrix );
2042 }
2043 
2044 void HighlightAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
2045 {
2046  Okular::AnnotationPrivate::setAnnotationProperties(node);
2047  m_highlightQuads.clear();
2048 
2049  // loop through the whole children looking for a 'hl' element
2050  QDomNode subNode = node.firstChild();
2051  while( subNode.isElement() )
2052  {
2053  QDomElement e = subNode.toElement();
2054  subNode = subNode.nextSibling();
2055  if ( e.tagName() != QLatin1String("hl") )
2056  continue;
2057 
2058  // parse the attributes
2059  if ( e.hasAttribute( QStringLiteral("type") ) )
2060  m_highlightType = (HighlightAnnotation::HighlightType)e.attribute( QStringLiteral("type") ).toInt();
2061 
2062  // parse all 'quad' subnodes
2063  QDomNode quadNode = e.firstChild();
2064  for ( ; quadNode.isElement(); quadNode = quadNode.nextSibling() )
2065  {
2066  QDomElement qe = quadNode.toElement();
2067  if ( qe.tagName() != QLatin1String("quad") )
2068  continue;
2069 
2071  q.setPoint( NormalizedPoint( qe.attribute( QStringLiteral("ax"), QStringLiteral("0.0") ).toDouble(), qe.attribute( QStringLiteral("ay"), QStringLiteral("0.0") ).toDouble() ), 0 );
2072  q.setPoint( NormalizedPoint( qe.attribute( QStringLiteral("bx"), QStringLiteral("0.0") ).toDouble(), qe.attribute( QStringLiteral("by"), QStringLiteral("0.0") ).toDouble() ), 1 );
2073  q.setPoint( NormalizedPoint( qe.attribute( QStringLiteral("cx"), QStringLiteral("0.0") ).toDouble(), qe.attribute( QStringLiteral("cy"), QStringLiteral("0.0") ).toDouble() ), 2 );
2074  q.setPoint( NormalizedPoint( qe.attribute( QStringLiteral("dx"), QStringLiteral("0.0") ).toDouble(), qe.attribute( QStringLiteral("dy"), QStringLiteral("0.0") ).toDouble() ), 3 );
2075  q.setCapStart( qe.hasAttribute( QStringLiteral("start") ) );
2076  q.setCapEnd( qe.hasAttribute( QStringLiteral("end") ) );
2077  q.setFeather( qe.attribute( QStringLiteral("feather"), QStringLiteral("0.1") ).toDouble() );
2078 
2079  q.transform( QTransform() );
2080 
2081  m_highlightQuads.append( q );
2082  }
2083 
2084  // loading complete
2085  break;
2086  }
2087 }
2088 
2089 AnnotationPrivate* HighlightAnnotationPrivate::getNewAnnotationPrivate()
2090 {
2091  return new HighlightAnnotationPrivate();
2092 }
2093 
2094 double HighlightAnnotationPrivate::distanceSqr( double x, double y, double xScale, double yScale ) const
2095 {
2096  NormalizedPoint point( x, y );
2097  double outsideDistance = DBL_MAX;
2098  for ( const HighlightAnnotation::Quad &quad : m_highlightQuads )
2099  {
2100  QLinkedList<NormalizedPoint> pathPoints;
2101 
2102  //first, we check if the point is within the area described by the 4 quads
2103  //this is the case, if the point is always on one side of each segments delimiting the polygon:
2104  pathPoints << quad.transformedPoint( 0 );
2105  int directionVote = 0;
2106  for ( int i = 1; i < 5; ++i )
2107  {
2108  NormalizedPoint thisPoint = quad.transformedPoint( i % 4 );
2109  directionVote += (isLeftOfVector( pathPoints.back(), thisPoint, point )) ? 1 : -1;
2110  pathPoints << thisPoint;
2111  }
2112  if ( abs( directionVote ) == 4 )
2113  return 0;
2114 
2115  //if that's not the case, we treat the outline as path and simply determine
2116  //the distance from the path to the point
2117  const double thisOutsideDistance = ::distanceSqr( x, y, xScale, yScale, pathPoints );
2118  if ( thisOutsideDistance < outsideDistance )
2119  outsideDistance = thisOutsideDistance;
2120  }
2121 
2122  return outsideDistance;
2123 }
2124 
2127 class Okular::StampAnnotationPrivate : public Okular::AnnotationPrivate
2128 {
2129  public:
2130  StampAnnotationPrivate()
2131  : AnnotationPrivate(), m_stampIconName( QStringLiteral("Draft") )
2132  {
2133  }
2134  void setAnnotationProperties( const QDomNode& node ) override;
2135  bool canBeResized() const override;
2136  AnnotationPrivate* getNewAnnotationPrivate() override;
2137 
2138  QString m_stampIconName;
2139 };
2140 
2141 StampAnnotation::StampAnnotation()
2142  : Annotation( *new StampAnnotationPrivate() )
2143 {
2144 }
2145 
2146 StampAnnotation::StampAnnotation( const QDomNode & description )
2147  : Annotation( *new StampAnnotationPrivate(), description )
2148 {
2149 }
2150 
2151 StampAnnotation::~StampAnnotation()
2152 {
2153 }
2154 
2155 void StampAnnotation::setStampIconName( const QString &name )
2156 {
2157  Q_D( StampAnnotation );
2158  d->m_stampIconName = name;
2159 }
2160 
2161 QString StampAnnotation::stampIconName() const
2162 {
2163  Q_D( const StampAnnotation );
2164  return d->m_stampIconName;
2165 }
2166 
2167 Annotation::SubType StampAnnotation::subType() const
2168 {
2169  return AStamp;
2170 }
2171 
2172 void StampAnnotation::store( QDomNode & node, QDomDocument & document ) const
2173 {
2174  Q_D( const StampAnnotation );
2175  // recurse to parent objects storing properties
2176  Annotation::store( node, document );
2177 
2178  // create [stamp] element
2179  QDomElement stampElement = document.createElement( QStringLiteral("stamp") );
2180  node.appendChild( stampElement );
2181 
2182  // append the optional attributes
2183  if ( d->m_stampIconName != QLatin1String("Draft") )
2184  stampElement.setAttribute( QStringLiteral("icon"), d->m_stampIconName );
2185 }
2186 
2187 void StampAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
2188 {
2189  Okular::AnnotationPrivate::setAnnotationProperties(node);
2190 
2191  // loop through the whole children looking for a 'stamp' element
2192  QDomNode subNode = node.firstChild();
2193  while( subNode.isElement() )
2194  {
2195  QDomElement e = subNode.toElement();
2196  subNode = subNode.nextSibling();
2197  if ( e.tagName() != QLatin1String("stamp") )
2198  continue;
2199 
2200  // parse the attributes
2201  if ( e.hasAttribute( QStringLiteral("icon") ) )
2202  m_stampIconName = e.attribute( QStringLiteral("icon") );
2203 
2204  // loading complete
2205  break;
2206  }
2207 }
2208 
2209 bool StampAnnotationPrivate::canBeResized() const
2210 {
2211  return true;
2212 }
2213 
2214 AnnotationPrivate* StampAnnotationPrivate::getNewAnnotationPrivate()
2215 {
2216  return new StampAnnotationPrivate();
2217 }
2218 
2221 class Okular::InkAnnotationPrivate : public Okular::AnnotationPrivate
2222 {
2223  public:
2224  InkAnnotationPrivate()
2225  : AnnotationPrivate()
2226  {
2227  }
2228 
2229  void transform( const QTransform &matrix ) override;
2230  void baseTransform( const QTransform &matrix ) override;
2231  void resetTransformation() override;
2232  double distanceSqr( double x, double y, double xScale, double yScale ) const override;
2233  void translate( const NormalizedPoint &coord ) override;
2234  void setAnnotationProperties( const QDomNode& node ) override;
2235  AnnotationPrivate* getNewAnnotationPrivate() override;
2236 
2238  QList< QLinkedList<NormalizedPoint> > m_transformedInkPaths;
2239 };
2240 
2241 InkAnnotation::InkAnnotation()
2242  : Annotation( *new InkAnnotationPrivate() )
2243 {
2244 }
2245 
2246 InkAnnotation::InkAnnotation( const QDomNode & description )
2247  : Annotation( *new InkAnnotationPrivate(), description )
2248 {
2249 }
2250 
2251 InkAnnotation::~InkAnnotation()
2252 {
2253 }
2254 
2255 void InkAnnotation::setInkPaths( const QList< QLinkedList<NormalizedPoint> > &paths )
2256 {
2257  Q_D( InkAnnotation );
2258  d->m_inkPaths = paths;
2259 }
2260 
2261 QList< QLinkedList<NormalizedPoint> > InkAnnotation::inkPaths() const
2262 {
2263  Q_D( const InkAnnotation );
2264  return d->m_inkPaths;
2265 }
2266 
2267 QList< QLinkedList<NormalizedPoint> > InkAnnotation::transformedInkPaths() const
2268 {
2269  Q_D( const InkAnnotation );
2270  return d->m_transformedInkPaths;
2271 }
2272 
2273 Annotation::SubType InkAnnotation::subType() const
2274 {
2275  return AInk;
2276 }
2277 
2278 void InkAnnotation::store( QDomNode & node, QDomDocument & document ) const
2279 {
2280  Q_D( const InkAnnotation );
2281  // recurse to parent objects storing properties
2282  Annotation::store( node, document );
2283 
2284  // create [ink] element
2285  QDomElement inkElement = document.createElement( QStringLiteral("ink") );
2286  node.appendChild( inkElement );
2287 
2288  // append the optional attributes
2289  if ( d->m_inkPaths.count() < 1 )
2290  return;
2291 
2292  QList< QLinkedList<NormalizedPoint> >::const_iterator pIt = d->m_inkPaths.begin(), pEnd = d->m_inkPaths.end();
2293  for ( ; pIt != pEnd; ++pIt )
2294  {
2295  QDomElement pathElement = document.createElement( QStringLiteral("path") );
2296  inkElement.appendChild( pathElement );
2297  const QLinkedList<NormalizedPoint> & path = *pIt;
2298  QLinkedList<NormalizedPoint>::const_iterator iIt = path.begin(), iEnd = path.end();
2299  for ( ; iIt != iEnd; ++iIt )
2300  {
2301  const NormalizedPoint & point = *iIt;
2302  QDomElement pointElement = document.createElement( QStringLiteral("point") );
2303  pathElement.appendChild( pointElement );
2304  pointElement.setAttribute( QStringLiteral("x"), QString::number( point.x ) );
2305  pointElement.setAttribute( QStringLiteral("y"), QString::number( point.y ) );
2306  }
2307  }
2308 }
2309 
2310 double InkAnnotationPrivate::distanceSqr( double x, double y, double xScale, double yScale ) const
2311 {
2312  double distance = DBL_MAX;
2313  for ( const QLinkedList<NormalizedPoint> &path : m_transformedInkPaths )
2314  {
2315  const double thisDistance = ::distanceSqr( x, y, xScale, yScale, path );
2316  if ( thisDistance < distance )
2317  distance = thisDistance;
2318  }
2319  return strokeDistance( distance, m_style.width() * xScale / ( m_page->m_width * 2 ) );
2320 }
2321 
2322 void InkAnnotationPrivate::transform( const QTransform &matrix )
2323 {
2324  AnnotationPrivate::transform( matrix );
2325 
2326  for ( int i = 0; i < m_transformedInkPaths.count(); ++i )
2327  {
2328  QMutableLinkedListIterator<NormalizedPoint> it( m_transformedInkPaths[ i ] );
2329  while ( it.hasNext() )
2330  it.next().transform( matrix );
2331  }
2332 }
2333 
2334 void InkAnnotationPrivate::baseTransform( const QTransform &matrix )
2335 {
2336  AnnotationPrivate::baseTransform( matrix );
2337 
2338  for ( int i = 0; i < m_inkPaths.count(); ++i )
2339  {
2340  QMutableLinkedListIterator<NormalizedPoint> it( m_inkPaths[ i ] );
2341  while ( it.hasNext() )
2342  it.next().transform( matrix );
2343  }
2344 }
2345 
2346 void InkAnnotationPrivate::resetTransformation()
2347 {
2348  AnnotationPrivate::resetTransformation();
2349 
2350  m_transformedInkPaths = m_inkPaths;
2351 }
2352 
2353 void InkAnnotationPrivate::translate( const NormalizedPoint &coord )
2354 {
2355  AnnotationPrivate::translate( coord );
2356 
2357  for ( int i = 0; i < m_inkPaths.count(); ++i )
2358  {
2359  QMutableLinkedListIterator<NormalizedPoint> it( m_inkPaths[ i ] );
2360  while ( it.hasNext() )
2361  {
2362  NormalizedPoint& p = it.next();
2363  p.x = p.x + coord.x;
2364  p.y = p.y + coord.y;
2365  }
2366  }
2367 }
2368 
2369 void InkAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
2370 {
2371  Okular::AnnotationPrivate::setAnnotationProperties(node);
2372  m_inkPaths.clear();
2373 
2374  // loop through the whole children looking for a 'ink' element
2375  QDomNode subNode = node.firstChild();
2376  while( subNode.isElement() )
2377  {
2378  QDomElement e = subNode.toElement();
2379  subNode = subNode.nextSibling();
2380  if ( e.tagName() != QLatin1String("ink") )
2381  continue;
2382 
2383  // parse the 'path' subnodes
2384  QDomNode pathNode = e.firstChild();
2385  while ( pathNode.isElement() )
2386  {
2387  QDomElement pathElement = pathNode.toElement();
2388  pathNode = pathNode.nextSibling();
2389 
2390  if ( pathElement.tagName() != QLatin1String("path") )
2391  continue;
2392 
2393  // build each path parsing 'point' subnodes
2395  QDomNode pointNode = pathElement.firstChild();
2396  while ( pointNode.isElement() )
2397  {
2398  QDomElement pointElement = pointNode.toElement();
2399  pointNode = pointNode.nextSibling();
2400 
2401  if ( pointElement.tagName() != QLatin1String("point") )
2402  continue;
2403 
2404  NormalizedPoint p;
2405  p.x = pointElement.attribute( QStringLiteral("x"), QStringLiteral("0.0") ).toDouble();
2406  p.y = pointElement.attribute( QStringLiteral("y"), QStringLiteral("0.0") ).toDouble();
2407  path.append( p );
2408  }
2409 
2410  // add the path to the path list if it contains at least 2 nodes
2411  if ( path.count() >= 2 )
2412  m_inkPaths.append( path );
2413  }
2414 
2415  // loading complete
2416  break;
2417  }
2418 
2419  m_transformedInkPaths = m_inkPaths;
2420 }
2421 
2422 AnnotationPrivate* InkAnnotationPrivate::getNewAnnotationPrivate()
2423 {
2424  return new InkAnnotationPrivate();
2425 }
2426 
2429 class Okular::CaretAnnotationPrivate : public Okular::AnnotationPrivate
2430 {
2431  public:
2432  CaretAnnotationPrivate()
2433  : AnnotationPrivate(), m_symbol( CaretAnnotation::None )
2434  {
2435  }
2436 
2437  void setAnnotationProperties( const QDomNode& node ) override;
2438  AnnotationPrivate* getNewAnnotationPrivate() override;
2439 
2440  CaretAnnotation::CaretSymbol m_symbol;
2441 };
2442 
2443 static QString caretSymbolToString( CaretAnnotation::CaretSymbol symbol )
2444 {
2445  switch ( symbol )
2446  {
2447  case CaretAnnotation::None:
2448  return QStringLiteral( "None" );
2449  case CaretAnnotation::P:
2450  return QStringLiteral( "P" );
2451  }
2452  return QString();
2453 }
2454 
2455 static CaretAnnotation::CaretSymbol caretSymbolFromString( const QString &symbol )
2456 {
2457  if ( symbol == QLatin1String( "None" ) )
2458  return CaretAnnotation::None;
2459  else if ( symbol == QLatin1String( "P" ) )
2460  return CaretAnnotation::P;
2461  return CaretAnnotation::None;
2462 }
2463 
2464 void CaretAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
2465 {
2466  Okular::AnnotationPrivate::setAnnotationProperties(node);
2467 
2468  // loop through the whole children looking for a 'caret' element
2469  QDomNode subNode = node.firstChild();
2470  while( subNode.isElement() )
2471  {
2472  QDomElement e = subNode.toElement();
2473  subNode = subNode.nextSibling();
2474  if ( e.tagName() != QLatin1String("caret") )
2475  continue;
2476 
2477  // parse the attributes
2478  if ( e.hasAttribute( QStringLiteral("symbol") ) )
2479  m_symbol = caretSymbolFromString( e.attribute( QStringLiteral("symbol") ) );
2480 
2481  // loading complete
2482  break;
2483  }
2484 }
2485 
2486 AnnotationPrivate* CaretAnnotationPrivate::getNewAnnotationPrivate()
2487 {
2488  return new CaretAnnotationPrivate();
2489 }
2490 
2491 CaretAnnotation::CaretAnnotation()
2492  : Annotation( *new CaretAnnotationPrivate() )
2493 {
2494 }
2495 
2496 CaretAnnotation::CaretAnnotation( const QDomNode & description )
2497  : Annotation( *new CaretAnnotationPrivate(), description )
2498 {
2499 }
2500 
2501 CaretAnnotation::~CaretAnnotation()
2502 {
2503 }
2504 
2505 void CaretAnnotation::setCaretSymbol( CaretAnnotation::CaretSymbol symbol )
2506 {
2507  Q_D( CaretAnnotation );
2508  d->m_symbol = symbol;
2509 }
2510 
2511 CaretAnnotation::CaretSymbol CaretAnnotation::caretSymbol() const
2512 {
2513  Q_D( const CaretAnnotation );
2514  return d->m_symbol;
2515 }
2516 
2517 Annotation::SubType CaretAnnotation::subType() const
2518 {
2519  return ACaret;
2520 }
2521 
2522 void CaretAnnotation::store( QDomNode & node, QDomDocument & document ) const
2523 {
2524  Q_D( const CaretAnnotation );
2525  // recurse to parent objects storing properties
2526  Annotation::store( node, document );
2527 
2528  // create [caret] element
2529  QDomElement caretElement = document.createElement( QStringLiteral("caret") );
2530  node.appendChild( caretElement );
2531 
2532  // append the optional attributes
2533  if ( d->m_symbol != None )
2534  caretElement.setAttribute( QStringLiteral("symbol"), caretSymbolToString( d->m_symbol ) );
2535 }
2536 
2539 class Okular::FileAttachmentAnnotationPrivate : public Okular::AnnotationPrivate
2540 {
2541  public:
2542  FileAttachmentAnnotationPrivate()
2543  : AnnotationPrivate(), icon( QStringLiteral("PushPin") ), embfile( nullptr )
2544  {
2545  }
2546  ~FileAttachmentAnnotationPrivate() override
2547  {
2548  delete embfile;
2549  }
2550 
2551  void setAnnotationProperties( const QDomNode& node ) override;
2552  AnnotationPrivate* getNewAnnotationPrivate() override;
2553 
2554  // data fields
2555  QString icon;
2556  EmbeddedFile *embfile;
2557 };
2558 
2559 void FileAttachmentAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
2560 {
2561  Okular::AnnotationPrivate::setAnnotationProperties(node);
2562 
2563  // loop through the whole children looking for a 'fileattachment' element
2564  QDomNode subNode = node.firstChild();
2565  while( subNode.isElement() )
2566  {
2567  QDomElement e = subNode.toElement();
2568  subNode = subNode.nextSibling();
2569  if ( e.tagName() != QLatin1String("fileattachment") )
2570  continue;
2571 
2572  // loading complete
2573  break;
2574  }
2575 }
2576 
2577 AnnotationPrivate* FileAttachmentAnnotationPrivate::getNewAnnotationPrivate()
2578 {
2579  return new FileAttachmentAnnotationPrivate();
2580 }
2581 
2582 FileAttachmentAnnotation::FileAttachmentAnnotation()
2583  : Annotation( *new FileAttachmentAnnotationPrivate() )
2584 {
2585 }
2586 
2587 FileAttachmentAnnotation::FileAttachmentAnnotation( const QDomNode & description )
2588  : Annotation( *new FileAttachmentAnnotationPrivate(), description )
2589 {
2590 }
2591 
2592 FileAttachmentAnnotation::~FileAttachmentAnnotation()
2593 {
2594 }
2595 
2596 void FileAttachmentAnnotation::store( QDomNode & node, QDomDocument & document ) const
2597 {
2598  // recurse to parent objects storing properties
2599  Annotation::store( node, document );
2600 
2601  // create [fileattachment] element
2602  QDomElement fileAttachmentElement = document.createElement( QStringLiteral("fileattachment") );
2603  node.appendChild( fileAttachmentElement );
2604 }
2605 
2606 Annotation::SubType FileAttachmentAnnotation::subType() const
2607 {
2608  return AFileAttachment;
2609 }
2610 
2611 QString FileAttachmentAnnotation::fileIconName() const
2612 {
2613  Q_D( const FileAttachmentAnnotation );
2614  return d->icon;
2615 }
2616 
2617 void FileAttachmentAnnotation::setFileIconName( const QString &iconName )
2618 {
2619  Q_D( FileAttachmentAnnotation );
2620  d->icon = iconName;
2621 }
2622 
2623 EmbeddedFile* FileAttachmentAnnotation::embeddedFile() const
2624 {
2625  Q_D( const FileAttachmentAnnotation );
2626  return d->embfile;
2627 }
2628 
2629 void FileAttachmentAnnotation::setEmbeddedFile( EmbeddedFile *ef )
2630 {
2631  Q_D( FileAttachmentAnnotation );
2632  d->embfile = ef;
2633 }
2634 
2635 
2638 class Okular::SoundAnnotationPrivate : public Okular::AnnotationPrivate
2639 {
2640  public:
2641  SoundAnnotationPrivate()
2642  : AnnotationPrivate(), icon( QStringLiteral("Speaker") ), sound( nullptr )
2643  {
2644  }
2645  ~SoundAnnotationPrivate() override
2646  {
2647  delete sound;
2648  }
2649 
2650  void setAnnotationProperties( const QDomNode& node ) override;
2651  AnnotationPrivate* getNewAnnotationPrivate() override;
2652 
2653  // data fields
2654  QString icon;
2655  Sound *sound;
2656 };
2657 
2658 void SoundAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
2659 {
2660  Okular::AnnotationPrivate::setAnnotationProperties(node);
2661 
2662  // loop through the whole children looking for a 'sound' element
2663  QDomNode subNode = node.firstChild();
2664  while( subNode.isElement() )
2665  {
2666  QDomElement e = subNode.toElement();
2667  subNode = subNode.nextSibling();
2668  if ( e.tagName() != QLatin1String("sound") )
2669  continue;
2670 
2671  // loading complete
2672  break;
2673  }
2674 }
2675 
2676 AnnotationPrivate* SoundAnnotationPrivate::getNewAnnotationPrivate()
2677 {
2678  return new SoundAnnotationPrivate();
2679 }
2680 
2682  : Annotation( *new SoundAnnotationPrivate() )
2683 {
2684 }
2685 
2687  : Annotation( *new SoundAnnotationPrivate(), description )
2688 {
2689 }
2690 
2692 {
2693 }
2694 
2695 void SoundAnnotation::store( QDomNode & node, QDomDocument & document ) const
2696 {
2697  // recurse to parent objects storing properties
2698  Annotation::store( node, document );
2699 
2700  // create [sound] element
2701  QDomElement soundElement = document.createElement( QStringLiteral("sound") );
2702  node.appendChild( soundElement );
2703 }
2704 
2706 {
2707  return ASound;
2708 }
2709 
2711 {
2712  Q_D( const SoundAnnotation );
2713  return d->icon;
2714 }
2715 
2717 {
2718  Q_D( SoundAnnotation );
2719  d->icon = iconName;
2720 }
2721 
2723 {
2724  Q_D( const SoundAnnotation );
2725  return d->sound;
2726 }
2727 
2729 {
2730  Q_D( SoundAnnotation );
2731  d->sound = s;
2732 }
2733 
2736 class Okular::MovieAnnotationPrivate : public Okular::AnnotationPrivate
2737 {
2738  public:
2739  MovieAnnotationPrivate()
2740  : AnnotationPrivate(), movie( nullptr )
2741  {
2742  }
2743  ~MovieAnnotationPrivate() override
2744  {
2745  delete movie;
2746  }
2747 
2748  void setAnnotationProperties( const QDomNode& node ) override;
2749  AnnotationPrivate* getNewAnnotationPrivate() override;
2750 
2751  // data fields
2752  Movie *movie;
2753 };
2754 
2755 void MovieAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
2756 {
2757  Okular::AnnotationPrivate::setAnnotationProperties(node);
2758 
2759  // loop through the whole children looking for a 'movie' element
2760  QDomNode subNode = node.firstChild();
2761  while( subNode.isElement() )
2762  {
2763  QDomElement e = subNode.toElement();
2764  subNode = subNode.nextSibling();
2765  if ( e.tagName() != QLatin1String("movie") )
2766  continue;
2767 
2768  // loading complete
2769  break;
2770  }
2771 }
2772 
2773 AnnotationPrivate* MovieAnnotationPrivate::getNewAnnotationPrivate()
2774 {
2775  return new MovieAnnotationPrivate();
2776 }
2777 
2779  : Annotation( *new MovieAnnotationPrivate() )
2780 {
2781 }
2782 
2784  : Annotation( *new MovieAnnotationPrivate(), description )
2785 {
2786 }
2787 
2789 {
2790 }
2791 
2792 void MovieAnnotation::store( QDomNode & node, QDomDocument & document ) const
2793 {
2794  // recurse to parent objects storing properties
2795  Annotation::store( node, document );
2796 
2797  // create [movie] element
2798  QDomElement movieElement = document.createElement( QStringLiteral("movie") );
2799  node.appendChild( movieElement );
2800 }
2801 
2803 {
2804  return AMovie;
2805 }
2806 
2808 {
2809  Q_D( const MovieAnnotation );
2810  return d->movie;
2811 }
2812 
2814 {
2815  Q_D( MovieAnnotation );
2816  d->movie = movie;
2817 }
2818 
2821 class Okular::ScreenAnnotationPrivate : public Okular::AnnotationPrivate
2822 {
2823  public:
2824  ScreenAnnotationPrivate();
2825  ~ScreenAnnotationPrivate() override;
2826 
2827  void setAnnotationProperties( const QDomNode& node ) override;
2828  AnnotationPrivate* getNewAnnotationPrivate() override;
2829 
2830  Okular::Action* m_action;
2832 };
2833 
2834 ScreenAnnotationPrivate::ScreenAnnotationPrivate()
2835  : m_action( nullptr )
2836 {
2837 }
2838 
2839 ScreenAnnotationPrivate::~ScreenAnnotationPrivate()
2840 {
2841  delete m_action;
2842  qDeleteAll( m_additionalActions );
2843 }
2844 
2845 void ScreenAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
2846 {
2847  Okular::AnnotationPrivate::setAnnotationProperties(node);
2848 
2849  // loop through the whole children looking for a 'screen' element
2850  QDomNode subNode = node.firstChild();
2851  while( subNode.isElement() )
2852  {
2853  QDomElement e = subNode.toElement();
2854  subNode = subNode.nextSibling();
2855  if ( e.tagName() != QLatin1String("screen") )
2856  continue;
2857 
2858  // loading complete
2859  break;
2860  }
2861 }
2862 
2863 AnnotationPrivate* ScreenAnnotationPrivate::getNewAnnotationPrivate()
2864 {
2865  return new ScreenAnnotationPrivate();
2866 }
2867 
2869  : Annotation( *new ScreenAnnotationPrivate() )
2870 {
2871 }
2872 
2874  : Annotation( *new ScreenAnnotationPrivate(), description )
2875 {
2876 }
2877 
2879 {
2880 }
2881 
2882 void ScreenAnnotation::store( QDomNode & node, QDomDocument & document ) const
2883 {
2884  // recurse to parent objects storing properties
2885  Annotation::store( node, document );
2886 
2887  // create [screen] element
2888  QDomElement movieElement = document.createElement( QStringLiteral("screen") );
2889  node.appendChild( movieElement );
2890 }
2891 
2893 {
2894  return AScreen;
2895 }
2896 
2898 {
2899  Q_D( ScreenAnnotation );
2900  if ( d->m_additionalActions.contains( type ) )
2901  delete d->m_additionalActions.value( type );
2902 
2903  d->m_additionalActions.insert( type, action );
2904 }
2905 
2907 {
2908  Q_D( const ScreenAnnotation );
2909  if ( !d->m_additionalActions.contains( type ) )
2910  return nullptr;
2911  else
2912  return d->m_additionalActions.value( type );
2913 }
2914 
2916 {
2917  Q_D( ScreenAnnotation );
2918 
2919  delete d->m_action;
2920  d->m_action = action;
2921 }
2922 
2924 {
2925  Q_D( const ScreenAnnotation );
2926  return d->m_action;
2927 }
2928 
2931 class Okular::WidgetAnnotationPrivate : public Okular::AnnotationPrivate
2932 {
2933  public:
2934  ~WidgetAnnotationPrivate() override;
2935  void setAnnotationProperties( const QDomNode& node ) override;
2936  AnnotationPrivate* getNewAnnotationPrivate() override;
2937 
2939 };
2940 
2941 WidgetAnnotationPrivate::~WidgetAnnotationPrivate()
2942 {
2943  qDeleteAll( m_additionalActions );
2944 }
2945 
2946 void WidgetAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
2947 {
2948  Okular::AnnotationPrivate::setAnnotationProperties(node);
2949 
2950  // loop through the whole children looking for a 'widget' element
2951  QDomNode subNode = node.firstChild();
2952  while( subNode.isElement() )
2953  {
2954  QDomElement e = subNode.toElement();
2955  subNode = subNode.nextSibling();
2956  if ( e.tagName() != QLatin1String("widget") )
2957  continue;
2958 
2959  // loading complete
2960  break;
2961  }
2962 }
2963 
2964 AnnotationPrivate* WidgetAnnotationPrivate::getNewAnnotationPrivate()
2965 {
2966  return new WidgetAnnotationPrivate();
2967 }
2968 
2970  : Annotation( *new WidgetAnnotationPrivate() )
2971 {
2972 }
2973 
2975  : Annotation( *new WidgetAnnotationPrivate, description )
2976 {
2977 }
2978 
2980 {
2981 }
2982 
2983 void WidgetAnnotation::store( QDomNode & node, QDomDocument & document ) const
2984 {
2985  // recurse to parent objects storing properties
2986  Annotation::store( node, document );
2987 
2988  // create [widget] element
2989  QDomElement movieElement = document.createElement( QStringLiteral("widget") );
2990  node.appendChild( movieElement );
2991 }
2992 
2994 {
2995  return AWidget;
2996 }
2997 
2999 {
3000  Q_D( WidgetAnnotation );
3001  if ( d->m_additionalActions.contains( type ) )
3002  delete d->m_additionalActions.value( type );
3003 
3004  d->m_additionalActions.insert( type, action );
3005 }
3006 
3008 {
3009  Q_D( const WidgetAnnotation );
3010  if ( !d->m_additionalActions.contains( type ) )
3011  return nullptr;
3012  else
3013  return d->m_additionalActions.value( type );
3014 }
3015 
3018 class Okular::RichMediaAnnotationPrivate : public Okular::AnnotationPrivate
3019 {
3020  public:
3021  RichMediaAnnotationPrivate();
3022  ~RichMediaAnnotationPrivate() override;
3023  void setAnnotationProperties( const QDomNode& node ) override;
3024  AnnotationPrivate* getNewAnnotationPrivate() override;
3025 
3026  // data fields
3027  Movie *movie;
3028  EmbeddedFile *embeddedFile;
3029 };
3030 
3031 RichMediaAnnotationPrivate::RichMediaAnnotationPrivate()
3032  : movie( nullptr ), embeddedFile( nullptr )
3033 {
3034 }
3035 
3036 RichMediaAnnotationPrivate::~RichMediaAnnotationPrivate()
3037 {
3038  delete movie;
3039  delete embeddedFile;
3040 }
3041 
3042 void RichMediaAnnotationPrivate::setAnnotationProperties( const QDomNode& node )
3043 {
3044  Okular::AnnotationPrivate::setAnnotationProperties(node);
3045 
3046  // loop through the whole children looking for a 'richMedia' element
3047  QDomNode subNode = node.firstChild();
3048  while( subNode.isElement() )
3049  {
3050  QDomElement e = subNode.toElement();
3051  subNode = subNode.nextSibling();
3052  if ( e.tagName() != QLatin1String("richMedia") )
3053  continue;
3054 
3055  // loading complete
3056  break;
3057  }
3058 }
3059 
3060 AnnotationPrivate* RichMediaAnnotationPrivate::getNewAnnotationPrivate()
3061 {
3062  return new RichMediaAnnotationPrivate();
3063 }
3064 
3066  : Annotation( *new RichMediaAnnotationPrivate() )
3067 {
3068 }
3069 
3071  : Annotation( *new RichMediaAnnotationPrivate, description )
3072 {
3073 }
3074 
3076 {
3077 }
3078 
3079 void RichMediaAnnotation::store( QDomNode & node, QDomDocument & document ) const
3080 {
3081  // recurse to parent objects storing properties
3082  Annotation::store( node, document );
3083 
3084  // create [richMedia] element
3085  QDomElement movieElement = document.createElement( QStringLiteral("richMedia") );
3086  node.appendChild( movieElement );
3087 }
3088 
3090 {
3091  return ARichMedia;
3092 }
3093 
3095 {
3096  Q_D( RichMediaAnnotation );
3097 
3098  delete d->movie;
3099  d->movie = movie;
3100 }
3101 
3103 {
3104  Q_D( const RichMediaAnnotation );
3105 
3106  return d->movie;
3107 }
3108 
3110 {
3111  Q_D( const RichMediaAnnotation );
3112 
3113  return d->embeddedFile;
3114 }
3115 
3117 {
3118  Q_D( RichMediaAnnotation );
3119 
3120  delete d->embeddedFile;
3121  d->embeddedFile = embeddedFile;
3122 }
int width() const
Returns the width of the window.
QDateTime modificationDate() const
Returns the last modification date of the annotation.
double opacity() const
Returns the opacity of the style.
A stamp annotation.
Definition: annotations.h:112
void store(QDomNode &parentNode, QDomDocument &document) const override
Stores the screen annotation as xml in document under the given parentNode.
NormalizedPoint is a helper class which stores the coordinates of a normalized point.
Definition: area.h:119
Movie * movie() const
Gets the movie object.
void setUniqueName(const QString &name)
Sets the unique name of the annotation.
QString author() const
Returns the author of the annotation.
static QDomElement findChildElement(const QDomNode &parentNode, const QString &name)
Returns the child element with the given name from the direct children of parentNode or a null elemen...
The Revision class contains all information about the revision of the annotation. ...
Definition: annotations.h:553
SoundAnnotation()
Creates a new sound annotation.
void setSpaces(int spaces)
Sets the spaces of the style.
void setAction(Action *action)
Sets the action that is executed when the annotation is triggered.
A movie annotation.
Definition: annotations.h:117
virtual ~AnnotationProxy()
Destroys the annotation proxy.
void setWidth(double width)
Sets the width of the style.
A rich media annotation.
Definition: annotations.h:120
void store(QDomNode &node, QDomDocument &document) const override
Stores the sound annotation as xml in document under the given parent node.
virtual SubType subType() const =0
Returns the sub type of the annotation.
A screen annotation.
Definition: annotations.h:118
QDomNode appendChild(const QDomNode &newChild)
void append(const T &value)
int marks() const
Returns the marks of the style.
void setWidth(int width)
Sets the width of the window.
QString attribute(const QString &name, const QString &defValue) const const
QDateTime creationDate() const
Returns the creation date of the annotation.
QString data() const const
QColor color() const
Returns the color of the style.
QLinkedList::iterator begin()
QVariant nativeId() const
Returns the "native" id of the annotation.
bool hasNext() const const
Is being moved (mouse drag and drop). If ExternallyDrawn, the generator must not draw it...
Definition: annotations.h:138
bool isElement() const const
WindingFill
A textual annotation.
Definition: annotations.h:108
void setLineEffect(LineEffect effect)
Sets the line effect of the style.
~MovieAnnotation() override
Destroys the movie annotation.
void setFlags(int flags)
Sets the flags of the window.
void setDisposeDataFunction(DisposeDataFunction func)
Sets a function to be called when the annotation is destroyed.
void setModificationDate(const QDateTime &date)
Sets the last modification date of the annotation.
A NormalizedRect is a rectangle which can be defined by two NormalizedPoints.
Definition: area.h:192
WidgetAnnotation()
Creates a new widget annotation.
int height() const
Returns the height of the window.
QDomCDATASection toCDATASection() const const
Style & style()
Returns a reference to the style object of the annotation.
void setCapEnd(bool value)
Sets whether a cap should be used at the end.
double y
The normalized y coordinate.
Definition: area.h:174
QString summary() const
Returns the summary of the window.
A line annotation.
Definition: annotations.h:109
Action * additionalAction(AdditionalActionType type) const
Returns the additional action of the given type or 0 if no action has been defined.
global.h
Definition: action.h:19
An embedded file into the document.
Definition: document.h:1400
void setOpacity(double opacity)
Sets the opacity of the style.
double toDouble(bool *ok) const const
void setYCorners(double yCorners)
Sets the y-corners of the style.
void setSoundIconName(const QString &iconName)
Sets the iconName of the icon for the sound annotation.
bool capEnd() const
Returns whether a cap should be used at the end.
void setContents(const QString &contents)
Sets the contents of the annotation.
QLinkedList::iterator end()
Is being resized (mouse drag and drop). If ExternallyDrawn, the generator must not draw it...
Definition: annotations.h:139
Revision()
Creates a new revision.
void setMovie(Movie *movie)
Sets the new movie object.
void setFlags(int flags)
Sets the flags of the annotation.
The Window class contains all information about the popup window of the annotation that is used to ed...
Definition: annotations.h:458
QDomNode nextSibling() const const
RevisionType type() const
Returns the type of the revision.
RevisionType
Describes the type of revision information.
Definition: annotations.h:176
SubType
Describes the type of annotation as defined in PDF standard.
Definition: annotations.h:106
QDomElement toElement() const const
int count(const T &value) const const
static QRect annotationGeometry(const Annotation *annotation, double scaleX, double scaleY)
Returns the geometry of the given annotation scaled by scaleX and scaleY.
void setCapStart(bool value)
Sets whether a cap should be used at the start.
void setAdditionalAction(AdditionalActionType type, Action *action)
Sets the additional action of the given type.
Action * action() const
Returns the action that is executed when the annotation is triggered or 0 if not action has been defi...
void translate(const NormalizedPoint &coord)
Move the annotation by the specified coordinates.
QString number(int n, int base)
QFont font()
Sound annotation.
Definition: annotations.h:1483
void setNativeId(const QVariant &id)
Sets the "native" id of the annotation.
Action * additionalAction(AdditionalActionType type) const
Returns the additional action of the given type or 0 if no action has been defined.
QString soundIconName() const
Gets the name of the icon.
int flags() const
Returns the flags of the window.
Sound * sound() const
Gets the sound object.
A geometrical annotation.
Definition: annotations.h:110
bool capStart() const
Returns whether a cap should be used at the start.
SubType subType() const override
Returns the sub type of the sound annotation.
bool hasAttribute(const QString &name) const const
void setPoint(const NormalizedPoint &point, int index)
Sets the normalized point at index.
void transform(const QTransform &matrix)
Transforms the quad coordinates with the transformation defined by matrix.
double yCorners() const
Returns the y-corners of the style.
void setXCorners(double xCorners)
Sets the x-corners of the style.
QDomNode getAnnotationPropertiesDomNode() const
Retrieve the QDomNode representing this annotation&#39;s properties.
void setEffectIntensity(double intensity)
Sets the effect intensity of the style.
void setAuthor(const QString &author)
Sets the author of the annotation.
~SoundAnnotation() override
Destroys the sound annotation.
void setAttribute(const QString &name, const QString &value)
RichMedia annotation.
Definition: annotations.h:1713
RichMediaAnnotation()
Creates a new rich media annotation.
int toInt(bool *ok, int base) const const
Is stored external.
Definition: annotations.h:136
int flags() const
Returns the flags of the annotation.
void setTopLeft(const NormalizedPoint &point)
Sets the top-left point of the window.
A widget annotation.
Definition: annotations.h:119
void setLineStyle(LineStyle style)
Sets the line style of the style.
static void storeAnnotation(const Annotation *annotation, QDomElement &element, QDomDocument &document)
Saves the annotation as a child of element taking care of saving all revisions if it has any...
Belongs to a reply.
Definition: annotations.h:168
SubType subType() const override
Returns the sub type of the screen annotation.
SubType subType() const override
Returns the sub type of the rich media annotation.
RevisionScope
Describes the scope of revision information.
Definition: annotations.h:166
void setAnnotation(Annotation *annotation)
Sets the annotation the revision belongs to.
Contains information about a sound object.
Definition: sound.h:26
An ink annotation.
Definition: annotations.h:113
bool containsPoint(const QPointF &point, Qt::FillRule fillRule) const const
A highlight annotation.
Definition: annotations.h:111
SubType subType() const override
Returns the sub type of the movie annotation.
void setColor(const QColor &color)
Sets the color of the style.
double xCorners() const
Returns the x-corners of the style.
int distance(const GeoCoordinates &coord1, const GeoCoordinates &coord2)
void setScope(RevisionScope scope)
Sets the scope of the revision.
double distanceSqr(double x, double y, double xScale, double yScale) const
Returns squared distance to normalized point (x, y) on a reference area of size xScale x yScale...
Definition: area.cpp:49
QRect geometry(int xScale, int yScale) const
Returns the rectangle mapped to a reference area of xScale x yScale.
Definition: area.cpp:230
void adjust(const NormalizedPoint &deltaCoord1, const NormalizedPoint &deltaCoord2)
Adjust the annotation by the specified coordinates.
double width() const
Returns the width of the style.
Is drawn externally (by the generator which provided it)
Definition: annotations.h:137
~Revision()
Destroys the revision.
~Style()
Destroys the style.
QDateTime fromString(const QString &string, Qt::DateFormat format)
QLinkedList::const_iterator constBegin() const const
bool hasNext() const const
AdditionalActionType
Describes the type of additional actions.
Definition: annotations.h:192
Encapsulates data that describes an action.
Definition: action.h:43
bool isNull() const const
void(* DisposeDataFunction)(const Okular::Annotation *)
A function to be called when the annotation is destroyed.
Definition: annotations.h:212
QLinkedList::const_iterator constEnd() const const
void setType(RevisionType type)
Sets the type of the revision.
void setEmbeddedFile(EmbeddedFile *embeddedFile)
Sets the embeddedFile representing the embedded file.
Window & window()
Returns a reference to the window object of the annotation.
static Annotation * createAnnotation(const QDomElement &element)
Restore an annotation (with revisions if needed) from the dom element.
Definition: annotations.cpp:90
Movie * movie() const
Gets the movie object.
NormalizedPoint transformedPoint(int index) const
Returns the transformed (e.g.
NormalizedRect transformedBoundingRectangle() const
Returns the transformed bounding rectangle of the annotation.
double x
The normalized x coordinate.
Definition: area.h:169
QDomNode firstChild() const const
A caret annotation.
Definition: annotations.h:114
int spaces() const
Returns the spaces of the style.
Movie annotation.
Definition: annotations.h:1543
~RichMediaAnnotation() override
Destroys the rich media annotation.
ScreenAnnotation()
Creates a new screen annotation.
void setMarks(int marks)
Sets the marks of the style.
bool canBeResized() const
Returns whether the annotation can be resized.
~WidgetAnnotation() override
Destroys the widget annotation.
void setCreationDate(const QDateTime &date)
Sets the creation date of the annotation.
void setAdditionalAction(AdditionalActionType type, Action *action)
Sets the additional action of the given type.
Annotation struct holds properties shared by all annotations.
Definition: annotations.h:91
void setHeight(int height)
Sets the height of the window.
double effectIntensity() const
Returns the effect intensity of the style.
void setSound(Sound *s)
Sets the s representing the sound of the file attachment annotation.
EmbeddedFile * embeddedFile() const
Gets the embedded file object.
LineStyle
Describes possible line styles for.
Definition: annotations.h:145
void setSummary(const QString &summary)
Sets the summary of the window.
QLinkedList< Revision > & revisions()
Returns a reference to the revision list of the annotation.
~Window()
Destroys the window.
~ScreenAnnotation() override
Destroys the screen annotation.
virtual void store(QDomNode &node, QDomDocument &document) const
Stores the annotation as xml in document under the given parent node.
The Style class contains all information about style of the annotation.
Definition: annotations.h:323
Style()
Creates a new style.
QString uniqueName() const
Returns the unique name of the annotation.
virtual ~Annotation()
Destroys the annotation.
LineEffect lineEffect() const
Returns the line effect of the style.
QString title() const
Returns the title of the window.
NormalizedPoint point(int index) const
Returns the normalized point at index.
QString tagName() const const
QString contents() const
Returns the contents of the annotation.
LineStyle lineStyle() const
Returns the line style of the style.
void store(QDomNode &parentNode, QDomDocument &document) const override
Stores the movie annotation as xml in document under the given parentNode.
QDomElement createElement(const QString &tagName)
MovieAnnotation()
Creates a new movie annotation.
void store(QDomNode &parentNode, QDomDocument &document) const override
Stores the widget annotation as xml in document under the given parentNode.
void setFeather(double width)
Sets the width of the drawing feather.
A sound annotation.
Definition: annotations.h:116
void setTitle(const QString &title)
Sets the title of the window.
Screen annotation.
Definition: annotations.h:1589
Annotation * annotation() const
Returns the annotation the revision belongs to.
bool canBeMoved() const
Returns whether the annotation can be moved.
void setMovie(Movie *movie)
Sets the new movie object.
LineEffect
Describes possible line effects for.
Definition: annotations.h:157
double feather() const
Returns the width of the drawing feather.
NormalizedRect boundingRectangle() const
Returns the bounding rectangle of the annotation.
RevisionScope scope() const
Returns the scope of the revision.
QRect united(const QRect &rectangle) const const
Describes a highlight quad of a text markup annotation.
Definition: annotations.h:1174
QList::iterator begin()
void setBoundingRectangle(const NormalizedRect &rectangle)
Sets the bounding rectangle of the annotation.
Widget annotation.
Definition: annotations.h:1658
SubType subType() const override
Returns the sub type of the widget annotation.
Contains information about a movie object.
Definition: movie.h:28
Window()
Creates a new window.
void append(const T &value)
void store(QDomNode &parentNode, QDomDocument &document) const override
Stores the rich media annotation as xml in document under the given parentNode.
bool openDialogAfterCreation() const
Returns whether the annotation dialog should be open after creation of the annotation or not...
NormalizedPoint topLeft() const
Returns the top-left point of the window.
void setAnnotationProperties(const QDomNode &node)
Sets annotations internal properties according to the contents of node.
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Jul 10 2020 22:34:38 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.