1 /* poppler-annotation.cc: qt interface to poppler
2  * Copyright (C) 2006, 2009 Albert Astals Cid <aacid@kde.org>
3  * Copyright (C) 2006, 2008, 2010 Pino Toscano <pino@kde.org>
4  * Adapting code from
5  *   Copyright (C) 2004 by Enrico Ros <eros.kde@email.it>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 // qt/kde includes
23 #include <QtXml/QDomElement>
24 #include <QtGui/QColor>
25 
26 // local includes
27 #include "poppler-annotation.h"
28 #include "poppler-link.h"
29 #include "poppler-qt4.h"
30 #include "poppler-annotation-private.h"
31 
32 // poppler includes
33 #include <Page.h>
34 #include <Annot.h>
35 
36 namespace Poppler {
37 
38 //BEGIN AnnotationUtils implementation
createAnnotation(const QDomElement & annElement)39 Annotation * AnnotationUtils::createAnnotation( const QDomElement & annElement )
40 {
41     // safety check on annotation element
42     if ( !annElement.hasAttribute( "type" ) )
43         return 0;
44 
45     // build annotation of given type
46     Annotation * annotation = 0;
47     int typeNumber = annElement.attribute( "type" ).toInt();
48     switch ( typeNumber )
49     {
50         case Annotation::AText:
51             annotation = new TextAnnotation( annElement );
52             break;
53         case Annotation::ALine:
54             annotation = new LineAnnotation( annElement );
55             break;
56         case Annotation::AGeom:
57             annotation = new GeomAnnotation( annElement );
58             break;
59         case Annotation::AHighlight:
60             annotation = new HighlightAnnotation( annElement );
61             break;
62         case Annotation::AStamp:
63             annotation = new StampAnnotation( annElement );
64             break;
65         case Annotation::AInk:
66             annotation = new InkAnnotation( annElement );
67             break;
68         case Annotation::ACaret:
69             annotation = new CaretAnnotation( annElement );
70             break;
71     }
72 
73     // return created annotation
74     return annotation;
75 }
76 
storeAnnotation(const Annotation * ann,QDomElement & annElement,QDomDocument & document)77 void AnnotationUtils::storeAnnotation( const Annotation * ann, QDomElement & annElement,
78     QDomDocument & document )
79 {
80     // save annotation's type as element's attribute
81     annElement.setAttribute( "type", (uint)ann->subType() );
82 
83     // append all annotation data as children of this node
84     ann->store( annElement, document );
85 }
86 
findChildElement(const QDomNode & parentNode,const QString & name)87 QDomElement AnnotationUtils::findChildElement( const QDomNode & parentNode,
88     const QString & name )
89 {
90     // loop through the whole children and return a 'name' named element
91     QDomNode subNode = parentNode.firstChild();
92     while( subNode.isElement() )
93     {
94         QDomElement element = subNode.toElement();
95         if ( element.tagName() == name )
96             return element;
97         subNode = subNode.nextSibling();
98     }
99     // if the name can't be found, return a dummy null element
100     return QDomElement();
101 }
102 //END AnnotationUtils implementation
103 
104 
105 //BEGIN Annotation implementation
AnnotationPrivate()106 AnnotationPrivate::AnnotationPrivate()
107     : flags( 0 )
108 {
109 }
110 
~AnnotationPrivate()111 AnnotationPrivate::~AnnotationPrivate()
112 {
113 }
114 
115 
Style()116 Annotation::Style::Style()
117     : opacity( 1.0 ), width( 1.0 ), style( Solid ), xCorners( 0.0 ),
118     yCorners( 0.0 ), marks( 3 ), spaces( 0 ), effect( NoEffect ),
119     effectIntensity( 1.0 ) {}
120 
Window()121 Annotation::Window::Window()
122     : flags( -1 ), width( 0 ), height( 0 ) {}
123 
Revision()124 Annotation::Revision::Revision()
125     : annotation( 0 ), scope( Reply ), type( None ) {}
126 
Annotation(AnnotationPrivate & dd)127 Annotation::Annotation( AnnotationPrivate &dd )
128     : d_ptr( &dd )
129 {
130 }
131 
~Annotation()132 Annotation::~Annotation()
133 {
134     Q_D( Annotation );
135     // delete all children revisions
136     QLinkedList< Annotation::Revision >::iterator it = d->revisions.begin(), end = d->revisions.end();
137     for ( ; it != end; ++it )
138         delete (*it).annotation;
139 
140     delete d_ptr;
141 }
142 
Annotation(AnnotationPrivate & dd,const QDomNode & annNode)143 Annotation::Annotation( AnnotationPrivate &dd, const QDomNode &annNode )
144     : d_ptr( &dd )
145 {
146     Q_D( Annotation );
147     // get the [base] element of the annotation node
148     QDomElement e = AnnotationUtils::findChildElement( annNode, "base" );
149     if ( e.isNull() )
150         return;
151 
152     // parse -contents- attributes
153     if ( e.hasAttribute( "author" ) )
154         d->author = e.attribute( "author" );
155     if ( e.hasAttribute( "contents" ) )
156         d->contents = e.attribute( "contents" );
157     if ( e.hasAttribute( "uniqueName" ) )
158         d->uniqueName = e.attribute( "uniqueName" );
159     if ( e.hasAttribute( "modifyDate" ) )
160         d->modDate = QDateTime::fromString( e.attribute( "modifyDate" ) );
161     if ( e.hasAttribute( "creationDate" ) )
162         d->creationDate = QDateTime::fromString( e.attribute( "creationDate" ) );
163 
164     // parse -other- attributes
165     if ( e.hasAttribute( "flags" ) )
166         d->flags = e.attribute( "flags" ).toInt();
167     if ( e.hasAttribute( "color" ) )
168         style.color = QColor( e.attribute( "color" ) );
169     if ( e.hasAttribute( "opacity" ) )
170         style.opacity = e.attribute( "opacity" ).toDouble();
171 
172     // parse -the-subnodes- (describing Style, Window, Revision(s) structures)
173     // Note: all subnodes if present must be 'attributes complete'
174     QDomNode eSubNode = e.firstChild();
175     while ( eSubNode.isElement() )
176     {
177         QDomElement ee = eSubNode.toElement();
178         eSubNode = eSubNode.nextSibling();
179 
180         // parse boundary
181         if ( ee.tagName() == "boundary" )
182         {
183             d->boundary.setLeft(ee.attribute( "l" ).toDouble());
184             d->boundary.setTop(ee.attribute( "t" ).toDouble());
185             d->boundary.setRight(ee.attribute( "r" ).toDouble());
186             d->boundary.setBottom(ee.attribute( "b" ).toDouble());
187         }
188         // parse penStyle if not default
189         else if ( ee.tagName() == "penStyle" )
190         {
191             style.width = ee.attribute( "width" ).toDouble();
192             style.style = (LineStyle)ee.attribute( "style" ).toInt();
193             style.xCorners = ee.attribute( "xcr" ).toDouble();
194             style.yCorners = ee.attribute( "ycr" ).toDouble();
195             style.marks = ee.attribute( "marks" ).toInt();
196             style.spaces = ee.attribute( "spaces" ).toInt();
197         }
198         // parse effectStyle if not default
199         else if ( ee.tagName() == "penEffect" )
200         {
201             style.effect = (LineEffect)ee.attribute( "effect" ).toInt();
202             style.effectIntensity = ee.attribute( "intensity" ).toDouble();
203         }
204         // parse window if present
205         else if ( ee.tagName() == "window" )
206         {
207             window.flags = ee.attribute( "flags" ).toInt();
208             window.topLeft.setX(ee.attribute( "top" ).toDouble());
209             window.topLeft.setY(ee.attribute( "left" ).toDouble());
210             window.width = ee.attribute( "width" ).toInt();
211             window.height = ee.attribute( "height" ).toInt();
212             window.title = ee.attribute( "title" );
213             window.summary = ee.attribute( "summary" );
214             // parse window subnodes
215             QDomNode winNode = ee.firstChild();
216             for ( ; winNode.isElement(); winNode = winNode.nextSibling() )
217             {
218                 QDomElement winElement = winNode.toElement();
219                 if ( winElement.tagName() == "text" )
220                     window.text = winElement.firstChild().toCDATASection().data();
221             }
222         }
223     }
224 
225     // get the [revisions] element of the annotation node
226     QDomNode revNode = annNode.firstChild();
227     for ( ; revNode.isElement(); revNode = revNode.nextSibling() )
228     {
229         QDomElement revElement = revNode.toElement();
230         if ( revElement.tagName() != "revision" )
231             continue;
232 
233         // compile the Revision structure crating annotation
234         Revision rev;
235         rev.scope = (RevScope)revElement.attribute( "revScope" ).toInt();
236         rev.type = (RevType)revElement.attribute( "revType" ).toInt();
237         rev.annotation = AnnotationUtils::createAnnotation( revElement );
238 
239         // if annotation is valid, add revision to internal list
240         if ( rev.annotation )
241             d->revisions.append( rev );
242     }
243 }
244 
store(QDomNode & annNode,QDomDocument & document) const245 void Annotation::store( QDomNode & annNode, QDomDocument & document ) const
246 {
247     Q_D( const Annotation );
248     // create [base] element of the annotation node
249     QDomElement e = document.createElement( "base" );
250     annNode.appendChild( e );
251 
252     // store -contents- attributes
253     if ( !d->author.isEmpty() )
254         e.setAttribute( "author", d->author );
255     if ( !d->contents.isEmpty() )
256         e.setAttribute( "contents", d->contents );
257     if ( !d->uniqueName.isEmpty() )
258         e.setAttribute( "uniqueName", d->uniqueName );
259     if ( d->modDate.isValid() )
260         e.setAttribute( "modifyDate", d->modDate.toString() );
261     if ( d->creationDate.isValid() )
262         e.setAttribute( "creationDate", d->creationDate.toString() );
263 
264     // store -other- attributes
265     if ( d->flags )
266         e.setAttribute( "flags", d->flags );
267     if ( style.color.isValid() && style.color != Qt::black )
268         e.setAttribute( "color", style.color.name() );
269     if ( style.opacity != 1.0 )
270         e.setAttribute( "opacity", QString::number( style.opacity ) );
271 
272     // Sub-Node-1 - boundary
273     QDomElement bE = document.createElement( "boundary" );
274     e.appendChild( bE );
275     bE.setAttribute( "l", QString::number( (double)d->boundary.left() ) );
276     bE.setAttribute( "t", QString::number( (double)d->boundary.top() ) );
277     bE.setAttribute( "r", QString::number( (double)d->boundary.right() ) );
278     bE.setAttribute( "b", QString::number( (double)d->boundary.bottom() ) );
279 
280     // Sub-Node-2 - penStyle
281     if ( style.width != 1 || style.style != Solid || style.xCorners != 0 ||
282          style.yCorners != 0.0 || style.marks != 3 || style.spaces != 0 )
283     {
284         QDomElement psE = document.createElement( "penStyle" );
285         e.appendChild( psE );
286         psE.setAttribute( "width", QString::number( style.width ) );
287         psE.setAttribute( "style", (int)style.style );
288         psE.setAttribute( "xcr", QString::number( style.xCorners ) );
289         psE.setAttribute( "ycr", QString::number( style.yCorners ) );
290         psE.setAttribute( "marks", style.marks );
291         psE.setAttribute( "spaces", style.spaces );
292     }
293 
294     // Sub-Node-3 - penEffect
295     if ( style.effect != NoEffect || style.effectIntensity != 1.0 )
296     {
297         QDomElement peE = document.createElement( "penEffect" );
298         e.appendChild( peE );
299         peE.setAttribute( "effect", (int)style.effect );
300         peE.setAttribute( "intensity", QString::number( style.effectIntensity ) );
301     }
302 
303     // Sub-Node-4 - window
304     if ( window.flags != -1 || !window.title.isEmpty() ||
305          !window.summary.isEmpty() || !window.text.isEmpty() )
306     {
307         QDomElement wE = document.createElement( "window" );
308         e.appendChild( wE );
309         wE.setAttribute( "flags", window.flags );
310         wE.setAttribute( "top", QString::number( window.topLeft.x() ) );
311         wE.setAttribute( "left", QString::number( window.topLeft.y() ) );
312         wE.setAttribute( "width", window.width );
313         wE.setAttribute( "height", window.height );
314         wE.setAttribute( "title", window.title );
315         wE.setAttribute( "summary", window.summary );
316         // store window.text as a subnode, because we need escaped data
317         if ( !window.text.isEmpty() )
318         {
319             QDomElement escapedText = document.createElement( "text" );
320             wE.appendChild( escapedText );
321             QDomCDATASection textCData = document.createCDATASection( window.text );
322             escapedText.appendChild( textCData );
323         }
324     }
325 
326     // create [revision] element of the annotation node (if any)
327     if ( d->revisions.isEmpty() )
328         return;
329 
330     // add all revisions as children of revisions element
331     QLinkedList< Revision >::const_iterator it = d->revisions.begin(), end = d->revisions.end();
332     for ( ; it != end; ++it )
333     {
334         // create revision element
335         const Revision & revision = *it;
336         QDomElement r = document.createElement( "revision" );
337         annNode.appendChild( r );
338         // set element attributes
339         r.setAttribute( "revScope", (int)revision.scope );
340         r.setAttribute( "revType", (int)revision.type );
341         // use revision as the annotation element, so fill it up
342         AnnotationUtils::storeAnnotation( revision.annotation, r, document );
343     }
344 }
345 
author() const346 QString Annotation::author() const
347 {
348     Q_D( const Annotation );
349     return d->author;
350 }
351 
setAuthor(const QString & author)352 void Annotation::setAuthor( const QString &author )
353 {
354     Q_D( Annotation );
355     d->author = author;
356 }
357 
contents() const358 QString Annotation::contents() const
359 {
360     Q_D( const Annotation );
361     return d->contents;
362 }
363 
setContents(const QString & contents)364 void Annotation::setContents( const QString &contents )
365 {
366     Q_D( Annotation );
367     d->contents = contents;
368 }
369 
uniqueName() const370 QString Annotation::uniqueName() const
371 {
372     Q_D( const Annotation );
373     return d->uniqueName;
374 }
375 
setUniqueName(const QString & uniqueName)376 void Annotation::setUniqueName( const QString &uniqueName )
377 {
378     Q_D( Annotation );
379     d->uniqueName = uniqueName;
380 }
381 
modificationDate() const382 QDateTime Annotation::modificationDate() const
383 {
384     Q_D( const Annotation );
385     return d->modDate;
386 }
387 
setModificationDate(const QDateTime & date)388 void Annotation::setModificationDate( const QDateTime &date )
389 {
390     Q_D( Annotation );
391     d->modDate = date;
392 }
393 
creationDate() const394 QDateTime Annotation::creationDate() const
395 {
396     Q_D( const Annotation );
397     return d->creationDate;
398 }
399 
setCreationDate(const QDateTime & date)400 void Annotation::setCreationDate( const QDateTime &date )
401 {
402     Q_D( Annotation );
403     d->creationDate = date;
404 }
405 
flags() const406 int Annotation::flags() const
407 {
408     Q_D( const Annotation );
409     return d->flags;
410 }
411 
setFlags(int flags)412 void Annotation::setFlags( int flags )
413 {
414     Q_D( Annotation );
415     d->flags = flags;
416 }
417 
boundary() const418 QRectF Annotation::boundary() const
419 {
420     Q_D( const Annotation );
421     return d->boundary;
422 }
423 
setBoundary(const QRectF & boundary)424 void Annotation::setBoundary( const QRectF &boundary )
425 {
426     Q_D( Annotation );
427     d->boundary = boundary;
428 }
429 
revisions()430 QLinkedList< Annotation::Revision >& Annotation::revisions()
431 {
432     Q_D( Annotation );
433     return d->revisions;
434 }
435 
revisions() const436 const QLinkedList< Annotation::Revision >& Annotation::revisions() const
437 {
438     Q_D( const Annotation );
439     return d->revisions;
440 }
441 
442 //END AnnotationUtils implementation
443 
444 
445 /** TextAnnotation [Annotation] */
446 class TextAnnotationPrivate : public AnnotationPrivate
447 {
448     public:
449         TextAnnotationPrivate();
450 
451         // data fields
452         TextAnnotation::TextType textType;
453         QString textIcon;
454         QFont textFont;
455         int inplaceAlign; // 0:left, 1:center, 2:right
456         QString inplaceText;  // overrides contents
457         QPointF inplaceCallout[3];
458         TextAnnotation::InplaceIntent inplaceIntent;
459 };
460 
TextAnnotationPrivate()461 TextAnnotationPrivate::TextAnnotationPrivate()
462     : AnnotationPrivate(), textType( TextAnnotation::Linked ),
463     textIcon( "Note" ), inplaceAlign( 0 ),
464     inplaceIntent( TextAnnotation::Unknown )
465 {
466 }
467 
TextAnnotation()468 TextAnnotation::TextAnnotation()
469     : Annotation( *new TextAnnotationPrivate() )
470 {}
471 
TextAnnotation(const QDomNode & node)472 TextAnnotation::TextAnnotation( const QDomNode & node )
473     : Annotation( *new TextAnnotationPrivate, node )
474 {
475     Q_D( TextAnnotation );
476 
477     // loop through the whole children looking for a 'text' element
478     QDomNode subNode = node.firstChild();
479     while( subNode.isElement() )
480     {
481         QDomElement e = subNode.toElement();
482         subNode = subNode.nextSibling();
483         if ( e.tagName() != "text" )
484             continue;
485 
486         // parse the attributes
487         if ( e.hasAttribute( "type" ) )
488             d->textType = (TextAnnotation::TextType)e.attribute( "type" ).toInt();
489         if ( e.hasAttribute( "icon" ) )
490             d->textIcon = e.attribute( "icon" );
491         if ( e.hasAttribute( "font" ) )
492             d->textFont.fromString( e.attribute( "font" ) );
493         if ( e.hasAttribute( "align" ) )
494             d->inplaceAlign = e.attribute( "align" ).toInt();
495         if ( e.hasAttribute( "intent" ) )
496             d->inplaceIntent = (TextAnnotation::InplaceIntent)e.attribute( "intent" ).toInt();
497 
498         // parse the subnodes
499         QDomNode eSubNode = e.firstChild();
500         while ( eSubNode.isElement() )
501         {
502             QDomElement ee = eSubNode.toElement();
503             eSubNode = eSubNode.nextSibling();
504 
505             if ( ee.tagName() == "escapedText" )
506             {
507                 d->inplaceText = ee.firstChild().toCDATASection().data();
508             }
509             else if ( ee.tagName() == "callout" )
510             {
511                 d->inplaceCallout[0].setX(ee.attribute( "ax" ).toDouble());
512                 d->inplaceCallout[0].setY(ee.attribute( "ay" ).toDouble());
513                 d->inplaceCallout[1].setX(ee.attribute( "bx" ).toDouble());
514                 d->inplaceCallout[1].setY(ee.attribute( "by" ).toDouble());
515                 d->inplaceCallout[2].setX(ee.attribute( "cx" ).toDouble());
516                 d->inplaceCallout[2].setY(ee.attribute( "cy" ).toDouble());
517             }
518         }
519 
520         // loading complete
521         break;
522     }
523 }
524 
~TextAnnotation()525 TextAnnotation::~TextAnnotation()
526 {
527 }
528 
store(QDomNode & node,QDomDocument & document) const529 void TextAnnotation::store( QDomNode & node, QDomDocument & document ) const
530 {
531     Q_D( const TextAnnotation );
532 
533     // recurse to parent objects storing properties
534     Annotation::store( node, document );
535 
536     // create [text] element
537     QDomElement textElement = document.createElement( "text" );
538     node.appendChild( textElement );
539 
540     // store the optional attributes
541     if ( d->textType != Linked )
542         textElement.setAttribute( "type", (int)d->textType );
543     if ( d->textIcon != "Comment" )
544         textElement.setAttribute( "icon", d->textIcon );
545     if ( d->inplaceAlign )
546         textElement.setAttribute( "align", d->inplaceAlign );
547     if ( d->inplaceIntent != Unknown )
548         textElement.setAttribute( "intent", (int)d->inplaceIntent );
549 
550     textElement.setAttribute( "font", d->textFont.toString() );
551 
552     // Sub-Node-1 - escapedText
553     if ( !d->inplaceText.isEmpty() )
554     {
555         QDomElement escapedText = document.createElement( "escapedText" );
556         textElement.appendChild( escapedText );
557         QDomCDATASection textCData = document.createCDATASection( d->inplaceText );
558         escapedText.appendChild( textCData );
559     }
560 
561     // Sub-Node-2 - callout
562     if ( d->inplaceCallout[0].x() != 0.0 )
563     {
564         QDomElement calloutElement = document.createElement( "callout" );
565         textElement.appendChild( calloutElement );
566         calloutElement.setAttribute( "ax", QString::number( d->inplaceCallout[0].x() ) );
567         calloutElement.setAttribute( "ay", QString::number( d->inplaceCallout[0].y() ) );
568         calloutElement.setAttribute( "bx", QString::number( d->inplaceCallout[1].x() ) );
569         calloutElement.setAttribute( "by", QString::number( d->inplaceCallout[1].y() ) );
570         calloutElement.setAttribute( "cx", QString::number( d->inplaceCallout[2].x() ) );
571         calloutElement.setAttribute( "cy", QString::number( d->inplaceCallout[2].y() ) );
572     }
573 }
574 
subType() const575 Annotation::SubType TextAnnotation::subType() const
576 {
577     return AText;
578 }
579 
textType() const580 TextAnnotation::TextType TextAnnotation::textType() const
581 {
582     Q_D( const TextAnnotation );
583     return d->textType;
584 }
585 
setTextType(TextAnnotation::TextType type)586 void TextAnnotation::setTextType( TextAnnotation::TextType type )
587 {
588     Q_D( TextAnnotation );
589     d->textType = type;
590 }
591 
textIcon() const592 QString TextAnnotation::textIcon() const
593 {
594     Q_D( const TextAnnotation );
595     return d->textIcon;
596 }
597 
setTextIcon(const QString & icon)598 void TextAnnotation::setTextIcon( const QString &icon )
599 {
600     Q_D( TextAnnotation );
601     d->textIcon = icon;
602 }
603 
textFont() const604 QFont TextAnnotation::textFont() const
605 {
606     Q_D( const TextAnnotation );
607     return d->textFont;
608 }
609 
setTextFont(const QFont & font)610 void TextAnnotation::setTextFont( const QFont &font )
611 {
612     Q_D( TextAnnotation );
613     d->textFont = font;
614 }
615 
inplaceAlign() const616 int TextAnnotation::inplaceAlign() const
617 {
618     Q_D( const TextAnnotation );
619     return d->inplaceAlign;
620 }
621 
setInplaceAlign(int align)622 void TextAnnotation::setInplaceAlign( int align )
623 {
624     Q_D( TextAnnotation );
625     d->inplaceAlign = align;
626 }
627 
inplaceText() const628 QString TextAnnotation::inplaceText() const
629 {
630     Q_D( const TextAnnotation );
631     return d->inplaceText;
632 }
633 
setInplaceText(const QString & text)634 void TextAnnotation::setInplaceText( const QString &text )
635 {
636     Q_D( TextAnnotation );
637     d->inplaceText = text;
638 }
639 
calloutPoint(int id) const640 QPointF TextAnnotation::calloutPoint( int id ) const
641 {
642     if ( id < 0 || id >= 3 )
643         return QPointF();
644 
645     Q_D( const TextAnnotation );
646     return d->inplaceCallout[id];
647 }
648 
setCalloutPoint(int id,const QPointF & point)649 void TextAnnotation::setCalloutPoint( int id, const QPointF &point )
650 {
651     if ( id < 0 || id >= 3 )
652         return;
653 
654     Q_D( TextAnnotation );
655     d->inplaceCallout[id] = point;
656 }
657 
inplaceIntent() const658 TextAnnotation::InplaceIntent TextAnnotation::inplaceIntent() const
659 {
660     Q_D( const TextAnnotation );
661     return d->inplaceIntent;
662 }
663 
setInplaceIntent(TextAnnotation::InplaceIntent intent)664 void TextAnnotation::setInplaceIntent( TextAnnotation::InplaceIntent intent )
665 {
666     Q_D( TextAnnotation );
667     d->inplaceIntent = intent;
668 }
669 
670 
671 /** LineAnnotation [Annotation] */
672 class LineAnnotationPrivate : public AnnotationPrivate
673 {
674     public:
675         LineAnnotationPrivate();
676 
677         // data fields (note uses border for rendering style)
678         QLinkedList<QPointF> linePoints;
679         LineAnnotation::TermStyle lineStartStyle;
680         LineAnnotation::TermStyle lineEndStyle;
681         bool lineClosed : 1;  // (if true draw close shape)
682         bool lineShowCaption : 1;
683         QColor lineInnerColor;
684         double lineLeadingFwdPt;
685         double lineLeadingBackPt;
686         LineAnnotation::LineIntent lineIntent;
687 };
688 
LineAnnotationPrivate()689 LineAnnotationPrivate::LineAnnotationPrivate()
690     : AnnotationPrivate(), lineStartStyle( LineAnnotation::None ),
691     lineEndStyle( LineAnnotation::None ), lineClosed( false ),
692     lineShowCaption( false ), lineLeadingFwdPt( 0 ), lineLeadingBackPt( 0 ),
693     lineIntent( LineAnnotation::Unknown )
694 {
695 }
696 
LineAnnotation()697 LineAnnotation::LineAnnotation()
698     : Annotation( *new LineAnnotationPrivate() )
699 {}
700 
LineAnnotation(const QDomNode & node)701 LineAnnotation::LineAnnotation( const QDomNode & node )
702     : Annotation( *new LineAnnotationPrivate(), node )
703 {
704     Q_D( LineAnnotation );
705 
706     // loop through the whole children looking for a 'line' element
707     QDomNode subNode = node.firstChild();
708     while( subNode.isElement() )
709     {
710         QDomElement e = subNode.toElement();
711         subNode = subNode.nextSibling();
712         if ( e.tagName() != "line" )
713             continue;
714 
715         // parse the attributes
716         if ( e.hasAttribute( "startStyle" ) )
717             d->lineStartStyle = (LineAnnotation::TermStyle)e.attribute( "startStyle" ).toInt();
718         if ( e.hasAttribute( "endStyle" ) )
719             d->lineEndStyle = (LineAnnotation::TermStyle)e.attribute( "endStyle" ).toInt();
720         if ( e.hasAttribute( "closed" ) )
721             d->lineClosed = e.attribute( "closed" ).toInt();
722         if ( e.hasAttribute( "innerColor" ) )
723             d->lineInnerColor = QColor( e.attribute( "innerColor" ) );
724         if ( e.hasAttribute( "leadFwd" ) )
725             d->lineLeadingFwdPt = e.attribute( "leadFwd" ).toDouble();
726         if ( e.hasAttribute( "leadBack" ) )
727             d->lineLeadingBackPt = e.attribute( "leadBack" ).toDouble();
728         if ( e.hasAttribute( "showCaption" ) )
729             d->lineShowCaption = e.attribute( "showCaption" ).toInt();
730         if ( e.hasAttribute( "intent" ) )
731             d->lineIntent = (LineAnnotation::LineIntent)e.attribute( "intent" ).toInt();
732 
733         // parse all 'point' subnodes
734         QDomNode pointNode = e.firstChild();
735         while ( pointNode.isElement() )
736         {
737             QDomElement pe = pointNode.toElement();
738             pointNode = pointNode.nextSibling();
739 
740             if ( pe.tagName() != "point" )
741                 continue;
742 
743             QPointF p(pe.attribute( "x", "0.0" ).toDouble(), pe.attribute( "y", "0.0" ).toDouble());
744             d->linePoints.append( p );
745         }
746 
747         // loading complete
748         break;
749     }
750 }
751 
~LineAnnotation()752 LineAnnotation::~LineAnnotation()
753 {
754 }
755 
store(QDomNode & node,QDomDocument & document) const756 void LineAnnotation::store( QDomNode & node, QDomDocument & document ) const
757 {
758     Q_D( const LineAnnotation );
759 
760     // recurse to parent objects storing properties
761     Annotation::store( node, document );
762 
763     // create [line] element
764     QDomElement lineElement = document.createElement( "line" );
765     node.appendChild( lineElement );
766 
767     // store the attributes
768     if ( d->lineStartStyle != None )
769         lineElement.setAttribute( "startStyle", (int)d->lineStartStyle );
770     if ( d->lineEndStyle != None )
771         lineElement.setAttribute( "endStyle", (int)d->lineEndStyle );
772     if ( d->lineClosed )
773         lineElement.setAttribute( "closed", d->lineClosed );
774     if ( d->lineInnerColor.isValid() )
775         lineElement.setAttribute( "innerColor", d->lineInnerColor.name() );
776     if ( d->lineLeadingFwdPt != 0.0 )
777         lineElement.setAttribute( "leadFwd", QString::number( d->lineLeadingFwdPt ) );
778     if ( d->lineLeadingBackPt != 0.0 )
779         lineElement.setAttribute( "leadBack", QString::number( d->lineLeadingBackPt ) );
780     if ( d->lineShowCaption )
781         lineElement.setAttribute( "showCaption", d->lineShowCaption );
782     if ( d->lineIntent != Unknown )
783         lineElement.setAttribute( "intent", d->lineIntent );
784 
785     // append the list of points
786     int points = d->linePoints.count();
787     if ( points > 1 )
788     {
789         QLinkedList<QPointF>::const_iterator it = d->linePoints.begin(), end = d->linePoints.end();
790         while ( it != end )
791         {
792             const QPointF & p = *it;
793             QDomElement pElement = document.createElement( "point" );
794             lineElement.appendChild( pElement );
795             pElement.setAttribute( "x", QString::number( p.x() ) );
796             pElement.setAttribute( "y", QString::number( p.y() ) );
797             ++it;
798         }
799     }
800 }
801 
subType() const802 Annotation::SubType LineAnnotation::subType() const
803 {
804     return ALine;
805 }
806 
linePoints() const807 QLinkedList<QPointF> LineAnnotation::linePoints() const
808 {
809     Q_D( const LineAnnotation );
810     return d->linePoints;
811 }
812 
setLinePoints(const QLinkedList<QPointF> & points)813 void LineAnnotation::setLinePoints( const QLinkedList<QPointF> &points )
814 {
815     Q_D( LineAnnotation );
816     d->linePoints = points;
817 }
818 
lineStartStyle() const819 LineAnnotation::TermStyle LineAnnotation::lineStartStyle() const
820 {
821     Q_D( const LineAnnotation );
822     return d->lineStartStyle;
823 }
824 
setLineStartStyle(LineAnnotation::TermStyle style)825 void LineAnnotation::setLineStartStyle( LineAnnotation::TermStyle style )
826 {
827     Q_D( LineAnnotation );
828     d->lineStartStyle = style;
829 }
830 
lineEndStyle() const831 LineAnnotation::TermStyle LineAnnotation::lineEndStyle() const
832 {
833     Q_D( const LineAnnotation );
834     return d->lineEndStyle;
835 }
836 
setLineEndStyle(LineAnnotation::TermStyle style)837 void LineAnnotation::setLineEndStyle( LineAnnotation::TermStyle style )
838 {
839     Q_D( LineAnnotation );
840     d->lineEndStyle = style;
841 }
842 
isLineClosed() const843 bool LineAnnotation::isLineClosed() const
844 {
845     Q_D( const LineAnnotation );
846     return d->lineClosed;
847 }
848 
setLineClosed(bool closed)849 void LineAnnotation::setLineClosed( bool closed )
850 {
851     Q_D( LineAnnotation );
852     d->lineClosed = closed;
853 }
854 
lineInnerColor() const855 QColor LineAnnotation::lineInnerColor() const
856 {
857     Q_D( const LineAnnotation );
858     return d->lineInnerColor;
859 }
860 
setLineInnerColor(const QColor & color)861 void LineAnnotation::setLineInnerColor( const QColor &color )
862 {
863     Q_D( LineAnnotation );
864     d->lineInnerColor = color;
865 }
866 
lineLeadingForwardPoint() const867 double LineAnnotation::lineLeadingForwardPoint() const
868 {
869     Q_D( const LineAnnotation );
870     return d->lineLeadingFwdPt;
871 }
872 
setLineLeadingForwardPoint(double point)873 void LineAnnotation::setLineLeadingForwardPoint( double point )
874 {
875     Q_D( LineAnnotation );
876     d->lineLeadingFwdPt = point;
877 }
878 
lineLeadingBackPoint() const879 double LineAnnotation::lineLeadingBackPoint() const
880 {
881     Q_D( const LineAnnotation );
882     return d->lineLeadingBackPt;
883 }
884 
setLineLeadingBackPoint(double point)885 void LineAnnotation::setLineLeadingBackPoint( double point )
886 {
887     Q_D( LineAnnotation );
888     d->lineLeadingBackPt = point;
889 }
890 
lineShowCaption() const891 bool LineAnnotation::lineShowCaption() const
892 {
893     Q_D( const LineAnnotation );
894     return d->lineShowCaption;
895 }
896 
setLineShowCaption(bool show)897 void LineAnnotation::setLineShowCaption( bool show )
898 {
899     Q_D( LineAnnotation );
900     d->lineShowCaption = show;
901 }
902 
lineIntent() const903 LineAnnotation::LineIntent LineAnnotation::lineIntent() const
904 {
905     Q_D( const LineAnnotation );
906     return d->lineIntent;
907 }
908 
setLineIntent(LineAnnotation::LineIntent intent)909 void LineAnnotation::setLineIntent( LineAnnotation::LineIntent intent )
910 {
911     Q_D( LineAnnotation );
912     d->lineIntent = intent;
913 }
914 
915 
916 /** GeomAnnotation [Annotation] */
917 class GeomAnnotationPrivate : public AnnotationPrivate
918 {
919     public:
920         GeomAnnotationPrivate();
921 
922         // data fields (note uses border for rendering style)
923         GeomAnnotation::GeomType geomType;
924         QColor geomInnerColor;
925         int geomWidthPt;
926 };
927 
GeomAnnotationPrivate()928 GeomAnnotationPrivate::GeomAnnotationPrivate()
929     : AnnotationPrivate(), geomType( GeomAnnotation::InscribedSquare ),
930     geomWidthPt( 18 )
931 {
932 }
933 
GeomAnnotation()934 GeomAnnotation::GeomAnnotation()
935     : Annotation( *new GeomAnnotationPrivate() )
936 {}
937 
GeomAnnotation(const QDomNode & node)938 GeomAnnotation::GeomAnnotation( const QDomNode & node )
939     : Annotation( *new GeomAnnotationPrivate(), node )
940 {
941     Q_D( GeomAnnotation );
942 
943     // loop through the whole children looking for a 'geom' element
944     QDomNode subNode = node.firstChild();
945     while( subNode.isElement() )
946     {
947         QDomElement e = subNode.toElement();
948         subNode = subNode.nextSibling();
949         if ( e.tagName() != "geom" )
950             continue;
951 
952         // parse the attributes
953         if ( e.hasAttribute( "type" ) )
954             d->geomType = (GeomAnnotation::GeomType)e.attribute( "type" ).toInt();
955         if ( e.hasAttribute( "color" ) )
956             d->geomInnerColor = QColor( e.attribute( "color" ) );
957         if ( e.hasAttribute( "width" ) )
958             d->geomWidthPt = e.attribute( "width" ).toInt();
959 
960         // loading complete
961         break;
962     }
963 }
964 
~GeomAnnotation()965 GeomAnnotation::~GeomAnnotation()
966 {
967 }
968 
store(QDomNode & node,QDomDocument & document) const969 void GeomAnnotation::store( QDomNode & node, QDomDocument & document ) const
970 {
971     Q_D( const GeomAnnotation );
972 
973     // recurse to parent objects storing properties
974     Annotation::store( node, document );
975 
976     // create [geom] element
977     QDomElement geomElement = document.createElement( "geom" );
978     node.appendChild( geomElement );
979 
980     // append the optional attributes
981     if ( d->geomType != InscribedSquare )
982         geomElement.setAttribute( "type", (int)d->geomType );
983     if ( d->geomInnerColor.isValid() )
984         geomElement.setAttribute( "color", d->geomInnerColor.name() );
985     if ( d->geomWidthPt != 18 )
986         geomElement.setAttribute( "width", d->geomWidthPt );
987 }
988 
subType() const989 Annotation::SubType GeomAnnotation::subType() const
990 {
991     return AGeom;
992 }
993 
geomType() const994 GeomAnnotation::GeomType GeomAnnotation::geomType() const
995 {
996     Q_D( const GeomAnnotation );
997     return d->geomType;
998 }
999 
setGeomType(GeomAnnotation::GeomType type)1000 void GeomAnnotation::setGeomType( GeomAnnotation::GeomType type )
1001 {
1002     Q_D( GeomAnnotation );
1003     d->geomType = type;
1004 }
1005 
geomInnerColor() const1006 QColor GeomAnnotation::geomInnerColor() const
1007 {
1008     Q_D( const GeomAnnotation );
1009     return d->geomInnerColor;
1010 }
1011 
setGeomInnerColor(const QColor & color)1012 void GeomAnnotation::setGeomInnerColor( const QColor &color )
1013 {
1014     Q_D( GeomAnnotation );
1015     d->geomInnerColor = color;
1016 }
1017 
geomPointWidth() const1018 int GeomAnnotation::geomPointWidth() const
1019 {
1020     Q_D( const GeomAnnotation );
1021     return d->geomWidthPt;
1022 }
1023 
setGeomPointWidth(int width)1024 void GeomAnnotation::setGeomPointWidth( int width )
1025 {
1026     Q_D( GeomAnnotation );
1027     d->geomWidthPt = width;
1028 }
1029 
1030 
1031 
1032 /** HighlightAnnotation [Annotation] */
1033 class HighlightAnnotationPrivate : public AnnotationPrivate
1034 {
1035     public:
1036         HighlightAnnotationPrivate();
1037 
1038         // data fields
1039         HighlightAnnotation::HighlightType highlightType;
1040         QList< HighlightAnnotation::Quad > highlightQuads; // not empty
1041 };
1042 
HighlightAnnotationPrivate()1043 HighlightAnnotationPrivate::HighlightAnnotationPrivate()
1044     : AnnotationPrivate(), highlightType( HighlightAnnotation::Highlight )
1045 {
1046 }
1047 
HighlightAnnotation()1048 HighlightAnnotation::HighlightAnnotation()
1049     : Annotation( *new HighlightAnnotationPrivate() )
1050 {}
1051 
HighlightAnnotation(const QDomNode & node)1052 HighlightAnnotation::HighlightAnnotation( const QDomNode & node )
1053     : Annotation( *new HighlightAnnotationPrivate(), node )
1054 {
1055     Q_D( HighlightAnnotation );
1056 
1057     // loop through the whole children looking for a 'hl' element
1058     QDomNode subNode = node.firstChild();
1059     while( subNode.isElement() )
1060     {
1061         QDomElement e = subNode.toElement();
1062         subNode = subNode.nextSibling();
1063         if ( e.tagName() != "hl" )
1064             continue;
1065 
1066         // parse the attributes
1067         if ( e.hasAttribute( "type" ) )
1068             d->highlightType = (HighlightAnnotation::HighlightType)e.attribute( "type" ).toInt();
1069 
1070         // parse all 'quad' subnodes
1071         QDomNode quadNode = e.firstChild();
1072         for ( ; quadNode.isElement(); quadNode = quadNode.nextSibling() )
1073         {
1074             QDomElement qe = quadNode.toElement();
1075             if ( qe.tagName() != "quad" )
1076                 continue;
1077 
1078             Quad q;
1079             q.points[0].setX(qe.attribute( "ax", "0.0" ).toDouble());
1080             q.points[0].setY(qe.attribute( "ay", "0.0" ).toDouble());
1081             q.points[1].setX(qe.attribute( "bx", "0.0" ).toDouble());
1082             q.points[1].setY(qe.attribute( "by", "0.0" ).toDouble());
1083             q.points[2].setX(qe.attribute( "cx", "0.0" ).toDouble());
1084             q.points[2].setY(qe.attribute( "cy", "0.0" ).toDouble());
1085             q.points[3].setX(qe.attribute( "dx", "0.0" ).toDouble());
1086             q.points[3].setY(qe.attribute( "dy", "0.0" ).toDouble());
1087             q.capStart = qe.hasAttribute( "start" );
1088             q.capEnd = qe.hasAttribute( "end" );
1089             q.feather = qe.attribute( "feather", "0.1" ).toDouble();
1090             d->highlightQuads.append( q );
1091         }
1092 
1093         // loading complete
1094         break;
1095     }
1096 }
1097 
~HighlightAnnotation()1098 HighlightAnnotation::~HighlightAnnotation()
1099 {
1100 }
1101 
store(QDomNode & node,QDomDocument & document) const1102 void HighlightAnnotation::store( QDomNode & node, QDomDocument & document ) const
1103 {
1104     Q_D( const HighlightAnnotation );
1105 
1106     // recurse to parent objects storing properties
1107     Annotation::store( node, document );
1108 
1109     // create [hl] element
1110     QDomElement hlElement = document.createElement( "hl" );
1111     node.appendChild( hlElement );
1112 
1113     // append the optional attributes
1114     if ( d->highlightType != Highlight )
1115         hlElement.setAttribute( "type", (int)d->highlightType );
1116     if ( d->highlightQuads.count() < 1 )
1117         return;
1118     // append highlight quads, all children describe quads
1119     QList< HighlightAnnotation::Quad >::const_iterator it = d->highlightQuads.begin(), end = d->highlightQuads.end();
1120     for ( ; it != end; ++it )
1121     {
1122         QDomElement quadElement = document.createElement( "quad" );
1123         hlElement.appendChild( quadElement );
1124         const Quad & q = *it;
1125         quadElement.setAttribute( "ax", QString::number( q.points[0].x() ) );
1126         quadElement.setAttribute( "ay", QString::number( q.points[0].y() ) );
1127         quadElement.setAttribute( "bx", QString::number( q.points[1].x() ) );
1128         quadElement.setAttribute( "by", QString::number( q.points[1].y() ) );
1129         quadElement.setAttribute( "cx", QString::number( q.points[2].x() ) );
1130         quadElement.setAttribute( "cy", QString::number( q.points[2].y() ) );
1131         quadElement.setAttribute( "dx", QString::number( q.points[3].x() ) );
1132         quadElement.setAttribute( "dy", QString::number( q.points[3].y() ) );
1133         if ( q.capStart )
1134             quadElement.setAttribute( "start", 1 );
1135         if ( q.capEnd )
1136             quadElement.setAttribute( "end", 1 );
1137         quadElement.setAttribute( "feather", QString::number( q.feather ) );
1138     }
1139 }
1140 
subType() const1141 Annotation::SubType HighlightAnnotation::subType() const
1142 {
1143     return AHighlight;
1144 }
1145 
highlightType() const1146 HighlightAnnotation::HighlightType HighlightAnnotation::highlightType() const
1147 {
1148     Q_D( const HighlightAnnotation );
1149     return d->highlightType;
1150 }
1151 
setHighlightType(HighlightAnnotation::HighlightType type)1152 void HighlightAnnotation::setHighlightType( HighlightAnnotation::HighlightType type )
1153 {
1154     Q_D( HighlightAnnotation );
1155     d->highlightType = type;
1156 }
1157 
highlightQuads() const1158 QList< HighlightAnnotation::Quad > HighlightAnnotation::highlightQuads() const
1159 {
1160     Q_D( const HighlightAnnotation );
1161     return d->highlightQuads;
1162 }
1163 
setHighlightQuads(const QList<HighlightAnnotation::Quad> & quads)1164 void HighlightAnnotation::setHighlightQuads( const QList< HighlightAnnotation::Quad > &quads )
1165 {
1166     Q_D( HighlightAnnotation );
1167     d->highlightQuads = quads;
1168 }
1169 
1170 
1171 /** StampAnnotation [Annotation] */
1172 class StampAnnotationPrivate : public AnnotationPrivate
1173 {
1174     public:
1175         StampAnnotationPrivate();
1176 
1177         // data fields
1178         QString stampIconName;
1179 };
1180 
StampAnnotationPrivate()1181 StampAnnotationPrivate::StampAnnotationPrivate()
1182     : AnnotationPrivate(), stampIconName( "Draft" )
1183 {
1184 }
1185 
StampAnnotation()1186 StampAnnotation::StampAnnotation()
1187     : Annotation( *new StampAnnotationPrivate() )
1188 {}
1189 
StampAnnotation(const QDomNode & node)1190 StampAnnotation::StampAnnotation( const QDomNode & node )
1191     : Annotation( *new StampAnnotationPrivate(), node )
1192 {
1193    Q_D( StampAnnotation );
1194 
1195     // loop through the whole children looking for a 'stamp' element
1196     QDomNode subNode = node.firstChild();
1197     while( subNode.isElement() )
1198     {
1199         QDomElement e = subNode.toElement();
1200         subNode = subNode.nextSibling();
1201         if ( e.tagName() != "stamp" )
1202             continue;
1203 
1204         // parse the attributes
1205         if ( e.hasAttribute( "icon" ) )
1206             d->stampIconName = e.attribute( "icon" );
1207 
1208         // loading complete
1209         break;
1210     }
1211 }
1212 
~StampAnnotation()1213 StampAnnotation::~StampAnnotation()
1214 {
1215 }
1216 
store(QDomNode & node,QDomDocument & document) const1217 void StampAnnotation::store( QDomNode & node, QDomDocument & document ) const
1218 {
1219    Q_D( const StampAnnotation );
1220 
1221     // recurse to parent objects storing properties
1222     Annotation::store( node, document );
1223 
1224     // create [stamp] element
1225     QDomElement stampElement = document.createElement( "stamp" );
1226     node.appendChild( stampElement );
1227 
1228     // append the optional attributes
1229     if ( d->stampIconName != "Draft" )
1230         stampElement.setAttribute( "icon", d->stampIconName );
1231 }
1232 
subType() const1233 Annotation::SubType StampAnnotation::subType() const
1234 {
1235     return AStamp;
1236 }
1237 
stampIconName() const1238 QString StampAnnotation::stampIconName() const
1239 {
1240     Q_D( const StampAnnotation );
1241     return d->stampIconName;
1242 }
1243 
setStampIconName(const QString & name)1244 void StampAnnotation::setStampIconName( const QString &name )
1245 {
1246     Q_D( StampAnnotation );
1247     d->stampIconName = name;
1248 }
1249 
1250 /** InkAnnotation [Annotation] */
1251 class InkAnnotationPrivate : public AnnotationPrivate
1252 {
1253     public:
1254         InkAnnotationPrivate();
1255 
1256         // data fields
1257         QList< QLinkedList<QPointF> > inkPaths;
1258 };
1259 
InkAnnotationPrivate()1260 InkAnnotationPrivate::InkAnnotationPrivate()
1261     : AnnotationPrivate()
1262 {
1263 }
1264 
InkAnnotation()1265 InkAnnotation::InkAnnotation()
1266     : Annotation( *new InkAnnotationPrivate() )
1267 {}
1268 
InkAnnotation(const QDomNode & node)1269 InkAnnotation::InkAnnotation( const QDomNode & node )
1270     : Annotation( *new InkAnnotationPrivate(), node )
1271 {
1272     Q_D( InkAnnotation );
1273 
1274     // loop through the whole children looking for a 'ink' element
1275     QDomNode subNode = node.firstChild();
1276     while( subNode.isElement() )
1277     {
1278         QDomElement e = subNode.toElement();
1279         subNode = subNode.nextSibling();
1280         if ( e.tagName() != "ink" )
1281             continue;
1282 
1283         // parse the 'path' subnodes
1284         QDomNode pathNode = e.firstChild();
1285         while ( pathNode.isElement() )
1286         {
1287             QDomElement pathElement = pathNode.toElement();
1288             pathNode = pathNode.nextSibling();
1289 
1290             if ( pathElement.tagName() != "path" )
1291                 continue;
1292 
1293             // build each path parsing 'point' subnodes
1294             QLinkedList<QPointF> path;
1295             QDomNode pointNode = pathElement.firstChild();
1296             while ( pointNode.isElement() )
1297             {
1298                 QDomElement pointElement = pointNode.toElement();
1299                 pointNode = pointNode.nextSibling();
1300 
1301                 if ( pointElement.tagName() != "point" )
1302                     continue;
1303 
1304                 QPointF p(pointElement.attribute( "x", "0.0" ).toDouble(), pointElement.attribute( "y", "0.0" ).toDouble());
1305                 path.append( p );
1306             }
1307 
1308             // add the path to the path list if it contains at least 2 nodes
1309             if ( path.count() >= 2 )
1310                 d->inkPaths.append( path );
1311         }
1312 
1313         // loading complete
1314         break;
1315     }
1316 }
1317 
~InkAnnotation()1318 InkAnnotation::~InkAnnotation()
1319 {
1320 }
1321 
store(QDomNode & node,QDomDocument & document) const1322 void InkAnnotation::store( QDomNode & node, QDomDocument & document ) const
1323 {
1324     Q_D( const InkAnnotation );
1325 
1326     // recurse to parent objects storing properties
1327     Annotation::store( node, document );
1328 
1329     // create [ink] element
1330     QDomElement inkElement = document.createElement( "ink" );
1331     node.appendChild( inkElement );
1332 
1333     // append the optional attributes
1334     if ( d->inkPaths.count() < 1 )
1335         return;
1336     QList< QLinkedList<QPointF> >::const_iterator pIt = d->inkPaths.begin(), pEnd = d->inkPaths.end();
1337     for ( ; pIt != pEnd; ++pIt )
1338     {
1339         QDomElement pathElement = document.createElement( "path" );
1340         inkElement.appendChild( pathElement );
1341         const QLinkedList<QPointF> & path = *pIt;
1342         QLinkedList<QPointF>::const_iterator iIt = path.begin(), iEnd = path.end();
1343         for ( ; iIt != iEnd; ++iIt )
1344         {
1345             const QPointF & point = *iIt;
1346             QDomElement pointElement = document.createElement( "point" );
1347             pathElement.appendChild( pointElement );
1348             pointElement.setAttribute( "x", QString::number( point.x() ) );
1349             pointElement.setAttribute( "y", QString::number( point.y() ) );
1350         }
1351     }
1352 }
1353 
subType() const1354 Annotation::SubType InkAnnotation::subType() const
1355 {
1356     return AInk;
1357 }
1358 
inkPaths() const1359 QList< QLinkedList<QPointF> > InkAnnotation::inkPaths() const
1360 {
1361    Q_D( const InkAnnotation );
1362    return d->inkPaths;
1363 }
1364 
setInkPaths(const QList<QLinkedList<QPointF>> & paths)1365 void InkAnnotation::setInkPaths( const QList< QLinkedList<QPointF> > &paths )
1366 {
1367    Q_D( InkAnnotation );
1368    d->inkPaths = paths;
1369 }
1370 
1371 
1372 /** LinkAnnotation [Annotation] */
1373 class LinkAnnotationPrivate : public AnnotationPrivate
1374 {
1375     public:
1376         LinkAnnotationPrivate();
1377         ~LinkAnnotationPrivate();
1378 
1379         // data fields
1380         Link * linkDestination;
1381         LinkAnnotation::HighlightMode linkHLMode;
1382         QPointF linkRegion[4];
1383 };
1384 
LinkAnnotationPrivate()1385 LinkAnnotationPrivate::LinkAnnotationPrivate()
1386     : AnnotationPrivate(), linkDestination( 0 ), linkHLMode( LinkAnnotation::Invert )
1387 {
1388 }
1389 
~LinkAnnotationPrivate()1390 LinkAnnotationPrivate::~LinkAnnotationPrivate()
1391 {
1392     delete linkDestination;
1393 }
1394 
LinkAnnotation()1395 LinkAnnotation::LinkAnnotation()
1396     : Annotation( *new LinkAnnotationPrivate() )
1397 {}
1398 
LinkAnnotation(const QDomNode & node)1399 LinkAnnotation::LinkAnnotation( const QDomNode & node )
1400     : Annotation( *new LinkAnnotationPrivate(), node )
1401 {
1402     Q_D( LinkAnnotation );
1403 
1404     // loop through the whole children looking for a 'link' element
1405     QDomNode subNode = node.firstChild();
1406     while( subNode.isElement() )
1407     {
1408         QDomElement e = subNode.toElement();
1409         subNode = subNode.nextSibling();
1410         if ( e.tagName() != "link" )
1411             continue;
1412 
1413         // parse the attributes
1414         if ( e.hasAttribute( "hlmode" ) )
1415             d->linkHLMode = (LinkAnnotation::HighlightMode)e.attribute( "hlmode" ).toInt();
1416 
1417         // parse all 'quad' subnodes
1418         QDomNode quadNode = e.firstChild();
1419         for ( ; quadNode.isElement(); quadNode = quadNode.nextSibling() )
1420         {
1421             QDomElement qe = quadNode.toElement();
1422             if ( qe.tagName() == "quad" )
1423             {
1424                 d->linkRegion[0].setX(qe.attribute( "ax", "0.0" ).toDouble());
1425                 d->linkRegion[0].setY(qe.attribute( "ay", "0.0" ).toDouble());
1426                 d->linkRegion[1].setX(qe.attribute( "bx", "0.0" ).toDouble());
1427                 d->linkRegion[1].setY(qe.attribute( "by", "0.0" ).toDouble());
1428                 d->linkRegion[2].setX(qe.attribute( "cx", "0.0" ).toDouble());
1429                 d->linkRegion[2].setY(qe.attribute( "cy", "0.0" ).toDouble());
1430                 d->linkRegion[3].setX(qe.attribute( "dx", "0.0" ).toDouble());
1431                 d->linkRegion[3].setY(qe.attribute( "dy", "0.0" ).toDouble());
1432             }
1433             else if ( qe.tagName() == "link" )
1434             {
1435                 QString type = qe.attribute( "type" );
1436                 if ( type == "GoTo" )
1437                 {
1438                     Poppler::LinkGoto * go = new Poppler::LinkGoto( QRect(), qe.attribute( "filename" ), LinkDestination( qe.attribute( "destination" ) ) );
1439                     d->linkDestination = go;
1440                 }
1441                 else if ( type == "Exec" )
1442                 {
1443                     Poppler::LinkExecute * exec = new Poppler::LinkExecute( QRect(), qe.attribute( "filename" ), qe.attribute( "parameters" ) );
1444                     d->linkDestination = exec;
1445                 }
1446                 else if ( type == "Browse" )
1447                 {
1448                     Poppler::LinkBrowse * browse = new Poppler::LinkBrowse( QRect(), qe.attribute( "url" ) );
1449                     d->linkDestination = browse;
1450                 }
1451                 else if ( type == "Action" )
1452                 {
1453                     Poppler::LinkAction::ActionType act;
1454                     QString actString = qe.attribute( "action" );
1455                     bool found = true;
1456                     if ( actString == "PageFirst" )
1457                         act = Poppler::LinkAction::PageFirst;
1458                     else if ( actString == "PagePrev" )
1459                         act = Poppler::LinkAction::PagePrev;
1460                     else if ( actString == "PageNext" )
1461                         act = Poppler::LinkAction::PageNext;
1462                     else if ( actString == "PageLast" )
1463                         act = Poppler::LinkAction::PageLast;
1464                     else if ( actString == "HistoryBack" )
1465                         act = Poppler::LinkAction::HistoryBack;
1466                     else if ( actString == "HistoryForward" )
1467                         act = Poppler::LinkAction::HistoryForward;
1468                     else if ( actString == "Quit" )
1469                         act = Poppler::LinkAction::Quit;
1470                     else if ( actString == "Presentation" )
1471                         act = Poppler::LinkAction::Presentation;
1472                     else if ( actString == "EndPresentation" )
1473                         act = Poppler::LinkAction::EndPresentation;
1474                     else if ( actString == "Find" )
1475                         act = Poppler::LinkAction::Find;
1476                     else if ( actString == "GoToPage" )
1477                         act = Poppler::LinkAction::GoToPage;
1478                     else if ( actString == "Close" )
1479                         act = Poppler::LinkAction::Close;
1480                     else if ( actString == "Print" )
1481                         act = Poppler::LinkAction::Print;
1482                     else
1483                         found = false;
1484                     if (found)
1485                     {
1486                         Poppler::LinkAction * action = new Poppler::LinkAction( QRect(), act );
1487                         d->linkDestination = action;
1488                     }
1489                 }
1490 #if 0
1491                 else if ( type == "Movie" )
1492                 {
1493                     Poppler::LinkMovie * movie = new Poppler::LinkMovie( QRect() );
1494                     d->linkDestination = movie;
1495                 }
1496 #endif
1497             }
1498         }
1499 
1500         // loading complete
1501         break;
1502     }
1503 }
1504 
~LinkAnnotation()1505 LinkAnnotation::~LinkAnnotation()
1506 {
1507 }
1508 
store(QDomNode & node,QDomDocument & document) const1509 void LinkAnnotation::store( QDomNode & node, QDomDocument & document ) const
1510 {
1511     Q_D( const LinkAnnotation );
1512 
1513     // recurse to parent objects storing properties
1514     Annotation::store( node, document );
1515 
1516     // create [hl] element
1517     QDomElement linkElement = document.createElement( "link" );
1518     node.appendChild( linkElement );
1519 
1520     // append the optional attributes
1521     if ( d->linkHLMode != Invert )
1522         linkElement.setAttribute( "hlmode", (int)d->linkHLMode );
1523 
1524     // saving region
1525     QDomElement quadElement = document.createElement( "quad" );
1526     linkElement.appendChild( quadElement );
1527     quadElement.setAttribute( "ax", QString::number( d->linkRegion[0].x() ) );
1528     quadElement.setAttribute( "ay", QString::number( d->linkRegion[0].y() ) );
1529     quadElement.setAttribute( "bx", QString::number( d->linkRegion[1].x() ) );
1530     quadElement.setAttribute( "by", QString::number( d->linkRegion[1].y() ) );
1531     quadElement.setAttribute( "cx", QString::number( d->linkRegion[2].x() ) );
1532     quadElement.setAttribute( "cy", QString::number( d->linkRegion[2].y() ) );
1533     quadElement.setAttribute( "dx", QString::number( d->linkRegion[3].x() ) );
1534     quadElement.setAttribute( "dy", QString::number( d->linkRegion[3].y() ) );
1535 
1536     // saving link
1537     QDomElement hyperlinkElement = document.createElement( "link" );
1538     linkElement.appendChild( hyperlinkElement );
1539     if ( d->linkDestination )
1540     {
1541         switch( d->linkDestination->linkType() )
1542         {
1543             case Poppler::Link::Goto:
1544             {
1545                 Poppler::LinkGoto * go = static_cast< Poppler::LinkGoto * >( d->linkDestination );
1546                 hyperlinkElement.setAttribute( "type", "GoTo" );
1547                 hyperlinkElement.setAttribute( "filename", go->fileName() );
1548                 hyperlinkElement.setAttribute( "destionation", go->destination().toString() );
1549                 break;
1550             }
1551             case Poppler::Link::Execute:
1552             {
1553                 Poppler::LinkExecute * exec = static_cast< Poppler::LinkExecute * >( d->linkDestination );
1554                 hyperlinkElement.setAttribute( "type", "Exec" );
1555                 hyperlinkElement.setAttribute( "filename", exec->fileName() );
1556                 hyperlinkElement.setAttribute( "parameters", exec->parameters() );
1557                 break;
1558             }
1559             case Poppler::Link::Browse:
1560             {
1561                 Poppler::LinkBrowse * browse = static_cast< Poppler::LinkBrowse * >( d->linkDestination );
1562                 hyperlinkElement.setAttribute( "type", "Browse" );
1563                 hyperlinkElement.setAttribute( "url", browse->url() );
1564                 break;
1565             }
1566             case Poppler::Link::Action:
1567             {
1568                 Poppler::LinkAction * action = static_cast< Poppler::LinkAction * >( d->linkDestination );
1569                 hyperlinkElement.setAttribute( "type", "Action" );
1570                 switch ( action->actionType() )
1571                 {
1572                     case Poppler::LinkAction::PageFirst:
1573                         hyperlinkElement.setAttribute( "action", "PageFirst" );
1574                         break;
1575                     case Poppler::LinkAction::PagePrev:
1576                         hyperlinkElement.setAttribute( "action", "PagePrev" );
1577                         break;
1578                     case Poppler::LinkAction::PageNext:
1579                         hyperlinkElement.setAttribute( "action", "PageNext" );
1580                         break;
1581                     case Poppler::LinkAction::PageLast:
1582                         hyperlinkElement.setAttribute( "action", "PageLast" );
1583                         break;
1584                     case Poppler::LinkAction::HistoryBack:
1585                         hyperlinkElement.setAttribute( "action", "HistoryBack" );
1586                         break;
1587                     case Poppler::LinkAction::HistoryForward:
1588                         hyperlinkElement.setAttribute( "action", "HistoryForward" );
1589                         break;
1590                     case Poppler::LinkAction::Quit:
1591                         hyperlinkElement.setAttribute( "action", "Quit" );
1592                         break;
1593                     case Poppler::LinkAction::Presentation:
1594                         hyperlinkElement.setAttribute( "action", "Presentation" );
1595                         break;
1596                     case Poppler::LinkAction::EndPresentation:
1597                         hyperlinkElement.setAttribute( "action", "EndPresentation" );
1598                         break;
1599                     case Poppler::LinkAction::Find:
1600                         hyperlinkElement.setAttribute( "action", "Find" );
1601                         break;
1602                     case Poppler::LinkAction::GoToPage:
1603                         hyperlinkElement.setAttribute( "action", "GoToPage" );
1604                         break;
1605                     case Poppler::LinkAction::Close:
1606                         hyperlinkElement.setAttribute( "action", "Close" );
1607                         break;
1608                     case Poppler::LinkAction::Print:
1609                         hyperlinkElement.setAttribute( "action", "Print" );
1610                         break;
1611                 }
1612                 break;
1613             }
1614             case Poppler::Link::Movie:
1615             {
1616                 hyperlinkElement.setAttribute( "type", "Movie" );
1617                 break;
1618             }
1619             case Poppler::Link::Sound:
1620             {
1621                 // FIXME: implement me
1622                 break;
1623             }
1624             case Poppler::Link::None:
1625                 break;
1626         }
1627     }
1628 }
1629 
subType() const1630 Annotation::SubType LinkAnnotation::subType() const
1631 {
1632     return ALink;
1633 }
1634 
linkDestionation() const1635 Link* LinkAnnotation::linkDestionation() const
1636 {
1637     Q_D( const LinkAnnotation );
1638     return d->linkDestination;
1639 }
1640 
setLinkDestination(Link * link)1641 void LinkAnnotation::setLinkDestination( Link *link )
1642 {
1643     Q_D( LinkAnnotation );
1644     delete d->linkDestination;
1645     d->linkDestination = link;
1646 }
1647 
linkHighlightMode() const1648 LinkAnnotation::HighlightMode LinkAnnotation::linkHighlightMode() const
1649 {
1650     Q_D( const LinkAnnotation );
1651     return d->linkHLMode;
1652 }
1653 
setLinkHighlightMode(LinkAnnotation::HighlightMode mode)1654 void LinkAnnotation::setLinkHighlightMode( LinkAnnotation::HighlightMode mode )
1655 {
1656     Q_D( LinkAnnotation );
1657     d->linkHLMode = mode;
1658 }
1659 
linkRegionPoint(int id) const1660 QPointF LinkAnnotation::linkRegionPoint( int id ) const
1661 {
1662     if ( id < 0 || id >= 4 )
1663         return QPointF();
1664 
1665     Q_D( const LinkAnnotation );
1666     return d->linkRegion[id];
1667 }
1668 
setLinkRegionPoint(int id,const QPointF & point)1669 void LinkAnnotation::setLinkRegionPoint( int id, const QPointF &point )
1670 {
1671     if ( id < 0 || id >= 4 )
1672         return;
1673 
1674     Q_D( LinkAnnotation );
1675     d->linkRegion[id] = point;
1676 }
1677 
1678 /** CaretAnnotation [Annotation] */
1679 class CaretAnnotationPrivate : public AnnotationPrivate
1680 {
1681     public:
1682         CaretAnnotationPrivate();
1683 
1684         // data fields
1685         CaretAnnotation::CaretSymbol symbol;
1686 };
1687 
caretSymbolToString(CaretAnnotation::CaretSymbol symbol)1688 static QString caretSymbolToString( CaretAnnotation::CaretSymbol symbol )
1689 {
1690     switch ( symbol )
1691     {
1692         case CaretAnnotation::None:
1693             return QString::fromLatin1( "None" );
1694         case CaretAnnotation::P:
1695             return QString::fromLatin1( "P" );
1696     }
1697     return QString();
1698 }
1699 
caretSymbolFromString(const QString & symbol)1700 static CaretAnnotation::CaretSymbol caretSymbolFromString( const QString &symbol )
1701 {
1702     if ( symbol == QLatin1String( "None" ) )
1703         return CaretAnnotation::None;
1704     else if ( symbol == QLatin1String( "P" ) )
1705         return CaretAnnotation::P;
1706     return CaretAnnotation::None;
1707 }
1708 
CaretAnnotationPrivate()1709 CaretAnnotationPrivate::CaretAnnotationPrivate()
1710     : AnnotationPrivate(), symbol( CaretAnnotation::None )
1711 {
1712 }
1713 
CaretAnnotation()1714 CaretAnnotation::CaretAnnotation()
1715     : Annotation( *new CaretAnnotationPrivate() )
1716 {
1717 }
1718 
CaretAnnotation(const QDomNode & node)1719 CaretAnnotation::CaretAnnotation( const QDomNode & node )
1720     : Annotation( *new CaretAnnotationPrivate(), node )
1721 {
1722     Q_D( CaretAnnotation );
1723 
1724     // loop through the whole children looking for a 'caret' element
1725     QDomNode subNode = node.firstChild();
1726     while( subNode.isElement() )
1727     {
1728         QDomElement e = subNode.toElement();
1729         subNode = subNode.nextSibling();
1730         if ( e.tagName() != "caret" )
1731             continue;
1732 
1733         // parse the attributes
1734         if ( e.hasAttribute( "symbol" ) )
1735             d->symbol = caretSymbolFromString( e.attribute( "symbol" ) );
1736 
1737         // loading complete
1738         break;
1739     }
1740 }
1741 
~CaretAnnotation()1742 CaretAnnotation::~CaretAnnotation()
1743 {
1744 }
1745 
store(QDomNode & node,QDomDocument & document) const1746 void CaretAnnotation::store( QDomNode & node, QDomDocument & document ) const
1747 {
1748     Q_D( const CaretAnnotation );
1749 
1750     // recurse to parent objects storing properties
1751     Annotation::store( node, document );
1752 
1753     // create [caret] element
1754     QDomElement caretElement = document.createElement( "caret" );
1755     node.appendChild( caretElement );
1756 
1757     // append the optional attributes
1758     if ( d->symbol != CaretAnnotation::None )
1759         caretElement.setAttribute( "symbol", caretSymbolToString( d->symbol ) );
1760 }
1761 
subType() const1762 Annotation::SubType CaretAnnotation::subType() const
1763 {
1764     return ACaret;
1765 }
1766 
caretSymbol() const1767 CaretAnnotation::CaretSymbol CaretAnnotation::caretSymbol() const
1768 {
1769     Q_D( const CaretAnnotation );
1770     return d->symbol;
1771 }
1772 
setCaretSymbol(CaretAnnotation::CaretSymbol symbol)1773 void CaretAnnotation::setCaretSymbol( CaretAnnotation::CaretSymbol symbol )
1774 {
1775     Q_D( CaretAnnotation );
1776     d->symbol = symbol;
1777 }
1778 
1779 /** FileAttachmentAnnotation [Annotation] */
1780 class FileAttachmentAnnotationPrivate : public AnnotationPrivate
1781 {
1782     public:
1783         FileAttachmentAnnotationPrivate();
1784         ~FileAttachmentAnnotationPrivate();
1785 
1786         // data fields
1787         QString icon;
1788         EmbeddedFile *embfile;
1789 };
1790 
FileAttachmentAnnotationPrivate()1791 FileAttachmentAnnotationPrivate::FileAttachmentAnnotationPrivate()
1792     : AnnotationPrivate(), icon( "PushPin" ), embfile( 0 )
1793 {
1794 }
1795 
~FileAttachmentAnnotationPrivate()1796 FileAttachmentAnnotationPrivate::~FileAttachmentAnnotationPrivate()
1797 {
1798     delete embfile;
1799 }
1800 
FileAttachmentAnnotation()1801 FileAttachmentAnnotation::FileAttachmentAnnotation()
1802     : Annotation( *new FileAttachmentAnnotationPrivate() )
1803 {
1804 }
1805 
FileAttachmentAnnotation(const QDomNode & node)1806 FileAttachmentAnnotation::FileAttachmentAnnotation( const QDomNode & node )
1807     : Annotation( *new FileAttachmentAnnotationPrivate(), node )
1808 {
1809     // loop through the whole children looking for a 'fileattachment' element
1810     QDomNode subNode = node.firstChild();
1811     while( subNode.isElement() )
1812     {
1813         QDomElement e = subNode.toElement();
1814         subNode = subNode.nextSibling();
1815         if ( e.tagName() != "fileattachment" )
1816             continue;
1817 
1818         // loading complete
1819         break;
1820     }
1821 }
1822 
~FileAttachmentAnnotation()1823 FileAttachmentAnnotation::~FileAttachmentAnnotation()
1824 {
1825 }
1826 
store(QDomNode & node,QDomDocument & document) const1827 void FileAttachmentAnnotation::store( QDomNode & node, QDomDocument & document ) const
1828 {
1829     // recurse to parent objects storing properties
1830     Annotation::store( node, document );
1831 
1832     // create [fileattachment] element
1833     QDomElement fileAttachmentElement = document.createElement( "fileattachment" );
1834     node.appendChild( fileAttachmentElement );
1835 }
1836 
subType() const1837 Annotation::SubType FileAttachmentAnnotation::subType() const
1838 {
1839     return AFileAttachment;
1840 }
1841 
fileIconName() const1842 QString FileAttachmentAnnotation::fileIconName() const
1843 {
1844     Q_D( const FileAttachmentAnnotation );
1845     return d->icon;
1846 }
1847 
setFileIconName(const QString & icon)1848 void FileAttachmentAnnotation::setFileIconName( const QString &icon )
1849 {
1850     Q_D( FileAttachmentAnnotation );
1851     d->icon = icon;
1852 }
1853 
embeddedFile() const1854 EmbeddedFile* FileAttachmentAnnotation::embeddedFile() const
1855 {
1856     Q_D( const FileAttachmentAnnotation );
1857     return d->embfile;
1858 }
1859 
setEmbeddedFile(EmbeddedFile * ef)1860 void FileAttachmentAnnotation::setEmbeddedFile( EmbeddedFile *ef )
1861 {
1862     Q_D( FileAttachmentAnnotation );
1863     d->embfile = ef;
1864 }
1865 
1866 /** SoundAnnotation [Annotation] */
1867 class SoundAnnotationPrivate : public AnnotationPrivate
1868 {
1869     public:
1870         SoundAnnotationPrivate();
1871         ~SoundAnnotationPrivate();
1872 
1873         // data fields
1874         QString icon;
1875         SoundObject *sound;
1876 };
1877 
SoundAnnotationPrivate()1878 SoundAnnotationPrivate::SoundAnnotationPrivate()
1879     : AnnotationPrivate(), icon( "Speaker" ), sound( 0 )
1880 {
1881 }
1882 
~SoundAnnotationPrivate()1883 SoundAnnotationPrivate::~SoundAnnotationPrivate()
1884 {
1885     delete sound;
1886 }
1887 
SoundAnnotation()1888 SoundAnnotation::SoundAnnotation()
1889     : Annotation( *new SoundAnnotationPrivate() )
1890 {
1891 }
1892 
SoundAnnotation(const QDomNode & node)1893 SoundAnnotation::SoundAnnotation( const QDomNode & node )
1894     : Annotation( *new SoundAnnotationPrivate(), node )
1895 {
1896     // loop through the whole children looking for a 'sound' element
1897     QDomNode subNode = node.firstChild();
1898     while( subNode.isElement() )
1899     {
1900         QDomElement e = subNode.toElement();
1901         subNode = subNode.nextSibling();
1902         if ( e.tagName() != "sound" )
1903             continue;
1904 
1905         // loading complete
1906         break;
1907     }
1908 }
1909 
~SoundAnnotation()1910 SoundAnnotation::~SoundAnnotation()
1911 {
1912 }
1913 
store(QDomNode & node,QDomDocument & document) const1914 void SoundAnnotation::store( QDomNode & node, QDomDocument & document ) const
1915 {
1916     // recurse to parent objects storing properties
1917     Annotation::store( node, document );
1918 
1919     // create [sound] element
1920     QDomElement soundElement = document.createElement( "sound" );
1921     node.appendChild( soundElement );
1922 }
1923 
subType() const1924 Annotation::SubType SoundAnnotation::subType() const
1925 {
1926     return ASound;
1927 }
1928 
soundIconName() const1929 QString SoundAnnotation::soundIconName() const
1930 {
1931     Q_D( const SoundAnnotation );
1932     return d->icon;
1933 }
1934 
setSoundIconName(const QString & icon)1935 void SoundAnnotation::setSoundIconName( const QString &icon )
1936 {
1937     Q_D( SoundAnnotation );
1938     d->icon = icon;
1939 }
1940 
sound() const1941 SoundObject* SoundAnnotation::sound() const
1942 {
1943     Q_D( const SoundAnnotation );
1944     return d->sound;
1945 }
1946 
setSound(SoundObject * s)1947 void SoundAnnotation::setSound( SoundObject *s )
1948 {
1949     Q_D( SoundAnnotation );
1950     d->sound = s;
1951 }
1952 
1953 /** MovieAnnotation [Annotation] */
1954 class MovieAnnotationPrivate : public AnnotationPrivate
1955 {
1956     public:
1957         MovieAnnotationPrivate();
1958         ~MovieAnnotationPrivate();
1959 
1960         // data fields
1961         MovieObject *movie;
1962         QString title;
1963 };
1964 
MovieAnnotationPrivate()1965 MovieAnnotationPrivate::MovieAnnotationPrivate()
1966     : AnnotationPrivate(), movie( 0 )
1967 {
1968 }
1969 
~MovieAnnotationPrivate()1970 MovieAnnotationPrivate::~MovieAnnotationPrivate()
1971 {
1972     delete movie;
1973 }
1974 
MovieAnnotation()1975 MovieAnnotation::MovieAnnotation()
1976     : Annotation( *new MovieAnnotationPrivate() )
1977 {
1978 }
1979 
MovieAnnotation(const QDomNode & node)1980 MovieAnnotation::MovieAnnotation( const QDomNode & node )
1981     : Annotation( *new MovieAnnotationPrivate(), node )
1982 {
1983     // loop through the whole children looking for a 'movie' element
1984     QDomNode subNode = node.firstChild();
1985     while( subNode.isElement() )
1986     {
1987         QDomElement e = subNode.toElement();
1988         subNode = subNode.nextSibling();
1989         if ( e.tagName() != "movie" )
1990             continue;
1991 
1992         // loading complete
1993         break;
1994     }
1995 }
1996 
~MovieAnnotation()1997 MovieAnnotation::~MovieAnnotation()
1998 {
1999 }
2000 
store(QDomNode & node,QDomDocument & document) const2001 void MovieAnnotation::store( QDomNode & node, QDomDocument & document ) const
2002 {
2003     // recurse to parent objects storing properties
2004     Annotation::store( node, document );
2005 
2006     // create [movie] element
2007     QDomElement movieElement = document.createElement( "movie" );
2008     node.appendChild( movieElement );
2009 }
2010 
subType() const2011 Annotation::SubType MovieAnnotation::subType() const
2012 {
2013     return AMovie;
2014 }
2015 
movie() const2016 MovieObject* MovieAnnotation::movie() const
2017 {
2018     Q_D( const MovieAnnotation );
2019     return d->movie;
2020 }
2021 
setMovie(MovieObject * movie)2022 void MovieAnnotation::setMovie( MovieObject *movie )
2023 {
2024     Q_D( MovieAnnotation );
2025     d->movie = movie;
2026 }
2027 
movieTitle() const2028 QString MovieAnnotation::movieTitle() const
2029 {
2030     Q_D( const MovieAnnotation );
2031     return d->title;
2032 }
2033 
setMovieTitle(const QString & title)2034 void MovieAnnotation::setMovieTitle( const QString &title )
2035 {
2036     Q_D( MovieAnnotation );
2037     d->title = title;
2038 }
2039 
2040 //BEGIN utility annotation functions
convertAnnotColor(AnnotColor * color)2041 QColor convertAnnotColor( AnnotColor *color )
2042 {
2043     if ( !color )
2044         return QColor();
2045 
2046     QColor newcolor;
2047     const double *color_data = color->getValues();
2048     switch ( color->getSpace() )
2049     {
2050         case AnnotColor::colorTransparent: // = 0,
2051             newcolor = Qt::transparent;
2052             break;
2053         case AnnotColor::colorGray: // = 1,
2054             newcolor.setRgbF( color_data[0], color_data[0], color_data[0] );
2055             break;
2056         case AnnotColor::colorRGB: // = 3,
2057             newcolor.setRgbF( color_data[0], color_data[1], color_data[2] );
2058             break;
2059         case AnnotColor::colorCMYK: // = 4
2060             newcolor.setCmykF( color_data[0], color_data[1], color_data[2], color_data[3] );
2061             break;
2062     }
2063     return newcolor;
2064 }
2065 //END utility annotation functions
2066 
2067 }
2068