1 /**
2  * Copyright (C) 2011-2012  Charlie Sharpsteen, Stefan Löffler
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the Free
6  * Software Foundation; either version 2, or (at your option) any later
7  * version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  */
14 #ifndef PDFDocumentView_H
15 #define PDFDocumentView_H
16 
17 #if QT_VERSION_MAJOR < 5
18   #include <QtGui/QtGui>
19 #else
20   #include <QtWidgets>
21 #endif
22 
23 #include <PDFBackend.h>
24 #include <PDFDocumentTools.h>
25 
26 namespace QtPDF {
27 
28 // Forward declare classes defined in this header.
29 class PDFDocumentScene;
30 class PDFPageGraphicsItem;
31 class PDFLinkGraphicsItem;
32 class PDFDocumentMagnifierView;
33 class PDFActionEvent;
34 class PDFDocumentView;
35 
36 
37 const int TILE_SIZE=1024;
38 
39 class PDFDocumentView : public QGraphicsView {
40   Q_OBJECT
41   typedef QGraphicsView Super;
42 
43   QSharedPointer<PDFDocumentScene> _pdf_scene;
44 
45   qreal _zoomLevel;
46   int _currentPage, _lastPage;
47 
48   QString _searchString;
49   QList<QGraphicsItem *> _searchResults;
50   QFutureWatcher< QList<Backend::SearchResult> > _searchResultWatcher;
51   int _currentSearchResult;
52   QBrush _searchResultHighlightBrush;
53   QBrush _currentSearchResultHighlightBrush;
54   bool _useGrayScale;
55 
56   friend class DocumentTool::AbstractTool;
57 
58 public:
59   enum PageMode { PageMode_SinglePage, PageMode_OneColumnContinuous, PageMode_TwoColumnContinuous, PageMode_Presentation };
60   enum MouseMode { MouseMode_MagnifyingGlass, MouseMode_Move, MouseMode_MarqueeZoom, MouseMode_Measure, MouseMode_Select };
61   enum Dock { Dock_TableOfContents, Dock_MetaData, Dock_Fonts, Dock_Permissions, Dock_Annotations };
62 
63   PDFDocumentView(QWidget *parent = 0);
64   ~PDFDocumentView();
65   void setScene(QSharedPointer<PDFDocumentScene> a_scene);
66   int currentPage();
67   int lastPage();
pageMode()68   PageMode pageMode() const { return _pageMode; }
zoomLevel()69   qreal zoomLevel() const { return _zoomLevel; }
useGrayScale()70   bool useGrayScale() const { return _useGrayScale; }
71   void fitInView(const QRectF & rect, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio);
72 
73   // The ownership of the returned pointers is transferred to the caller (i.e.,
74   // he has to destroy them, unless the `parent` widget does that automatically)
75   // They are fully wired to this PDFDocumentView (e.g., clicking on entries in
76   // the table of contents will change this view)
77   QDockWidget * dockWidget(const Dock type, QWidget * parent = NULL);
78 
armedTool()79   DocumentTool::AbstractTool * armedTool() const { return _armedTool; }
triggerContextClick(const int page,const QPointF pos)80   void triggerContextClick(const int page, const QPointF pos) { emit contextClick(page, pos); }
81 
82   QGraphicsPathItem * addHighlightPath(const unsigned int page, const QPainterPath & path, const QBrush & brush, const QPen & pen = Qt::NoPen);
83   QGraphicsPathItem * addHighlightPath(const unsigned int page, const QRectF & rect, const QBrush & brush, const QPen & pen = Qt::NoPen) {
84     QPainterPath p;
85     p.addRect(rect);
86     return addHighlightPath(page, p, brush, pen);
87   }
88   QGraphicsPathItem * addHighlightPath(const unsigned int page, const QPainterPath & path, const QColor color, const QPen & pen = Qt::NoPen) {
89     return addHighlightPath(page, path, QBrush(color), pen);
90   }
91 
searchResultHighlightBrush()92   QBrush searchResultHighlightBrush() const { return _searchResultHighlightBrush; }
93   void setSearchResultHighlightBrush(const QBrush & brush);
94 
currentSearchResultHighlightBrush()95   QBrush currentSearchResultHighlightBrush() const { return _currentSearchResultHighlightBrush; }
96   void setCurrentSearchResultHighlightBrush(const QBrush & brush);
97 
canGoPrevViewRects()98   bool canGoPrevViewRects() const { return !_oldViewRects.empty(); }
99 
100 public slots:
101   void goPrev();
102   void goNext();
103   void goFirst();
104   void goLast();
105   void goPrevViewRect();
106   // `alignment` can be (a combination of) 0, Qt::AlignLeft, Qt::AlignRight,
107   // Qt::AlignHCenter, Qt::AlignTop, Qt::AlignBottom, Qt::AlignVCenter.
108   // 0 corresponds to no alignment, i.e., the view will change so that the
109   // rectangle of page pageNum closest to the original viewport rect is visible.
110   void goToPage(const int pageNum, const int alignment = Qt::AlignLeft | Qt::AlignTop);
111   // Similar to the one above, but view is aligned at `anchor`. Note that the
112   // default alignment is centering here, which is also used if `alignment` == 0.
113   // `anchor` must be given in item coordinates
114   void goToPage(const int pageNum, const QPointF anchor, const int alignment = Qt::AlignHCenter | Qt::AlignVCenter);
115   void goToPDFDestination(const PDFDestination & dest, bool saveOldViewRect = true);
116   void setPageMode(const PageMode pageMode, const bool forceRelayout = false);
setSinglePageMode()117   void setSinglePageMode() { setPageMode(PageMode_SinglePage); }
setOneColContPageMode()118   void setOneColContPageMode() { setPageMode(PageMode_OneColumnContinuous); }
setTwoColContPageMode()119   void setTwoColContPageMode() { setPageMode(PageMode_TwoColumnContinuous); }
setPresentationMode()120   void setPresentationMode() { setPageMode(PageMode_Presentation); }
121   void setMouseMode(const MouseMode newMode);
setMouseModeMagnifyingGlass()122   void setMouseModeMagnifyingGlass() { setMouseMode(MouseMode_MagnifyingGlass); }
setMouseModeMove()123   void setMouseModeMove() { setMouseMode(MouseMode_Move); }
setMouseModeMarqueeZoom()124   void setMouseModeMarqueeZoom() { setMouseMode(MouseMode_MarqueeZoom); }
setMouseModeMeasure()125   void setMouseModeMeasure() { setMouseMode(MouseMode_Measure); }
setMouseModeSelect()126   void setMouseModeSelect() { setMouseMode(MouseMode_Select); }
127   void setMagnifierShape(const DocumentTool::MagnifyingGlass::MagnifierShape shape);
128   void setMagnifierSize(const int size);
129   void setUseGrayScale(const bool grayScale = true) { _useGrayScale = grayScale; }
130 
131   void zoomBy(const qreal zoomFactor, const QGraphicsView::ViewportAnchor anchor = QGraphicsView::AnchorViewCenter);
132   void zoomIn(const QGraphicsView::ViewportAnchor anchor = QGraphicsView::AnchorViewCenter);
133   void zoomOut(const QGraphicsView::ViewportAnchor anchor = QGraphicsView::AnchorViewCenter);
134   void zoomToRect(QRectF a_rect);
135   void zoomFitWindow();
136   void zoomFitWidth();
137   void zoom100();
138   void setZoomLevel(const qreal zoomLevel, const QGraphicsView::ViewportAnchor anchor = QGraphicsView::AnchorViewCenter);
139 
140   void search(QString searchText, Backend::SearchFlags flags = Backend::Search_CaseInsensitive);
141   void nextSearchResult();
142   void previousSearchResult();
143   void clearSearchResults();
144 
145 signals:
146   void changedPage(int pageNum);
147   void changedZoom(qreal zoomLevel);
148   void changedPageMode(QtPDF::PDFDocumentView::PageMode newMode);
149   // emitted, e.g., if a new document was loaded, or if the existing document
150   // has changed (e.g., if it was unlocked)
151   void changedDocument(const QWeakPointer<QtPDF::Backend::Document> newDoc);
152 
153   void searchProgressChanged(int percent, int occurrences);
154   void searchResultHighlighted(const int pageNum, const QList<QPolygonF> region);
155 
156   void requestOpenUrl(const QUrl url);
157   void requestExecuteCommand(QString command);
158   void requestOpenPdf(QString filename, QtPDF::PDFDestination destination, bool newWindow);
159   void contextClick(const int page, const QPointF pos);
160 
161 protected:
162   // Keep track of the current page by overloading the widget paint event.
163   void paintEvent(QPaintEvent *event);
164   void keyPressEvent(QKeyEvent *event);
165   void keyReleaseEvent(QKeyEvent *event);
166   void mousePressEvent(QMouseEvent * event);
167   void mouseMoveEvent(QMouseEvent * event);
168   void mouseReleaseEvent(QMouseEvent * event);
169   void wheelEvent(QWheelEvent * event);
170   void changeEvent(QEvent * event);
171 
172   // Maybe this will become public later on
173   // Ownership of tool is transferred to PDFDocumentView
174   void registerTool(DocumentTool::AbstractTool * tool);
175 
176   DocumentTool::AbstractTool * getToolByType(const DocumentTool::AbstractTool::Type type);
177 
178   void armTool(const DocumentTool::AbstractTool::Type toolType);
179   void armTool(DocumentTool::AbstractTool * tool);
180   void disarmTool();
181 
182 protected slots:
183   void maybeUpdateSceneRect();
184   void maybeArmTool(uint modifiers);
185   void pdfActionTriggered(const QtPDF::PDFAction * action);
186   // Note: view specifies which part of the page should be visible and must
187   // therefore be given in page coordinates
188   void goToPage(const PDFPageGraphicsItem * page, const QRectF view, const bool mayZoom = false);
189   void goToPage(const PDFPageGraphicsItem * page, const int alignment = Qt::AlignLeft | Qt::AlignTop);
190   void goToPage(const PDFPageGraphicsItem * page, const QPointF anchor, const int alignment = Qt::AlignHCenter | Qt::AlignVCenter);
191   void searchResultReady(int index);
192   void searchProgressValueChanged(int progressValue);
193   void switchInterfaceLocale(const QLocale & newLocale);
194   void reinitializeFromScene();
195 
196 private:
197   PageMode _pageMode;
198   MouseMode _mouseMode;
199   QCursor _hiddenCursor;
200   QVector<DocumentTool::AbstractTool*> _tools;
201   DocumentTool::AbstractTool * _armedTool;
202   QMap<uint, DocumentTool::AbstractTool*> _toolAccessors;
203 
204   QStack<PDFDestination> _oldViewRects;
205 
206   static QTranslator * _translator;
207   static QString _translatorLanguage;
208 
209   // Never try to set a vanilla QGraphicsScene, always use a PDFGraphicsScene.
210   void setScene(QGraphicsScene *scene);
211   // Parent class has no copy constructor.
212   Q_DISABLE_COPY(PDFDocumentView)
213 };
214 
215 class PDFDocumentMagnifierView : public QGraphicsView {
216   Q_OBJECT
217   typedef QGraphicsView Super;
218 
219   PDFDocumentView * _parent_view;
220   qreal _zoomLevel, _zoomFactor;
221 
222   DocumentTool::MagnifyingGlass::MagnifierShape _shape;
223   int _size;
224 
225 public:
226   PDFDocumentMagnifierView(PDFDocumentView *parent = 0);
227   // the zoom factor multiplies the parent view's _zoomLevel
228   void setZoomFactor(const qreal zoomFactor);
229   void setPosition(const QPoint pos);
setShape(const DocumentTool::MagnifyingGlass::MagnifierShape shape)230   void setShape(const DocumentTool::MagnifyingGlass::MagnifierShape shape) { setSizeAndShape(_size, shape); }
setSize(const int size)231   void setSize(const int size) { setSizeAndShape(size, _shape); }
232   void setSizeAndShape(const int size, const DocumentTool::MagnifyingGlass::MagnifierShape shape);
233   // ensures all settings are in sync with the parent view
234   // make sure you call it before calling show()!
235   // Note: we cannot override show() because prepareToShow() usually needs to be
236   // called before setPosition as well (as it adjusts the region accessible in
237   // setPosition())
238   void prepareToShow();
239 
240   QPixmap& dropShadow();
241 
242 protected:
wheelEvent(QWheelEvent * event)243   void wheelEvent(QWheelEvent * event) { event->ignore(); }
244   void paintEvent(QPaintEvent * event);
245 
246   QPixmap _dropShadow;
247 };
248 
249 
250 class PDFDocumentInfoWidget : public QWidget
251 {
252   Q_OBJECT
253   friend class PDFDocumentView;
254 public:
QWidget(parent)255   PDFDocumentInfoWidget(QWidget * parent = NULL, const QString & title = QString(), const QString & objectName = QString()) : QWidget(parent) { setObjectName(objectName); setWindowTitle(title); }
~PDFDocumentInfoWidget()256   virtual ~PDFDocumentInfoWidget() { }
257   // If the widget has a fixed size, it should not be resized (it can, e.g., be
258   // put into a QScrollArea instead).
259 public slots:
260   void setWindowTitle(const QString & windowTitle);
261 signals:
262   void windowTitleChanged(const QString &);
263 protected slots:
initFromDocument(const QWeakPointer<QtPDF::Backend::Document> doc)264   virtual void initFromDocument(const QWeakPointer<QtPDF::Backend::Document> doc) { _doc = doc; }
retranslateUi()265   virtual void retranslateUi() { };
266   virtual void clear() = 0;
267 protected:
268   virtual void changeEvent(QEvent * event);
269   // we need to keep a reference to the document to allow dynamic lookup of data
270   // (e.g., when retranslating the widget)
271   QWeakPointer<QtPDF::Backend::Document> _doc;
272 };
273 
274 class PDFToCInfoWidget : public PDFDocumentInfoWidget
275 {
276   Q_OBJECT
277 public:
278   PDFToCInfoWidget(QWidget * parent);
279   virtual ~PDFToCInfoWidget();
280 
281 protected slots:
282   void initFromDocument(const QWeakPointer<QtPDF::Backend::Document> newDoc);
283   void clear();
284   virtual void retranslateUi();
285 signals:
286   void actionTriggered(const QtPDF::PDFAction*);
287 private slots:
288   void itemSelectionChanged();
289 private:
290   static void recursiveAddTreeItems(const QList<Backend::PDFToCItem> & tocItems, QTreeWidgetItem * parentTreeItem);
291   static void recursiveClearTreeItems(QTreeWidgetItem * parent);
292   QTreeWidget * _tree;
293 };
294 
295 class PDFMetaDataInfoWidget : public PDFDocumentInfoWidget
296 {
297   Q_OBJECT
298 public:
299   PDFMetaDataInfoWidget(QWidget * parent);
~PDFMetaDataInfoWidget()300   virtual ~PDFMetaDataInfoWidget() { }
301 
302 protected slots:
303   void initFromDocument(const QWeakPointer<QtPDF::Backend::Document> doc);
304   void clear();
305   virtual void retranslateUi();
306   void reload();
307 private:
308   QGroupBox * _documentGroup;
309   QLabel * _title, * _titleLabel;
310   QLabel * _author, * _authorLabel;
311   QLabel * _subject, * _subjectLabel;
312   QLabel * _keywords, * _keywordsLabel;
313   QGroupBox * _processingGroup;
314   QLabel * _creator, * _creatorLabel;
315   QLabel * _producer, * _producerLabel;
316   QLabel * _creationDate, * _creationDateLabel;
317   QLabel * _modDate, * _modDateLabel;
318   QLabel * _trapped, * _trappedLabel;
319   QGroupBox * _otherGroup;
320 };
321 
322 class PDFFontsInfoWidget : public PDFDocumentInfoWidget
323 {
324   Q_OBJECT
325 public:
326   PDFFontsInfoWidget(QWidget * parent);
~PDFFontsInfoWidget()327   virtual ~PDFFontsInfoWidget() { }
328 
329 protected slots:
330   void initFromDocument(const QWeakPointer<QtPDF::Backend::Document> doc);
331   void clear();
332   virtual void retranslateUi();
333   void reload();
334 protected:
showEvent(QShowEvent * event)335   virtual void showEvent(QShowEvent * event) { initFromDocument(_doc); }
336 private:
337   QTableWidget * _table;
338 };
339 
340 class PDFPermissionsInfoWidget : public PDFDocumentInfoWidget
341 {
342   Q_OBJECT
343 public:
344   PDFPermissionsInfoWidget(QWidget * parent);
~PDFPermissionsInfoWidget()345   virtual ~PDFPermissionsInfoWidget() { }
346 
347 protected slots:
348   void initFromDocument(const QWeakPointer<QtPDF::Backend::Document> doc);
349   void clear();
350   virtual void retranslateUi();
351   void reload();
352 private:
353   QLabel * _print, * _printLabel;
354   QLabel * _modify, * _modifyLabel;
355   QLabel * _extract, * _extractLabel;
356   QLabel * _addNotes, * _addNotesLabel;
357   QLabel * _form, * _formLabel;
358 };
359 
360 class PDFAnnotationsInfoWidget : public PDFDocumentInfoWidget
361 {
362   Q_OBJECT
363 
364   QFutureWatcher< QList< QSharedPointer<Annotation::AbstractAnnotation> > > _annotWatcher;
365   QTableWidget * _table;
366 
367   static QList< QSharedPointer<Annotation::AbstractAnnotation> > loadAnnotations(QWeakPointer<Backend::Page> thePage);
368 
369 public:
370   PDFAnnotationsInfoWidget(QWidget * parent);
~PDFAnnotationsInfoWidget()371   virtual ~PDFAnnotationsInfoWidget() { }
372 
373 protected slots:
374   void initFromDocument(const QWeakPointer<QtPDF::Backend::Document> newDoc);
375   void clear();
376   virtual void retranslateUi();
377   void annotationsReady(int index);
378 };
379 
380 // Cannot use QGraphicsGridLayout and similar classes for pages because it only
381 // works for QGraphicsLayoutItem (i.e., QGraphicsWidget)
382 class PDFPageLayout : public QObject {
383   Q_OBJECT
384   struct LayoutItem {
385     PDFPageGraphicsItem * page;
386     int row;
387     int col;
388   };
389 
390   QList<LayoutItem> _layoutItems;
391   int _numCols;
392   int _firstCol;
393   qreal _xSpacing; // spacing in pixel @ zoom=1
394   qreal _ySpacing;
395   bool _isContinuous;
396 
397 public:
398   PDFPageLayout();
~PDFPageLayout()399   virtual ~PDFPageLayout() { }
columnCount()400   int columnCount() const { return _numCols; }
firstColumn()401   int firstColumn() const { return _firstCol; }
xSpacing()402   qreal xSpacing() const { return _xSpacing; }
ySpacing()403   qreal ySpacing() const { return _ySpacing; }
isContinuous()404   bool isContinuous() const { return _isContinuous; }
405   void setContinuous(const bool continuous = true);
406 
407   void setColumnCount(const int numCols);
408   void setColumnCount(const int numCols, const int firstCol);
409   void setFirstColumn(const int firstCol);
410   void setXSpacing(const qreal xSpacing);
411   void setYSpacing(const qreal ySpacing);
412   int rowCount() const;
413 
414   void addPage(PDFPageGraphicsItem * page);
415   void removePage(PDFPageGraphicsItem * page);
416   void insertPage(PDFPageGraphicsItem * page, PDFPageGraphicsItem * before = NULL);
clearPages()417   void clearPages() { _layoutItems.clear(); }
418 
419 public slots:
420   void relayout();
421 
422 signals:
423   void layoutChanged(const QRectF sceneRect);
424 
425 private:
426   void rearrange();
427   void continuousModeRelayout();
428   void singlePageModeRelayout();
429 };
430 
431 
432 class PDFDocumentScene : public QGraphicsScene
433 {
434   Q_OBJECT
435   typedef QGraphicsScene Super;
436 
437   const QSharedPointer<Backend::Document> _doc;
438 
439   // This may change to a `QSet` in the future
440   QList<QGraphicsItem*> _pages;
441   int _lastPage;
442   PDFPageLayout _pageLayout;
443   QFileSystemWatcher _fileWatcher;
444   QTimer _reloadTimer;
445   double _dpiX, _dpiY;
446 
447   void handleActionEvent(const PDFActionEvent * action_event);
448 
449 public:
450   PDFDocumentScene(QSharedPointer<Backend::Document> a_doc, QObject *parent = 0, const double dpiX = -1, const double dpiY = -1);
451 
452   QWeakPointer<Backend::Document> document();
453   QList<QGraphicsItem*> pages();
454   QList<QGraphicsItem*> pages(const QPolygonF &polygon);
455   QGraphicsItem* pageAt(const int idx);
456   QGraphicsItem* pageAt(const QPointF &pt);
457   int pageNumAt(const QPolygonF &polygon);
458   int pageNumAt(const QPointF &pt);
459   int pageNumFor(const PDFPageGraphicsItem * const graphicsItem) const;
pageLayout()460   PDFPageLayout& pageLayout() { return _pageLayout; }
461 
462   void showOnePage(const int pageIdx);
463   void showOnePage(const PDFPageGraphicsItem * page);
464   void showAllPages();
465 
watchForDocumentChangesOnDisk()466   bool watchForDocumentChangesOnDisk() const { return _fileWatcher.files().size() > 0; }
467   void setWatchForDocumentChangesOnDisk(const bool doWatch = true);
468 
469   int lastPage();
470 
document()471   const QWeakPointer<Backend::Document> document() const { return _doc.toWeakRef(); }
472 
473   void setResolution(const double dpiX, const double dpiY);
474 
475 signals:
476   void pageChangeRequested(int pageNum);
477   void pageLayoutChanged();
478   void pdfActionTriggered(const QtPDF::PDFAction * action);
479   void documentChanged(const QWeakPointer<QtPDF::Backend::Document> doc);
480 
481 public slots:
482   void doUnlockDialog();
483   void retranslateUi();
484   void reloadDocument();
485 
486 protected slots:
487   void pageLayoutChanged(const QRectF& sceneRect);
488   void reinitializeScene();
489   void finishUnlock();
490 
491 protected:
492   // Used in non-continuous mode to keep track of currently shown page across
493   // reloads. -2 is used in continuous mode. -1 indicates an invalid value.
494   int _shownPageIdx;
495   bool event(QEvent* event);
496 
497   QWidget * _unlockWidget;
498   QLabel * _unlockWidgetLockText, * _unlockWidgetLockIcon;
499   QPushButton * _unlockWidgetUnlockButton;
500 
501 private:
502   // Parent has no copy constructor, so this class shouldn't either. Also, we
503   // hold some information in an `auto_ptr` which does interesting things on
504   // copy that C++ newbies may not expect.
505   Q_DISABLE_COPY(PDFDocumentScene)
506 };
507 
508 
509 // Inherits from `QGraphicsOject` instead of `QGraphicsItem` in order to
510 // support SIGNALS/SLOTS used by threaded rendering.
511 //
512 // NOTE: __`QGraphicsObject` was added in Qt 4.6__
513 class PDFPageGraphicsItem : public QGraphicsObject
514 {
515   Q_OBJECT
516   typedef QGraphicsObject Super;
517 
518   QWeakPointer<Backend::Page> _page;
519 
520   double _dpiX;
521   double _dpiY;
522   // the nominal (i.e., unmagnified) page size in pixel
523   QSizeF _pageSize;
524   int _pageNum;
525 
526   bool _linksLoaded;
527   bool _annotationsLoaded;
528 
529   QTransform _pageScale, _pointScale;
530   qreal _zoomLevel;
531 
532   friend class PageProcessingRenderPageRequest;
533   friend class PageProcessingLoadLinksRequest;
534 //  friend class PDFPageLayout;
535 
536   static void imageToGrayScale(QImage & img);
537 
538 public:
539   PDFPageGraphicsItem(QWeakPointer<Backend::Page> a_page, const double dpiX, const double dpiY, QGraphicsItem *parent = 0);
540 
541   // This seems fragile as it assumes no other code declaring a custom graphics
542   // item will choose the same ID for it's object types. Unfortunately, there
543   // appears to be no equivalent of `registerEventType` for `QGraphicsItem`
544   // subclasses.
545   enum { Type = UserType + 1 };
546   int type() const;
547 
548   void paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
549 
550   virtual QRectF boundingRect() const;
551 
page()552   QWeakPointer<Backend::Page> page() const { return _page; }
553 
554   // Maps the point _point_ from the page's coordinate system (in pt) to this
555   // item's coordinate system - chain with mapToScene and related methods to get
556   // coordinates in other systems
557   QPointF mapFromPage(const QPointF & point) const;
558   // Maps the point _point_ from the item's coordinate system to the page's
559   // coordinate system (in pt) - chain with mapFromScene and related methods to
560   // convert from coordinates in other systems
561   QPointF mapToPage(const QPointF & point) const;
562 
pageScale()563   QTransform pageScale() { return _pageScale; }
pointScale()564   QTransform pointScale() { return _pointScale; }
565 
566   // get the nominal (i.e., unmagnified) page size in pixel
pageSizeF()567   QSizeF pageSizeF() const { return _pageSize; }
pageNum()568   int pageNum() const { return _pageNum; }
569 
570 protected:
571   bool event(QEvent *event);
572 
573 private:
574   // Parent has no copy constructor.
575   Q_DISABLE_COPY(PDFPageGraphicsItem)
576 
577 private slots:
578   void addLinks(QList< QSharedPointer<Annotation::Link> > links);
579   void addAnnotations(QList< QSharedPointer<Annotation::AbstractAnnotation> > annotations);
580 };
581 
582 // TODO: Should be turned into a QGraphicsPolygonItem
583 class PDFLinkGraphicsItem : public QGraphicsRectItem {
584   typedef QGraphicsRectItem Super;
585 
586   QSharedPointer<Annotation::Link> _link;
587   bool _activated;
588 
589 public:
590   PDFLinkGraphicsItem(QSharedPointer<Annotation::Link> a_link, QGraphicsItem *parent = 0);
591   // See concerns in `PDFPageGraphicsItem` for why this feels fragile.
592   enum { Type = UserType + 2 };
593   int type() const;
594   void retranslateUi();
595 
596 protected:
597   void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
598   void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
599 
600   void mousePressEvent(QGraphicsSceneMouseEvent *event);
601   void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
602 
603 private:
604   // Parent class has no copy constructor.
605   Q_DISABLE_COPY(PDFLinkGraphicsItem)
606 };
607 
608 
609 // TODO: Should be turned into a QGraphicsPolygonItem
610 class PDFMarkupAnnotationGraphicsItem : public QGraphicsRectItem {
611   typedef QGraphicsRectItem Super;
612 
613   QSharedPointer<Annotation::Markup> _annot;
614   bool _activated;
615   QWidget * _popup;
616 
617 public:
618   PDFMarkupAnnotationGraphicsItem(QSharedPointer<Annotation::Markup> annot, QGraphicsItem *parent = 0);
619   // See concerns in `PDFPageGraphicsItem` for why this feels fragile.
620   enum { Type = UserType + 3 };
621   int type() const;
622 
623 protected:
624   void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
625   void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
626 
627   void mousePressEvent(QGraphicsSceneMouseEvent *event);
628   void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
629 
630 private:
631   // Parent class has no copy constructor.
632   Q_DISABLE_COPY(PDFMarkupAnnotationGraphicsItem)
633 };
634 
635 class PDFActionEvent : public QEvent {
636   typedef QEvent Super;
637 
638 public:
639   PDFActionEvent(const PDFAction * action);
640   static QEvent::Type ActionEvent;
641   const PDFAction * action;
642 };
643 
644 } // namespace QtPDF
645 
646 // Note: Q_DECLARE_METATYPE must be specified _outside_ any namespace
647 // declaration (according to Qt docs)
648 
649 // We need to declare a QList<PDFLinkGraphicsItem *> meta-type so we can
650 // pass it through inter-thread (i.e., queued) connections
651 Q_DECLARE_METATYPE(QList<QtPDF::PDFLinkGraphicsItem *>)
652 // We need to declare a QList<PDFMarkupAnnotationGraphicsItem *> meta-type so we can
653 // pass it through inter-thread (i.e., queued) connections
654 Q_DECLARE_METATYPE(QList<QtPDF::PDFMarkupAnnotationGraphicsItem *>)
655 
656 
657 #endif // End header include guard
658 
659 // vim: set sw=2 ts=2 et
660