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

KDE's Doxygen guidelines are available online.