1 /***************************************************************************
2 * Copyright (C) 2005 by Enrico Ros <eros.kde@email.it> *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 ***************************************************************************/
10 #include "pageviewannotator.h"
13 #include <qapplication.h>
21 #include <kiconloader.h>
23 #include <kstandarddirs.h>
24 #include <kinputdialog.h>
33 #include "core/area.h"
34 #include "core/document.h"
35 #include "core/page.h"
36 #include "core/annotations.h"
38 #include "annotationtools.h"
41 /** @short PickPointEngine */
42 class PickPointEngine
: public AnnotatorEngine
45 PickPointEngine( const QDomElement
& engineElement
)
46 : AnnotatorEngine( engineElement
), clicked( false ), pixmap( 0 ),
47 xscale( 1.0 ), yscale( 1.0 )
49 // parse engine specific attributes
50 pixmapName
= engineElement
.attribute( "hoverIcon" );
51 QString stampname
= m_annotElement
.attribute( "icon" );
52 if ( m_annotElement
.attribute( "type" ) == "Stamp" && !stampname
.simplified().isEmpty() )
53 pixmapName
= stampname
;
54 center
= QVariant( engineElement
.attribute( "center" ) ).toBool();
56 size
= engineElement
.attribute( "size", "32" ).toInt( &ok
);
59 m_block
= QVariant( engineElement
.attribute( "block" ) ).toBool();
61 // create engine objects
62 if ( !pixmapName
.simplified().isEmpty() )
63 pixmap
= new QPixmap( DesktopIcon( pixmapName
, size
) );
71 QRect
event( EventType type
, Button button
, double nX
, double nY
, double xScale
, double yScale
, const Okular::Page
* page
)
75 pagewidth
= page
->width();
76 pageheight
= page
->height();
77 // only proceed if pressing left button
81 // start operation on click
82 if ( type
== Press
&& clicked
== false )
88 // repaint if moving while pressing
89 else if ( type
== Move
&& clicked
== true )
92 // operation finished on release
93 else if ( type
== Release
&& clicked
== true )
95 m_creationCompleted
= true;
100 // update variables and extents (zoom invariant rect)
103 if ( center
&& pixmap
)
105 rect
.left
= nX
- ( pixmap
->width() / ( xScale
* 2.0 ) );
106 rect
.top
= nY
- ( pixmap
->height() / ( yScale
* 2.0 ) );
113 rect
.right
= rect
.left
+ ( pixmap
? pixmap
->width() / xScale
: 0 );
114 rect
.bottom
= rect
.top
+ ( pixmap
? pixmap
->height() / yScale
: 0 );
115 QRect boundrect
= rect
.geometry( (int)xScale
, (int)yScale
).adjusted( 0, 0, 1, 1 );
118 Okular::NormalizedRect
tmprect( qMin( startpoint
.x
, point
.x
), qMin( startpoint
.y
, point
.y
), qMax( startpoint
.x
, point
.x
), qMax( startpoint
.y
, point
.y
) );
119 boundrect
|= tmprect
.geometry( (int)xScale
, (int)yScale
).adjusted( 0, 0, 1, 1 );
124 void paint( QPainter
* painter
, double xScale
, double yScale
, const QRect
& /*clipRect*/ )
130 QPen origpen
= painter
->pen();
131 QPen pen
= painter
->pen();
132 pen
.setStyle( Qt::DashLine
);
133 painter
->setPen( pen
);
134 Okular::NormalizedRect
tmprect( qMin( startpoint
.x
, point
.x
), qMin( startpoint
.y
, point
.y
), qMax( startpoint
.x
, point
.x
), qMax( startpoint
.y
, point
.y
) );
135 QRect realrect
= tmprect
.geometry( (int)xScale
, (int)yScale
);
136 painter
->drawRect( realrect
);
137 painter
->setPen( origpen
);
140 painter
->drawPixmap( QPointF( rect
.left
* xScale
, rect
.top
* yScale
), *pixmap
);
144 QList
< Okular::Annotation
* > end()
146 m_creationCompleted
= false;
148 // find out annotation's description node
149 if ( m_annotElement
.isNull() )
150 return QList
< Okular::Annotation
* >();
152 // find out annotation's type
153 Okular::Annotation
* ann
= 0;
154 QString typeString
= m_annotElement
.attribute( "type" );
155 // create TextAnnotation from path
156 if ( typeString
== "FreeText") //<annotation type="Text"
159 QString prompt
= i18n( "Text of the new note:" );
161 QString note
= KInputDialog::getMultiLineText( i18n( "New Text Note" ), prompt
, QString(), &resok
);
165 Okular::TextAnnotation
* ta
= new Okular::TextAnnotation();
167 ta
->setInplaceText( note
);
168 ta
->setTextType( Okular::TextAnnotation::InPlace
);
170 rect
.left
= qMin(startpoint
.x
,point
.x
);
171 rect
.top
= qMin(startpoint
.y
,point
.y
);
172 rect
.right
= qMax(startpoint
.x
,point
.x
);
173 rect
.bottom
= qMax(startpoint
.y
,point
.y
);
174 kDebug().nospace() << "xyScale=" << xscale
<< "," << yscale
;
175 static int padding
= 2;
176 QFontMetricsF
mf(ta
->textFont());
177 QRectF rcf
= mf
.boundingRect( Okular::NormalizedRect( rect
.left
, rect
.top
, 1.0, 1.0 ).geometry( (int)pagewidth
, (int)pageheight
).adjusted( padding
, padding
, -padding
, -padding
),
178 Qt::AlignTop
| Qt::AlignLeft
| Qt::TextWordWrap
, ta
->inplaceText() );
179 rect
.right
= qMax(rect
.right
, rect
.left
+(rcf
.width()+padding
*2)/pagewidth
);
180 rect
.bottom
= qMax(rect
.bottom
, rect
.top
+(rcf
.height()+padding
*2)/pageheight
);
181 ta
->setBoundingRectangle( this->rect
);
182 ta
->window().setSummary( "TextBox" );
185 else if ( typeString
== "Text")
187 Okular::TextAnnotation
* ta
= new Okular::TextAnnotation();
189 ta
->setTextType( Okular::TextAnnotation::Linked
);
190 ta
->window().setText( QString() );
191 //ta->window.flags &= ~(Okular::Annotation::Hidden);
195 rect
.right
=rect
.left
+iconhei
;
196 rect
.bottom
=rect
.top
+iconhei
*xscale
/yscale
;
197 ta
->setBoundingRectangle( this->rect
);
198 ta
->window().setSummary( "Note" );
200 // create StampAnnotation from path
201 else if ( typeString
== "Stamp" )
203 Okular::StampAnnotation
* sa
= new Okular::StampAnnotation();
205 sa
->setStampIconName( pixmapName
);
207 rect
.left
= qMin( startpoint
.x
, point
.x
);
208 rect
.top
= qMin( startpoint
.y
, point
.y
);
209 rect
.right
= qMax( startpoint
.x
, point
.x
);
210 rect
.bottom
= qMax( startpoint
.y
, point
.y
);
211 QRectF rcf
= rect
.geometry( (int)xscale
, (int)yscale
);
212 const int ml
= ( rcf
.bottomRight() - rcf
.topLeft() ).toPoint().manhattanLength();
213 if ( ml
<= QApplication::startDragDistance() )
215 double stampxscale
= size
/ xscale
;
216 double stampyscale
= size
/ yscale
;
219 rect
.left
= point
.x
- stampxscale
/ 2;
220 rect
.top
= point
.y
- stampyscale
/ 2;
227 rect
.right
= rect
.left
+ stampxscale
;
228 rect
.bottom
= rect
.top
+ stampyscale
;
230 sa
->setBoundingRectangle( rect
);
232 // create GeomAnnotation
233 else if ( typeString
== "GeomSquare" || typeString
== "GeomCircle" )
235 Okular::GeomAnnotation
* ga
= new Okular::GeomAnnotation();
238 if ( typeString
== "GeomSquare" )
239 ga
->setGeometricalType( Okular::GeomAnnotation::InscribedSquare
);
241 ga
->setGeometricalType( Okular::GeomAnnotation::InscribedCircle
);
242 ga
->style().setWidth( 5 );
244 rect
.left
= qMin( startpoint
.x
, point
.x
);
245 rect
.top
= qMin( startpoint
.y
, point
.y
);
246 rect
.right
= qMax( startpoint
.x
, point
.x
);
247 rect
.bottom
= qMax( startpoint
.y
, point
.y
);
248 ga
->setBoundingRectangle( rect
);
253 return QList
< Okular::Annotation
* >();
255 // set common attributes
256 ann
->style().setColor( m_annotElement
.hasAttribute( "color" ) ?
257 m_annotElement
.attribute( "color" ) : m_engineColor
);
258 if ( m_annotElement
.hasAttribute( "opacity" ) )
259 ann
->style().setOpacity( m_annotElement
.attribute( "opacity", "1.0" ).toDouble() );
262 return QList
< Okular::Annotation
* >() << ann
;
267 Okular::NormalizedRect rect
;
268 Okular::NormalizedPoint startpoint
;
269 Okular::NormalizedPoint point
;
273 double xscale
,yscale
;
274 double pagewidth
, pageheight
;
279 /** @short PolyLineEngine */
280 class PolyLineEngine
: public AnnotatorEngine
283 PolyLineEngine( const QDomElement
& engineElement
)
284 : AnnotatorEngine( engineElement
), last( false )
286 // parse engine specific attributes
287 m_block
= engineElement
.attribute( "block" ) == "true";
289 // numofpoints represents the max number of points for the current
290 // polygon/polyline, with a pair of exceptions:
291 // -1 means: the polyline must close on the first point (polygon)
292 // 0 means: construct as many points as you want, right-click
293 // to construct the last point
294 numofpoints
= engineElement
.attribute( "points" ).toInt( &ok
);
299 QRect
event( EventType type
, Button button
, double nX
, double nY
, double xScale
, double yScale
, const Okular::Page
* /*page*/ )
301 // only proceed if pressing left button
302 // if ( button != Left )
310 if ( button
== Right
)
313 // move the second point
314 else if ( type
== Move
)
318 QRect oldmovingrect
= movingrect
;
319 movingrect
= rect
| QRect( (int)( movingpoint
.x
* xScale
), (int)( movingpoint
.y
* yScale
), 1, 1 );
320 return oldmovingrect
| movingrect
;
322 else if ( type
== Release
)
324 Okular::NormalizedPoint tmppoint
;
327 if ( fabs( tmppoint
.x
- newPoint
.x
+ tmppoint
.y
- newPoint
.y
) > 1e-2 )
330 if ( numofpoints
== -1 && points
.count() > 1 && ( fabs( points
[0].x
- newPoint
.x
+ points
[0].y
- newPoint
.y
) < 1e-2 ) )
336 points
.append( newPoint
);
337 rect
|= QRect( (int)( newPoint
.x
* xScale
), (int)( newPoint
.y
* yScale
), 1, 1 );
339 // end creation if we have constructed the last point of enough points
340 if ( last
|| points
.count() == numofpoints
)
342 m_creationCompleted
= true;
344 normRect
= Okular::NormalizedRect( rect
, xScale
, yScale
);
351 void paint( QPainter
* painter
, double xScale
, double yScale
, const QRect
& /*clipRect*/ )
353 if ( points
.count() < 1 )
356 if ( m_block
&& points
.count() == 2 )
358 Okular::NormalizedPoint first
= points
[0];
359 Okular::NormalizedPoint second
= points
[1];
360 // draw a semitransparent block around the 2 points
361 painter
->setPen( m_engineColor
);
362 painter
->setBrush( QBrush( m_engineColor
.light(), Qt::Dense4Pattern
) );
363 painter
->drawRect( (int)(first
.x
* (double)xScale
), (int)(first
.y
* (double)yScale
),
364 (int)((second
.x
- first
.x
) * (double)xScale
), (int)((second
.y
- first
.y
) * (double)yScale
) );
368 // draw a polyline that connects the constructed points
369 painter
->setPen( QPen( m_engineColor
, 2 ) );
370 for ( int i
= 1; i
< points
.count(); ++i
)
371 painter
->drawLine( (int)(points
[i
- 1].x
* (double)xScale
), (int)(points
[i
- 1].y
* (double)yScale
),
372 (int)(points
[i
].x
* (double)xScale
), (int)(points
[i
].y
* (double)yScale
) );
373 painter
->drawLine( (int)(points
.last().x
* (double)xScale
), (int)(points
.last().y
* (double)yScale
),
374 (int)(movingpoint
.x
* (double)xScale
), (int)(movingpoint
.y
* (double)yScale
) );
378 QList
< Okular::Annotation
* > end()
380 m_creationCompleted
= false;
382 // find out annotation's description node
383 if ( m_annotElement
.isNull() )
384 return QList
< Okular::Annotation
* >();
386 // find out annotation's type
387 Okular::Annotation
* ann
= 0;
388 QString typeString
= m_annotElement
.attribute( "type" );
390 // create LineAnnotation from path
391 if ( typeString
== "Line" || typeString
== "Polyline" || typeString
== "Polygon" )
393 if ( points
.count() < 2 )
394 return QList
< Okular::Annotation
* >();
397 Okular::LineAnnotation
* la
= new Okular::LineAnnotation();
399 QLinkedList
<Okular::NormalizedPoint
> list
;
400 for ( int i
= 0; i
< points
.count(); ++i
)
401 list
.append( points
[ i
] );
403 la
->setLinePoints( list
);
405 if ( numofpoints
== -1 )
406 la
->setLineClosed( true );
408 la
->setBoundingRectangle( normRect
);
414 return QList
< Okular::Annotation
* >();
416 // set common attributes
417 ann
->style().setColor( m_annotElement
.hasAttribute( "color" ) ?
418 m_annotElement
.attribute( "color" ) : m_engineColor
);
419 if ( m_annotElement
.hasAttribute( "opacity" ) )
420 ann
->style().setOpacity( m_annotElement
.attribute( "opacity", "1.0" ).toDouble() );
423 return QList
< Okular::Annotation
* >() << ann
;
427 QList
<Okular::NormalizedPoint
> points
;
428 Okular::NormalizedPoint newPoint
;
429 Okular::NormalizedPoint movingpoint
;
432 Okular::NormalizedRect normRect
;
438 /** @short TextSelectorEngine */
439 class TextSelectorEngine
: public AnnotatorEngine
442 TextSelectorEngine( const QDomElement
& engineElement
, PageView
* pageView
)
443 : AnnotatorEngine( engineElement
), m_pageView( pageView
),
446 // parse engine specific attributes
449 ~TextSelectorEngine()
454 QRect
event( EventType type
, Button button
, double nX
, double nY
, double xScale
, double yScale
, const Okular::Page
* /*page*/ )
456 // only proceed if pressing left button
457 if ( button
!= Left
)
464 QRect oldrect
= rect
;
468 else if ( type
== Move
)
472 QPoint
start( (int)( lastPoint
.x
* item()->uncroppedWidth() ), (int)( lastPoint
.y
* item()->uncroppedHeight() ) );
473 QPoint
end( (int)( nX
* item()->uncroppedWidth() ), (int)( nY
* item()->uncroppedHeight() ) );
476 Okular::RegularAreaRect
* newselection
= m_pageView
->textSelectionForItem( item(), start
, end
);
477 if ( !newselection
->isEmpty() )
479 QList
<QRect
> geom
= newselection
->geometry( (int)xScale
, (int)yScale
);
481 Q_FOREACH ( const QRect
& r
, geom
)
483 if ( newrect
.isNull() )
489 selection
= newselection
;
497 else if ( type
== Release
&& selection
)
499 m_creationCompleted
= true;
504 void paint( QPainter
* painter
, double xScale
, double yScale
, const QRect
& /*clipRect*/ )
508 painter
->setPen( Qt::NoPen
);
509 QColor col
= m_engineColor
;
510 col
.setAlphaF( 0.5 );
511 painter
->setBrush( col
);
512 foreach( const Okular::NormalizedRect
& r
, *selection
)
514 painter
->drawRect( r
.geometry( (int)xScale
, (int)yScale
) );
519 QList
< Okular::Annotation
* > end()
521 m_creationCompleted
= false;
524 if ( m_annotElement
.isNull() || !selection
)
525 return QList
< Okular::Annotation
* >();
527 // find out annotation's type
528 Okular::Annotation
* ann
= 0;
529 QString typeString
= m_annotElement
.attribute( "type" );
531 Okular::HighlightAnnotation::HighlightType type
= Okular::HighlightAnnotation::Highlight
;
532 bool typevalid
= false;
533 // create HighlightAnnotation's from the selected area
534 if ( typeString
== "Highlight" )
536 type
= Okular::HighlightAnnotation::Highlight
;
539 else if ( typeString
== "Squiggly" )
541 type
= Okular::HighlightAnnotation::Squiggly
;
544 else if ( typeString
== "Underline" )
546 type
= Okular::HighlightAnnotation::Underline
;
549 else if ( typeString
== "StrikeOut" )
551 type
= Okular::HighlightAnnotation::StrikeOut
;
556 Okular::HighlightAnnotation
* ha
= new Okular::HighlightAnnotation();
557 ha
->setHighlightType( type
);
558 ha
->setBoundingRectangle( Okular::NormalizedRect( rect
, item()->uncroppedWidth(), item()->uncroppedHeight() ) );
559 foreach ( const Okular::NormalizedRect
& r
, *selection
)
561 Okular::HighlightAnnotation::Quad q
;
562 q
.setCapStart( false );
563 q
.setCapEnd( false );
565 q
.setPoint( Okular::NormalizedPoint( r
.left
, r
.bottom
), 0 );
566 q
.setPoint( Okular::NormalizedPoint( r
.right
, r
.bottom
), 1 );
567 q
.setPoint( Okular::NormalizedPoint( r
.right
, r
.top
), 2 );
568 q
.setPoint( Okular::NormalizedPoint( r
.left
, r
.top
), 3 );
569 ha
->highlightQuads().append( q
);
579 return QList
< Okular::Annotation
* >();
581 // set common attributes
582 ann
->style().setColor( m_annotElement
.hasAttribute( "color" ) ?
583 m_annotElement
.attribute( "color" ) : m_engineColor
);
584 if ( m_annotElement
.hasAttribute( "opacity" ) )
585 ann
->style().setOpacity( m_annotElement
.attribute( "opacity", "1.0" ).toDouble() );
587 // return annotations
588 return QList
< Okular::Annotation
* >() << ann
;
593 PageView
* m_pageView
;
594 // TODO: support more pages
595 Okular::RegularAreaRect
* selection
;
596 Okular::NormalizedPoint lastPoint
;
601 /** PageViewAnnotator **/
603 PageViewAnnotator::PageViewAnnotator( PageView
* parent
, Okular::Document
* storage
)
604 : QObject( parent
), m_document( storage
), m_pageView( parent
),
605 m_toolBar( 0 ), m_engine( 0 ), m_textToolsEnabled( false ), m_toolsEnabled( false ),
606 m_lastToolID( -1 ), m_lockedItem( 0 )
608 // load the tools from the 'xml tools definition' file. store the tree internally.
609 QFile
infoFile( KStandardDirs::locate("data", "okular/tools.xml") );
610 if ( infoFile
.exists() && infoFile
.open( QIODevice::ReadOnly
) )
612 QDomDocument
doc( "annotatingTools" );
613 if ( doc
.setContent( &infoFile
) )
615 m_toolsDefinition
= doc
.elementsByTagName("annotatingTools").item( 0 ).toElement();
617 // create the AnnotationToolItems from the XML dom tree
618 QDomNode toolDescription
= m_toolsDefinition
.firstChild();
619 while ( toolDescription
.isElement() )
621 QDomElement toolElement
= toolDescription
.toElement();
622 if ( toolElement
.tagName() == "tool" )
624 AnnotationToolItem item
;
625 item
.id
= toolElement
.attribute("id").toInt();
626 item
.text
= i18n( toolElement
.attribute( "name" ).toUtf8() );
627 item
.pixmap
= toolElement
.attribute("pixmap");
628 QDomNode shortcutNode
= toolElement
.elementsByTagName( "shortcut" ).item( 0 );
629 if ( shortcutNode
.isElement() )
630 item
.shortcut
= shortcutNode
.toElement().text();
631 QDomNodeList engineNodeList
= toolElement
.elementsByTagName( "engine" );
632 if ( engineNodeList
.size() > 0 )
634 QDomElement engineEl
= engineNodeList
.item( 0 ).toElement();
635 if ( !engineEl
.isNull() && engineEl
.hasAttribute( "type" ) )
636 item
.isText
= engineEl
.attribute( "type" ) == QLatin1String( "TextSelector" );
638 m_items
.push_back( item
);
640 toolDescription
= toolDescription
.nextSibling();
644 kWarning() << "AnnotatingTools XML file seems to be damaged";
648 kWarning() << "Unable to open AnnotatingTools XML definition";
651 PageViewAnnotator::~PageViewAnnotator()
656 void PageViewAnnotator::setEnabled( bool on
)
662 m_toolBar
->hideAndDestroy();
664 // deactivate the active tool, if any
665 slotToolSelected( -1 );
669 // if no tools are defined, don't show the toolbar
670 if ( !m_toolsDefinition
.hasChildNodes() )
676 m_toolBar
= new PageViewToolBar( m_pageView
, m_pageView
->viewport() );
677 m_toolBar
->setSide( (PageViewToolBar::Side
)Okular::Settings::editToolBarPlacement() );
678 m_toolBar
->setItems( m_items
);
679 m_toolBar
->setToolsEnabled( m_toolsEnabled
);
680 m_toolBar
->setTextToolsEnabled( m_textToolsEnabled
);
681 connect( m_toolBar
, SIGNAL( toolSelected(int) ),
682 this, SLOT( slotToolSelected(int) ) );
683 connect( m_toolBar
, SIGNAL( orientationChanged(int) ),
684 this, SLOT( slotSaveToolbarOrientation(int) ) );
688 m_toolBar
->showAndAnimate();
690 // ask for Author's name if not already set
691 if ( Okular::Settings::identityAuthor().isEmpty() )
693 // get default username from the kdelibs/kdecore/KUser
695 QString userName
= currentUser
.property( KUser::FullName
).toString();
696 // ask the user for confirmation/change
697 bool firstTry
= true;
698 while ( firstTry
|| userName
.isEmpty() )
700 QString prompt
= firstTry
? i18n( "Please insert your name or initials:" ) :
701 i18n( "You must set this name:" );
702 userName
= KInputDialog::getText( i18n("Annotations author"), prompt
, userName
);
706 Okular::Settings::setIdentityAuthor( userName
);
707 Okular::Settings::self()->writeConfig();
711 void PageViewAnnotator::setTextToolsEnabled( bool enabled
)
713 m_textToolsEnabled
= enabled
;
715 m_toolBar
->setTextToolsEnabled( m_textToolsEnabled
);
718 void PageViewAnnotator::setToolsEnabled( bool enabled
)
720 m_toolsEnabled
= enabled
;
722 m_toolBar
->setToolsEnabled( m_toolsEnabled
);
725 bool PageViewAnnotator::routeEvents() const
727 return m_engine
&& m_toolBar
;
730 QRect
PageViewAnnotator::routeEvent( QMouseEvent
* e
, PageViewItem
* item
)
732 if ( !item
) return QRect();
734 // find out mouse event type
735 AnnotatorEngine::EventType eventType
= AnnotatorEngine::Press
;
736 if ( e
->type() == QEvent::MouseMove
)
737 eventType
= AnnotatorEngine::Move
;
738 else if ( e
->type() == QEvent::MouseButtonRelease
)
739 eventType
= AnnotatorEngine::Release
;
741 // find out the pressed button
742 AnnotatorEngine::Button button
= AnnotatorEngine::None
;
743 Qt::MouseButtons buttonState
= ( eventType
== AnnotatorEngine::Move
) ? e
->buttons() : e
->button();
744 if ( buttonState
== Qt::LeftButton
)
745 button
= AnnotatorEngine::Left
;
746 else if ( buttonState
== Qt::RightButton
)
747 button
= AnnotatorEngine::Right
;
749 // find out normalized mouse coords inside current item
750 const QRect
& itemRect
= item
->uncroppedGeometry();
751 double nX
= item
->absToPageX(e
->x());
752 double nY
= item
->absToPageY(e
->y());
756 // 1. lock engine to current item
757 if ( m_lockedItem
&& item
!= m_lockedItem
)
759 if ( !m_lockedItem
&& eventType
== AnnotatorEngine::Press
)
762 m_engine
->setItem( m_lockedItem
);
765 // 2. use engine to perform operations
766 QRect paintRect
= m_engine
->event( eventType
, button
, nX
, nY
, itemRect
.width(), itemRect
.height(), item
->page() );
768 // 3. update absolute extents rect and send paint event(s)
769 if ( paintRect
.isValid() )
771 // 3.1. unite old and new painting regions
772 QRegion
compoundRegion( m_lastDrawnRect
);
773 m_lastDrawnRect
= paintRect
;
774 m_lastDrawnRect
.translate( itemRect
.left(), itemRect
.top() );
775 // 3.2. decompose paint region in rects and send paint events
776 QVector
<QRect
> rects
= compoundRegion
.unite( m_lastDrawnRect
).rects();
777 for ( int i
= 0; i
< rects
.count(); i
++ )
778 m_pageView
->widget()->update( rects
[i
] );
779 modifiedRect
= compoundRegion
.boundingRect() | m_lastDrawnRect
;
782 // 4. if engine has finished, apply Annotation to the page
783 if ( m_engine
->creationCompleted() )
785 // apply engine data to the Annotation's and reset engine
786 QList
< Okular::Annotation
* > annotations
= m_engine
->end();
787 // attach the newly filled annotations to the page
788 foreach ( Okular::Annotation
* annotation
, annotations
)
790 if ( !annotation
) continue;
792 annotation
->setCreationDate( QDateTime::currentDateTime() );
793 annotation
->setModificationDate( QDateTime::currentDateTime() );
794 annotation
->setAuthor( Okular::Settings::identityAuthor() );
795 m_document
->addPageAnnotation( m_lockedItem
->pageNumber(), annotation
);
798 // go on creating annotations of the same type
799 // for now, disable the "construct again the same annotation"
800 //slotToolSelected( m_lastToolID );
801 slotToolSelected( -1 );
802 m_toolBar
->selectButton( -1 );
808 bool PageViewAnnotator::routeKeyEvent( QKeyEvent
* event
)
810 if ( event
->key() == Qt::Key_Escape
)
812 m_toolBar
->selectButton( -1 );
818 bool PageViewAnnotator::routePaints( const QRect
& wantedRect
) const
820 return m_engine
&& m_toolBar
&& wantedRect
.intersects( m_lastDrawnRect
) && m_lockedItem
;
823 void PageViewAnnotator::routePaint( QPainter
* painter
, const QRect
& paintRect
)
825 // if there's no locked item, then there's no decided place to draw on
830 // [DEBUG] draw the paint region if enabled
831 if ( Okular::Settings::debugDrawAnnotationRect() )
832 painter
->drawRect( paintRect
);
834 // move painter to current itemGeometry rect
835 const QRect
& itemRect
= m_lockedItem
->uncroppedGeometry();
837 painter
->translate( itemRect
.topLeft() );
838 // TODO: Clip annotation painting to cropped page.
840 // transform cliprect from absolute to item relative coords
841 QRect annotRect
= paintRect
.intersect( m_lastDrawnRect
);
842 annotRect
.translate( -itemRect
.topLeft() );
844 // use current engine for painting (in virtual page coordinates)
845 m_engine
->paint( painter
, m_lockedItem
->uncroppedWidth(), m_lockedItem
->uncroppedHeight(), annotRect
);
849 void PageViewAnnotator::slotToolSelected( int toolID
)
851 // terminate any previous operation
858 if ( m_lastDrawnRect
.isValid() )
860 m_pageView
->widget()->update( m_lastDrawnRect
);
861 m_lastDrawnRect
= QRect();
864 // store current tool for later usage
865 m_lastToolID
= toolID
;
867 // handle tool deselection
870 m_pageView
->displayMessage( QString() );
874 // for the selected tool create the Engine
875 QDomNode toolNode
= m_toolsDefinition
.firstChild();
876 while ( toolNode
.isElement() )
878 QDomElement toolElement
= toolNode
.toElement();
879 toolNode
= toolNode
.nextSibling();
881 // only find out the element describing selected tool
882 if ( toolElement
.tagName() != "tool" || toolElement
.attribute("id").toInt() != toolID
)
885 // parse tool properties
886 QDomNode toolSubNode
= toolElement
.firstChild();
887 while ( toolSubNode
.isElement() )
889 QDomElement toolSubElement
= toolSubNode
.toElement();
890 toolSubNode
= toolSubNode
.nextSibling();
892 // create the AnnotatorEngine
893 if ( toolSubElement
.tagName() == "engine" )
895 QString type
= toolSubElement
.attribute( "type" );
896 if ( type
== "SmoothLine" )
897 m_engine
= new SmoothPathEngine( toolSubElement
);
898 else if ( type
== "PickPoint" )
899 m_engine
= new PickPointEngine( toolSubElement
);
900 else if ( type
== "PolyLine" )
901 m_engine
= new PolyLineEngine( toolSubElement
);
902 else if ( type
== "TextSelector" )
903 m_engine
= new TextSelectorEngine( toolSubElement
, m_pageView
);
905 kWarning().nospace() << "tools.xml: engine type:'" << type
<< "' is not defined!";
907 // display the tooltip
908 else if ( toolSubElement
.tagName() == "tooltip" )
910 QString tip
= toolSubElement
.text();
911 if ( !tip
.isEmpty() )
912 m_pageView
->displayMessage( i18nc( "Annotation tool", tip
.toUtf8() ), PageViewMessage::Annotation
);
916 // consistancy warning
918 kWarning() << "tools.xml: couldn't find good engine description. check xml.";
920 // stop after parsing selected tool's node
925 void PageViewAnnotator::slotSaveToolbarOrientation( int side
)
927 Okular::Settings::setEditToolBarPlacement( (int)side
);
928 Okular::Settings::self()->writeConfig();
931 #include "pageviewannotator.moc"